1、不变性
如果某个对象在被创建后其状态就不能被修改,那么这个对象就被称为不可变对象。满足同步需求的另一种方法就是使用不可变对象。不可变对象一定是线程安全的。当满足以下条件时,对象才是不可变的:
- 对象创建以后其状态就不能改变
- 对象的所有域都是final类型
- 对象是正确创建的,在对象创建期间,this引用没有泄露
2、final域
final类型的域是不能修改的,但如果final域所引用的对象是可变的,那么这些被引用的对象是可以修改的。final域的对象在构造函数中不会被重排序,所以final域也能保证初始化过程的安全性。和“除非需要更高的可见性,否则应将所有的域都声明为私用域”一样,“除非需要某个域是可变的,否则应将其声明为final域”也是一个良好的编程习惯
3、安全发布
到目前为止,我们重点讨论的是如何确保对象不被发布,例如让对象封闭在线程或另一个对象的内部。当然,在某些情况下我们希望在多个线程间共享对象,此时必须确保安全地进行共享。然而,如果只是像下面程序那样将对象引用保存到公有域中,那么还不足以安全地发布这个对象。
代码语言:javascript复制 //不安全的发布 public User user; public void initialize() { user = new User(42); }
由于存在可见性问题,其他线程看到的User对象将处于不一致的状态,即便在该对象的构造函数中已经正确地构建了不变性条件。这种不正确的发布导致其他线程看到尚未创建完成的对象。
4、安全发布的常用模式
一个正确构造的对象可以通过以下方式来安全地发布:
- 在静态初始化函数中初始化一个对象引用
- 将对象的引用保存到volatile类型的域或者AtomicReferance对象中
- 将对象的引用保存到某个正确构造对象的final类型域汇总
- 将对象的引用保存到一个由锁保护的域中(例如Vector,synchronized List)
注:本文为Wayne原创,未经许可不得在任何平台转载。如需转载,与作者联系