coucurrentHashMap如何高效的实现线程安全的?
Java提供了不同层面的线程安全的支持,传统的集合框架内部,提供了同步包装,利用Collections可以生成,但是粒度都很粗,都是Synchronized的
后来并发包中提供所谓的线程安全容器类
例如ConcurrentHashMap CopyOnWriteArrayList
ArrayBlockingQueue SynchronousQueue.
ConcurrentHashMap本身也是在不断的演进的
早期的ConcurrentHashMap,实现基于的是
分离锁,内部分段,存放了HashEntry的数组,每次只锁住对应的段,Segment的数量有所谓的concurrentcyLevel决定,默认是16
然后HashEntry内部使用了volatile的value来保证可见性,并且利用了不可变和Unsafe来进行改进操作
对于put,通过哈希计算避免了哈希冲突,然后Segment进行相对应的put操作
ConcurrentHashMap获取再入锁,保证数据一致性,就是在Segment基于ReentrantLock
对于扩容,则是对于Segment进行扩容
对于更新,则是判断key是否数组里面,进行了重复的判断操作
后来在Java8就进行了改进
内部存储改进为HashMap结构非常相似
内部的Segment定义,只是为了保证序列化的兼容性
初始化的操作改了了lazy-load,避免了初始化开销
数据存储利用volatile进行可用性
使用CAS等操作,在特定场景进行无锁的操作
使用Unsage LongAddr等底层手段,进行极端情况的优化
Key是final的,value的声明为volatile保证可见性
并发的put如何实现的
初始化操作实现在initTable里面,里面利用了CAS尝试利用SizeCtl进行互斥,进行竞争性的初始化,就spin
而里面的size操作,使用sumCount方法
利用了近似AtomicLong的方式,进行了分段进行计数,最后进行求和