JUC创建线程的第三种方式-Callable

377 阅读2分钟

创建线程的三种方式,前两种就不多说了,分别是继承Thread类与实现Runnable接口,这次讲的是第三种Callable接口。首先,先对比一下Runnable接口和Callable接口的区别

//Runnable接口
class MyThreadRunnable implements Runnable {
    @Override
    public void run() {
      
    }
}

//Callable
class MyThreadCallable implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        System.out.println("come in here");
        return 1024;
    }
}

可以看到Callable接口存在泛型,并且方法有返回值,这是对原来老技术的增强,因为存在了返回值,所以提高了线程的细粒度。

创建Callable线程的方式

  • 如果直接创建线程,传入实现了Callable接口的类,会提示错误 原因是Thread并不存在Callable的构造器

这里我们就要借用另一个类FutureTask,这个类实现了RunnableFuture接口,且该接口继承了Runnable接口,同时,这个类的构造方法刚好需要传入Callable接口的实现类;

FutureTask实现RunnableFuture接口,而RunnableFuture继承Runnable接口,并且在FutureTask构造方法中,可以传入Callable

所以,我们创建线程的方式如下

因此,创建线程的方式如下

  • 资源类
class MyThread implements Callable<Integer>{
    @Override
    public Integer call() throws Exception {
        System.out.println(Thread.currentThread().getName()+"进入了Callable");
        TimeUnit.SECONDS.sleep(3);
        //返回值
        return 1024;
    }
}
  • 主方法
public class _创建线程第三种方式之Callable接口 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {

//        Thread thread = new Thread(MyThread);

        FutureTask futureTask = new FutureTask(new MyThread());
        new Thread(futureTask,"AA").start();
        //get方法获取返回值
        System.out.println(futureTask.get());
    }
}

启动可以正常运行,并且能获得返回值

其中有两个点需要注意一下

  • get()方法具有阻塞效果,一般放在最后,不然会阻塞线程
  • 如果有两个线程使用同一个实例,只会执行一次,因为一个futureTask,不管几个线程调用,调用的都是同一个futureTask对象。同一个FutureTask实例在多个线程重复使用,只会进行一次