一、Callable vs Runnable
(1)Callable接口有返回值,Runnable接口无返回值;
(2)Callable接口会抛异常,Runnable接口不会抛异常;
(3)落地方法不一样,Callable是call,Runnable是run;
二、怎么用
2.1、直接替换Runnable是否可行
不可行。因为Thread类的构造方法根本没有Callable。
2.2、适用场景
这像认识一个不认识的同学,我可以找中间人介绍。
三、FutureTask
3.1、概述
未来的任务,用它干一件事,异步调用。main方法就像一个糖葫芦,一个个方法由main串起来。
问题:解决不了正常调用挂起引起的堵塞问题。
案例:
(1)老师上着课,口渴了,去买水不合适,讲课线程继续,我可以单起个线程找班长帮忙买水,水买回来了放桌上,我需要的时候再去get;
(2)4个同学,A计算1+20、B计算21+30、C计算31*到40、D计算41+50,是不是C的计算量有点大啊,FutureTask单起个线程给C计算,我先汇总ABD,最后等C计算完了再汇总
C,拿到最终结果;
(3)高考:会做的先做,不会的放在后面做;
3.2、原理
在主线程中需要执行比较耗时的操作时,但又不想阻塞主线程时,可以把这些任务交给FutureTask对象在后台完成,当主线程将来需要时,就可以通过FutureTask对象获得后台作业的计算结果或者执行状态。一般FutureTask对象多用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果。
仅在计算完成时才能检索结果;如果计算尚未完成,则阻塞 get 方法。一旦计算完成,就不能再重新开始或取消计算。get方法而获取结果只有在计算完成时获取,否则会一直阻塞直到任务转入完成状态,然后会返回结果或者抛出异常。
只计算一次get方法放到最后。
3.3、案例代码
3.3.1、CallableThread
/**
* @Author : 一叶浮萍归大海
* @Date: 2023/11/20 16:27
* @Description: 王五计算21*22*23*...*25
*/
public class CallableThread implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum = 1;
for (int i = 21; i <= 25; i++) {
sum *= i;
}
Thread.sleep(1);
return sum;
}
}
3.3.2、CallableMainApp
/**
* @Author : 一叶浮萍归大海
* @Date: 2023/11/20 16:01
* @Description:
* 需求描述:
* 三个同学安排任务如下:
* (1)张三计算 1+2+3+...+10
* (2)李四计算 11+12+13+...+20
* (3)王五计算 21*22*23*...*25
* 把三个人的计算结果求和,求出总结果
*/
public class CallableMainApp {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<Integer> wangwuFutureTask = new FutureTask<>(new CallableThread());
AtomicReference<Integer> zhangsanSumResult = new AtomicReference<>(0);
AtomicReference<Integer> lisiSumResult = new AtomicReference<>(0);
/**
* 张三计算 1+2+3+...+10
*/
new Thread(() -> {
try {
int zhangsanSum = 0;
for (int i = 1; i <= 10; i++) {
zhangsanSum += i;
}
zhangsanSumResult.set(zhangsanSum);
} catch (Exception e) {
e.printStackTrace();
}
}, "zhangsan").start();
/**
* 李四计算 11+12+13+...+20
*/
new Thread(() -> {
try {
int lisiSum = 0;
for (int i = 11; i <= 20; i++) {
lisiSum += i;
}
lisiSumResult.set(lisiSum);
} catch (Exception e) {
e.printStackTrace();
}
}, "lisi").start();
/**
* 王五计算 21*22*23*...*25
*/
new Thread(wangwuFutureTask, "wangwu").start();
System.out.println("zhangsanResult = " + zhangsanSumResult.get());
System.out.println("lisiResult = " + lisiSumResult.get());
while (!wangwuFutureTask.isDone()) {
System.out.println("=====================>王五拼命计算中");
}
Integer wangwuResult = wangwuFutureTask.get();
System.out.println("wangwuResult = " + wangwuResult);
Integer sum = zhangsanSumResult.get() + lisiSumResult.get() + wangwuResult;
System.out.println("sum = " + sum);
}
}