通过使用对外可见的状态不可变的对象,无需额外的同步访问控制。既保证了数据一致性,又避免了同步访问控制所产生的额外开销和问题,也简化了编程。
状态不可变的对象:对象一经创建,其对外可见的状态就保持不变,如String和Integer。
Immutable Object模式:将现实世界中状态可变的实体建模为状态不可变对象,并通过创建不同的状态不可变对象来反映现实世界实体的状态变更。
类图
ImmutableObject:负责存储一组不可变状态
Manipulator:负责维护ImmutableObject所建模的现实世界实体状态的变更。
不可变对象的使用主要包括以下几种类型:
- 获取单个状态的值
- 获取一组状态的快照:防御性复制/返回一个只读的对象,避免对外泄露
- 生成新的不可变对象实例
一个严格意义上的不可变对象要满足以下所有条件:
- 类本身使用final修饰:防止其子类改变其定义的行为
- 所有字段都用final修饰:语义上说明字段引用不可改变。在多线程环境下由JMM保证了被修饰字段所引用对象的初始化安全。
- 在对象创建过程中,this关键字没有泄露,防止其他类(如该类的内部匿名类)在对象创建过程中修改其状态
- 任何字段,如果引用了其他状态可变的对象(如集合、数组等),则这些字段必须是private修饰的,切字段值不能对外暴露。如果要返回这些字段值,应该进行防御性复制。
适用场景
- 被建模对象的状态变化不频繁:频繁创建新的不可变对象,会增加垃圾回收的负担和CPU消耗
- 同时对一组相关数据进行写操作,需要保证原子性
JAVA标准库实例
CopyOnWriteArrayList:专门针对遍历比修改操作更加频繁的场景