前言:前面我们讲了线程封闭技术(确保对象不被发布)和发布不可变对象。
3.5 安全发布
在某些情况下,我们希望在多个线程间共享对象,此时必须确保进行安全的共享。
3.5.3 安全发布的常用模式
要安全的发布一个对象,对象的引用以及对象的状态必须同时对其他线程可见。一个正确构造的对象可以通过以下方式安全的发布:
(1)在静态初始化函数中初始化一个对象引用。
(2)将对象的引用保存到volatile类型的域或者AtomicReference对象中。
(3)将对象的引用保存到某个正确构造对象的final类型域中。
(4)将对象的引用保存到一个由锁保护的域中。
3.5.4 事实不可变对象
如果对象在技术上看来是可变的,但其状态在发布后不会再改变,那么把这种对象称作“事实不可变对象”。
在没有任何额外的同步情况下,任何线程都可以安全地使用被安全发布的事实不可变对象。
例如,Date 本身是可变的,但如果将它作为不可变对象来使用,那么在多个线程间共享Date对象时,就可以省去对锁的使用。假设需要维护一个map,其中保存了每位用户的最近登陆时间:
public Map<String,Date> lastLogin =Collections.synchronizedMap(new HashMap<String,Date>);
如果Date 对象的值在被放入Map后就不会改变,那么synchronizedMap中的同步机制就足以使Date值被安全的发布,并且在访问这些Date值时不需要额外的同步。
对象的发布需求取决于它的可变性:
(1)不可变对象可以通过任意机制发布。
(2)事实不可变对象必须通过安全方式来发布。
(3)可变对象必须通过安全方式发布,并且必须是线程安全的或者由某个锁保护起来。