ConcurrentHashMap 与 Hashtable
粘贴复制于:https://blog.csdn.net/lzwglory/article/details/79978788
集合是编程中最常用的数据结构。而谈到并发,几乎总是离不开集合这类高级数据结构的支持。比如两个线程需要同时访问一个中间临界区(Queue),比如常会用缓存作为外部文件的副本(HashMap)。这篇文章主要分析jdk1.5的3种并发集合类型(concurrent,copyonright,queue)中的ConcurrentHashMap,让我们从原理上细致的了解它们,能够让我们在深度项目开发中获益非浅。

| V get(Object key, int hash) { if (count != 0) { // read-volatile HashEntry e = getFirst(hash); while (e != null) { if (e.hash == hash && key.equals(e.key)) { V v = e.value; if (v != null) return v; return readValueUnderLock(e); // recheck } e = e.next; } } return null; } |
| V readValueUnderLock(HashEntry e) { lock(); try { return e.value; } finally { unlock(); } } |
put操作一上来就锁定了整个segment,这当然是为了并发的安全,修改数据是不能并发进行的,必须得有个判断是否超限的语句以确保容量不足时能够rehash,而比较难懂的是这句int index = hash & (tab.length - 1),原来segment里面才是真正的hashtable,即每个segment是一个传统意义上的hashtable,如上图,从两者的结构就可以看出区别,这里就是找出需要的entry在table的哪一个位置,之后得到的entry就是这个链的第一个节点,如果e!=null,说明找到了,这是就要替换节点的值(onlyIfAbsent == false),否则,我们需要new一个entry,它的后继是first,而让tab[index]指向它,什么意思呢?实际上就是将这个新entry插入到链头,剩下的就非常容易理解了。
|
V put(K key, int hash, V value, boolean onlyIfAbsent) { lock(); try { int c = count; if (c++ > threshold) // ensure capacity rehash(); HashEntry[] tab = table; int index = hash & (tab.length - 1); HashEntry first = (HashEntry) tab[index]; HashEntry e = first; while (e != null && (e.hash != hash || !key.equals(e.key))) e = e.next; V oldValue; if (e != null) { oldValue = e.value; if (!onlyIfAbsent) e.value = value; } else { oldValue = null; ++modCount; tab[index] = new HashEntry(key, hash, first, value); count = c; // write-volatile } return oldValue; } finally { unlock(); } } |
remove操作非常类似put,但要注意一点区别,中间那个for循环是做什么用的呢?(*号标记)从代码来看,就是将定位之后的所有entry克隆并拼回前面去,但有必要吗?每次删除一个元素就要将那之前的元素克隆一遍?这点其实是由entry的不变性来决定的,仔细观察entry定义,发现除了value,其他所有属性都是用final来修饰的,这意味着在第一次设置了next域之后便不能再改变它,取而代之的是将它之前的节点全都克隆一次。至于entry为什么要设置为不变性,这跟不变性的访问不需要同步从而节省时间有关,关于不变性的更多内容,请参阅之前的文章《线程高级---线程的一些编程技巧》
|
V remove(Object key, int hash, Object value) { lock(); try { int c = count - 1; HashEntry[] tab = table; int index = hash & (tab.length - 1); HashEntry first = (HashEntry)tab[index]; HashEntry e = first; while (e != null && (e.hash != hash || !key.equals(e.key))) e = e.next; V oldValue = null; if (e != null) { V v = e.value; if (value == null || value.equals(v)) { oldValue = v; // All entries following removed node can stay // in list, but all preceding ones need to be // cloned. ++modCount; HashEntry newFirst = e.next; * for (HashEntry p = first; p != e; p = p.next) * newFirst = new HashEntry(p.key, p.hash, newFirst, p.value); tab[index] = newFirst; count = c; // write-volatile } } return oldValue; } finally { unlock(); } } |
|
static final class HashEntry { final K key; final int hash; volatile V value; final HashEntry next; HashEntry(K key, int hash, HashEntry next, V value) { this.key = key; this.hash = hash; this.next = next; this.value = value; } } |
以上,分析了几个最简单的操作,限于篇幅,这里不再对rehash或iterator等实现进行讨论,有兴趣可以参考src。
ConcurrentHashMap 与 Hashtable的更多相关文章
- ConcurrentHashMap和Hashtable区别
Hashtable:synchronized是针对整张Hash表的,即每次锁住整张表让线程独占安全的背后是巨大的浪费 ConcurrentHashMap和Hashtable主要区别就是围绕着锁的粒度以 ...
- HashMap的扩容机制, ConcurrentHashMap和Hashtable主要区别
源代码查看,有三个常量, static final int DEFAULT_INITIAL_CAPACITY = 16; static final int MAXIMUM_CAPACITY = 1 & ...
- 沉淀再出发:java中的HashMap、ConcurrentHashMap和Hashtable的认识
沉淀再出发:java中的HashMap.ConcurrentHashMap和Hashtable的认识 一.前言 很多知识在学习或者使用了之后总是会忘记的,但是如果把这些只是背后的原理理解了,并且记忆下 ...
- Java基础知识强化之集合框架笔记78:ConcurrentHashMap之 ConcurrentHashMap、Hashtable、HashMap、TreeMap区别
1. Hashtable: (1)是一个包含单向链的二维数组,table数组中是Entry<K,V>存储,entry对象: (2)放入的value不能为空: (3)线程安全的,所有方法均用 ...
- hashmap,ConcurrentHashMap与hashtable的区别
1.hashmap与hashtable的区别 1.我们从他们的定义就可以看出他们的不同,HashTable基于Dictionary类,而HashMap是基于AbstractMap.Dictionary ...
- 源码分析--ConcurrentHashMap与HashTable(JDK1.8)
ConcurrentHashMap和Hashtable都是线程安全的K-V型容器.本篇从源码入手,简要说明它们两者的实现原理和区别. 与HashMap类似,ConcurrentHashMap底层也是以 ...
- ConcurrentHashMap 和 Hashtable 的区别
ConcurrentHashMap 和 Hashtable 的区别主要体现在实现线程安全的方式上不同. 1.底层的数据结构: ConcurrentHashMap 在jdk1.7之前采用的是 分段的数组 ...
- 为什么ConcurrentHashMap,HashTable不支持key,value为null?
ConcurrentHashmap.HashMap和Hashtable都是key-value存储结构,但他们有一个不同点是 ConcurrentHashmap.Hashtable不支持key或者val ...
- ConcurrentHashMap、HashTable、HashMap的区别
HashTable与ConcurrentHashMap: 相同点:都是线程安全的,可以在多线程的环境下运行.key和value都不能为null 区别:性能上的差异.HashTable每次操作对象都会锁 ...
随机推荐
- Excel读写
http://www.cnblogs.com/mingforyou/archive/2013/08/26/3282922.html 读Excel代码如下: import java.io.File;im ...
- 【Java千问】你了解代理模式吗?
代理模式详解 1 什么是代理模式? 一句话描述:代理模式是一种使用代理对象来执行目标对象的方法并在代理对象中增强目标对象方法的一种设计模式. 详细描述: 1.理论基础-代理模式是设计原则中的“开闭原则 ...
- vis.js 4.21.0 Timeline localization
from:http://visjs.org/timeline_examples.html https://github.com/almende/vis https://github.com/momen ...
- 快速使用CSS Grid布局,实现响应式设计
常用Grid布局属性介绍 下面从一个简单Grid布局例子说起. CSS Grid 布局由两个核心组成部分是 wrapper(父元素)和 items(子元素). wrapper 是实际的 grid(网格 ...
- Ubuntu下面MySQL的参数文件my.cnf浅析
前几天刚接手一个MySQL数据,操作系统为Ubuntu 16.04.5 LTS, 数据库版本为5.7.23-0ubuntu0.16.04.1(APT方式安装的MySQL).这个操作系统下的MySQL ...
- 20181225-Linux Shell Bash环境下自动化创建ssh互信脚本
20181225-Linux Shell Bash环境下自动化创建ssh互信脚本 1. 我的Blog 博客园 https://www.cnblogs.com/piggybaba/ 个人网站 http: ...
- OV摄像头图像采集基础知识总结
目前FPGA用于图像采集 传输 处理 显示应用越来越多,主要原因是图像处理领域的火热以及FPGA强大的并行处理能力.本文以OV7725为例,对摄像头使用方面的基础知识做个小的总结,为后续做个铺垫. 下 ...
- typora快捷键
目录 基础信息 常用快捷键 修改快捷键 基础信息 typora是一款极佳的markdown写作软件,编辑和预览两者合二为一,免费良心软件,推荐使用. 官网:https://www.typora.io/ ...
- Ubuntu17.04 sudo apt-get update升级错误
最近在折腾Ubuntu,安装的是17.04版本的.想安装PHP7.X最新版本,但是要先升级.利用sudo apt-get update命名后,出现了以下报错: 忽略:1 http://cn.archi ...
- Vue学习之路1-集成环境安装
1.前言 Vue 是一款友好的.多用途且高性能的javascript框架,与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用,它能够帮你创建可维护性和可测试性更强的代码库,Vue是渐进式的j ...