FutureTask设计解释
1.正真开启线程是Thread类(构造函数接受Runnable类型的参数),而Thread又继承了Runnable,执行的就是run()方法。
2.Runnable是一个任务体。
3.Callable也是一个任务体。(相较于Runnable能返回结果而已)
3.Future可以视为一个工具类
源码分析
// FutureTask实现了Runnable类,即可作为任务体传递给Thread执行
// 重写run()方法,最终都是执行Callable的call()方法
public void run() {
// 虚假代码.....
Callable<V> c = callable;
result = c.call();
}
// 如果接收Runnable呢,其实就是做了一个适配转换
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
}
// 可以忽略不看,就是封多了一层方法而已
public static <T> Callable<T> callable(Runnable task, T result) {
if (task == null)
throw new NullPointerException();
return new RunnableAdapter<T>(task, result);
}
// 正在的转换
private static final class RunnableAdapter<T> implements Callable<T> {
private final Runnable task;
private final T result;
RunnableAdapter(Runnable task, T result) {
this.task = task;
this.result = result;
}
public T call() {
// 执行了Runnable方法的run()方法,返回值类型为传入的泛型
task.run();
return result;
}
}
FutureTask任务状态流转
- NEW:当FutureTask被初始创建的时候的状态。
- COMPLETING和NORMAL:当任务被执行完毕,FutureTask会将执行结果设置给FutureTask的outcome属性,在设置之前会将FutureTask的状态修改为COMPLETING,在设置之后会将FutureTask的状态修改为NORMAL。
- EXCEPTIONAL:当任务在被执行的过程中抛了异常,FutureTask会将异常信息设置给FutureTask的outcome属性,在设置之前会将FutureTask的状态修改为COMPLETING,在设置之后会将FutureTask的状态修改为EXCEPTIONAL。
- CANCELLED:当外部想要取消任务,而又不允许当任务正在执行的时候被取消的时候会将FutureTask的状态修改为CANCELLED。
- INTERRUPTING和NTERRUPTED:当外部想要取消任务,同时允许当任务正在执行的时候被取消的时候,会先将FutureTask的状态设置为INTERRUPTING,然后设置执行任务的线程的中断标记位,最后将Future的状态设置为INTERRUPTED。
FutureTask的状态流转可能流程
NEW—>COMPLETING—>NORMAL(任务执行正常)。
NEW—>COMPLETING—>EXCEPTIONAL(任务执行异常)。
NEW—>CANCELLED(不允许执行中的取消)。
NEW—>INTERRUPTING—>INTERRUPTED(允许执行中的取消)。
Future相关方法解析
// 返回值 :已完成或者已取消的前提下调用将返回false;true表示取消成功(任务将不再被执行,)。
// 参数:true表示停止正在执行的任务;false表示不打断正在执行的任务,任务可以正常完成;
boolean cancel(boolean mayInterruptIfRunning);
// 重点示例:先调用了cancel(参数无论是true/false),这时候再启动线程任务将不被执行
FutureTask futureTask = new FutureTask(new Runn5());
futureTask.cancel(true);
Thread thread = new Thread(futureTask);
thread.start();
// 其实就是cancel()的返回值
boolean isCancelled();
// 任务被取消或者已完成,以及发生异常终止,都将返回true
boolean isDone();
// 线程阻塞获取结果
V get() throws InterruptedException, ExecutionException,CancellationException;
// 线程 阻塞获取结果,传入等待时长,超过等待时长抛出TimeoutException
V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, CancellationException,TimeoutException;
ThreadPoolExecutor
ThreadPoolExecutor_UML按照默认线程池是实现ExecutorService接口的,按照ExecutorService接口定义的行为,我们可以将Runnable或Callable任务提交到线程池让其去被执行,而被提交的Runnable或Callable任务都会被包装成FutureTask,丢到任务队列,由线程池的工作线程去执行。使用线程池不仅可以提高应用的响应时间,还可以避免”java.lang.OutOfMemoryError: unable to create new native thread” 之类的错误。
ExecutorService方法解析
// 提交任务执行,在调用此方法前调用了shutdown()则会报RejectedExecutionException异常
<T> Future<T> submit(Callable<T> task);
// 线程池会停止接受新的任务,但会完成已提交的任务
void shutdown();
// 返回已提交还没执行的线程,对于正在执行的任务一般会调用interrupt方法尝试中断
List<Runnable> shutdownNow();
// 判断是否执行了shutdown或者shutdownNow()方法
boolean isShutdown();
//获取所有任务是否已经结束,当调用shutdown或者shutdownNow方法后,并且所有提交的任务完成后返回为true
boolean isTerminated();
// 阻塞等待所有任务结束,可以设置timeout,如果超时了所有任务还未完成则返回false,反之
boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;
// 批量提交任务,整个过程为阻塞,是因为内部执行了Future.get(),所有任务都执行完毕后才返回。
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException;
// 和上面方法相同,只是了限定时间
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException;
网友评论