【8、java8的ConcurrentHashMap为何放弃分段锁,为什么要使用CAS+Synchronized取代Segment+ReentrantLock】

219 阅读2分钟

在Java 8之前

ConcurrentHashMap 使用分段锁(Segment)来控制并发访问。每个段都是一个独立的哈希表,只包含总容量的一部分,每个段都有自己的锁,因此不同的线程可以同时访问不同的段。这种方法在高并发场景下表现良好,但由于锁的开销和段的数量限制,它的性能随着并发度的增加而下降。 在Java 8中

ConcurrentHashMap 采用了一种新的机制来实现更好的并发性能:它使用CAS(Compare and Swap)和synchronized来取代分段锁。这种实现方式被称为"数组+链表+红黑树",即每个桶内部采用链表或红黑树来存储键值对,当桶内键值对数量达到一定阈值时,链表会自动转化为红黑树,以提高查找效率。

在Java 8的 ConcurrentHashMap 中,整个哈希表被分成若干个段,每个段都被实现为一个数组,每个数组元素都是一个链表或红黑树。每个元素都是一个桶,通过哈希函数将键值对映射到桶中。每个桶内部都通过synchronized来实现同步,以保证线程安全性。而对于读操作,使用了无锁的CAS操作。 相比于分段锁,这种实现方式有以下优点:

减少锁竞争:由于每个桶内部采用了synchronized来实现同步,不同的线程可以同时访问不同的桶,从而减少了锁竞争。

更高的并发度:由于不再受限于固定数量的段,ConcurrentHashMap 可以根据需要动态调整大小,并支持更高的并发度。

更好的扩展性:由于不再需要维护多个段的锁,因此在扩展时可以更容易地添加或删除桶,而不需要重构整个数据结构。

更好的性能:使用CAS操作替代了分段锁,避免了分段锁中的自旋等待开销,提高了并发性能。 总结

总之,Java 8的 ConcurrentHashMap 放弃了分段锁,采用了CAS和synchronized的方式来实现更好的并发性能,从而能够更好地满足高并发场景下的需求。