29 | 如何使用设计模式优化并发编程?
29 | 如何使用设计模式优化并发编程?
讲述:李良
时长06:24大小5.85M
线程上下文设计模式
Thread-Per-Message 设计模式
Worker-Thread 设计模式
总结
思考题
赞 6
提建议
精选留言(23)
- 峰2019-07-27讲真,我是觉得设计模式是优化代码组织结构的,性能提升只是因为你的实现途径导致了你适合用某种设计模式,so感觉这样标题怪怪的。 如果要这么说的话,mapreduce或者说javase引入的forkjoin,流水线模式,cow就都是了。
作者回复: 是的,有些设计模式更多的是优化代码逻辑结构,但还是有很多设计模式也起到了优化性能效果。例如,文中的Worker-Thread 设计模式其实就是一种线程池的优化方式,在并发量大时,一般的代码逻辑要么是串行执行,要么使用创建线程并发执行,在大量并发时两者都可能会出现性能瓶颈,而这种Worker-Thread 这样的设计方式则即可以并发执行,又避免创建过多的线程导致性能瓶颈。
共 2 条评论19 - Jxin2019-07-291.最常用的多线程设计模式应该是生产者消费者模式,在分布式系统,该模式现在一般也由Mq来承接。(以rocketMq为例)好处有:消峰,解耦,消息堆积,多broker并行消费,单broker串行(顺序)消费,发布订阅,分组消费,失败重试,死信管理等等。 2.其他的业务不常用,比如lmmutability(不变模式,Long类的内部静态类对象池),还有个实时赋值COW,指得一提的应该还有个Actor,但java不支持,要玩又得引第三方包,所以java生产也不会用。 3.forkjoin并行处理也是使用的多线程执行子任务,但这个应该算不上多线程设计模式,感觉说是多线程应用更好,其中的任务窃取挺有意思。展开
作者回复: 很赞
13 - 张德2019-07-30老师好 我还用过reactor模式 这个多线程的thread-per-message感觉和reactor模式有点像 又有一些区别 但我就是总结不出之间的区别 老师能不能点化一下 多谢
作者回复: 我们在之前也讲过reactor模式,reactor模式是基于事件驱动,并且有专门有一个监听线程池监听事件,一旦有事件进来,将会再通过handler线程池来处理具体的业务,实现更为复杂,性能要比thread-per-message更佳
共 2 条评论5 - QQ怪2019-07-27比起Worker-Thread 设计模式类似工厂车间工人的工作模式,还有用的比较多的是生产者和消费者模式,与之前的不同的是,生产者和消费者模式核心是一个任务队列,生产者生产任务到任务队列中,消费者从队列消费任务,优点是解耦和平衡两者之前的速度差异。
作者回复: 对的,分析的很到位。下一讲中我们会详细聊到生产者消费者模式。
3 - undifined2019-07-27老师,有一个问题没想明白,就是异步的请求处理中,每一个线程接收将请求交给处理的线程后,怎么拿到返回结果并返回给用户呢
作者回复: 可以通过Future模式拿到返回结果,虽然是异步执行,如果要等待返回结果,则主线程还是在阻塞等待。
3 - 风轻扬2019-09-14//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呢?这一句是多余的吧?展开
作者回复: 是的,多余了
2 - -W.LI-2019-07-28老师啊!有没有好的书推荐,我觉得设计模式很好,源码应该是学习设计模式最好的老师,可是我的能力看源码感觉太早了。我就之前看过header first。感觉理解完全不够。好的设计模式和算法都能在系统性能有瓶颈的时候提升系统。我认识到它的重要了可是不得门,入不了难受啊。
作者回复: 我记得大学时候读过一本《大话设计模式》的书籍不错,讲解的通俗易懂。
共 3 条评论2 - 陆离2019-07-27老师,讲到并发这里,我想问一个前面讲过的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、这个是轻量级升级为重量级就会带过来的,暂时没有观察到具体的作用
共 3 条评论2 - nightmare2019-07-27一个注册逻辑,下面有注册实现数组,注册实现里面有队列,并且本身实现runable ,注册门面依次从注册实现数组获取一个注册实现 并把请求放到注册实现的队列中,请求由一个注册实现来完成,请求由唯一的注册实现来完成,不会有并发问题 而且如果 注册实现有复杂业务 还可以加上 work thread模式来优化
作者回复: 赞,现学现用
2 - aoe2019-10-10除了文中第一个设计模式,其他设计模式在《图解Java多线程设计模式》中都有更详细的介绍。感谢老师的分享,如果能在专栏的第一篇文章中推荐一些相关的书籍就更好了。1
- 风轻扬2019-09-14老师,前几天看了一篇帖子,上面说System.currentMills在高并下下也会有性能问题。我看您直接用的,并没有做优化。您在实际工作中,有没有碰见过System.currentMills影响性能的例子呢?
作者回复: 这个性能我猜是说的相对的,只是说System.currentTimeMillis() 性能损耗更大
1 - Liam2019-07-29老师好,文中提到,通过threadlocal动态切换数据源是什么意思?指的是用一个threadlocal的map管理多数据源的连接,每次都从map去拿不同datasource的连接吗?
作者回复: 对的,例如读写分离,ThreadLocal存放了读从库数据源和写主库数据源,如果是查询操作,则切换为读数据源,如果是新增修改删除操作,则切换为写数据源。
共 3 条评论1 - 晓杰2019-07-28请问老师packageChannel中的成员变量count不会存在线程安全问题吗
作者回复: 我们对put take方法已经加锁了,所以是线程安全的。
1 - Sherk2021-07-14老师我有一个疑惑,ThreadLocal不是线程独享的么,线程是拿不到其他线程设置的applicationContext。所以这边applicationContext还是一个共享的上下文信息吗
- 平民人之助2021-07-11搞设计模式也要比较容易调试和排查问题
- 姜大大2020-12-19老师,关于ThreadLocal我有个问题,在entry数组中, ThreadLocal作为key是弱引用,那垃圾回收随时就会把它回收了,那这样没有key就获取不到value,是不是说使用 ThreadLocal不能一定保证能获取到数据啊。帮忙解答一下
- 不工2020-12-15// 获取ActionContext单例 public static class ContextHolder { private final static ActionContext actionContext = new ActionContext(); } 为什么不在ActionContext的get方法里直接获取,要兜一圈从静态类中获取?
- Gavin2020-07-27老师,请问下使用ThreadLocal是不是有这样一个问题,线程开始是设置一个变量,key是弱引用,中间由于GC回收了key,会导致最后获取不到一开始设置的值。
- 停三秒2020-02-01老师,其实我觉得worker-thread设计模式就是生产者消费者模式。执行流水线的take的Worker就是消费者,执行put的一方就是生产者。
作者回复: 是的
1 - Mr wind2019-12-13还是不明白Worker-Thread 设计模式相比普通线程池的优点是什么呢,两者都可以创建固定的线程,都会在满载时等待。
作者回复: 是的,原理都是生产者消费者模式。