-
Callable、Furture、FurtureTask
-
示意图:
-
Callable
-
引入场景:使用Runnable创建线程,但是需要返回值
-
Runnable源码:内部的run是没有返回值的
@FunctionalInterface public interface Runnable { public abstract void run(); }
-
-
概述:接口方法带有返回值(传入的泛型)
-
本质上来说还是一个接口,但是这个里面
@FunctionalInterface public interface Callable<V> { V call() throws Exception; }
-
-
线程源码(Thread.java):并不是所有的方法都支持Callable参数(传进去可能也用不了,构造不支持)
- 这个时候就引入了FurtureTask
-
-
FurtureTask:既可以作为Runnable交给线程执行;又可以作为Furture拿到Callable的结果
-
概述:
- 在JDK1.6之前,是有AQS进行实现的;1.7后完全实现了一套,但是还是基于AQS
- 既实现了Runnable接口,又实现了Furture接口(获得处理结果),还可以拿到Callable的返回值;
-
使得Callable可以被线程执行,无视Thread类中不能接受Callable类型参数的问题:
-
实现了RunnableFurture
public class FutureTask<V> implements RunnableFuture<V>-
RunnableFuture(这是一个接口):扩展自Runnable接口(意味着这个FutureTask是可以交给线程来执行的,这个东西就可以当成一个Runnable进行使用)
public interface RunnableFuture<V> extends Runnable, Future<V> { void run(); }
-
-
FurtureTask类持有了Callable
private Callable<V> callable;-
查看FurtureTask构造函数:可以接受一个Callable类型的实例,包装成一个FurtureTask,交给线程来执行
public FutureTask(Callable<V> callable) { if (callable == null) throw new NullPointerException(); this.callable = callable; this.state = NEW; // ensure visibility of callable }
-
-
-
概述
-
RunnableFuture扩展自Furture接口
-
Furture:JDK定义的,可以获得自定义执行任务的结果;还可以取消这个任务的执行
- 就是将FurtureTask交给线程去执行的时候,想要拿到这个任务的执行结果,这个时候可以通过FurtureTask去拿到结果
-
示意图:
-
-
-
-
具体使用:使用FurtureTask配合Callable进行计算(需要拿到返回值并且添加随机中断)
-
实现流程:
-
自定义业务类,实现Callable接口(这个东西就可以拿到线程执行结果的返回值,但是它不能适配所有的Thread方法;但是FurtureTask就可以,因为这家伙实现了Runnable接口,同时Thread内部有个构造方法,可以接收Runnable的实例化对象,此时就相当于转成了Thread的对象)
- 需要添加中断检查机制
-
主线程中:
-
实例化实现了Callable接口的类,拿到对象
-
将对象传给FurtureTask,进行包装(Callable就可以交给线程执行了)
-
将FurtureTask传给Thread
-
采用随机中断机制
- 在具体中断中调用FurtureTask的cancel方法并传入true
-
-
-
实现细节:
-
FurtureTask调用中断的时候,不一定会执行(需要在线程中添加对应的逻辑)
-
FurtureTask调用中断
futureTask.cancel(true); -
在线程中检查中断
if(Thread.currentThread().isInterrupted()){ System.out.println("Callable子线程任务被中断"); return null; }
-
-
-
完整代码:
package cn.enjoyedu.ch2.future; import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; /** *类说明:演示Future等的使用 */ public class UseFuture { /*实现Callable接口,允许有返回值*/ private static class UseCallable implements Callable<Integer>{ private int sum; @Override public Integer call() throws Exception { System.out.println("Callable子线程开始计算!"); // Thread.sleep(2000); for(int i=0 ;i<5000;i++){ if(Thread.currentThread().isInterrupted()){ System.out.println("Callable子线程任务被中断"); return null; } sum=sum+i; } System.out.println("Callable子线程计算结束!结果为: "+sum); return sum; } } public static void main(String[] args) throws InterruptedException, ExecutionException { //获取Callable实例 UseCallable useCallable = new UseCallable(); //用FurtureTask进行包装,这样就可以交给线程执行了,需要将Callable作为泛型实例 FutureTask<Integer> futureTask //用FutureTask包装Callable = new FutureTask<>(useCallable); //将任务交给线程执行 new Thread(futureTask).start();//交给Thread去运行 Random r = new Random(); //必须加上一个休眠时间,因为线程可能没有启动完成 Thread.sleep(1000); //FurtureTask既可以去拿线程的执行结果,也可以去终止任务(要终止一个线程,需要在内部进行处理) //用随机的方式决定是获得结果还是终止任务 if(r.nextBoolean()) { System.out.println("Get UseCallable result = "+futureTask.get()); }else { System.out.println("中断计算。 "); futureTask.cancel(true); } } } -
运行截图(主线程中的随机中断机制选择不中断):实在不放心,可以打印随机的值来看
-
运行截图(主线程中的随机中断机制选择中断):实在不放心,可以打印随机的值来看
-
-
\