一开始很犹豫这要不要写这篇文章,在网上看了不少文章写的都很不错,可是秉持着更全更易懂的原则,仍是打算本身整理一篇。也参考了不少的文章博客,但愿这篇文章可以真正的帮到你。(同时吐槽下,稀土掘金就不能增长一个分类专区的功能吗,这样博客写多了,很差归类的)java
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) 复制代码
线程池建立线程的时候,若是当前的线程总个数 < corePoolSize,那么新建的线程为核心线程,若是当前线程总个数 >= corePoolSize,那么新建的线程为非核心线程。 核心线程默认会一直存活下去,即使是空闲状态,可是若是设置了allowCoreThreadTimeOut(true)的话,那么核心线程空闲时间达到keepAliveTime也将关闭。缓存
核心线程数 + 非核心线程数 = 最大线程数量微信
非核心线程在空闲状态下,超过keepAliveTime时间,就会被回收,若是核心线程设置了allowCoreThreadTimeOut(true)的话,那么在空闲时,超过keepAliveTime时间,也会被回收。并发
时、分、秒、毫秒等ide
当有任务到来时,会指派给核心线程去执行,等核心线程都被占用了,那么再有新的任务,就会加入到队列中,等队列满了,再有任务,就再启动非核心线程去执行。经常使用的队列以下spa
SynchronousQueue 使用这个队列时,当有任务到来的时候,它并不存任务,而是直接将任务丢给线程去执行,若是线程都在被占用,它就会建立线程去处理这个任务,因此通常使用这个缓存队列的时候,maximumPoolSize(线程池能容纳的最大线程数量)设置到 Integer.MAX_VALUE,否则任务数超过maximumPoolSize限制而建立不了线程。线程
LinkedBlockingQueue 使用这个队列是,当有任务到来的时候,若是当前的核心线程数 < corePoolSize,它会新建核心线程去执行任务,若是当前核心线程数 >= corePoolSize时,它会将还未被执行的任务存储起来,等待执行,可是这个队列,没有存储上限,因此尼,这也就形成了,maximumPoolSize(总线程数),永远不会超过corePoolSize。此队列按 FIFO(先进先出)原则对任务进行操做。3d
ArrayBlockingQueue 使用这个队列尼,能够设置队列的长度,那么当任务到来的时候,核心线程数 < corePoolSize时, 则建立核心线程去执行任务,若是核心线程数 >= corePoolSize时,加入到队列里面,等待执行,若是队列也满了,则新建非核心线程去执行任务。此队列按 FIFO(先进先出)原则对元素进行操做。可是线程数不能超过总线程数。code
DelayQueue(延时队列) 任务到来时,首先先加入到队列中,只有达到了指定的延时时间,才会执行任务。cdn
用来建立线程池中的线程,用默认的便可。
当任务过多时,即:当前线程数已经达到了最大线程数,缓冲队列也已经满了,或者线程池关闭了,那么再来的任务请求,咱们会拒绝,怎么拒绝尼?有如下几个方案:
“当你有了,原配,想再娶个小三时,原配的态度”,默认策略,简单粗暴,直接拒绝抛异常(RejectedExecutionException)
“原配的太粗暴,无法子,只能把小三的电话,微信都删掉了,不再来往了”,DiscardPolicy策略就是,直接丢弃,可是不抛异常。若是线程队列已满,则后续提交的任务都会被丢弃。
“可是原配看久了,很腻了,算了,人生短短几十年,何须委屈本身,休妻,腾地方,娶小三”,DiscardOldestPolicy策略就是,直接丢弃掉队伍最前面的任务,再从新提交后面新来的任务。
CallerRunsPolicy
“唉,原配虽然很差看,可是家里有背景,不敢随意抛弃,后面的小三仍是哪来的回哪去吧,找个熟人照顾着”,CallerRunsPolicy策略就是不抛弃任务,由调用者运行这个任务,好比主线程启动了线程池去运行这个任务,如今线程池满了,那么这个任务就由主线程进行调用执行了。
总结一下 让任务到来的时候,会执行如下的流程
明白了吗?若是你不想本身写一个线程池,有更简单的方式,就是系统已经为咱们定义好了几个线程池,下面介绍下他们的使用,看看有没有符合你要求的,。
看下图
建立一个定长的线程池,可控制线程最大的并发数,超出的部分任务,会在队列中等待,适用于:已知并发压力的状况下,对线程数作限制。实际上就是只使用核心线程。
private void testFiexdThreadPool() {
ExecutorService threadPool = Executors.newFixedThreadPool(3);
for (int n = 0; n < 10; n++){
final int finalN = n;
threadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+":"+ finalN);
}
});
}
}
复制代码
结果
建立一个单线程化的线程池,它只会用惟一的工做线程来执行任务,保证全部任务按照指定顺序(FIFO, LIFO, 优先级)执行。
private void testSingleThreadExecutor(){
ExecutorService threadPool = Executors.newSingleThreadExecutor();
for (int n = 0; n < 10; n++){
final int finalN = n;
threadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+":"+ finalN);
}
});
}
}
复制代码
结果
建立一个可缓存线程池,若是线程池长度超过处理须要,可灵活回收空闲线程,若无可回收,则新建线程。
private void testCachedThreadPool(){
ExecutorService threadPool = Executors.newCachedThreadPool();
for (int n = 0; n < 10; n++){
final int finalN = n;
threadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+":"+ finalN);
}
});
}
}
复制代码
结果
建立一个可按期或者延时执行任务的定长线程池,支持定时及周期性任务执行。
private void testScheduledThreadPool(){
ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(5);
for (int n = 0; n < 10; n++){
final int finalN = n;
threadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+":"+ finalN);
}
}, 3, 2, TimeUnit.SECONDS);
}
}
复制代码
结果