百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分类 > 正文

Java线程池newCachedThreadPool和newFixedThreadPool对比

ztj100 2025-05-23 21:37 68 浏览 0 评论

概述

谈到线程池, Java中提供了很多选择。其中, cached thread pool 和 thread thread pool 是最常用到的两个。在本教程中,我们将从底层源码,来分析比较他们是如何工作的,以及有什么不同。

Cached Thread Pool

让我们来看看 Java 在调用
Executors.newCachedThreadPool ()时是如何创建缓存线程池的:

public static ExecutorService newCachedThreadPool() {

return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS,

new SynchronousQueue<Runnable>());

}

从上面的代码中, 我们看到了newCachedThreadPool是通过SynchronousQueue来实现的,意思就是,假设有一个新的任务,如果队列上有一个空闲线程在等待,则任务生成器将任务移交给该线程。 否则,由于队列总是满的,执行程序将创建一个新线程来处理该任务。

它使用了一种叫做“同步切换”的策略,当且仅当另一个线程能同步接收该任务时,才可以对该项进行排队。 换句话说,SynchronousQueue 不能容纳任何任务。

缓存池从零个线程开始,可能会增长为 Integer.MAX VALUE 线程。 实际上,缓存线程池的唯一限制是可用的系统资源,即系统可打开的线程数。

当然,为了更好的管理资源,缓存的线程池将删除空闲一分钟的线程。

Cached Thread Pool用例

Cached Thread Pool会将线程缓存(因此而得名)一段时间,以便为其他任务重新使用它们。 因此,当我们处理合理数量的短期任务时,该线程池能运行的很好。

这里有两个关键点, 合理数量和短期。为了说明这一点,我们用一段伪代码举个例子:

Callable<String> task = () -> {

long oneHundredMicroSeconds = 100_000;

long startedAt = System.nanoTime();

while (System.nanoTime() - startedAt <= oneHundredMicroSeconds);

return "Done";

};

cachedPool = Executors.newCachedThreadPool();

tasks = IntStream.rangeClosed(1, 1_000_000).mapToObj(i -> task).collect(toList());

result = cachedPool.invokeAll(tasks);

在这里,我们将提交100万个任务,每个任务需要100微秒完成。这将导致大量线程转换为不合理的内存使用,更糟糕的是,大量 CPU 上下文切换。 这两种异常情况都会严重影响整体性能。

因此,当执行时间不可预测时,或者数量比较大的任务时,我们应该避免使用这个线程池。

Fixed Thread Pool

让我们来看一下固定线程池源码中是如何实现的:

public static ExecutorService newFixedThreadPool(int nThreads) {

return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS,

new LinkedBlockingQueue<Runnable>());

}

这里,固定线程池使用了LinkedBlockingQueue来实现。

与缓存的线程池相反,这个线程池使用的是一个具有固定数量的,没有过期时间的无界队列。 因此,固定线程池会尝试使用固定数量的线程来执行传入的任务,而不是不断增加线程数量。 当所有线程都处于忙碌状态时,执行器将为新任务排队。 这样,我们就可以更好地控制程序的资源消耗。

因此,固定线程池更适合于执行时间不可预测的任务。

cached/fixed Thread Pool 共同的缺点

到目前为止,我们只列举了缓存线程池和固定线程池之间的区别。以及他们适合使用的场景。

但是两者都有一个共同的缺点,当有大量任务时,不管是cached thread pool 通过增加线程数量来处理,还是fixed Thread Pool对新任务进行排队处理,都会消耗大量内存来创建线程或排队任务。 更糟糕的是,缓存的线程池还会导致大量的处理器上下文切换。

所以,为了更好地控制资源消耗,强烈建议创建一个自定义 ThreadPoolExecutor:

boundedQueue = new ArrayBlockingQueue<Runnable>(1000);

new ThreadPoolExecutor(10, 20, 60, SECONDS, boundedQueue, new AbortPolicy());

在这里,我们的线程池可以有多达20个线程,并且只能将多达1000个任务排队。 此外,当它不能接受任何更多的负载时,它将简单地抛出一个异常。

总结

在本教程中,我们了解了 JDK 源代码,看到了不同的 executor 在底层是如何工作的。 然后,我们比较了固定线程池和缓存线程池,以及他们适合的使用场景。最后,我们尝试使用自定义线程池来解决这些线程池由于自身设计问题,导致的资源消耗问题。

相关推荐

这个 JavaScript Api 已被废弃!请慎用!

在开发过程中,我们可能会不自觉地使用一些已经被标记为废弃的JavaScriptAPI。这些...

JavaScript中10个“过时”的API,你的代码里还在用吗?

JavaScript作为一门不断发展的语言,其API也在持续进化。新的、更安全、更高效的API不断涌现,而一些旧的API则因为各种原因(如安全问题、性能瓶颈、设计缺陷或有了更好的替代品)被标记为“废...

几大开源免费的 JavaScript 富文本编辑器测评

MarkDown编辑器用的时间长了,发现发现富文本编辑器用起来是真的舒服。...

比较好的网页里面的 html 编辑器 推荐

如果您正在寻找嵌入到网页中的HTML编辑器,以便用户可以直接在网页上编辑HTML内容,以下是几个备受推荐的:CKEditor:CKEditor是一个功能强大的、开源的富文本编辑器,可以嵌入到...

Luckysheet 实现excel多人在线协同编辑

前言前些天看到Luckysheet支持协同编辑Excel,正符合我们协同项目的一部分,故而想进一步完善协同文章,但是遇到了一下困难,特此做声明哈,若侵权,请联系我删除文章!若侵犯版权、个人隐私,请联系...

从 Element UI 源码的构建流程来看前端 UI 库设计

作者:前端森林转发链接:https://mp.weixin.qq.com/s/ziDMLDJcvx07aM6xoEyWHQ引言...

手把手教你如何用 Decorator 装饰你的 Typescript?「实践」

作者:Nealyang转发连接:https://mp.weixin.qq.com/s/PFgc8xD7gT40-9qXNTpk7A...

推荐五个优秀的富文本编辑器

富文本编辑器是一种可嵌入浏览器网页中,所见即所得的文本编辑器。对于许多从事前端开发的小伙伴来说并不算陌生,它的应用场景非常广泛,平时发个评论、写篇博客文章等都能见到它的身影。...

基于vue + element的后台管理系统解决方案

作者:林鑫转发链接:https://github.com/lin-xin前言该方案作为一套多功能的后台框架模板,适用于绝大部分的后台管理系统(WebManagementSystem)开发。基于v...

开源富文本编辑器Quill 2.0重磅发布

开源富文本编辑器Quill正式发布2.0版本。官方TypeScript声明...

Python之Web开发框架学习 Django-表单处理

在Django中创建表单实际上类似于创建模型。同样,我们只需要从Django类继承,则类属性将是表单字段。让我们在myapp文件夹中添加一个forms.py文件以包含我们的应用程序表单。我们将创建一个...

Django测试入门:打造坚实代码基础的钥匙

这一篇说一下django框架的自动化测试,...

Django ORM vs SQLAlchemy:到底谁更香?从入门到上头的选择指南

阅读文章前辛苦您点下“关注”,方便讨论和分享,为了回馈您的支持,我将每日更新优质内容。...

超详细的Django 框架介绍,它来了!

时光荏苒,一晃小编的Tornado框架系列也结束了。这个框架虽然没有之前的FastAPI高流量,但是,它也是小编的心血呀。总共16篇博文,从入门到进阶,包含了框架的方方面面。虽然小编有些方面介绍得不是...

20《Nginx 入门教程》使用 Nginx 部署 Python 项目

今天的目标是完成一个PythonWeb项目的线上部署,我们使用最新的Django项目搭建一个简易的Web工程,然后基于Nginx服务部署该PythonWeb项目。1.前期准备...

取消回复欢迎 发表评论: