昨天我们讲了无状态对象、不可变对象、线程特有对象这三种线程安全设计;今天我们讲剩下两种:装饰器模式、并发集合
装饰器模式:为类动态增加额外功能,用来实现线程安全:为非线程安全对象创建一个相应的线程安全的外包装对象;客户端不访问非线程安全对象而是访问其外包装对象。
Java.util.Collections.synchronizedX()方法就是使用装饰器模式将指定的非线程安全的集合对象对外暴露为线程安全的集合对象。X可以为Set、List、Map等
其缺点
a、同步集合的iterator方法返回的Iterator实例并不是线程安全的,为保障遍历操作的线程安全性,我们需要对遍历操作加锁。
b、这些同步集合在实现线程安全时通常使用一个粗粒度的锁,导致高争用、较大的上下文开销
并发集合
非线程安全对象 |
并发集合类 |
共同接口 |
遍历实现方式 |
ArrayList |
CopyOnWriteArrayList |
List |
快照 |
LinkedList |
ConcurrentLinkedQueue |
Queue |
快照 |
HashSet |
CopyOnWriteArraySet |
Set |
准实时 |
HashMap |
ConcurrentHashMap |
Map |
准实时 |
TreeMap |
ConcurrentSkipListMap |
SortedMap |
准实时 |
TreeSet |
ConcurrentSkipListSet |
SortedSet |
准实时 |
快照:是在Iterator实例被创建的那一刻遍历对象内部结构的一个只读副本(对象),快照是只读的,不支持remove方法,当遍历的集合较大时,开销较大
准实时:实时遍历对象内部结构,支持remove方法,多线程之间不适宜共享同一个Iterator实例
并发集合内部在保障其线程安全的时候通常不借助锁,而是使用CAS操作,比相应的同步集合高
关于ConcurrentHashMap这个类的分析,网上一篇博客分析得挺好,可以看下
最后总结下,这两篇说的保障线程安全的设计技术:
线程安全设计分以下几种:
a、Java运行时空间:堆空间及非堆空间,可被多个线程共享
b、无状态对象
c、不可变对象
d、线程特有对象:ThreadLocal
e、装饰器模式:同步集合synchronizedX()方法
f、 并发集合