创建线程的几种方式(二)

186 阅读1分钟

实现Runnable接口的run方法

跟上一种方式一样,我们既可以显式声明一个实现类来实现Runnable接口,可以直接使用匿名类

显式声明实现类

  private void createThread4(){
    Thread thread = new Thread(new myRunnable());
    thread.start();
  }

  class myRunnable implements Runnable{
    @Override
    public void run() {
      System.out.println("Thread4 started");
    }
  }

使用匿名类

  private void createThread5(){
    Runnable runnable = new Runnable() {
      @Override
      public void run() {
        System.out.println("Thread5 started");
      }
    };
    Thread thread = new Thread(runnable);
    thread.start();
  }

实现Callable接口

从代码可以看出,实现Runnable的方式也很简单,但是无法获取run方法的返回值,这在很多场景下是无法接受的.如何获取线程的返回值呢?

实现Callable接口的call方法.Callable是个泛型接口,你可以根据需要指定具体类型来表示返回值类型,在实现call方法时返回该类型,具体如下:

  private void createThread6(){
    Callable<Integer> callable = new Callable<Integer>() {
      @Override
      public Integer call() throws Exception {
        return 10;
      }
    };
    //Callable<Integer> callable = () -> 10;
    FutureTask<Integer> futureTask = new FutureTask<>(callable);
    Thread thread = new Thread(futureTask);
    thread.start();
    try {
      System.out.println("Thread4 started");
      int result = futureTask.get();
      System.out.println(result);
    } catch (InterruptedException e) {
      e.printStackTrace();
    } catch (ExecutionException e) {
      e.printStackTrace();
    }
  }

上面显式实现了Callable接口,当然,你也可以使用匿名类或lambda表达式来实现,大家可以作为练习.然后声明FutureTask来获取该线程的返回值.因为FutureTask也实现了Runnable接口,所以我们把它作为参数传递给Thread对象,等线程启动后后调用FutureTask的get方法来获取返回值.

注意:必须先启动线程再调用FutureTask的get方法,因为该方法会阻塞当前线程,如果先调用它,而执行它的线程未启动(没有调用该线程的start方法)那么它后面的代码将永远无法得到运行.

总结

上面三种方式本质上也是一类:实现Runnable接口! Callable可以看作Runnable的变体.在下篇文章中我们将介绍如何使用线程池来创建线程