新建如下示例代码,创建1个corePoolSize为2,maximumPoolSize为3的线程池:
import java.util.concurrent.*; public class ThreadPoolExecutorTest { public static void main(String[] args) { ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 3, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1)); threadPoolExecutor.execute(() -> { try { Thread.sleep(3 * 1000); System.out.println("任务1执行线程:" + Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } }); threadPoolExecutor.execute(() -> { System.out.println("任务2执行线程:" + Thread.currentThread().getName()); }); } }运行结果为:
任务2执行线程:pool-1-thread-2
任务1执行线程:pool-1-thread-1
可以看出,因为线程池中的线程数小于corePoolSize,线程池创建了2个核心线程来分别执行任务1和任务2。
修改代码为如下所示,开启3个任务:
import java.util.concurrent.*; public class ThreadPoolExecutorTest { public static void main(String[] args) { ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 3, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1)); threadPoolExecutor.execute(() -> { try { Thread.sleep(3 * 1000); System.out.println("任务1执行线程:" + Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } }); threadPoolExecutor.execute(() -> { try { Thread.sleep(5 * 1000); System.out.println("任务2执行线程:" + Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } }); threadPoolExecutor.execute(() -> System.out.println("任务3执行线程:" + Thread.currentThread().getName())); } }运行结果为:
任务1执行线程:pool-1-thread-1
任务3执行线程:pool-1-thread-1
任务2执行线程:pool-1-thread-2
可以看出,执行任务3时并没有新建线程,而是先放入了工作队列,最后由线程1执行完成。
在上面的代码中新增个任务4:
threadPoolExecutor.execute(() -> System.out.println("任务4执行线程:" + Thread.currentThread().getName()));此时运行结果为:
任务4执行线程:pool-1-thread-3
任务3执行线程:pool-1-thread-3
任务1执行线程:pool-1-thread-1
任务2执行线程:pool-1-thread-2
可以看出,任务3是先放入了工作队列,任务4放不到工作队列(空间已满),所以创建了第3个线程来执行,执行完毕后从队列里获取到任务3执行,任务1和任务2分别由线程1和线程2执行。
修改下任务4的代码,并添加任务5:
threadPoolExecutor.execute(() -> { try { Thread.sleep(2 * 1000); System.out.println("任务4执行线程:" + Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } }); threadPoolExecutor.execute(() -> System.out.println("任务5执行线程:" + Thread.currentThread().getName()));此时运行结果为:
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task ThreadPoolExecutorTest$$Lambda$5/935044096@179d3b25 rejected from java.util.concurrent.ThreadPoolExecutor@254989ff[Running, pool size = 3, active threads = 3, queued tasks = 1, 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 ThreadPoolExecutorTest.main(ThreadPoolExecutorTest.java:37)
任务4执行线程:pool-1-thread-3
任务3执行线程:pool-1-thread-3
任务1执行线程:pool-1-thread-1
任务2执行线程:pool-1-thread-2
可以看出,当提交任务5时,由于工作队列已满, 且线程池中的线程数已经为3,所以该任务被抛弃并抛出了java.util.concurrent.RejectedExecutionException异常。
如果你看到了这里,是否会好奇参数maximumPoolSize设置为多少合适呢?
这个问题,我们下次讲解,欢迎持续关注,哈哈!
6. 源码及参考源码地址:https://github.com/zwwhnly/springboot-action.git,欢迎下载。
Brian Goetz《Java并发编程实战》
怎么查看处理器(cpu)的核数
ThreadPoolExecutor使用方法
Java线程池-ThreadPoolExecutor原理分析与实战
深入理解 Java 多线程核心知识:跳槽面试必备
互联网大厂Java面试题:使用无界队列的线程池会导致内存飙升吗?【石杉的架构笔记】
最后,欢迎关注我的微信公众号:「申城异乡人」,所有博客会同步更新。