![e6f3ae72ea5dcc62e977496bb1f1d382.png](https://i-blog.csdnimg.cn/blog_migrate/c0741d6e087402cf63a6347992913318.jpeg)
排队处理
线程池是一个在高并发常见非常常用的技术。但是其中的奥秘你是否真的了解过。比如线程池中的默认线程数和最大线程数是什么关系?缓存对象又是如何使用的?
通过一个简单的示例把线程池整明白了。自定义一个线程池,并且设置一个有界的缓冲队列;
package com.ubuntuvim.spring.thread;import java.util.concurrent.*;public class MyThreadPoolExecutor { public static void main(String[] args) { // 线程池维护线程的最少数量 int corePoolSize = 2; // 线程池维护线程的最大数量 int maximumPoolSize = 4; // 线程池维护线程所允许的空闲时间的单位 // TimeUnit.SECONDS // 线程池维护所允许的空闲时间 long keepAliveTime = 10; // 线程池所使用的缓存队列,当任务达到最大线程数时会把任务放在缓冲队列中,然后有空的线程会逐个执行里面的任务 int workQueueSize = 50; // 定义一个线程池 ThreadPoolExecutor executor = new ThreadPoolExecutor( corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, // ArrayBlockingQueue是有界的缓冲队列 new ArrayBlockingQueue<>(workQueueSize)); for (int i = 1; i <= 50; i++) { try { System.out.println("i = " + i); int task = i; executor.execute(() -> { System.out.println(Thread.currentThread().getName() + "在执行任务:" + task); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } }); System.out.println("getActiveCount = " + executor.getActiveCount()); System.out.println("getTaskCount = " + executor.getTaskCount()); System.out.println("getCompletedTaskCount = " + executor.getCompletedTaskCount()); System.out.println("getMaximumPoolSize = " + executor.getMaximumPoolSize()); System.out.println("workQueueSize = " + executor.getQueue().size()); } catch (Exception e) { e.printStackTrace(); } } executor.shutdown(); }}
核心参数:corePoolSize,线程池默认存活的线程数,或者说是最小的线程数maximumPoolSize,线程池中可以创建的最大线程数,或者说是线程池中线程数上限workQueueSize,缓冲队列上限
处理任务的优先级为:核心线程corePoolSize处理任务、最大线程maximumPoolSize、任务队列workQueue,如果三者都满了使用handler处理被拒绝的任务。
一开始启动,线程池有两个线程可以接收并处理任务,但是任务比较耗时一下子就来了很多任务,导致2个线程无法满足, 此时 corePoolSize <= maximumPoolSize所以可以创建新的线程接收任务,就有了4个线程在接收任务(默认的两个+新创建的2个)。
但是任务量还是很多,四个线程仍然无法完全处理,只能把任务放在缓冲队列中,4个线程在处理任务的同时把处理不过来的任务放在缓冲队列但是缓冲队列也是有上限的,比如它的上限是5,也就是说只能缓冲5个任务。
如果任务量太大,并且每个任务都处理很耗时(处理完一个就从缓冲队列拿走一个,队列元素数量也就减1)。导致缓冲队列也满了。
这种情况下就会抛出拒绝任务异常java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(这个是默认的拒绝异常)
验证
- 缓冲队列设置比较小,比如workQueueSize=5时,很容易就出现任务拒绝异常
- 如果直接设置缓冲队列workQueueSize=50,肯定不会有问题。所有任务都可以放到缓冲队列中,等待线程池中的线程来处理即可。
workQueueSize=5的运行结果:
i = 1pool-1-thread-1在执行任务: 1getActiveCount = 1getTaskCount = 1getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 0i = 2getActiveCount = 2getTaskCount = 2pool-1-thread-2在执行任务: 2getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 0i = 3getActiveCount = 2getTaskCount = 3getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 1i = 4getActiveCount = 2getTaskCount = 4getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 2i = 5getActiveCount = 2getTaskCount = 5getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 3i = 6getActiveCount = 2getTaskCount = 6getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 4i = 7getActiveCount = 2getTaskCount = 7getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 5i = 8getActiveCount = 3getTaskCount = 8getCompletedTaskCount = 0getMaximumPoolSize = 4pool-1-thread-3在执行任务: 8workQueueSize = 5i = 9getActiveCount = 4pool-1-thread-4在执行任务: 9getTaskCount = 9getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 5i = 10i = 11i = 12i = 13i = 14i = 15i = 16i = 17i = 18i = 19i = 20i = 21i = 22i = 23i = 24i = 25i = 26i = 27i = 28i = 29i = 30i = 31i = 32i = 33i = 34i = 35i = 36i = 37i = 38i = 39i = 40i = 41i = 42i = 43i = 44i = 45java.util.concurrent.RejectedExecutionException: Task com.ubuntuvim.spring.thread.MyThreadPoolExecutor$$Lambda$1/142257191@7229724f rejected from java.util.concurrent.ThreadPoolExecutor@4c873330[Running, pool size = 4, active threads = 4, queued tasks = 5, completed tasks = 0] at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063) at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830) at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379) at com.ubuntuvim.spring.thread.MyThreadPoolExecutor.main(MyThreadPoolExecutor.java:45)java.util.concurrent.RejectedExecutionException: Task com.ubuntuvim.spring.thread.MyThreadPoolExecutor$$Lambda$1/142257191@776ec8df rejected from java.util.concurrent.ThreadPoolExecutor@4c873330[Running, pool size = 4, active threads = 4, queued tasks = 5, completed tasks = 0] ………………中间还有很多同类型异常信息,略写。 at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063) at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830) at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379) at com.ubuntuvim.spring.thread.MyThreadPoolExecutor.main(MyThreadPoolExecutor.java:45)java.util.concurrent.RejectedExecutionException: Task com.ubuntuvim.spring.thread.MyThreadPoolExecutor$$Lambda$1/142257191@37a71e93 rejected from java.util.concurrent.ThreadPoolExecutor@4c873330[Running, pool size = 4, active threads = 4, queued tasks = 5, completed tasks = 0] at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063) at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830) at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379) at com.ubuntuvim.spring.thread.MyThreadPoolExecutor.main(MyThreadPoolExecutor.java:45)i = 46i = 47i = 48i = 49i = 50pool-1-thread-2在执行任务: 3pool-1-thread-1在执行任务: 4pool-1-thread-3在执行任务: 5pool-1-thread-4在执行任务: 6pool-1-thread-1在执行任务: 7BUILD SUCCESSFUL in 10s35 actionable tasks: 2 executed, 33 up-to-date下午11:28:12: Task execution finished 'MyThreadPoolExecutor.main()'.
从运行结果上看,只有少数几个人能执行成功,其他的任务都被直接拒绝了。
workQueueSize=50的运行结果:
> Task :test-env:MyThreadPoolExecutor.main()i = 1pool-1-thread-1在执行任务: 1getActiveCount = 1getTaskCount = 1getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 0i = 2getActiveCount = 2getTaskCount = 2getCompletedTaskCount = 0getMaximumPoolSize = 4pool-1-thread-2在执行任务: 2workQueueSize = 0i = 3getActiveCount = 2getTaskCount = 3getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 1i = 4getActiveCount = 2getTaskCount = 4getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 2i = 5getActiveCount = 2getTaskCount = 5getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 3i = 6getActiveCount = 2getTaskCount = 6getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 4i = 7getActiveCount = 2getTaskCount = 7getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 5i = 8getActiveCount = 2getTaskCount = 8getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 6i = 9getActiveCount = 2getTaskCount = 9getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 7i = 10getActiveCount = 2getTaskCount = 10getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 8i = 11getActiveCount = 2getTaskCount = 11getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 9i = 12getActiveCount = 2getTaskCount = 12getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 10i = 13getActiveCount = 2getTaskCount = 13getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 11i = 14getActiveCount = 2getTaskCount = 14getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 12i = 15getActiveCount = 2getTaskCount = 15getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 13i = 16getActiveCount = 2getTaskCount = 16getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 14i = 17getActiveCount = 2getTaskCount = 17getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 15i = 18getActiveCount = 2getTaskCount = 18getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 16i = 19getActiveCount = 2getTaskCount = 19getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 17i = 20getActiveCount = 2getTaskCount = 20getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 18i = 21getActiveCount = 2getTaskCount = 21getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 19i = 22getActiveCount = 2getTaskCount = 22getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 20i = 23getActiveCount = 2getTaskCount = 23getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 21i = 24getActiveCount = 2getTaskCount = 24getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 22i = 25getActiveCount = 2getTaskCount = 25getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 23i = 26getActiveCount = 2getTaskCount = 26getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 24i = 27getActiveCount = 2getTaskCount = 27getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 25i = 28getActiveCount = 2getTaskCount = 28getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 26i = 29getActiveCount = 2getTaskCount = 29getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 27i = 30getActiveCount = 2getTaskCount = 30getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 28i = 31getActiveCount = 2getTaskCount = 31getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 29i = 32getActiveCount = 2getTaskCount = 32getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 30i = 33getActiveCount = 2getTaskCount = 33getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 31i = 34getActiveCount = 2getTaskCount = 34getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 32i = 35getActiveCount = 2getTaskCount = 35getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 33i = 36getActiveCount = 2getTaskCount = 36getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 34i = 37getActiveCount = 2getTaskCount = 37getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 35i = 38getActiveCount = 2getTaskCount = 38getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 36i = 39getActiveCount = 2getTaskCount = 39getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 37i = 40getActiveCount = 2getTaskCount = 40getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 38i = 41getActiveCount = 2getTaskCount = 41getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 39i = 42getActiveCount = 2getTaskCount = 42getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 40i = 43getActiveCount = 2getTaskCount = 43getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 41i = 44getActiveCount = 2getTaskCount = 44getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 42i = 45getActiveCount = 2getTaskCount = 45getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 43i = 46getActiveCount = 2getTaskCount = 46getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 44i = 47getActiveCount = 2getTaskCount = 47getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 45i = 48getActiveCount = 2getTaskCount = 48getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 46i = 49getActiveCount = 2getTaskCount = 49getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 47i = 50getActiveCount = 2getTaskCount = 50getCompletedTaskCount = 0getMaximumPoolSize = 4workQueueSize = 48pool-1-thread-1在执行任务: 3pool-1-thread-2在执行任务: 4pool-1-thread-2在执行任务: 5pool-1-thread-1在执行任务: 6pool-1-thread-1在执行任务: 7pool-1-thread-2在执行任务: 8pool-1-thread-1在执行任务: 9pool-1-thread-2在执行任务: 10pool-1-thread-2在执行任务: 11pool-1-thread-1在执行任务: 12pool-1-thread-1在执行任务: 13pool-1-thread-2在执行任务: 14pool-1-thread-1在执行任务: 15pool-1-thread-2在执行任务: 16pool-1-thread-1在执行任务: 17pool-1-thread-2在执行任务: 18pool-1-thread-2在执行任务: 19pool-1-thread-1在执行任务: 20pool-1-thread-2在执行任务: 21pool-1-thread-1在执行任务: 22pool-1-thread-1在执行任务: 23pool-1-thread-2在执行任务: 24pool-1-thread-2在执行任务: 25pool-1-thread-1在执行任务: 26pool-1-thread-2在执行任务: 27pool-1-thread-1在执行任务: 28pool-1-thread-1在执行任务: 29pool-1-thread-2在执行任务: 30pool-1-thread-2在执行任务: 31pool-1-thread-1在执行任务: 32pool-1-thread-2在执行任务: 33pool-1-thread-1在执行任务: 34pool-1-thread-1在执行任务: 35pool-1-thread-2在执行任务: 36pool-1-thread-1在执行任务: 37pool-1-thread-2在执行任务: 38pool-1-thread-1在执行任务: 39pool-1-thread-2在执行任务: 40pool-1-thread-1在执行任务: 42pool-1-thread-2在执行任务: 41pool-1-thread-2在执行任务: 43pool-1-thread-1在执行任务: 44pool-1-thread-2在执行任务: 46pool-1-thread-1在执行任务: 45pool-1-thread-2在执行任务: 47pool-1-thread-1在执行任务: 48pool-1-thread-2在执行任务: 50pool-1-thread-1在执行任务: 49BUILD SUCCESSFUL in 56s35 actionable tasks: 2 executed, 33 up-to-date下午11:32:38: Task execution finished 'MyThreadPoolExecutor.main()'.
从运行结果可以看到,由于任务太耗时,2个线程处理不过来在处理的同时,直接新建2个线程,但是还是处理不过来,于是把任务放在缓冲队列中,缓冲队列的任务数也一直往上增。但是由于缓冲队列比较大可以容纳很多任务,从而没有出现队列爆满,在队列中的任务只要等着处理完成就可以了。
最后再回顾一下前面的要点:
处理任务的优先级为:核心线程corePoolSize处理任务、最大线程maximumPoolSize、任务队列workQueue,如果三者都满了使用handler处理被拒绝的任务。
也就是说先用默认的线程数处理任务,处理不过来则创建新的线程帮忙处理,如果还是处理不过来则放在缓冲队列中,任务排队处理。如果缓冲队列中也装不下,直接把任务拒绝掉。