与Runnable对比
class MyThread implements Runnable{
@Override
public void run() {
}
}
class MyThread2 implements Callable<Integer>{
@Override
public Integer call() throws Exception {
return null;
}
}
两者有什么区别?
- 方法名不同
- 是否有返回值
- 是否抛异常
使用
*newThread时,发现无法使用Callable直接替换Runnable,只能寻找将两个关联在一起的中间类,实现了Runnable接口的子接口RunnableFuture下,有一个FutureTask的类,这个类中有一个FutureTask(Callable<V> callable)
的构造方法,就是它将Runnable与Callable连在了一起。
public class CallableDemo{
public static void main(String[] args) throws Exception{
FutureTask f = new FutureTask(new MyThread());
new Thread(f,"A").start();
// 获取返回值
System.out.println(f.get());
}
}
class MyThread implements Callable<Integer>{
@Override
public Integer call() throws Exception{
System.out.println("test");
return 1024;
}
}
例子
(1)老师上着课,口渴了,自己去买水不合适,耽误讲课,但是可以找班长帮忙买水,过了一会,班长把水买回来了,这期间老师既没耽误讲课,又把喝水的问题解决了。
(2)4个同学,A算1+20,B算21+30,C算31*到40,D算41+50,因为C的计算量有点过大,如果执意等它,则会耽误其它的运算,此时FutureTask单起个线程给C计算,主线程先算ABD,最后等C计算完了再返回到主线程,这期间既没在C上面多花时间,又得到了ABD的运算结果。
解析
-
在主线程中需要执行比较耗时的操作时,但又不想阻塞主线程时,可以把这些作业交给Future对象在后台完成,当主线程将来需要时,就可以通过Future对象获得后台作业的计算结果或者执行状态。
-
一般FutureTask多用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果。
-
get方法只能在计算完成时获取结果,也就是放在当前方法中的最后一行,否则会一直阻塞,直到任务转入完成状态,然后返回结果或者抛出异常。
-
一个FutureTask只能供线程调用一次,当其他线程再次调用时,因为是一个对象,所以会直接使用之前的结果
*已经有Runnable接口,为什么还要出现Callable接口?请你谈谈它的诞生的前身背景?
- 因为并发,异步导致Callable接口的出现
- 主要是用Callable能够实现当多个任务执行时,若有一个任务耗时较长,可以把这个任务放到后台执行,主线程先完成其他任务,最后再等后台的任务结束,再一起进行总的计算。