1,设置线程安全的类的过程中,需要包含以下3个基本要素。
- 找出构成对象状态的所有变量(例如:有的以一个变量作为一种状态,有的以多个变量的组合作为一种状态)
- 找出约束状态变量的不变性条件(例如:一个Long型变量,使用时规定不能为负值,这个负值就是不可变状态)
- 建立对象状态的并发访问管理策略(例如:是如何同步这些状态,是使用内置锁或私有锁)
2,在具体设计时,要按以下步骤:
- 收集同步需求。(由于不变性条件以及后验条件在状态及状态转换上施加了各种约束,因此就需要额外的同步与封装。)
- 找出不可变状态。(例如:一个Long型变量,使用时规定不能为负值,这个负值就是不可变状态)
- 找出后验证条件来判断状态迁移是否有效。(例如:一个递增计数器,当前值是17,下一个值只能是18)
- 依赖状态的操作:如果在某个操作中包含有基于状态的先验条件,那么这个操作就称为依赖状态的操作。(例如,在从一个Map里删除一个元素时,先要验证Map是否为空)
- 注意状态的所有权(就是引用)。许多情况下,所有权与封装总是相互关联的。如果发布了某个可变对象的引用,那么就不再拥有独占的控制权。
3,创建可并发对象的方法之一:实例封闭。
将数据封闭在对象内部,可以将数据的访问限制在对象的方法上,从而更容易确保线程在访问数据时,总能持有正确的锁。
4,线程安全性的委托。
委托给已经实现线程安全的类,例如:ConcurrentMap。
5,在现有的线程安全类中添加功能,方法有以下几个。
- 扩展这个类。例如:扩展Vector。
- 客户端加锁。是指把要添加功能的类,放到另一个类里,但这个要添加功能的类是public的,所以可能无法保证同步。
- 组合。是指,创建一个类,来完全包装要添加功能的类,让外面只能用包装类来访问它。
线程有关的方法或类:
- Collections.unmodifiableMap:生成一个不可修改的Map。
- Collections.synchronizedList:生成一个同步的List。
- CopyOnWriteArrayList:CopyOnWrite容器即写时复制的容器。通俗的理解是当我们往一个容器添加(修改,删除也一样)元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。这样做的好处是我们可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。
参考:JAVA中的COPYONWRITE容器