28 | Immutability模式:如何利用不变性解决并发问题?
该思维导图由 AI 生成,仅供参考
快速实现具备不可变性的类
- 深入了解
- 翻译
- 解释
- 总结
Immutability模式是一种解决并发问题的设计模式,通过让共享变量只有读操作而没有写操作来保持不变性,从而避免并发问题。实现具备不可变性的类很简单,只需将所有属性设置为final,并且只允许存在只读方法。Java中的String和基础类型的包装类都具备不可变性,通过不可变性保证线程安全性。在使用Immutability模式时,需要注意对象的所有属性都是final的,并且不可变对象也需要正确发布。另外,利用享元模式可以避免创建重复对象,减少内存占用。不可变对象虽然是线程安全的,但引用这些对象的对象并不一定是线程安全的,需要注意保证可见性和原子性。Immutability模式是解决并发问题的简单方法,建议在解决并发问题时首先尝试该模式。除了具备不变性的对象,还有一种更简单的不变性对象,即无状态对象,其内部没有属性,只有方法。无状态对象在多线程和分布式领域都具有性能优势。 文章中还提到了一个示例代码,讨论了一个Account类的不可变性问题。该类的属性是final的,并且只有get方法,但是其中的user属性是StringBuffer类型,这可能导致对象的可变性。读者可以思考该类是否具备不可变性,并在留言区分享自己的想法。 总的来说,本文介绍了Immutability模式及其在并发编程中的重要性,以及如何实现不可变对象和注意事项。同时,通过示例代码引发了读者的思考,增加了互动性和参与度。
《Java 并发编程实战》,新⼈⾸单¥59
全部留言(51)
- 最新
- 精选
- 木卫六这段代码应该是线程安全的,但它不是不可变模式。StringBuffer只是字段引用不可变,值是可以调用StringBuffer的方法改变的,这个需要改成把字段改成String这样的不可变对象来解决。
作者回复: 👍
2019-05-05387 - 拯救地球好累---总结--- 1. 不可变类的特点:类、属性都是final的,方法是只读的 2. 为了解决有些不可变类每次创建一个新对象导致内存浪费的问题:享元模式/对象池 3. 注意事项:区别引用不可变和实际内容不可变 4. 更简单的不可变对象:无状态对象
作者回复: 👍
2019-07-2844 - 炎炎这个专栏一直看到这儿,真的很棒,课后问题也很好,让我对并发编程有了一个整体的了解,之前看书一直看不懂,老师带着梳理一遍,看书也容易多了,非常感谢老师,希望老师再出专栏
作者回复: 感谢一路相伴😄
2019-05-2416 - yangfinal StringBuffer user; StingBuffer 是 引用 类型, 当我们说它final StingBuffer user 不可变时,实际上说的是它user指向堆内存的地址不可变, 但堆内存的user对象,通过sub append 方法实际是可变的……
作者回复: 👍
2019-05-1313 - 水滴s老师,问下 Bar这个类的foo属性的设值在多线程下为什么会有原子性问题,我理解的只会有可见性问题?
作者回复: 严格讲你是对的,仅仅是设置属性这个操作不涉及原子性。只有类似foo=new Foo(),这种组合操作时才会有原子性问题,这时候的原子性出在foo的属性上,而不是bar的属性foo上。对象赋值的原子性问题一般都是因为组合操作。
2019-12-12210 - 第一装甲集群司令克莱斯特随着课程的深入,越来越看不懂了。我不嫌丢人,不藏拙,这专栏,我一定会二刷,三刷,直到啃下来这块硬骨头!
作者回复: 加油吧!
2020-07-215 - 发条橙子 。老师五一节日快乐。 思考题 : 不可变类的三要素 :类、属性、方法都是不可变的。 思考题这个类虽然是final ,属性也是final并且没有修改的方法 , 但是 stringbuffer这个属性的内容是可变的 , 所以应该没有满足三要素中的属性不可变 , 应该不属于不可变类 。 另外老师我有个问题想问下, 我看jdk一些源码里,也用了对象做锁。 例如 我有个变量 final ConcurrentHashMap cache , 有些方法中会对 cache变量 put新的值 , 但是还有用这个对象做 synchronized(cache) 对象锁 , 这种做法对么? 如果对的话,是因为管程只判断对象的首地址没有改变的原因么 ,希望老师指点一下😁
作者回复: 感谢感谢😂 你的问题有点笼统,jdk也不是没有bug,sync的锁是记在对象头里的
2019-05-022 - 小马爹“String 和 Long、Integer、Double 等基础类型的包装类都具备不可变性,这些对象的线程安全性都是靠不可变性来保证的。” 这里有点不太理解,既然String 和 Long、Integer、Double具备不可变,不可变意味着线程安全,那不就可以说String 和 Long、Integer、Double 是线程安全的了?
作者回复: 是线程安全的
2022-05-091 - 嗨喽上面得SafeWM类代码会不会有ABA问题呢,老师
作者回复: 版本号会一直增加,所以不会有aba问题
2019-06-132 - Jialin根据文章内容,一个类具备不可变属性需要满足"类和属性都必须是 final 的,所有方法均是只读的",类的属性如果是引用型,该属性对应的类也需要满足不可变类的条件,且不能提供修改该属性的方法, Account类的唯一属性user是final的,提供的方法是可读的,user的类型是StringBuffer,StringBuffer也是final的,这样看来,Account类是不可变性的,但是去看StringBuffer的源码,你会发现StringBuffer类的属性value是可变的<String类中的value定义:private final char value[];StringBuffer类中的value定义:char[] value;>,并且提供了append(Object object)和setCharAt(int index, char ch)修改value. 所以,Account类不具备不可变性2019-05-025116