Java并发编程之线程池的使用 (3)

新建如下示例代码,创建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异常。

Java并发编程之线程池的使用

如果你看到了这里,是否会好奇参数maximumPoolSize设置为多少合适呢?

这个问题,我们下次讲解,欢迎持续关注,哈哈!

6. 源码及参考

源码地址:https://github.com/zwwhnly/springboot-action.git,欢迎下载。

Brian Goetz《Java并发编程实战》

怎么查看处理器(cpu)的核数

ThreadPoolExecutor使用方法

Java线程池-ThreadPoolExecutor原理分析与实战

深入理解 Java 多线程核心知识:跳槽面试必备

互联网大厂Java面试题:使用无界队列的线程池会导致内存飙升吗?【石杉的架构笔记】

最后,欢迎关注我的微信公众号:「申城异乡人」,所有博客会同步更新。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpjwfw.html