对象的组合
一、设计线程安全的类
在设计线程安全类的过程中需要考虑一下要素;
- 找出构成对象状态的所有变量
- 找出约束状态变量的不变性条件
- 建立对象状态的并发管理策略
- 构成对象状态的所有变量
- 如果该对象的所有域都是基本类型的变量,则这些基本类型的变量就构成了该对象的状态
- 如果该对象中包含引用类型的变量,则被引用对象的状态变量也一起构成该对象的状态变量
2. 构建线程安全的类之实例封闭
实例封闭是指将类的状态变量(基本类型或者引用类型)封装在类的内部,只是对外暴露相应的接口,并且在接口上实现同步,如果要访问该类的状态变量只能通过开放的同步接口,这样调用客户端不需要进行多余的同步代码。
对于引用类型的状态变量,在通过公开的接口访问该状态时候,一定要注意不要把这个引用对象(如果对象是可变对象,需要复制,如果是不可变对象则不需要)逸出,通常可以通过clone()方法返回该引用的一个副本。
(1)实例封闭之java监视器模式
当从头构建一个线程安全的类,或者将多个非线程安全的类组合成一个线程安全的类时,java监视器模式是非常有用的,但是如果类中的各个组件已经是线程安全的,就需
要考虑线程安全性的委托了。
对象只有在完全初始化后,其final变量对其它线程才是可见的。这说明,final变量的初始化可以在不使用synchronization的情况下实现线程安全。这样,final变量实现了
真正意义上的final(即,不-可-变),而不会在初始化过程中、后在多线程中看起来会改变。
3. 线程安全性的委托
(1)如果一个对象中只有一个线程安全的状态变量,则可以完全可以见对该状态变量的访问委托给变量本身;如果对象中有n个互相独立的线程安全的状态变量时,也可以简单
将对变量的安全访问委托给状态变量即可。但是如果这些状态变量之间有制约关系,则可能还需要额外的同步手段。
4. 构建线程安全的类之发布底层的状态变量
当把一个类线程的安全性委托给底层的状态变量时,什么情况下才能发布这个状态变量使客户端代码可以修改该底层状态变量的值?
5. 构建线程安全类之在现有的线程安全类中添加功能
(1)客户端加锁机制
客户端加锁是指对于使用某个对象X的客户端代码,必须使用X本身用于保护其自身状态的锁来保护这段客户端代码,才能实现真正意义上的同步和原子性。要使用客户端加锁,客户端必须知道对象X使用的是哪一个锁。
错误的客户端加锁代码:
注意:此处客户端的同步是完全没有作用的,因为list中同步使用的锁肯定不是此处ListHelper中使用的锁。
(2)当为现有的类添加一个原子操作时,有一种更好的方法:组合