创建线程的三种方式,前两种就不多说了,分别是继承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实例在多个线程重复使用,只会进行一次