创建线程的两种方式:Thread和Runnable,但它们都有一个缺点:无法获取返回值。
如果需要进行异步运算,而且需要获取运算的结果值,可以使用Callable和FutureTask。
FutureTask API
-
boolean isCancelled()
是否取消。 -
boolean isDone()
是否计算结束。 -
boolean cancel(boolean mayInterruptIfRunning)
取消计算,mayInterruptIfRunning(运行时允许是否中断)。 -
V get()
获取计算结果,会阻塞。 -
V get(long timeout, TimeUnit unit)
获取计算结果,设置一个超时时间。
使用例子
public class CallableDemo implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 0; i < 100; i++) {
sum += i;
}
return sum;
}
public static void main(String[] args) throws Exception {
CallableDemo demo = new CallableDemo();
//不要直接get(),会无限阻塞,因为没有开启线程去计算
FutureTask<Integer> task = new FutureTask(demo);
new Thread(task).start();
Integer taskResult = task.get();
System.out.println("result:"+taskResult);
//result:4950
}
}
FutureTask创建后,在开启线程计算前不要直接调用get(),否则会无限阻塞下去。
手写实现
/**
* @Author: 潘
* @Date: 2019/11/6 15:10
* @Description: 手写实现Callable
*/
@FunctionalInterface
public interface MyCallable<V> {
V call();
}
class MyTask<V> implements Runnable{
private MyCallable<V> myCallable;
private V v;
public MyTask(MyCallable<V> myCallable) {
this.myCallable = myCallable;
}
@Override
public synchronized void run() {
v = myCallable.call();
//计算完毕 通知线程
notifyAll();
}
public synchronized V get(){
while (true) {
if (v != null) {
return v;
}
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
MyCallable<Integer> callable = () -> {
int sum = 0;
for (int i = 0; i < 10; i++) {
//模拟复杂计算耗时
SleepUtil.sleep(100);
sum+=i;
}
return sum;
};
MyTask<Integer> task = new MyTask<>(callable);
//开启线程,callable开始计算
new Thread(task).start();
System.out.println("MyCallable开始进行计算...");
//main线程还可进行其他操作
for (int i = 0; i < 3; i++) {
System.out.println("main线程继续其他操作:" + i);
}
System.out.println("main线程准备获取结果,此时开始阻塞...");
//在需要时获取结果,未计算完会阻塞,计算完会直接返回
Integer result = task.get();
System.out.println("MyCallable 结果:"+result);
}
}
输出如下:
MyCallable开始进行计算...
main线程继续其他操作:0
main线程继续其他操作:1
main线程继续其他操作:2
main线程准备获取结果,此时开始阻塞...
MyCallable 结果:45