线程安全问题在我们应用中无处不在。线程非安全的HashMap的put()、get()操作会触发引起死循环的问题。有三种不同的同步map操作
1.HashTable
2.Collection.synchronizedMap(Map)
3.ConcurrentHashMap
ConcurrentHashMap实在JDK1.5以后引入,它是最为线程同步Map中优先级被推荐高于HashTable,不仅因为在高并发的情况下,ConcurrentHashMap支持线程同步,而且ConcurrentHashMap的性能比HashTable高,因为ConcurrentHashMap是锁住了部分Map,而HashTable和SynchronizedMap是锁住整个Map在有排序的操作中。
在ConcurrentHashMap的策略中,ConcurrentHashMap分解成不同的segments,每个segments 管理自己内部hash table。
锁发生在申请更新操作时候,在恢复的条件中,它同时也支持在高并发的条件下更新操作,获取最新的结果集。
我们假定有有4个线程访问一个容量为32的ConcurrentHashMap时候,我们可能会想要Table会分区成4segments,每个segments都管理容量为8的Hash table。
ConcurrentHashMap的数据结构可能会是这样。
Segment
ConcurrentHashMap默认是有16segments,其中任意一个都关注、锁中map单一的bucket,意味着同一时间,16个线程能够修改Map(只有多个个取决于多少bucket),并发水平的增长依赖于concurrencylevel
public ConcurrentHashMap(int initialCapacity,float loadFactor, int concurrencyLevel)
最大是2的16次,用比较大的level,可能会浪费空间和时间,用的太小可能会引起线程的竞争。
Put Entry
ConcurrentHashMap不允许空值,它需要定位到segment的索引位置,以便于拿到准确的bucket
Put If Absent
ConcurrentMap offers new method putIfAbsent() which is similar to put except that the value will not be overridden if key already exists. This is equivalent to
except that the action is performed atomically.
containsKey is not synchronized so the above code may cause unexpected behavior. Lets look into the below scenario:
- Thread A is trying to remove a key, calls remove(key), acquires lock.
- Thread B tries to execute above code, calls containsKey(key). The key exists as Thread A has not yet released the lock so the old value is returned.
- Thread A removes the key and releases the lock.
The above scenario proves that the code is not atomic as it returned a key which it thinks exists but actually doesn’t.
Also, performance wise it is slow, containsKey has to locate the segment and traverse through the table to find the key. Method put needs to do the same traversing to locate the bucket and put the value. The new method putIfAbsent is a bit faster as it avoids double traversing. It goes through the same internal flow as put, avoids overriding the old value if key already exists and simply returns the old value.
Summary
相关推荐
`ConcurrentHashMap`是Java并发包(`java.util.concurrent`)中的一个重要组成部分,它提供了一个线程安全的哈希表实现。与传统的`Hashtable`相比,`ConcurrentHashMap`具有更高的并发性能,这主要得益于它的分段锁...
java本地缓存ConcurrentHashMap
`ConcurrentHashMap`内部维护了一个`Segment`数组,每个`Segment`对象都是一个小型的`HashTable`。数组的长度通常是2的幂次方,以便于通过位运算快速定位到对应的`Segment`。 **2. HashEntry** `HashEntry`类表示...
Java并发编程中的ConcurrentHashMap是HashMap的一个线程安全版本,设计目标是在高并发场景下提供高效的数据访问。相比HashTable,ConcurrentHashMap通过采用锁分离技术和更细粒度的锁定策略来提升性能。HashTable...
Java利用ConcurrentHashMap实现本地缓存demo; 基本功能有缓存有效期、缓存最大数、缓存存入记录、清理线程、过期算法删除缓存、LRU算法删除、获取缓存值等功能。 复制到本地项目的时候,记得改包路径哦~
在Java并发编程中,ConcurrentHashMap是一个重要的并发集合。它是由Doug Lea在JSR166y中引入,并在Java 5中提供的一种线程安全的HashMap实现。与传统的HashMap相比,ConcurrentHashMap在多线程环境下具有更好的性能...
源码分析见我博文:http://blog.csdn.net/wabiaozia/article/details/50684556
其中,Segment 分段锁是 ConcurrentHashMap 中的核心组件,它继承自 ReentrantLock,内部拥有一个 Entry 数组,数组中的每个元素又是一个链表。这种结构使得 ConcurrentHashMap能够实现真正的并发访问。 ...
在JDK 1.8版本中,`ConcurrentHashMap`中的`computeIfAbsent`方法存在一个潜在的死循环问题。这个bug主要出现在并发操作时,当`ConcurrentHashMap`需要进行扩容并且`computeIfAbsent`正在执行计算的过程中,可能会...
ConcurrentHashMap是Java并发编程中的一个重要组件,用于解决高并发情况下的数据存储问题。在面试中,ConcurrentHashMap的底层原理、put方法的实现细节都是高频考点。本文将对ConcurrentHashMap#put方法的源码进行...
在Java 7中,`HashMap`内部由数组和链表构成,当多个键映射到同一个哈希桶时,会形成链表。如果链表过长,查询效率会降低,此时Java 8引入了红黑树优化,当链表长度达到8时,会转换为红黑树,进一步提高查找效率。 ...
ConcurrentHashMap是J.U.C(java.util.concurrent包)的重要成员,它是HashMap的一个线程安全的、支持高效并发的版本。在默认理想状态下,ConcurrentHashMap可以支持16个线程执行并发写操作及任意数量线程的读操作。...
为了缓解这一问题,`ConcurrentHashMap`采用了一种称为锁分离的技术,即使用多个锁来分别保护散列表的不同部分。 - **分段(Segment)的概念**:`ConcurrentHashMap`内部将散列表划分为多个段,每个段都是一个小的...
而ConcurrentHashMap是线程安全的HashMap实现,它在Java 7中采用了分段锁(Segment)的设计,每个Segment实际上是一个小型的HashMap,通过锁来确保并发安全。put过程包括: 1. 确保Segment初始化,如果需要则创建新...
程序员面试加薪必备_ConcurrentHashMap底层原理与源码分析深入详解
在Java面试中,经常会问到关于数据结构如HashTable和ConcurrentHashMap的细节,以及它们在并发编程中的使用。 最后,文档中出现了诸如“2399”、“1328”、“2645”、“2633”等数字,很可能是引用了一些代码片段或...
`ConcurrentHashMap`是Java并发编程中非常重要的一个数据结构,它是线程安全的HashMap实现。在理解`ConcurrentHashMap`的实现原理之前,我们先来看看哈希表的基本概念。 哈希表是一种键值对存储的数据结构,通过键...