立即学习:https://edu.csdn.net/course/play/27126/357994?utm_source=blogtoedu
对比jdk1.7和1.8的差别,介绍ConcurrentHashMap 和HashMap 和SynchronizedMap 的差别
- HashMap 线程不安全
- jdk1.7以“锁”segment的方式保证并发
- JDK1.8里,以“CAS”的方式保证并发
- SynchronizedMap的put和get封装了HashMap 相关方法,并通过互斥锁保证线程安全
- ConcurrentHashMap 做put时,用CAS+Synchronized保证线程安全,更轻量
jdk1.7的实现方式
- segment数组-HashEtry数组-HashEntry列表
- 读时不加锁,写时加锁segment
- 两次hash,一次定位到segment,一次定位到HashEntry头部
jdk1.8的实现方式
- 以node数组加列表或红黑树的方式实现
- 冲突 会产生链表,链表数大于8,以红黑树方式存储
- 遍历链表时间复杂度是O(n),遍历红黑树时Of(logN),利于冲突数大的场景
jdk1.8里put的实现细节
- 如果Node数组为空,则调用initTable方法初始化Node数组
- 计算key的hash值,并定位到Node里的对应位置
- 如果当前Node位置为空,即无冲突,则以CAS方式插入
- 多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。
通过put和get源码,了解ConcurrentHashMap 的底层结构和hash流程
以CAS+Synchronized管理并发的方式
CAS的讲解
- Compare And Swap, CAS (V,E,N) 如V等于E,则将V设为N,若V和E不等,说明已有其他线程做了更新,当前线程什么都不做,或更改V、E和N参数再重试
- put里的casTabAt方法,实际调用compareAndSwapObject
- 比较当前tab里的i号索引是否为null,是则插入Node<k,v>,不是则说明有其他线程已更改,不做操作
jdk1.8里put的实现细节
- 如果当前Node不为空,对该Node加synchronized锁,并加入到该Node锁指向的链表里
- 如当前Node包含链表节点数大于8,则用treeifyBin方法把链表转红黑树
- 如当前Node已经用红黑树存储数据,则通过putTreeVal 方法插入新的键值对
JDK1.8里get方法的实现细节
- 计算key的hash值,如果Node数组里匹配到首结点即返回
- 否则调用next方法遍历链表或红黑树,由于可能会有冲突,需调用equals
以实例介绍volatile的含义