首先先来看一道题
选择下列选项中正确的一项?
A.ConcurrentHashMap使用synchronized关键字保证线程安全
B.HashMap实现了Collction接口
C.Array.asList方法返回java.util.ArrayList对象
D.SimpleDateFormat是线程不安全的
答案是:D
Array.asList方法返回List对象,而不是ArrayList对象
那其他三个选项都是正确的
那下面来意义解析一下
Map接口下的子类ConcurrentHasnMap,HashMap,HashTable.TreeMap有什么关系与区别呢?
先来看HashMap TreeMap Hashtable的联系与区别
联系:
这三个类都是Map接口下常用的子类,
区别:
- 底层实现:HashTable基于哈希表实现,TreeMap基于红黑树实现,HashMap基于哈希表+红黑树(JDK1.8之后,JDK1.8基于哈希表)
- 关于null:HashMap允许key与value都为空,HashTable key与value均不允许空,TreeMap 只允许value为空,key不能为空(因为内部是按照key排序的)
- 线程安全性:HashMap,TreeMap采用异步处理,线程不安全,性能较高,HashTable采用synchronized同步方法,线程安全,性能较低(因为锁的是整个哈希表,读读互斥)
ConcurrentHashMap是如何高效实现线程安全?
HashTable锁的是整个哈希表(锁的个数只有一个,粒度很粗,读读互斥)
ConcurrentHashMap锁的个数更多且粒度更细
ConcurrentHashMap JDK1.7 与 JDK 1.8 的区别
(1)JDK1.7之前的ConcurrentHashMap采用Segement分段锁机制+哈希表
底层采用数组+链表+红黑树的存储结构。
Segement初始化为16之后,不再扩容
扩容发生在Segement对应的小哈希表
ConcurrentHashMap锁的是Segement,由Hashtable的一把锁增加为16把锁,锁的粒度更粗(支持的并发线程数增加,线程1拿到Segement1的锁并不会影响线程2访问Segement2)
Segement是ReentrantLock的子类,使用Lock来保证线程安全
(2)JDK1.8 ConcurrentHashMap采用哈希表+红黑树存储结构
Segement没有具体作用,只保留了结构
ConcurrenthHashMap锁的是哈希桶,锁的粒度更加粗,锁的个数会随着哈希表的扩容而增加
利用CAS+Synchronized代码块来保证线程安全性