1、ConcurrentHashMap分段锁
-
JDK1.7是采用分段锁的思想,对整个桶数组进行切割分段(segment),给每一段数据配置一把锁,当一个线程占用锁访问一段数据的时候,其他的数据也能被其他的线程访问到;
-
ConcurrentHashMap是由Segment数组结构和HashEntry数组结构组成的:Segment实现了ReentrantLock,是一种可重入锁,来扮演锁的角色;HashEntry用于存储键值对数据。
-
static class Segment<K,V> extends ReentrantLock implements Serializable{}
-
一个ConcurrentHashMap包含一个Segment数组(是一种数组和链表结构),一个Segment包含一个HashEntry数组,每个HashEntry是 一个链表结构的元素,一个Segment守护一个HashEntry数组,要想对HashEntry数组进行修改就必须先获得Segment的锁
- JDK1.8取消了Segment分段锁,采用CAS和synchronized来保证线程安全,数据结构和jdk1.8的HashMap类似,synchronized只锁定当前链表/红黑树的首节点,这样只要hash不冲突就不会产生并发,提高效率N
2、ConcurrentHashMap和HashTable的区别?
-
底层数据结构:jdk1.7的ConcurrentHashMap的底层采用分段的数组和链表实现,jdk1.8之后和HashMap一样采用数组+链表/红黑树,HashTable的底层数据结构是数组+链表
-
线程安全方面:都是线程安全的;
- 实现线程安全的方式区别:jdk1.7时,ConcurrentHashMap(分段锁)对整个桶数组进行了分割分段(segment),每一把锁只锁容器中的一部分数据,多线程访问容器的不太段的数据的时候就不会存在锁竞争,提高并发访问率。jdk1.8就摒弃了segment分割分段的思路,直接用Node数组+链表+红黑树的数据结构来实现,并发控制用synchronized和CAS来操作。 HashTable使用synchronized来保证线程安全,效率很低