建立=>销毁=>建立
对系统对开销很大,使用线程池能够避免重复的开销一说到线程池天然就会想到池化技术。java
其实所谓池化技术,就是把一些可以复用的东西放到池中,避免重复建立、销毁的开销,从而极大提升性能。并发
常见池化技术的例如:性能
JDK 1.5 推出了三大API用来建立线程:线程
Executors.newCachedThreadPool()
:无限线程池(最大21亿)Executors.newFixedThreadPool(nThreads)
:固定大小的线程池Executors.newSingleThreadExecutor()
:单个线程的线程池这三个API的底层其实都是由同一个类实现的:ThreadPoolExecutor
类code
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }
ThreadPoolExecutor
类ThreadPoolExecutor
类主要有如下七个参数:对象
int corePoolSize
: 核心线程池大小int maximumPoolSize
: 最大核心线程池大小long keepAliveTime
: 线程空闲后的存活时间TimeUnit unit
: 超时单位BlockingQueue<Runnable> workQueue
: 阻塞队列ThreadFactory threadFactory
: 线程工厂:建立线程的,通常默认RejectedExecutionHandler handle
: 拒绝策略拒绝策略就是当队列满时,线程如何去处理新来的任务。继承
Java内置了四种拒绝策略:接口
ThreadPoolExecutor.CallerRunsPolicy()
队列
ThreadPoolExecutor.AbortPolicy()
内存
ThreadPoolExecutor.DiscardPolicy()
ThreadPoolExecutor.DiscardOldestPolicy()
功能:只要线程池没有关闭,就由提交任务的当前线程处理。
使用场景:通常在不容许失败、对性能要求不高、并发量较小的场景下使用。
功能:当触发拒绝策略时,直接抛出拒绝执行的异常
使用场景:ThreadPoolExecutor
中默认的策略就是AbortPolicy
,因为ExecutorService
接口的系列ThreadPoolExecutor
都没有显示的设置拒绝策略,因此默认的都是这个。
功能:直接丢弃这个任务,不触发任何动做
使用场景:提交的任务可有可无,通常用的少。
功能:弹出队列头部的元素,而后尝试执行,至关于排队的时候把第一我的打死,而后本身代替
使用场景:发布消息、修改消息相似场景。当老消息还未执行,此时新的消息又来了,这时未执行的消息的版本比如今提交的消息版本要低就能够被丢弃了。
RUNNING
天然是运行状态,指能够接受任务执行队列里的任务SHUTDOWN
指调用了 shutdown()
方法,再也不接受新任务了,可是队列里的任务得执行完毕。STOP
指调用了 shutdownNow()
方法,再也不接受新任务,同时抛弃阻塞队列里的全部任务并中断全部正在执行任务。TIDYING
全部任务都执行完毕,在调用 shutdown()/shutdownNow()
中都会尝试更新为这个状态。TERMINATED
终止状态,当执行 terminated()
后会更新为这个状态。提交一个任务到线程池中,线程池的处理流程以下:
判断线程池里的核心线程是否都在执行任务
线程池判断工做队列是否已满
判断线程池里的全部线程是否都处于工做状态
不过最好不要使用Executors
来建立线程,缘由以下(参考自——阿里巴巴Java开发手册):
FixedThreadPool
和 SingleThreadPool
: 容许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而致使 OOMCachedThreadPool
: 容许的建立线程数量为 Integer.MAX_VALUE,可能会建立大量的线程,从而致使 OOM推荐使用ThreadPoolExecutor
类自行建立
// 自定义线程池 ExecutorService threadPool = new ThreadPoolExecutor( 2, Runtime.getRuntime().availableProcessors(),//CPU的核心数,适合CPU密集型任务 3, TimeUnit.SECONDS, new LinkedBlockingDeque<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardOldestPolicy());
线程池不是越大越好,要根据任务类型合理进行配置
有两个方法能够执行任务execute
和submit
execute
提交没有返回值,不能判断是否执行成功。submit
会返回一个Future
对象,经过Future
的get()
方法来获取返回值。区别:
execute
提交的方式只能提交一个Runnable的对象submit
有三种submit
有返回值,而execute
没有submit
方便Exception
处理execute
是Executor
接口中惟必定义的方法submit
是ExecutorService
(该接口继承Executor
)中定义的方法线程池使用完毕,须要对其进行关闭,有两种方法
shutdown()
:再也不继续接收新的任务,执行完成已有任务后关闭
shutdownNow()
:直接关闭,若果有任务尝试中止