没有合适的资源?快使用搜索试试~ 我知道了~
Java并发编程笔记之ConcurrentHashMap原理探究.docx
1.该资源内容由用户上传,如若侵权请联系客服进行举报
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
版权申诉
0 下载量 36 浏览量
2022-06-21
22:01:05
上传
评论
收藏 175KB DOCX 举报
温馨提示
试读
32页
HashTable是一个线程安全的类,它使用synchronized来锁住整张Hash表来实现线程安全,即每次锁住整张表让线程独占,相当于所有线程进行读写时都去竞争一把锁,导致效率非常低下。ConcurrentHashMap可以做到读取数据不加锁,并且其内部的结构可以让其在进行写操作的时候能够将锁的粒度保持地尽量地小,允许多个修改操作并发进行,其关键在于使用了锁分离技术。它使用了多个锁来控制对hash表的不同部分进行的修改。ConcurrentHashMap内部使用段(Segment)来表示这些不同的部分,每个段其实就是一个小的Hashtable,它们有自己的锁。只要多个修改操作发生在不同的段上,它们就可以并发进行。
资源推荐
资源详情
资源评论
Java 并发编程笔记之 ConcurrentHashMap 原
理探究
在多线程环境下,使用 HashMap 进行 put 操作时存在丢失数据的情况,为了避
免这种 bug 的隐患,强烈建议使用 ConcurrentHashMap 代替 HashMap。
HashTable 是一个线程安全的类,它使用 synchronized 来锁住整张 Hash 表来
实现线程安全,即每次锁住整张表让线程独占,相当于所有线程进行读写时都
去竞争一把锁,导致效率非常低下。ConcurrentHashMap 可以做到读取数据不
加锁,并且其内部的结构可以让其在进行写操作的时候能够将锁的粒度保持地
尽量地小,允许多个修改操作并发进行,其关键在于使用了锁分离技术。它使
用了多个锁来控制对 hash 表的不同部分进行的修改。ConcurrentHashMap 内
部使用段(Segment)来表示这些不同的部分,每个段其实就是一个小的
Hashtable,它们有自己的锁。只要多个修改操作发生在不同的段上,它们就可
以并发进行。
CouncurrentHashMap 实现原理
ConcurrentHashMap 为了提高本身的并发能力,在内部采用了一个叫做
Segment 的结构,一个 Segment 其实就是一个类 Hash Table 的结构,
Segment 内部维护了一个链表数组,我们用下面这一幅图来看下
ConcurrentHashMap 的内部结构,从下面的结构我们可以了解到,
ConcurrentHashMap 定位一个元素的过程需要进行两次 Hash 操作,第一次
Hash 定位到 Segment ,第二次 Hash 定位到元素所在的链表的头部,因此,
这一种结构的带来的副作用是 Hash 的过程要比普通的 HashMap 要长,但是
带来的好处是写操作的时候可以只对元素所在的 Segment 进行操作即可,不会
影响到其他的 Segment,这样,在最理想的情况下,ConcurrentHashMap 可
以最高同时支持 Segment 数量大小的写操作(刚好这些写操作都非常平均地分
布在所有的 Segment 上),所以,通过这一种结构,ConcurrentHashMap 的
并发能力可以大大的提高。我们用下面这一幅图来看下 ConcurrentHashMap
的内部结构详情图,如下:
不难看出,ConcurrentHashMap 采用了二次 hash 的方式,第一次 hash 将 key
映射到对应的 segment,而第二次 hash 则是映射到 segment 的不同桶(bucket)
中。
为什么要用二次 hash,主要原因是为了构造分离锁,使得对于 map 的修改不
会锁住整个容器,提高并发能力。当然,没有一种东西是绝对完美的,二次
hash 带来的问题是整个 hash 的过程比 hashmap 单次 hash 要长,所以,如果
不是并发情形,不要使用 concurrentHashmap。
JAVA7 之前 ConcurrentHashMap 主要采用锁机制,在对某个 Segment 进行操
作时,将该 Segment 锁定,不允许对其进行非查询操作,而在 JAVA8 之后采
用 CAS 无锁算法,这种乐观操作在完成前进行判断,如果符合预期结果才给予
执行,对并发操作提供良好的优化.
让我们先看 JDK1.7 的 ConcurrentHashMap 的原理分析
JDK1.7 的 ConcurrentHashMap
如上所示,是由 Segment 数组、HashEntry 组成,和 HashMap 一样,仍然是
数组加链表。
让我们看看 Segment 里面的成员变量,源码如下:
static final class Segment<K,V> extends ReentrantLock implements
Serializable {
transient volatile int count; //Segment 中元素的数量
transient int modCount; //对 table 的大小造成影响的操作的数量(比如
put 或者 remove 操作)
transient int threshold; //阈值,Segment 里面元素的数量超过这个值那
么就会对 Segment 进行扩容
final float loadFactor; //负载因子,用于确定 threshold
transient volatile HashEntry<K,V>[] table; //链表数组,数组中的每一个
元素代表了一个链表的头部
}
接着再看看 HashEntry 中的组成,源码如下:
/**
* ConcurrentHashMap 列表 Entry。注意,这不会作为用户可见的 Map.Entry 导出。
*/
static final class HashEntry<K,V> {
final int hash;
final K key;
volatile V value;
volatile HashEntry<K,V> next;
HashEntry(int hash, K key, V value, HashEntry<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
/**
* 设置具有 volatile 写语义的 next 字段。
final void setNext(HashEntry<K,V> n) {
UNSAFE.putOrderedObject(this, nextOffset, n);
}
// Unsafe mechanics
static final sun.misc.Unsafe UNSAFE;
//下一个 HashEntry 的偏移量
static final long nextOffset;
static {
try {
UNSAFE = sun.misc.Unsafe.getUnsafe();
Class k = HashEntry.class;
//获取 HashEntry next 在内存中的偏移量
nextOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("next"));
} catch (Exception e) {
throw new Error(e);
}
}
}
和 HashMap 非常类似,唯一的区别就是其中的核心数据如 value ,以及链表
都是 volatile 修饰的,保证了获取时的可见性。
原理上来说:ConcurrentHashMap 采用了分段锁技术,其中 Segment 继承于
ReentrantLock 。不会像 HashTable 那样不管是 put 还是 get 操作都需要做同
步处理,理论上 ConcurrentHashMap 支持 CurrencyLevel (Segment 数组数
量) 的线程并发。每当一个线程占用锁访问一个 Segment 时,不会影响到其他
的 Segment。
接着让我们继续看看 JDK1.7 中 ConcurrentHashMap 的成员变量和构造函数,
源码如下:
// 默认初始容量
static final int DEFAULT_INITIAL_CAPACITY = 16;
// 默认加载因子
static final float DEFAULT_LOAD_FACTOR = 0.75f;
// 默认 segment 层级
static final int DEFAULT_CONCURRENCY_LEVEL = 16;
// 最大容量
static final int MAXIMUM_CAPACITY = 1 << 30;
// segment 最小容量
static final int MIN_SEGMENT_TABLE_CAPACITY = 2;
// 一个 segment 最大容量
static final int MAX_SEGMENTS = 1 << 16;
// 锁之前重试次数
static final int RETRIES_BEFORE_LOCK = 2;
public ConcurrentHashMap() {
this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR,
DEFAULT_CONCURRENCY_LEVEL);
剩余31页未读,继续阅读
资源评论
小兔子平安
- 粉丝: 209
- 资源: 1940
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功