Immuteable Object - 不可变对象
Immuteable Object
不可变对象模式,多线程共享变量的情况下,既能保证共享变量访问的线程安全,又能避免锁本身带来的消耗所产生的模式。
问题起源
在项目开发过程中,涉及多线程部分的功能多少都会碰到多线程间共享变量的问题,若还存在多个线程都可能对共享变量进行修改的可能性,为保证访问数据的一致性,通常会使用同步访问控制,如显示锁和CAS操作。而锁操作会带来额外的开销,如上下文切换,等待时间等。
模式描述
而Immuteable Object(不可变对象)
意图是通过使用对外可见但不可变对象使被共享对象具有无需加锁的线程安全性。Java种的String、Integer对象即是如此。
模式架构
- Immuteable Object:负责存储一组不可变数据,该参与者不对外暴露可以修改内容数据的方法。
- getStateX, getStateY: 这些方法返回
Immuteable Object
实例所维护的数据的值,这些变量在对象实例化时通过构造器参数获得值。 - getStateSnapshot:返回
Immuteable Object
实例所维护的一组数据的快照
- getStateX, getStateY: 这些方法返回
- Manipulator:负责维护Immuteable Object对象的状态变更,当相应的实体状态改变时,参与者负责生成新的Immutable Object以反映新的实例状态。
- changeStateTo:根据新的状态值生成
Immuteable Object
实例
- changeStateTo:根据新的状态值生成
模式运行时序图
客户端通过Imuuteable Object
提供的get方法获取模式内部的数据值 -> 当客户端需要更新数据值时,调用Manipulator
的changeStateTo
方法更新数据 -> Manipulator
通过创建新的Immuteable Object
反映数据的更新,并返回刚创建的不可变对象 -> 客户端调用Immuteable Object
对象的getStateSnapshot
方法获取实例数据快照
- 通过
final
字段修饰类对象,以及类所持字段,防止其状态被通过获取到的对象直接修改。
Ps: 通过final
字段修饰的对象可以保证其修饰对象或字段是已完成初始化的 - 引用了其它可变对象的字段,需要将字段修饰符设为
private
,且值不能对外暴露,若有方法需要这些字段值,则应该进行防御性复制。
实例代码
1 | // Immutable Object |
总结
由于不可变对象天然的线程安全性,使得开发过程中可以避免显示锁的使用和消耗
- 适用
- 描述对象状态数据变化不频繁
- 对一组数据进行修改且要保证数据原子性
- 作为HashMap的Key
- 注意
- 需对可变字段做防御性复制