解决并发问题,其实最简单的办法就是让共享变量只有读操作,而没有写操作。这个办法如此重要,以至于被上升到了一种解决并发问题的设计模式:不变性(Immutability)模式。所谓不变性,简单来讲,就是对象一旦被创建之后,状态就不再发生变化。换句话说,就是变量一旦被赋值,就不允许修改了(没有写操作);没有修改操作,也就是保持了不变性。

快速实现具备不可变性的类

将一个类所有的属性都设置成 final 的,并且只允许存在只读方法,那么这个类基本上就具备不可变性了。更严格的做法是这个类本身也是 final 的,也就是不允许继承。因为子类可以覆盖父类的方法,有可能改变不可变性,所以推荐你在实际工作中,使用这种更严格的做法。

经常用到的 String 和 Long、Integer、Double 等基础类型的包装类都具备不可变性。

利用享元模式避免创建重复对象

享元模式本质上其实就是一个对象池,利用享元模式创建对象的逻辑也很简单:创建之前,首先去对象池里看看是不是存在;如果已经存在,就利用对象池里的对象;如果不存在,就会新创建一个对象,并且把这个新创建出来的对象放进对象池里。

使用 Immutability 模式的注意事项

1. 对象的所有属性都是 final 的,并不能保证不可变性;
2. 不可变对象也需要正确发布。

例如下面的代码中,Bar 的属性 foo虽然是 final 的,依然可以通过 setAge() 方法来设置 foo 的属性 age。所以,在使用Immutability 模式的时候一定要确认保持不变性的边界在哪里,是否要求属性对象也具备不可变性。

class Foo{int age = 0;int name = "abc";
}final class Bar {final Foo foo;void setAge(int a){foo.age = a;}
}

下面我们再看看如何正确地发布不可变对象。不可变对象虽然是线程安全的,但是并不意味着引用这些不可变对象的对象就是线程安全的。例如在下面的代码中,Foo 具备不可变性,线程安全,但是类 Bar 并不是线程安全的,类 Bar 中持有对 Foo 的引用 foo,对 foo这个引用的修改在多线程中并不能保证可见性和原子性。

//Foo 线程安全
final class Foo{final int age = 0;final int name = "abc";
}//Bar 线程不安全
class Bar {Foo foo;void setFoo(Foo f){this.foo = f;}
}

如果你的程序仅仅需要 foo 保持可见性,无需保证原子性,那么可以将 foo 声明为volatile 变量,这样就能保证可见性。如果你的程序需要保证原子性,那么可以通过原子类来实现。

public class SafeWM {class WMRange{final int upper;final int lower;WMRange(int upper,int lower){// 省略构造函数实现}}final AtomicReference<WMRange>rf = new AtomicReference<>(new WMRange(0,0));// 设置库存上限public void setUpper(int v){while(true){WMRange or = rf.get();// 检查参数合法性if(v < or.lower){throw new IllegalArgumentException();}WMRange nr = new WMRange(v, or.lower);if(rf.compareAndSet(or, nr)){return;}}}
}

Java并发编程实战~Immutability模式相关推荐

  1. Java并发编程实战~Thread-Per-Message模式

    我们曾经把并发编程领域的问题总结为三个核心问题:分工.同步和互斥.其中,同步和互斥相关问题更多地源自微观,而分工问题则是源自宏观.我们解决问题,往往都是从宏观入手,在编程领域,软件的设计过程也是先从概 ...

  2. Java并发编程实战~Balking模式

    上一篇文章中,我们提到可以用"多线程版本的 if"来理解 Guarded Suspension 模式,不同于单线程中的 if,这个"多线程版本的 if"是需要等 ...

  3. Java并发编程实战~Copy-on-Write模式

    Copy-on-Write 模式的应用领域 1.在操作系统领域.类 Unix 的操作系统中创建进程的 API 是 fork(),传统的 fork() 函数会创建父进程的一个完整副本 2.很多文件系统也 ...

  4. 《Java 并发编程实战》--读书笔记

    Java 并发编程实战 注: 极客时间<Java 并发编程实战>–读书笔记 GitHub:https://github.com/ByrsH/Reading-notes/blob/maste ...

  5. Java并发编程实战笔记2:对象的组合

    设计线程安全的类 在设计现车让安全类的过程之中,需要包含以下三步: 找出构成对象状态的所有变量 找出约束状态变量的不变性条件 建立对象状态的并发访问策略 实例封闭 通过封闭机制与合适的加锁策略结合起来 ...

  6. Java并发编程实战_不愧是领军人物!这种等级的“Java并发编程宝典”谁能撰写?...

    前言 大家都知道并发编程技术就是在同一个处理器上同时的去处理多个任务,充分的利用到处理器的每个核心,最大化的发挥处理器的峰值性能,这样就可以避免我们因为性能而产生的一些问题. 大厂的核心负载肯定是非常 ...

  7. java并发编程实战学习(3)--基础构建模块

    转自:java并发编程实战 5.3阻塞队列和生产者-消费者模式 BlockingQueue阻塞队列提供可阻塞的put和take方法,以及支持定时的offer和poll方法.如果队列已经满了,那么put ...

  8. 视频教程-Java并发编程实战-Java

    Java并发编程实战 2018年以超过十倍的年业绩增长速度,从中高端IT技术在线教育行业中脱颖而出,成为在线教育领域一匹令人瞩目的黑马.咕泡学院以教学培养.职业规划为核心,旨在帮助学员提升技术技能,加 ...

  9. 【极客时间】《Java并发编程实战》学习笔记

    目录: 开篇词 | 你为什么需要学习并发编程? 内容来源:开篇词 | 你为什么需要学习并发编程?-极客时间 例如,Java 里 synchronized.wait()/notify() 相关的知识很琐 ...

最新文章

  1. 一份520页的机器学习笔记!附下载链接
  2. SQL Server的WAITFOR DELAY注入
  3. 网络营销外包——企业如何选择网站服务器?网络营销外包来帮你!
  4. 2020年,数据中心的绿色技术演进与创新
  5. [转]对C#泛型中的new()约束的一点思考
  6. 列表的定义、索引、添加、删除、查找、排序
  7. SQL基础【六、and与or】
  8. android eclipse的环境配置
  9. Java基础学习总结(127)——Java方法应该返回空对象还是null
  10. 【遥感数字图像处理】实验:遥感影像增强方法大全处理看过来(Erdas版)
  11. 显卡硬解4k测试软件,看看GPU解码!GTX970显卡实测硬解4K视频
  12. 2022Android设备唯一标识(AndroidID,OAID等 )
  13. FPGA简单实现数据过采样
  14. python百度云链接哔哩哔哩弹幕网_python预课05 爬虫初步学习+jieba分词+词云库+哔哩哔哩弹幕爬取示例(数据分析pandas)...
  15. PHP与MySQL交互实现网页登录注册功能(步骤超详细!!!)
  16. 状态方程simulink仿真_控制系统设计与仿真作业与复习资料
  17. 深度解析B端设计规范如何落地?
  18. SAP客户主数据相关表
  19. 计算机应用二级客观题,计算机二级客观题
  20. 修改360浏览器主页

热门文章

  1. iOS 覆盖率检测原理与增量代码测试覆盖率工具实现
  2. 技术如何转型产品经理
  3. 会议交流—PPT下载|DataFunSummit2022:知识图谱在线峰会PPT合集!
  4. 论文浅尝 | DRUM:一种端到端的可微的知识图谱上的规则学习方法
  5. 论文浅尝 | Complex Embeddings for Simple Link Prediction
  6. 5 操作系统第二章 进程管理 线程介绍
  7. SpringBoot无法找到加载类 ,应用Feign其他服务无法package两类问题
  8. map key char*
  9. iOS事件的响应和传递机制
  10. 《构建之法》 读书笔记(4)