Collections包下的容器
Collections.synchronizedList Collections.synchronizedSet Collections.synchronizedMap
或者Vector、HashTable实现线程安全
JUC包下的容器
由HashTable引出ConcurrentHashMap
- HashTable是使用synchronized实现同步,是对一个大的数组加一把锁,锁住的是对象整体。
- ConcurrentHashMap采用的是分段式锁,将大的Map拆分成N个晓得Segment,在put的时候会根据hash来确定具体存放在哪个segment中,Segment内部的同步机制是基于Lock操作的,每个Segment都会分配一把锁。这样访问不同数据段的时候就实现了并发访问。
ConcurrentHashMap
- jdk1.7使用分割分段(segment),形式是Reentrantlock + segment数组+hashEntry数组+链表。
- segment是一种可重入锁(ReentrantLock);HashEntry用于存储键值对数据。
- Jdk1.8使用node数组,摒弃segment概念。形式为:node数组 + 链表/红黑树 + synchronized + cas。
- 其中node只能用于链表的情况下,当冲突链表达到一定阈值(8)时,链表会转换成红黑树。并发控制使用synchronized和cas来操作。
- cas+volatile实现线程安全。
好处:
1. JDK1.8再次实现降低了锁的粒度,JDK1.7版本锁的粒度是基于segment的,包含多个hashEntry,而JDK1.8锁的粒度就是HashEntry
2. 使用红黑树来优化链表
(从HashTable(所有线程都竞争一个synchronized,table锁)->concurrentHashMap(segment -> node)锁的粒度一直在降低)