线程安全问题在我们应用中无处不在。线程非安全的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
相关推荐
java本地缓存ConcurrentHashMap
java源码剖析-ConcurrentHashMap
ConcurrentHashMap源码剖析
源码分析见我博文:http://blog.csdn.net/wabiaozia/article/details/50684556
Java利用ConcurrentHashMap实现本地缓存demo; 基本功能有缓存有效期、缓存最大数、缓存存入记录、清理线程、过期算法删除缓存、LRU算法删除、获取缓存值等功能。 复制到本地项目的时候,记得改包路径哦~
HashTable是一个线程安全的类,它使用...ConcurrentHashMap内部使用段(Segment)来表示这些不同的部分,每个段其实就是一个小的Hashtable,它们有自己的锁。只要多个修改操作发生在不同的段上,它们就可以并发进行。
ConcurrentHashMap具体是怎么实现线程安全的呢,肯定不可能是每个方法加synchronized,那样就变成了HashTable。
computeIfAbsent方法会初始化一个ReservationNode来占位,它会等待计算完毕后替换当前的占位对象。 这时候ConcurrentHashMap达到容量扩容而忽略了ReservationNode情况,调用put的时候在synchronized(f)没有对...
解析concurrenthashmap的源码,学习多线程的思想
ConcurrentHashMap是Java并发编程中的一个重要组件,用于解决高并发情况下的数据存储问题。在面试中,ConcurrentHashMap的底层原理、put方法的实现细节都是高频考点。本文将对ConcurrentHashMap#put方法的源码进行...
ConcurrentHashMap是J.U.C(java.util.concurrent包)的重要成员,它是HashMap的一个线程安全的、支持高效并发的版本。在默认理想状态下,ConcurrentHashMap可以支持16个线程执行并发写操作及任意数量线程的读操作。...
程序员面试加薪必备_ConcurrentHashMap底层原理与源码分析深入详解
ConcurrentHashMap是一个线程安全的HashTable,它的主要功能是提供了一组和HashTable功能相同但是线程安全的方法。ConcurrentHashMap可以做到读取数据不加锁,并且其内部的结构可以让其在进行写操作的时候能够将锁的...
ConcurrentHashMap之实现细节
concurrenthashmap1.7的源码分析
Java——并发容器之ConcurrentHashMap;Java——并发容器之ConcurrentHashMap;Java——并发容器之ConcurrentHashMap;Java——并发容器之ConcurrentHashMap;Java——并发容器之ConcurrentHashMap;Java——并发...
java7-8中的 HashMap和ConcurrentHashMap全解析
ConcurrentHashMap的实现原理(纯干货)
Java并发编程之ConcurrentHashMap Java并发编程之ConcurrentHashMap.pdf
ConcurrentHashMap的实现原理(JDK1.7和JDK1.8),并说明了在jdk1.7与jdk1.8的不同实现原理