29 | 如何使用设计模式优化并发编程?
该思维导图由 AI 生成,仅供参考
线程上下文设计模式
- 深入了解
- 翻译
- 解释
- 总结
本文介绍了如何使用设计模式优化并发编程。首先介绍了线程上下文设计模式,通过具体案例展示了在多线程编程中如何使用上下文来传递信息,并通过ThreadLocal实现了上下文的设计。其次,介绍了Thread-Per-Message设计模式,通过Socket服务端的例子展示了如何使用该设计模式处理I/O操作。最后指出了使用线程池来代替线程的创建和销毁,以避免性能问题。文章内容涵盖了并发编程中常用的设计模式及优化方法,对于需要进行并发编程优化的读者具有一定的参考价值。 此外,文章还介绍了Worker-Thread设计模式,通过示例展示了如何使用该模式来减少频繁创建、销毁线程所带来的性能开销,以及无限制地创建线程所带来的内存溢出风险。通过物流分拣的作业场景,演示了Worker-Thread设计模式的实现过程,为读者提供了直观的应用案例。 总的来说,本文通过介绍多种设计模式及其在并发编程中的应用,为读者提供了丰富的优化思路和方法,对于需要优化多线程业务的读者具有一定的指导意义。
《Java 性能调优实战》,新⼈⾸单¥59
全部留言(23)
- 最新
- 精选
- 峰讲真,我是觉得设计模式是优化代码组织结构的,性能提升只是因为你的实现途径导致了你适合用某种设计模式,so感觉这样标题怪怪的。 如果要这么说的话,mapreduce或者说javase引入的forkjoin,流水线模式,cow就都是了。
作者回复: 是的,有些设计模式更多的是优化代码逻辑结构,但还是有很多设计模式也起到了优化性能效果。例如,文中的Worker-Thread 设计模式其实就是一种线程池的优化方式,在并发量大时,一般的代码逻辑要么是串行执行,要么使用创建线程并发执行,在大量并发时两者都可能会出现性能瓶颈,而这种Worker-Thread 这样的设计方式则即可以并发执行,又避免创建过多的线程导致性能瓶颈。
2019-07-27220 - Jxin1.最常用的多线程设计模式应该是生产者消费者模式,在分布式系统,该模式现在一般也由Mq来承接。(以rocketMq为例)好处有:消峰,解耦,消息堆积,多broker并行消费,单broker串行(顺序)消费,发布订阅,分组消费,失败重试,死信管理等等。 2.其他的业务不常用,比如lmmutability(不变模式,Long类的内部静态类对象池),还有个实时赋值COW,指得一提的应该还有个Actor,但java不支持,要玩又得引第三方包,所以java生产也不会用。 3.forkjoin并行处理也是使用的多线程执行子任务,但这个应该算不上多线程设计模式,感觉说是多线程应用更好,其中的任务窃取挺有意思。
作者回复: 很赞
2019-07-2913 - 张德老师好 我还用过reactor模式 这个多线程的thread-per-message感觉和reactor模式有点像 又有一些区别 但我就是总结不出之间的区别 老师能不能点化一下 多谢
作者回复: 我们在之前也讲过reactor模式,reactor模式是基于事件驱动,并且有专门有一个监听线程池监听事件,一旦有事件进来,将会再通过handler线程池来处理具体的业务,实现更为复杂,性能要比thread-per-message更佳
2019-07-3026 - QQ怪比起Worker-Thread 设计模式类似工厂车间工人的工作模式,还有用的比较多的是生产者和消费者模式,与之前的不同的是,生产者和消费者模式核心是一个任务队列,生产者生产任务到任务队列中,消费者从队列消费任务,优点是解耦和平衡两者之前的速度差异。
作者回复: 对的,分析的很到位。下一讲中我们会详细聊到生产者消费者模式。
2019-07-273 - undifined老师,有一个问题没想明白,就是异步的请求处理中,每一个线程接收将请求交给处理的线程后,怎么拿到返回结果并返回给用户呢
作者回复: 可以通过Future模式拿到返回结果,虽然是异步执行,如果要等待返回结果,则主线程还是在阻塞等待。
2019-07-273 - 风轻扬//InputStreamReader读取原始的字节流,FileReader继承自InputStreamReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); out = new PrintWriter(socket.getOutputStream(), true); while ((msg = br.readLine()) != null && msg.length() != 0) { System.out.println("server received:" + msg); out.write("received~\n"); out.flush(); } 老师,您在新建PrintWriter实例的时候,已经设置了自动刷新。为什么还要out.flush呢?这一句是多余的吧?
作者回复: 是的,多余了
2019-09-142 - -W.LI-老师啊!有没有好的书推荐,我觉得设计模式很好,源码应该是学习设计模式最好的老师,可是我的能力看源码感觉太早了。我就之前看过header first。感觉理解完全不够。好的设计模式和算法都能在系统性能有瓶颈的时候提升系统。我认识到它的重要了可是不得门,入不了难受啊。
作者回复: 我记得大学时候读过一本《大话设计模式》的书籍不错,讲解的通俗易懂。
2019-07-2832 - 陆离老师,讲到并发这里,我想问一个前面讲过的synchronized锁升级的几个问题。 1.当锁由无锁状态升级到偏向锁时,除了将Mark Work中的线程ID替换是否还有其他操作?替换完线程ID就代表获取到了锁吗? 2.当锁状态为偏向锁状态时, 其他线程竞争锁只是CAS替换线程ID吗?如果之前的线程还没有执行完呢? 3.针对第2个问题,假设线程T1获取到了偏向锁,将线程ID设为T1。线程T2尝试获取偏向锁时,先检测锁的Mark Word线程ID是否为T2,如果不是,会CAS替换,这个时候的期望值为null,更新值为T2,失败后进入偏向锁撤销。stop-the-world后检测T1是否存活,如果否清空Mark work线程ID,锁恢复为无锁状态,唤醒T2,接着尝试获取锁。流程是这样的吗? 4.当锁升级为轻量级锁时,获取锁的标志是锁指针指向线程的锁记录,当有其他线程尝试CAS获取锁时,期望值是无锁时,Mark word中为hash age 01这样的内容吗? 5.当线程释放轻量锁时,需要将锁记录替换回Mark Word中,这种情况下锁还未释放为什么会有失败? 6.当锁升级为重量锁后,开始使用monitor对象,为什么Mark Word中还会把内容替换为指向线程锁记录的指针?这个时候还需要使用Mark word吗? 期待老师及同学的解答
作者回复: 1、替换之后,“是否偏向锁”标志位设置为 1; 2、如果获取锁失败,代表当前锁有一定的竞争,偏向锁将升级为轻量级锁; 3、是的; 4、标志位为00; 5、如果是锁释放轻量级锁,直接将指向轻量级锁的指针置为null就可以了; 6、这个是轻量级升级为重量级就会带过来的,暂时没有观察到具体的作用
2019-07-2732 - nightmare一个注册逻辑,下面有注册实现数组,注册实现里面有队列,并且本身实现runable ,注册门面依次从注册实现数组获取一个注册实现 并把请求放到注册实现的队列中,请求由一个注册实现来完成,请求由唯一的注册实现来完成,不会有并发问题 而且如果 注册实现有复杂业务 还可以加上 work thread模式来优化
作者回复: 赞,现学现用
2019-07-272 - 停三秒老师,其实我觉得worker-thread设计模式就是生产者消费者模式。执行流水线的take的Worker就是消费者,执行put的一方就是生产者。
作者回复: 是的
2020-02-011