学习ConcurrentHashMap需要达到以下三点:
一、比较HashMap为什么不是线程安全的,及HashTable是如何实现的安全的,并且HashTable有什么问题?
二、深入理解CHM各项并发优化的原理。
三、掌握锁优化的方法。
1、HashTable的问题(很暴力):
CHM对于HashTable的问题进行的优化:
如下图对Key进行hash后,高位用来找segment,低位用来找table。
因为JDK1.5时的hash算法会导致hashcode的高位不均匀分布,对于30000以下的整数key, hash出来后大部分集中在第16个segment中,对于50万以下的整数key,hash出来后大部分集中在第14,15个segment中,这样就退化为了HashTable。而JDK1.6时的hash算法实现高低位的均匀分布。
JDK1.7之前的16个segment在一开始全都实例化出来,但是JDK1.7之后需要哪个new哪个。因为segment是需要的时候创建,所以有可能多个线程访问的时候有可见性问题,所以JDK1.7大量的使用了volatile来保证segment的线程安全。
jdk8开始,没有了段,所以只在hash的entry上加锁,缩小了范围。
为何放弃分段锁? 段Segment继承了重入锁ReentrantLock,有了锁的功能,每个锁控制的是一段,当每个Segment越来越大时,锁的粒度就变得有些大了。
jdk5~7基于段元素个数求和,二次不同就加锁再求一次。 jkd8没有了段,引入CounterCell, 本质上也是分段计数。
我们在多线程程序设计过程中可以借鉴什么呢?