ConcurrentHashMap的put方法
使用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。
那么我们put和putIfAbsent对比:
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方法的更多相关文章
- ConcurrentHashMap的size方法是线程安全的吗?
前言 之前在面试的过程中有被问到,ConcurrentHashMap的size方法是线程安全的吗? 这个问题,确实没有答好.这次来根据源码来了解一下,具体是怎么一个实现过程. ConcurrentHa ...
- concurrentHashMap的put方法详解
本文主要介绍ConcurrentHashMap的put操作如果有错误的地方欢迎大家指出. 1.ConcurrentHashMap的put操作 ConcurrentHashMap的put操作主要有3种方 ...
- ConcurrentHashMap的size()方法(1.7和1.8)
在1.7和1.8版本中,计算size()方法有写不同.先介绍1.7版本的实现. 1.7版本 在1.7版本中,有一个重要的类Segment,利用它来实现分段锁 static final class Se ...
- 并发容器ConcurrentHashMap#put方法解析
jdk1.7.0_79 HashMap可以说是每个Java程序员用的最多的数据结构之一了,无处不见它的身影.关于HashMap,通常也能说出它不是线程安全的.这篇文章要提到的是在多线程并发环境下的Ha ...
- 8.并发容器ConcurrentHashMap#put方法解析
jdk1.7.0_79 HashMap可以说是每个Java程序员用的最多的数据结构之一了,无处不见它的身影.关于HashMap,通常也能说出它不是线程安全的.这篇文章要提到的是在多线程并发环境下的Ha ...
- ConcurrentHashMap内存泄漏问题
问题背景 上周,同事写了一段ConcurrentHashMap的测试代码,说往map里放了32个元素就内存溢出了,我大致看了一下他的代码及运行的jvm参数,觉得很奇怪,于是就自己捣鼓了一下.首先上一段 ...
- Java多线程系列--“JUC集合”04之 ConcurrentHashMap
概要 本章是JUC系列的ConcurrentHashMap篇.内容包括:ConcurrentHashMap介绍ConcurrentHashMap原理和数据结构ConcurrentHashMap函数列表 ...
- Java并发编程:并发容器之ConcurrentHashMap(转载)
Java并发编程:并发容器之ConcurrentHashMap(转载) 下面这部分内容转载自: http://www.haogongju.net/art/2350374 JDK5中添加了新的concu ...
- JDK1.7 ConcurrentHashMap 源码浅析
概述 ConcurrentHashMap是HashMap的线程安全版本,使用了分段加锁的方案,在高并发时有比较好的性能. 本文分析JDK1.7中ConcurrentHashMap的实现. 正文 Con ...
- Java ConcurrentHashMap
通过分析Hashtable就知道,synchronized是针对整张Hash表的,即每次锁住整张表让线程独占, ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术. ...
随机推荐
- 从零开始配置vim(31)——git 配置
很抱歉又拖更了这么久了,在这个新公司我想快速度过试用期,所以大部分的精力主要花在日常工作上面.但是这个系列还是得更新下去,平时只能抽有限的业余时间来准备.这就导致我写这些文章就慢了一些. 废话不多说, ...
- TeXStudio与Bakoma TeX 结合实现实时阅览
参考链接:VSCode 或 TeXStudio LaTeX 配置方法 - 知乎 相信大家在使用TeXStudio时候,每次修改完毕都要运行一下再能看到PDF界面,这样做十分不方便,因此先给出如下操作办 ...
- 遥感图像处理笔记之【Сrор field boundary detection: approaches and main challenges】
遥感图像处理学习(6) 前言 遥感系列第6篇.遥感图像处理方向的学习者可以参考或者复刻 本文初编辑于2023年12月16日 2024年1月24日搬运至本人博客园平台 文章标题:Сrор field b ...
- centOS系统 迁移docker镜像及数据文件到指定目录
话说我今天正在快乐的敲代码,突然看到IDE报警磁盘空间不足了,du -h 查看了一下磁盘占用情况,发现是自己的docker镜像全部放/var/lib/docker目录下 这个系统磁盘给根目录只分配了5 ...
- Star 4.2k,这是我用过最舒服的跨平台Redis桌面客户端
项目介绍 Tiny RDM 一个现代化轻量级的跨平台Redis桌面客户端,支持Mac.Windows和Linux 软件截图 运行效果 版本展示 配置连接 项目亮点 极致轻量 极小包体,随处安装随处使用 ...
- 会话跟踪技术之COOKIE
会话跟踪技术之COOKIE 一.为什么要用会话控制 我们需要我们的站点可以跟踪客户端与服务器之间的交互,保存和记忆每个用户的身份和信息. 几个疑问 我先访问A页面后访问B页面,HTTP无法知道是不是同 ...
- ElasticSearch7.3学习(七)----Mapping映射入门
1.mapping映射 概念:自动或手动为index中的_doc建立的一种数据结构和相关配置,简称为mapping映射.插入几条数据,让es自动为我们建立一个索引 PUT /website/_doc/ ...
- 关于行结束符(CR、LF)、回车、换行
CR(Carriage Return)表示回车 LF(Line Feed)表示换行 Dos和Windows采用回车+换行(CR+LF)表示下一行而UNIX/Linux采用换行符(LF)表示下一行苹果机 ...
- HttpClientTemplate JDK11以上的版本,可以用,我写的。
package com.diandaxia.common.template; import com.fasterxml.jackson.databind.ObjectMapper; import or ...
- NC16496 [NOIP2014]飞扬的小鸟
题目链接 题目 题目描述 为了简化问题,我们对游戏规则进行了简化和改编: \1. 游戏界面是一个长为n,高 为m的二维平面,其中有k个管道(忽略管道的宽度). \2. 小鸟始终在游戏界面内移动.小鸟从 ...