线程池整体架构图
线程池大致介绍
Executor
:线程池顶级接口;
ExecutorService
:线程池次级接口,对Executor
做了一些扩展,增加了一些功能;
ScheduledExecutorService
:对ExecutorService
做了一些扩展,增加一些定时任务相关的功能;
AbstractExecutorService
:抽象类,运用模板方法设计模式实现了一部分方法;
ThreadPoolExecutor
:普通线程池类,包含最基本的一些线程池操作相关的方法实现;
ScheduledThreadPoolExecutor
:定时任务线程池类,用于实现定时任务相关功能;
ForkJoinPool
:新型线程池类,java7
中新增的线程池类,基于工作窃取理论实现,运用于大任务拆小任务,任务无限多的场景;
Excutors
:线程池工具类,定义了一些快速实现线程池的方法
ThreadPool的五种状态
RUNNING
:接收新任务和进程队列任务
SHUTDOWN
:不接收新任务,但是接收进程队列任务
STOP
:不接收新任务也不接收进程队列任务,并且打断正在进行中的任务
TIDYING
:所有任务终止,待处理任务数量为0,线程转换为TIDYING
,将会执行terminated
钩子函数
TERMINATED
:terminated()
执行完成
五种状态间的切换
RUNNING
->SHUTDOWN
:调用shutdown()
方法
(RUNNING or SHUTDOWN)
->STOP
:调用shutdownNow()
方法
SHUTDOWN
->TIDYING
:队列和线程池都是空的
STOP
->TIDYING
:线程池为空
TIDYING
->TERMINATED
:钩子函数terminated()
执行完成
ExecutorService
介绍
// 关闭线程池,不再接受新任务,但已经提交的任务会执行完成
void shutdown();
/**
* 立即关闭线程池,尝试停止正在运行的任务,未执行的任务将不再执行
* 被迫停止及未执行的任务将以列表的形式返回
*/
List<Runnable> shutdownNow();
// 检查线程池是否已关闭
boolean isShutdown();
// 检查线程池是否已终止,只有在shutdown()或shutdownNow()之后调用才有可能为true
boolean isTerminated();
// 在指定时间内线程池达到终止状态了才会返回true
boolean awaitTermination ( long timeout, TimeUnit unit) throws InterruptedException;
// 执行有返回值的任务,任务的返回值为task.call()的结果
<T> Future<T> submit ( Callable<T> task);
/**
* 执行有返回值的任务,任务的返回值为这里传入的result
* 当然只有当任务执行完成了调用get()时才会返回
*/
<T> Future<T> submit ( Runnable task, T result);
/**
* 执行有返回值的任务,任务的返回值为null
* 当然只有当任务执行完成了调用get()时才会返回
*/
Future<?> submit (Runnable task);
// 批量执行任务,只有当这些任务都完成了这个方法才会返回
<T> List<Future<T>> invokeAll ( Collection<? extends Callable<T>> tasks)
throws InterruptedException;
/*
* 在指定时间内批量执行任务,未执行完成的任务将被取消
* 这里的timeout是所有任务的总时间,不是单个任务的时间
*/
<T> List<Future<T>> invokeAll ( Collection<? extends Callable<T>> tasks, long timeout,
TimeUnit unit) throws InterruptedException;
// 返回任意一个已完成任务的执行结果,未执行完成的任务将被取消
<T> T invokeAny ( Collection<? extends Callable<T>> tasks)
throws InterruptedException, ExecutionException;
// 在指定时间内如果有任务已完成,则返回任意一个已完成任务的执行结果,未执行完成的任务将被取消
<T> T invokeAny ( Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;}
创建线程的方式
继承
Thread
实现Runnable
接口
实现Callable
接口
对比
采用实现Runnable
、Callable
接口的方式创建多线程
优势是:
线程类只是实现了Runnable
接口或Callable
接口,还可以继承其他类。
在这种方式下,多个线程可以共享同一个target
对象,所以非常适合多个相同线程来处
同一份资源的情况,从而可以将CPU
、代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。
劣势是:
编程稍微复杂,如果要访问当前线程,则必须使用Thread.currentThread()
方法。
使用继承Thread
类的方式创建多线程
优势是:
编写简单,如果需要访问当前线程,则无需使用Thread.currentThread()
方法,直接使用this即可获得当前线程。
劣势是:
线程类已经继承了Thread
类,所以不能再继承其他父类。
Runnable
和Callable
的区别
Callable
规定(重写)的方法是call()
,Runnable
规定(重写)的方法是run()
Callable
的任务执行后可返回值,而Runnable
的任务是不能返回值的
call
方法可以抛出异常,run
方法不可以
运行Callable
任务可以拿到一个Future
对象,表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。通过Future
对象可以了解任务执行情况,可取消任务的执行,还可获取执行结果