Java中不可变的对象可以确保线程安全,其核心是其状态在创建后无法修改。这种“一旦创建,就永远不会改变”的特征消除了多线程环境中共享数据竞争的可能性。
不可变对象的关键设计原则
要使一个类成为不可变类,需要遵循几个基本规则:
- 类声明为final:防止子类通过继承破坏不可变性
- 使用private和final修改所有字段,以确保外部不能访问和修改内部状态
- 不提供任何setter或修改状态的方法:在运行过程中避免更改属性值
- 所有字段都是正确初始化的,this引用不会泄露:this不能在结构过程中传递给外部方法
- 如果包含可变对象字段,则必须深度复制并保持私有:例如,数组和集合需要防御性复制
为什么不可变对象是线程安全的?线程安全的本质问题是多个线程同时读写相同的数据,导致结果不确定。不可变对象从根本上切断了这个问题:
- 由于读取操作不会改变状态,多个线程可以同时读取同一不变对象的示例。
- 没有写作操作,所以不需要同步控制(如synchronized)来协调读写
- 构造完成后,对象的状态固定,JVM内存模型确保final字段的初始安全
- 即使多个线程并发访问,也总是看到完整结构后的状态,没有中间态问题
典型示例:String类型
Java中的String是典型的不可变类:
- 内部char数组被声明为final,内容不可变
- 每次“修改”字符串实际返回新实例,原对象不变
- 多个线程可以安全地共享相同的字符串常量
基本上就是这样。只要对象不能修改,就不需要协调线程之间的访问,自然实现线程安全。该设计简单高效,特别适用于高并发场景下的数据共享。