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

12 | 如何用面向对象思想写好并发程序?

避免共享变量“逸出”
利用面向对象思想编写并发程序的关键点
宏观原则
管程及其他同步工具
不变模式
避免共享
竞态条件和if语句
例子:库存下限要小于库存上限
约束条件决定并发访问策略
使用final关键字修饰不变的共享变量
共享变量作为对象属性封装
面向对象思想中的封装特性
延伸阅读
课后思考
总结
三、制定并发访问策略
二、识别共享变量间的约束条件
一、封装共享变量
面向对象思想与并发编程的关系
如何用面向对象思想写好并发程序?

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

在工作中,我发现很多同学在设计之初都是直接按照单线程的思路来写程序的,而忽略了本应该重视的并发问题;等上线后的某天,突然发现诡异的 Bug,再历经千辛万苦终于定位到问题所在,却发现对于如何解决已经没有了思路。
关于这个问题,我觉得咱们今天很有必要好好聊聊“如何用面向对象思想写好并发程序”这个话题。
面向对象思想与并发编程有关系吗?本来是没关系的,它们分属两个不同的领域,但是在 Java 语言里,这两个领域被无情地融合在一起了,好在融合的效果还是不错的:在 Java 语言里,面向对象思想能够让并发编程变得更简单
那如何才能用面向对象思想写好并发程序呢?结合我自己的工作经验来看,我觉得你可以从封装共享变量、识别共享变量间的约束条件和制定并发访问策略这三个方面下手。

一、封装共享变量

并发程序,我们关注的一个核心问题,不过是解决多线程同时访问共享变量的问题。在《03 | 互斥锁(上):解决原子性问题》中,我们类比过球场门票的管理,现实世界里门票管理的一个核心问题是:所有观众只能通过规定的入口进入,否则检票就形同虚设。在编程世界这个问题也很重要,编程领域里面对于共享变量的访问路径就类似于球场的入口,必须严格控制。好在有了面向对象思想,对共享变量的访问路径可以轻松把控。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文介绍了如何利用面向对象思想编写并发程序,重点在于利用面向对象的封装特性来封装共享变量,并避免“逸出”。作者提出了封装共享变量、识别约束条件以及制定并发访问策略等方法和原则,以帮助读者编写健壮的并发程序。文章内容涵盖了面向对象思想与并发编程的关系、共享变量的封装、约束条件的识别以及并发访问策略的制定,为读者提供了全面的并发编程指导。此外,作者还提到了延伸阅读推荐的书籍,以便读者深入学习相关内容。整体而言,本文为读者提供了深入理解并发编程的机会,并为他们解决并发问题提供了思考的方向。

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

全部留言(101)

  • 最新
  • 精选
  • magict4
    1. 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-26
    15
    180
  • 海鸿
    我看有些人评论用volatie,volatie只能保证可见性,但是保证不了原子性,所以得加锁保证互斥。 老师我这样理解对吗?

    作者回复: 相当正确!

    2019-03-26
    8
    63
  • 江南豆沙包
    令哥,一直在追你的专栏,结合公司目前实际情况,有个疑问,如果你专栏中的例子中的共享信息,是整个系统维度的,系统又是多实例集群部署的,我们该怎么办呢,能不能在思想或实现思路上给点建议指导。

    作者回复: 感谢信任!我们这里说的共享是进程级别的,如果是分布式计算只能靠redis,db,zk这些来搞分布式的锁,当然不共享是最好的解决方案。

    2019-03-26
    4
    31
  • QQ怪
    必须加锁啊,synchronized (this)就行了,最简单加锁吧,volatile只能保证内存可见性,并不能保证原子性

    作者回复: 👍

    2019-03-27
    2
    28
  • 我是卖报小行家
    前面有个朋友说final保证不会逃逸,理解应该有误,fianl的禁止重排序前提是构造函数里面没有this逃逸,他只保证final变量不会重排序到构造函数之外。并不保证逃逸。

    作者回复: 👍

    2019-03-27
    4
    18
  • 罗洲
    思考题:对于两个互相比较的变量来说,赋值的时候只能加锁来控制。但是这也会带来性能问题,不过可以采用读锁和写锁来优化,申请写锁了就互斥,读锁可以并发访问,这样性能相对粗粒度的锁来说会高点。

    作者回复: 👍

    2019-03-26
    2
    12
  • zero
    public 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-27
    2
    8
  • 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-29
    4
    7
  • Airsaid
    「迫不得已时才使用低级的同步原语:低级的同步原语主要指的是 synchronized、Lock、Semaphore 等,这些虽然感觉简单,但实际上并没那么简单,一定要小心使用。」 老师您好,这里内置锁和显式锁都是低级同步原语,那什么是高级同步原语呢?

    作者回复: 内置的支持并发的数据结构等等

    2020-03-04
    2
    5
  • 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-07
    5
    4
收起评论
显示
设置
留言
99+
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部