使用JDK8

源码:

    public V put(K key, V value) {
return putVal(key, value, false);
} /** Implementation for put and putIfAbsent */
final V putVal(K key, V value, boolean onlyIfAbsent) {
if (key == null || value == null) throw new NullPointerException();
int hash = spread(key.hashCode());
int binCount = 0;
for (Node<K,V>[] tab = table;;) {
Node<K,V> f; int n, i, fh;
if (tab == null || (n = tab.length) == 0)
tab = initTable();
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
if (casTabAt(tab, i, null,
new Node<K,V>(hash, key, value, null)))
break; // no lock when adding to empty bin
}
else if ((fh = f.hash) == MOVED)
tab = helpTransfer(tab, f);
else {
V oldVal = null;
synchronized (f) {
if (tabAt(tab, i) == f) {
if (fh >= 0) {
binCount = 1;
for (Node<K,V> e = f;; ++binCount) {
K ek;
if (e.hash == hash &&
((ek = e.key) == key ||
(ek != null && key.equals(ek)))) {
oldVal = e.val;
if (!onlyIfAbsent)
e.val = value;
break;
}
Node<K,V> pred = e;
if ((e = e.next) == null) {
pred.next = new Node<K,V>(hash, key,
value, null);
break;
}
}
}
else if (f instanceof TreeBin) {
Node<K,V> p;
binCount = 2;
if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,
value)) != null) {
oldVal = p.val;
if (!onlyIfAbsent)
p.val = value;
}
}
}
}
if (binCount != 0) {
if (binCount >= TREEIFY_THRESHOLD)
treeifyBin(tab, i);
if (oldVal != null)
return oldVal;
break;
}
}
}
addCount(1L, binCount);
return null;
}

分析:

put

put方法进入,然后进入putVal方法,可以看到onlyIfAbsent的值为false。

那么我们putputIfAbsent对比:

    public V putIfAbsent(K key, V value) {
return putVal(key, value, true);
}

onlyIfAbsent为true,当该位置为没有值,则加入。如果该位置有值,则保持原来的值,不进行覆盖。

如果大家还是不清楚那就看看网上关于putIfAbsent方法的使用讲解。

putVal

  • spread方法计算hash

  • 进入table数组(ConcurrentHashMap结构是Node数组+链表+红黑树)

  • 如果table数组为null,则先initTable方法来初始化数组

        private final Node<K,V>[] initTable() {
    Node<K,V>[] tab; int sc;
    while ((tab = table) == null || tab.length == 0) {
    if ((sc = sizeCtl) < 0)
    Thread.yield(); // lost initialization race; just spin
    else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
    try {
    if ((tab = table) == null || tab.length == 0) {
    int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
    @SuppressWarnings("unchecked")
    Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
    table = tab = nt;
    sc = n - (n >>> 2);
    }
    } finally {
    sizeCtl = sc;
    }
    break;
    }
    }
    return tab;
    }

    sizeCtl小于零说明有其他线程也在初始化数组,则让当前线程yield,让出cpu时间片。那如果我们自己初始化数组,则需要CAS加自旋。

  • 如果该数组位置上没有元素,那么则直接添加

  • 如果f.hash等于-1,说明需要扩容了

  • 最后我们对链表头结点,或者对红黑树头结点加锁

  • 如果是链表,遍历之,如果遇到key的值(注意不是key的hash值)和链表中的key的值有相等的,则覆盖value。如果遍历到最后都没遇到key值一样的,那就放到链表结尾吧。

  • 如果是树,那就用putTreeVal方法了

ConcurrentHashMap的put方法的更多相关文章

  1. ConcurrentHashMap的size方法是线程安全的吗?

    前言 之前在面试的过程中有被问到,ConcurrentHashMap的size方法是线程安全的吗? 这个问题,确实没有答好.这次来根据源码来了解一下,具体是怎么一个实现过程. ConcurrentHa ...

  2. concurrentHashMap的put方法详解

    本文主要介绍ConcurrentHashMap的put操作如果有错误的地方欢迎大家指出. 1.ConcurrentHashMap的put操作 ConcurrentHashMap的put操作主要有3种方 ...

  3. ConcurrentHashMap的size()方法(1.7和1.8)

    在1.7和1.8版本中,计算size()方法有写不同.先介绍1.7版本的实现. 1.7版本 在1.7版本中,有一个重要的类Segment,利用它来实现分段锁 static final class Se ...

  4. 并发容器ConcurrentHashMap#put方法解析

    jdk1.7.0_79 HashMap可以说是每个Java程序员用的最多的数据结构之一了,无处不见它的身影.关于HashMap,通常也能说出它不是线程安全的.这篇文章要提到的是在多线程并发环境下的Ha ...

  5. 8.并发容器ConcurrentHashMap#put方法解析

    jdk1.7.0_79 HashMap可以说是每个Java程序员用的最多的数据结构之一了,无处不见它的身影.关于HashMap,通常也能说出它不是线程安全的.这篇文章要提到的是在多线程并发环境下的Ha ...

  6. ConcurrentHashMap内存泄漏问题

    问题背景 上周,同事写了一段ConcurrentHashMap的测试代码,说往map里放了32个元素就内存溢出了,我大致看了一下他的代码及运行的jvm参数,觉得很奇怪,于是就自己捣鼓了一下.首先上一段 ...

  7. Java多线程系列--“JUC集合”04之 ConcurrentHashMap

    概要 本章是JUC系列的ConcurrentHashMap篇.内容包括:ConcurrentHashMap介绍ConcurrentHashMap原理和数据结构ConcurrentHashMap函数列表 ...

  8. Java并发编程:并发容器之ConcurrentHashMap(转载)

    Java并发编程:并发容器之ConcurrentHashMap(转载) 下面这部分内容转载自: http://www.haogongju.net/art/2350374 JDK5中添加了新的concu ...

  9. JDK1.7 ConcurrentHashMap 源码浅析

    概述 ConcurrentHashMap是HashMap的线程安全版本,使用了分段加锁的方案,在高并发时有比较好的性能. 本文分析JDK1.7中ConcurrentHashMap的实现. 正文 Con ...

  10. Java ConcurrentHashMap

    通过分析Hashtable就知道,synchronized是针对整张Hash表的,即每次锁住整张表让线程独占, ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术. ...

随机推荐

  1. OCR文字检测与识别系统:融合文字检测、文字识别和方向分类器的综合解决方案

    1. OCR文字检测与识别系统:融合文字检测.文字识别和方向分类器的综合解决方案 前两章主要介绍了DBNet文字检测算法以及CRNN文字识别算法.然而对于我们实际场景中的一张图像,想要单独基于文字检测 ...

  2. C++ STL 标准模板库(排序/集合/适配器)算法

    C++ 标准模板库STL,是一个使用模板技术实现的通用程序库,该库由容器container,算法algorithm,迭代器iterator,容器和算法之间通过迭代器进行无缝连接,其中所包含的数据结构都 ...

  3. 飞桨paddlespeech语音唤醒推理C INT8 定点实现

    前面的文章(飞桨paddlespeech语音唤醒推理C定点实现)讲了INT16的定点实现.因为目前商用的语音唤醒方案推理几乎都是INT8的定点实现,于是我又做了INT8的定点实现. 实现前做了一番调研 ...

  4. 关于elementui日期组件 date.getHours() is not a function 等问题

    问题 日期控件中,假设当前显示日期为2020-01-01,现在需要修改为2020-01-03:点开日期组件框点击选择其他日期时, 控制台有可能会报错,显示 date.getHours()  is  n ...

  5. [Spring 6.0源码解析] @Configuration注解源码解析

    Spring 6.0源码解析之@Configuration 首先写一个启动代码: public class ConfigurationAnnotationTest { private static f ...

  6. 探索C语言中的联合体与枚举:数据多面手的完美组合!

    ​ 欢迎大家来到贝蒂大讲堂 养成好习惯,先赞后看哦~ 所属专栏:C语言学习 贝蒂的主页:Betty's blog 1. 联合体的定义 联合体又叫共用体,它是一种特殊的数据类型,允许您在相同的内存位置存 ...

  7. 机器学习基础03DAY

    特征降维 降维 PCA(Principal component analysis),主成分分析.特点是保存数据集中对方差影响最大的那些特征,PCA极其容易受到数据中特征范围影响,所以在运用PCA前一定 ...

  8. CF1822F Gardening Friends

    题目链接 题解 知识点:树的直径,枚举. 考虑一个结论:树上任意点的最远点一定是树的直径的端点. 那么对于一个根节点,只要知道了树的直径,那么我们就可以立即得到最远距离,即乘 \(k\) 树的价值. ...

  9. NC20185 [JSOI2010]缓存交换

    题目链接 题目 题目描述 在计算机中,CPU只能和高速缓存Cache直接交换数据.当所需的内存单元不在Cache中时,则需要从主存里把数据调入Cache.此时,如果Cache容量已满,则必须先从中删除 ...

  10. Apache log4j2远程代码执行漏洞

    漏洞描述 Apache Log4j2是一个基于Java的日志记录工具.该工具重写了Log4j框架,并且引入了大量丰富的特性.该日志框架被大量用于业务系统开发,用来记录日志信息.大多数情况下,开发者可能 ...