-
(1) Java内存模型为不可变对象的共享提供了特殊的初始化安全性保证, 即使在发布这些对象时没有同步
(2) 在没有额外同步的情况下, 也可以保证安全访问final类型的域(但是如果final类型的域所指向的是可变对象, 还是需要同步)
-
一个正确构造的对象, 可以通过以下方式安全发布
(1) 静态初始化函数中初始化一个对象引用
JVM内部存在的同步机制保证
(2) 将对象的引用保存到volatile类型的域或者AtomicReference对象中
(3) 将对象的引用保存到某个正确构造对象的final类型域中
(4) 将对象的引用保存到一个由锁保护的域中
(将对象放入到某个带锁的容器例如Vector, synchronizedList再发布也属于这种情形)
所有的安全发布机制都能确保, 当对象的引用对所有访问该对象的线程可见时, 对象发布时的状态对于所有线程也将是可见的。如果对象状态不再改变, 那么足以确保任何访问都是安全的
-
事实不可变对象
(1) 如果对象从技术上看可变, 但是其状态从发布后不会再改变, 则这种对象称为事实不可变对象(例如java.util.Date类)
(2) 在没有额外的同步的情况下, 任何线程都可以安全的使用被安全发布的事实不可变对象
-
可变对象
不仅在发布时需要使用同步, 每次对象访问时也要使用同步来确保后续修改操作的可见性
示例
public class Holder { private int n; public Holder(int n) { this.n = n; } public void assertSanity() { if (n != n) { throw new AssertionError("This statement is false."); } } }
在多线程环境下, Holder很可能没有被正确发布, 造成某个线程中未必看到其他线程构造好的n的值, 从而造成AssertionError; 如果将n用final修饰, 则可以避免这个问题
-
对象的发布需求
不可变对象: 任意机制发布
事实不可变对象: 安全发布方式(4种)
可变对象: 由某个锁保护发布