Java 并发编程实战
王宝令
资深架构师
72486 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 51 讲
学习攻略 (1讲)
Java 并发编程实战
15
15
1.0x
00:00/00:00
登录|注册

34 | Worker Thread模式:如何避免重复创建线程?

解决方案:为不同的任务创建不同的线程池
线程死锁场景
解决方案:为不同的任务创建不同的线程池
线程死锁场景
为线程赋予业务相关的名字
指明拒绝策略
创建有界队列
异步打印字符串“QQ”
小灰同学的代码问题
避免线程死锁
为线程赋予业务相关的名字
指明拒绝策略
创建有界队列
限制创建线程的上限
避免重复创建、销毁线程
使用线程池需要注意的问题
Worker Thread模式优点
避免线程死锁
正确创建线程池
使用线程池实现Worker Thread模式
车间工作模式比喻
与Thread-Per-Message模式对比
介绍Worker Thread模式
解决方案
问题分析
注意事项
优点
总结
实现
概述
异步编程
线程池
Worker Thread模式

该思维导图由 AI 生成,仅供参考

上一篇文章中,我们介绍了一种最简单的分工模式——Thread-Per-Message 模式,对应到现实世界,其实就是委托代办。这种分工模式如果用 Java Thread 实现,频繁地创建、销毁线程非常影响性能,同时无限制地创建线程还可能导致 OOM,所以在 Java 领域使用场景就受限了。
要想有效避免线程的频繁创建、销毁以及 OOM 问题,就不得不提今天我们要细聊的,也是 Java 领域使用最多的 Worker Thread 模式。

Worker Thread 模式及其实现

Worker Thread 模式可以类比现实世界里车间的工作模式:车间里的工人,有活儿了,大家一起干,没活儿了就聊聊天等着。你可以参考下面的示意图来理解,Worker Thread 模式中 Worker Thread 对应到现实世界里,其实指的就是车间里的工人。不过这里需要注意的是,车间里的工人数量往往是确定的。
车间工作示意图
那在编程领域该如何模拟车间的这种工作模式呢?或者说如何去实现 Worker Thread 模式呢?通过上面的图,你很容易就能想到用阻塞队列做任务池,然后创建固定数量的线程消费阻塞队列中的任务。其实你仔细想会发现,这个方案就是 Java 语言提供的线程池。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

Worker Thread模式是解决线程频繁创建、销毁以及OOM问题的有效方案。它类比于现实世界中车间的工作模式,通过创建固定数量的线程来消费阻塞队列中的任务,从而避免了线程频繁创建、销毁的问题。在Java领域,线程池是实现Worker Thread模式的最佳选择,它能够避免无限制地创建线程导致OOM,并且能够限制线程的最大数量。 正确创建线程池的方法包括使用有界队列来接收任务、指明拒绝策略以及为线程赋予业务相关的名字。此外,文章还强调了避免线程死锁的重要性,特别是在存在任务依赖关系的情况下,建议为不同的任务创建不同的线程池。 总的来说,Worker Thread模式能够有效解决线程频繁创建、销毁以及OOM问题,而线程池是实现该模式的重要工具。然而,在使用线程池时,需要格外谨慎,包括正确创建线程池、避免线程死锁问题以及处理任务异常等方面需要引起重视。 小灰同学的代码存在问题,因为他在任务中再次提交了任务给线程池,可能导致死锁或其他问题。正确的做法是直接打印字符串“QQ”而不是再次提交任务给线程池。 总的来说,本文介绍了Worker Thread模式及线程池的重要性和正确使用方法,对于需要解决线程频繁创建、销毁以及OOM问题的开发人员具有重要参考价值。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Java 并发编程实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(40)

  • 最新
  • 精选
  • vector
    工厂里只有一个工人,他的工作就是同步的等待工厂里其他人给他提供东西,然而并没有其他人,他将等到天荒地老,海枯石烂~

    作者回复: 比喻很形象👍

    2019-05-16
    103
  • 曾轼麟
    EagerThreadPool 老师这个线程池可以避免死锁的情况,死锁的时候会自动撑大

    作者回复: 👍👍

    2019-05-23
    2
    65
  • Geek_42f729
    看了一遍评论,有一部分同学回答了课后思考的结论,但是没有描述产生该结论的原因,我来描述一下吧,有不对的地方还请老师、同学们指出; 结论是:小灰写的代码会被一直阻塞; 原因是: 1. 通过Executors.newSingleThreadExecutor()创建的线程池默认是1个核心线程 + 无界工作队列; 2. 第一次submit时,会把池中唯一的一个核心线程给占用; 3. 第二次submit时,由于没有空闲的线程,并且工作队列也没满,所以线程池会把提交的任务添加到工作队列,然后等待空闲线程来执行该任务; 4. 在第二次submit时使用了.get()方法,这里会一直等到线程返回执行结果; 5. 由于两次submit是嵌套执行的,并且此时线程池中也没有空闲线程,所以第二次submit的任务永远不会被执行,.get()方法会就被永远阻塞,从而导致第一次submit的线程也被永远阻塞。

    作者回复: 分析很到位

    2022-03-18
    2
    19
  • zero
    感觉这程序会调用栈内存溢出,这段代码相当于无限的递归调用啊。不知道理解的对不对,请老师指点。

    作者回复: 不是递归,但会死锁

    2019-05-18
    15
  • 木刻
    希望老师能开一栏专门讲一讲Linux下多线程并发情况下程序性能的排查和调优。谢谢老师

    作者回复: 好累😂

    2019-05-17
    9
  • ack
    老师,请教个问题,线程死锁那个代码,是活锁吗,思考题我也认为是活锁

    作者回复: 我觉得是死锁,活锁有释放再获取的过程

    2019-05-16
    6
  • Mr_杨
    老师请教个问题,如果不同业务用不同线程池,保证不了线程数量,会带来并发线程过大,如何控制频繁上下文切换的问题

    作者回复: 无解,必须控制线程数量。

    2019-11-07
    2
  • 王成
    最近工作中遇到一个关于线程池的问题,莫名其妙的线程就不在执行 问题的原因是 每个线程都会去请求一次http,但是时间长了会出现阻塞现象(http工具类写的有点问题) 最终解决方案,除了优化工具类,还给每一个线程设置了超时时间

    作者回复: 设置超时绝对是最佳实践,否则必然出事

    2021-07-07
    1
  • 张申傲
    越来越发现,软件领域中的很多问题,都可以向现实世界寻求答案。

    作者回复: 一般人解决问题都是以现实世界模型为主的

    2021-03-22
    1
  • Monday
    本篇就是一个主题,java创建线程池,并特别注意 1、生产中拒绝使用Executors提供的初始化线程池的方法(因为使用无解队列) 2、生产环境应根据业务自定义拒绝策略

    作者回复: ������������

    2020-12-20
    3
收起评论
显示
设置
留言
40
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部