12 | 如何用面向对象思想写好并发程序?
王宝令
该思维导图由 AI 生成,仅供参考
在工作中,我发现很多同学在设计之初都是直接按照单线程的思路来写程序的,而忽略了本应该重视的并发问题;等上线后的某天,突然发现诡异的 Bug,再历经千辛万苦终于定位到问题所在,却发现对于如何解决已经没有了思路。
关于这个问题,我觉得咱们今天很有必要好好聊聊“如何用面向对象思想写好并发程序”这个话题。
面向对象思想与并发编程有关系吗?本来是没关系的,它们分属两个不同的领域,但是在 Java 语言里,这两个领域被无情地融合在一起了,好在融合的效果还是不错的:在 Java 语言里,面向对象思想能够让并发编程变得更简单。
那如何才能用面向对象思想写好并发程序呢?结合我自己的工作经验来看,我觉得你可以从封装共享变量、识别共享变量间的约束条件和制定并发访问策略这三个方面下手。
一、封装共享变量
并发程序,我们关注的一个核心问题,不过是解决多线程同时访问共享变量的问题。在《03 | 互斥锁(上):解决原子性问题》中,我们类比过球场门票的管理,现实世界里门票管理的一个核心问题是:所有观众只能通过规定的入口进入,否则检票就形同虚设。在编程世界这个问题也很重要,编程领域里面对于共享变量的访问路径就类似于球场的入口,必须严格控制。好在有了面向对象思想,对共享变量的访问路径可以轻松把控。
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
- 深入了解
- 翻译
- 解释
- 总结
本文介绍了如何利用面向对象思想编写并发程序,重点在于利用面向对象的封装特性来封装共享变量,并避免“逸出”。作者提出了封装共享变量、识别约束条件以及制定并发访问策略等方法和原则,以帮助读者编写健壮的并发程序。文章内容涵盖了面向对象思想与并发编程的关系、共享变量的封装、约束条件的识别以及并发访问策略的制定,为读者提供了全面的并发编程指导。此外,作者还提到了延伸阅读推荐的书籍,以便读者深入学习相关内容。整体而言,本文为读者提供了深入理解并发编程的机会,并为他们解决并发问题提供了思考的方向。
仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Java 并发编程实战》,新⼈⾸单¥59
《Java 并发编程实战》,新⼈⾸单¥59
立即购买
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
登录 后留言
全部留言(101)
- 最新
- 精选
- magict41. setUpper() 跟 setLower() 都加上 "synchronized" 关键字。不要太在意性能,老师都说了,避免过早优化。 2. 如果性能有问题,可以把 lower 跟 upper 两个变量封装到一个类中,例如 ``` public class Boundary { private final lower; private final upper; public Boundary(long lower, long upper) { if(lower >= upper) { // throw exception } this.lower = lower; this.upper = upper; } } ``` 移除 SafeVM 的 setUpper() 跟 setLower() 方法,并增入 setBoundary(Boundary boundary) 方法。
作者回复: 👍👍
2019-03-2615180 - 海鸿我看有些人评论用volatie,volatie只能保证可见性,但是保证不了原子性,所以得加锁保证互斥。 老师我这样理解对吗?
作者回复: 相当正确!
2019-03-26863 - 江南豆沙包令哥,一直在追你的专栏,结合公司目前实际情况,有个疑问,如果你专栏中的例子中的共享信息,是整个系统维度的,系统又是多实例集群部署的,我们该怎么办呢,能不能在思想或实现思路上给点建议指导。
作者回复: 感谢信任!我们这里说的共享是进程级别的,如果是分布式计算只能靠redis,db,zk这些来搞分布式的锁,当然不共享是最好的解决方案。
2019-03-26431 - QQ怪必须加锁啊,synchronized (this)就行了,最简单加锁吧,volatile只能保证内存可见性,并不能保证原子性
作者回复: 👍
2019-03-27228 - 我是卖报小行家前面有个朋友说final保证不会逃逸,理解应该有误,fianl的禁止重排序前提是构造函数里面没有this逃逸,他只保证final变量不会重排序到构造函数之外。并不保证逃逸。
作者回复: 👍
2019-03-27418 - 罗洲思考题:对于两个互相比较的变量来说,赋值的时候只能加锁来控制。但是这也会带来性能问题,不过可以采用读锁和写锁来优化,申请写锁了就互斥,读锁可以并发访问,这样性能相对粗粒度的锁来说会高点。
作者回复: 👍
2019-03-26212 - zeropublic class SafeWM { // 库存上限 private final AtomicLong upper = new AtomicLong(0); // 库存下限 private final AtomicLong lower = new AtomicLong(0); // 设置库存上限 void setUpper(long v) { synchronized (this) { // 检查参数合法性 if (v < lower.get()) { throw new IllegalArgumentException(); } upper.set(v); } } // 设置库存下限 void setLower(long v) { synchronized (this) { // 检查参数合法性 if (v > upper.get()) { throw new IllegalArgumentException(); } lower.set(v); } } // 省略其他业务代码 } 老师,这样处理可以吗?
作者回复: 可以
2019-03-2728 - Cc又想到一种,既然两个变量要同时锁定,那就把两个变量封装成一个,然后使用cas操作。这样行不行,另外老师帮我看看volatile是不是有多余的地方 ··········· volatile AtomicReference<Inventory> inventory = new AtomicReference<>(); static class Inventory { private volatile long upper = 0; private volatile long lower = 0; } void setUpper(long v) { long low; Inventory oldObj; Inventory newObj; do { oldObj = inventory.get(); if (v >= (low = oldObj.lower)) { throw new IllegalArgumentException(); } newObj = new Inventory(); newObj.lower = low; newObj.upper = v; } while (inventory.compareAndSet(oldObj, newObj)); } void setLower(long v) { long upp; Inventory oldObj; Inventory newObj; do { oldObj = inventory.get(); if (v <= (upp = oldObj.upper)) { throw new IllegalArgumentException(); } newObj = new Inventory(); newObj.lower = v; newObj.upper = upp; } while (inventory.compareAndSet(oldObj, newObj)); }
作者回复: 我觉得这个没有问题,volatile 换成 final会更好
2019-03-2947 - Airsaid「迫不得已时才使用低级的同步原语:低级的同步原语主要指的是 synchronized、Lock、Semaphore 等,这些虽然感觉简单,但实际上并没那么简单,一定要小心使用。」 老师您好,这里内置锁和显式锁都是低级同步原语,那什么是高级同步原语呢?
作者回复: 内置的支持并发的数据结构等等
2020-03-0425 - Geek_a8e9a2老师,这个方案如何? public class SafeVm { private volatile long upNum = 10; private volatile long lowNum = 1; private ReadWriteLock upLock = new ReentrantReadWriteLock(); private ReadWriteLock lowLock = new ReentrantReadWriteLock(); void setUpper(long newUpValue) { lowLock.readLock().lock(); try { if (newUpValue < lowNum) { throw new IllegalArgumentException(); } upLock.writeLock().lock(); try { upNum = newUpValue; } finally { upLock.writeLock().unlock(); } } finally { lowLock.readLock().unlock(); } } void setLower(long newLowValue) { upLock.readLock().lock(); try { if (newLowValue > upNum) { throw new IllegalArgumentException(); } lowLock.writeLock().lock(); try { lowNum = newLowValue; } finally { lowLock.writeLock().unlock(); } } finally { upLock.readLock().unlock(); } } }
作者回复: 想了半天,应该没问题
2020-11-0754
收起评论