FutureTask的概念
Future接口定义了操作异步任务执行一些方法,如获取异步任务的执行结果、取消任务的执行、判断任务是否被取消、判断任务执行是否完毕等。
比如主线程让一个子线程去执行任务,子线程可能比较耗时,启动子线程开始执行任务后,主线程就去做其他事情了,过了一会才去获取子任务的执行结果。
FutureTask的缺点
get()容易导致阻塞 :只要出现get方法,不管是否计算完成都阻塞等待结果出来再运行
解决办法:用轮询(CAS)替代阻塞
(但是轮询也不见得好,轮询的方式会耗费无谓的CPU资源,而且也不见得能及时地得到计算结果。)
代码示例
通过FutureTask定义一个子线程futureTask,在主线程t1中调用。
这样t1可以将一些费时的事情交给子线程处理,t1然后继续执行,最后子线程再将处理结果返回给主线程。
例子
(以老师上课为例,老师(主线程t1)上课突然口渴了,如果他停止授课,自己去接水(费时的事情),同学们的上课体验就不会太好。如果他喊班长(子线程futureTask)帮他去接水,自己继续授课,同学们的上课体验就是连贯的。最后老师也拿到了班长接的水(处理结果))
public class FutureTaskDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
//定义一个子线程
FutureTask<Integer> futureTask = new FutureTask<>(() -> {
System.out.println(Thread.currentThread().getName() + "\t" + "---come in");
//暂停几秒线程
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 1024;
});
new Thread(futureTask,"t1").start();
//获取子线程的结果,推荐放在最后
System.out.println(futureTask.get()); //不见不散,只要出现get方法,不管是否计算完成都阻塞等待结果出来再运行
}
}
get()阻塞
只要出现get方法,不管是否计算完成都阻塞等待结果出来再运行。
此时,出现get方法,但是因无法获取返回值,导致阻塞。
public class FutureTaskDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
//定义一个子线程
FutureTask<Integer> futureTask = new FutureTask<>(() -> {
System.out.println(Thread.currentThread().getName() + "\t" + "---come in");
//暂停几秒线程
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 1024;
});
System.out.println(futureTask.get());
new Thread(futureTask,"t1").start();
}
}
get:过时不后,只等待设定的时间
设置指定时间,当在规定时间内,子线程仍未得到结果,就报错java.util.concurrent.TimeoutException
public class FutureTaskDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
//定义一个子线程
FutureTask<Integer> futureTask = new FutureTask<>(() -> {
System.out.println(Thread.currentThread().getName() + "\t" + "---come in");
//暂停几秒线程
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 1024;
});
new Thread(futureTask,"t1").start();
System.out.println(futureTask.get(2L,TimeUnit.SECONDS));//过时不后,只等待设定的时间
}
}
isDone()轮询
用轮询(CAS)替代阻塞
public class FutureTaskDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
//定义一个子线程
FutureTask<Integer> futureTask = new FutureTask<>(() -> {
System.out.println(Thread.currentThread().getName() + "\t" + "---come in");
//暂停几秒线程
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 1024;
});
new Thread(futureTask,"t1").start();
//不要阻塞,尽量使用轮询替代阻塞
while (true){
if(futureTask.isDone()){
System.out.println("---result: "+futureTask.get());
break;
}else {
System.out.println("还在计算中");
}
}
}
}