1. 首页
  2. java并发

004-四、Java并发 Java 线程池之 ThreadPoolExecutor(下)

引言

因为上一章节篇幅有限,所以我决定把 一文秒懂 Java 线程池 拆分为三篇文章单独介绍。本章节,我们就来看看 ThreadPoolExecutor

ThreadPoolExecutor

ThreadPoolExecutor 是一个可被继承 ( extends ) 的线程池实现,包含了用于微调的许多参数和钩子。

我们并不会讨论 ThreadPoolExecutor 类中的所有的参数和钩子,只会讨论几个主要的配置参数:

1、 corePoolSize
2、 maximumPoolSize
3、 keepAliveTime

ThreadPoolExecutor 创建的线程池由固定数量的核心线程组成,这些线程在 ThreadPoolExecutor 生命周期内始终存在,除此之外还有一些额外的线程可能会被创建,并会在不需要时主动销毁。corePoolSize 参数用于指定在线程池中实例化并保留的核心线程数。如果所有核心线程都忙,并且提交了更多任务,则允许线程池增长到 maximumPoolSize

keepAliveTime 参数是额外的线程( 即,实例化超过 corePoolSize 的线程 )在空闲状态下的存活时间。

这三个参数涵盖了广泛的使用场景,但最典型的配置是在 Executors 静态方法中预定义的。

Executors.newFixedThreadPool()

例如,Executors.newFixedThreadPool() 静态方法创建了一个 ThreadPoolExecutor ,它的参数 corePoolSizemaximumPoolSize 都是相等的,且参数 keepAliveTime 始终为 0 ,也就意味着此线程池中的线程数始终相同。


ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2); executor.submit(() -> { Thread.sleep(1000); return null; }); executor.submit(() -> { Thread.sleep(1000); return null; }); executor.submit(() -> { Thread.sleep(1000); return null; }); assertEquals(2, executor.getPoolSize()); assertEquals(1, executor.getQueue().size());

上面这个示例中,我们实例化了一个固定线程数为 2ThreadPoolExecutor。这意味着如果同时运行的任务的数量始终小于或等于 2 ,那么这些任务会立即执行。否则,其中一些任务可能会被放入队列中等待轮到它们。

上面这个示例中,我们创建了三个 Callable 任务,通过睡眠模拟 1000 毫秒的繁重工作。前两个任务将立即执行,第三个任务必须在队列中等待。我们可以通过在提交任务后立即调用 getPoolSize()getQueue().size() 来方法来验证。

Executors.newCachedThreadPool()

Executors 还提供了 Executors.newCachedThreadPool() 静态方法创建另一个预配置的 ThreadPoolExecutor。该方法创建的线程池没有任何核心线程,因为它将 corePoolSize 属性设置为 0,但同时有可以创建最大数量的额外线程,因为它将 maximumPoolSize 设置为 Integer.MAX_VALUE ,且将 keepAliveTime 的值设置为 60 秒。

这些参数值意味着缓存的线程池可以无限制地增长以容纳任何数量的已提交任务。但是,当不再需要线程时,它们将在 60秒不活动后被销毁。这种线程池的使用场景一般是你的应用程序中有很多短期任务。


ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newCachedThreadPool(); executor.submit(() -> { Thread.sleep(1000); return null; }); executor.submit(() -> { Thread.sleep(1000); return null; }); executor.submit(() -> { Thread.sleep(1000); return null; }); assertEquals(3, executor.getPoolSize()); assertEquals(0, executor.getQueue().size());

上面这个示例中的队列大小始终为 0 ,因为在内部使用了 SynchronousQueue 的实例。在 SynchronousQueue 中,插入和删除操作总是成对出现且同时发生。因此队列实际上从不包含任何内容。

Executors.newSingleThreadExecutor()

Executors.newSingleThreadExecutor() 静态方法则创建另一种典型的只包含单个线程的 ThreadPoolExecutor 实例。

这种单线程执行程序是创建事件循环的理想选择。

在这个单线程 ThreadPoolExecutor 实例中,属性 corePoolSize 和属性 maximumPoolSize 的值都为 1,而属性 keepAliveTime 的值为 0

在单线程 ThreadPoolExecutor 实例中,所有的任务都按顺序执行。因此,下面的示例中,任务完成后标志的值是 2


AtomicInteger counter = new AtomicInteger(); ExecutorService executor = Executors.newSingleThreadExecutor(); executor.submit(() -> { counter.set(1); }); executor.submit(() -> { counter.compareAndSet(1, 2); });

此外,单线程 ThreadPoolExecutor 实例使用了不可变包装器进行修饰,因此在创建后无法重新配置。当然了,这也是我们无法将该示例强制转换为 ThreadPoolExecutor 的原因。

写完了如果写得有什么问题,希望读者能够给小编留言,也可以点击[此处扫下面二维码关注微信公众号](https://www.ycbbs.vip/?p=28 "此处扫下面二维码关注微信公众号")

看完两件小事

如果你觉得这篇文章对你挺有启发,我想请你帮我两个小忙:

  1. 关注我们的 GitHub 博客,让我们成为长期关系
  2. 把这篇文章分享给你的朋友 / 交流群,让更多的人看到,一起进步,一起成长!
  3. 关注公众号 「方志朋」,公众号后台回复「666」 免费领取我精心整理的进阶资源教程
  4. JS中文网,Javascriptc中文网是中国领先的新一代开发者社区和专业的技术媒体,一个帮助开发者成长的社区,是给开发者用的 Hacker News,技术文章由为你筛选出最优质的干货,其中包括:Android、iOS、前端、后端等方面的内容。目前已经覆盖和服务了超过 300 万开发者,你每天都可以在这里找到技术世界的头条内容。

    本文著作权归作者所有,如若转载,请注明出处

    转载请注明:文章转载自「 Java极客技术学习 」https://www.javajike.com

    标题:004-四、Java并发 Java 线程池之 ThreadPoolExecutor(下)

    链接:https://www.javajike.com/article/1271.html

« 005-五、Java并发 ScheduledThreadPoolExecutor
003-三、Java并发 Java 线程池 ( Thread Pool ) (上)»

相关推荐

QR code