您好,登录后才能下订单哦!
在多线程环境下,HashMap
并不是线程安全的,因此在并发场景下使用HashMap
可能会导致数据不一致的问题。为了解决这个问题,Java提供了ConcurrentHashMap
,它是HashMap
的线程安全版本。ConcurrentHashMap
通过分段锁(Segment)和CAS操作来实现高效的并发控制,从而在多线程环境下提供高性能的读写操作。
本文将深入分析ConcurrentHashMap
的源码,探讨其内部实现机制,包括数据结构、初始化、put操作、get操作、remove操作、扩容机制、并发控制、迭代器以及性能分析等方面。
ConcurrentHashMap
是Java集合框架中的一个重要类,它实现了ConcurrentMap
接口,提供了线程安全的哈希表实现。与HashMap
不同,ConcurrentHashMap
通过分段锁(Segment)和CAS操作来实现高效的并发控制,从而在多线程环境下提供高性能的读写操作。
ConcurrentHashMap
的主要特点包括:
ConcurrentHashMap
通过分段锁和CAS操作来保证线程安全。ConcurrentHashMap
通过分段锁和CAS操作来实现高效的并发控制,从而在多线程环境下提供高性能的读写操作。ConcurrentHashMap
支持动态扩容,可以根据需要自动调整容量。ConcurrentHashMap
的核心数据结构是一个数组,数组中的每个元素是一个Node
节点。Node
节点是ConcurrentHashMap
的基本存储单元,它包含了键值对以及指向下一个节点的指针。
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
volatile V val;
volatile Node<K,V> next;
Node(int hash, K key, V val, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.val = val;
this.next = next;
}
public final K getKey() { return key; }
public final V getValue() { return val; }
public final int hashCode() { return key.hashCode() ^ val.hashCode(); }
public final String toString(){ return key + "=" + val; }
public final V setValue(V value) {
throw new UnsupportedOperationException();
}
}
ConcurrentHashMap
的数组是一个Node
数组,数组中的每个元素是一个Node
节点。Node
节点是ConcurrentHashMap
的基本存储单元,它包含了键值对以及指向下一个节点的指针。
transient volatile Node<K,V>[] table;
ConcurrentHashMap
还包含一个Segment
数组,Segment
是ConcurrentHashMap
的分段锁,每个Segment
包含一个HashEntry
数组,HashEntry
是Segment
的基本存储单元。
final Segment<K,V>[] segments;
Segment
是ConcurrentHashMap
的分段锁,每个Segment
包含一个HashEntry
数组,HashEntry
是Segment
的基本存储单元。
static final class Segment<K,V> extends ReentrantLock implements Serializable {
private static final long serialVersionUID = 2249069246763182397L;
transient volatile HashEntry<K,V>[] table;
transient int count;
transient int modCount;
transient int threshold;
final float loadFactor;
Segment(float lf, int threshold, HashEntry<K,V>[] tab) {
this.loadFactor = lf;
this.threshold = threshold;
this.table = tab;
}
}
HashEntry
是Segment
的基本存储单元,它包含了键值对以及指向下一个节点的指针。
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;
}
}
ConcurrentHashMap
的初始化过程主要包括以下几个步骤:
ConcurrentHashMap
的初始容量是根据传入的initialCapacity
和concurrencyLevel
参数计算的。ConcurrentHashMap
的Segment
数组是根据concurrencyLevel
参数创建的。Segment
包含一个HashEntry
数组,HashEntry
数组的容量是根据initialCapacity
和concurrencyLevel
参数计算的。public ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel) {
if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0)
throw new IllegalArgumentException();
if (concurrencyLevel > MAX_SEGMENTS)
concurrencyLevel = MAX_SEGMENTS;
int sshift = 0;
int ssize = 1;
while (ssize < concurrencyLevel) {
++sshift;
ssize <<= 1;
}
this.segmentShift = 32 - sshift;
this.segmentMask = ssize - 1;
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
int c = initialCapacity / ssize;
if (c * ssize < initialCapacity)
++c;
int cap = MIN_SEGMENT_TABLE_CAPACITY;
while (cap < c)
cap <<= 1;
Segment<K,V> s0 = new Segment<K,V>(loadFactor, (int)(cap * loadFactor), (HashEntry<K,V>[])new HashEntry[cap]);
Segment<K,V>[] ss = (Segment<K,V>[])new Segment[ssize];
UNSAFE.putOrderedObject(ss, SBASE, s0);
this.segments = ss;
}
ConcurrentHashMap
的put
操作主要包括以下几个步骤:
Segment
。Segment
加锁,保证线程安全。Segment
的HashEntry
数组中插入新的节点。Segment
的锁。public V put(K key, V value) {
Segment<K,V> s;
if (value == null)
throw new NullPointerException();
int hash = hash(key);
int j = (hash >>> segmentShift) & segmentMask;
if ((s = (Segment<K,V>)UNSAFE.getObject(segments, (j << SSHIFT) + SBASE)) == null)
s = ensureSegment(j);
return s.put(key, hash, value, false);
}
Segment
的put
操作主要包括以下几个步骤:
HashEntry
。HashEntry
链表中插入新的节点。Segment
的计数。final V put(K key, int hash, V value, boolean onlyIfAbsent) {
HashEntry<K,V> node = tryLock() ? null : scanAndLockForPut(key, hash, value);
V oldValue;
try {
HashEntry<K,V>[] tab = table;
int index = (tab.length - 1) & hash;
HashEntry<K,V> first = entryAt(tab, index);
for (HashEntry<K,V> e = first;;) {
if (e != null) {
K k;
if ((k = e.key) == key || (e.hash == hash && key.equals(k))) {
oldValue = e.value;
if (!onlyIfAbsent) {
e.value = value;
++modCount;
}
break;
}
e = e.next;
} else {
if (node != null)
node.setNext(first);
else
node = new HashEntry<K,V>(hash, key, value, first);
int c = count + 1;
if (c > threshold && tab.length < MAXIMUM_CAPACITY)
rehash(node);
else
setEntryAt(tab, index, node);
++modCount;
count = c;
oldValue = null;
break;
}
}
} finally {
unlock();
}
return oldValue;
}
ConcurrentHashMap
的get
操作主要包括以下几个步骤:
Segment
。HashEntry
。HashEntry
链表中查找对应的节点。public V get(Object key) {
Segment<K,V> s;
HashEntry<K,V>[] tab;
int h = hash(key);
long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null && (tab = s.table) != null) {
for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile(tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE); e != null; e = e.next) {
K k;
if ((k = e.key) == key || (e.hash == h && key.equals(k)))
return e.value;
}
}
return null;
}
ConcurrentHashMap
的remove
操作主要包括以下几个步骤:
Segment
。Segment
加锁,保证线程安全。Segment
的HashEntry
数组中删除对应的节点。Segment
的锁。public V remove(Object key) {
int hash = hash(key);
Segment<K,V> s = segmentForHash(hash);
return s == null ? null : s.remove(key, hash, null);
}
Segment
的remove
操作主要包括以下几个步骤:
HashEntry
。HashEntry
链表中删除对应的节点。Segment
的计数。final V remove(Object key, int hash, Object value) {
if (!tryLock())
scanAndLock(key, hash);
V oldValue = null;
try {
HashEntry<K,V>[] tab = table;
int index = (tab.length - 1) & hash;
HashEntry<K,V> first = entryAt(tab, index);
HashEntry<K,V> e = first;
while (e != null && (e.hash != hash || !key.equals(e.key)))
e = e.next;
if (e != null) {
V v = e.value;
if (value == null || value.equals(v)) {
oldValue = v;
++modCount;
HashEntry<K,V> newFirst = e.next;
for (HashEntry<K,V> p = first; p != e; p = p.next)
newFirst = new HashEntry<K,V>(p.hash, p.key, p.value, newFirst);
setEntryAt(tab, index, newFirst);
count = c;
}
}
} finally {
unlock();
}
return oldValue;
}
ConcurrentHashMap
的扩容机制主要包括以下几个步骤:
HashEntry
数组。private void rehash(HashEntry<K,V> node) {
HashEntry<K,V>[] oldTable = table;
int oldCapacity = oldTable.length;
int newCapacity = oldCapacity << 1;
threshold = (int)(newCapacity * loadFactor);
HashEntry<K,V>[] newTable = (HashEntry<K,V>[]) new HashEntry[newCapacity];
int sizeMask = newCapacity - 1;
for (int i = 0; i < oldCapacity ; i++) {
HashEntry<K,V> e = oldTable[i];
if (e != null) {
HashEntry<K,V> next = e.next;
int idx = e.hash & sizeMask;
if (next == null)
newTable[idx] = e;
else {
HashEntry<K,V> lastRun = e;
int lastIdx = idx;
for (HashEntry<K,V> last = next; last != null; last = last.next) {
int k = last.hash & sizeMask;
if (k != lastIdx) {
lastIdx = k;
lastRun = last;
}
}
newTable[lastIdx] = lastRun;
for (HashEntry<K,V> p = e; p != lastRun; p = p.next) {
int h = p.hash;
int k = h & sizeMask;
HashEntry<K,V> n = newTable[k];
newTable[k] = new HashEntry<K,V>(h, p.key, p.value, n);
}
}
}
}
int nodeIndex = node.hash & sizeMask;
node.setNext(newTable[nodeIndex]);
newTable[nodeIndex] = node;
table = newTable;
}
ConcurrentHashMap
的并发控制主要通过分段锁(Segment)和CAS操作来实现。每个Segment
是一个独立的锁,不同的Segment
之间可以并发操作,从而提高了并发性能。
ConcurrentHashMap
的并发控制主要包括以下几个方面:
ConcurrentHashMap
通过分段锁来实现高效的并发控制。每个Segment
是一个独立的锁,不同的Segment
之间可以并发操作。ConcurrentHashMap
通过CAS操作来实现高效的并发控制。CAS操作是一种无锁操作,它通过比较并交换的方式来实现原子操作。final V put(K key, int hash, V value, boolean onlyIfAbsent) {
HashEntry<K,V> node = tryLock() ? null : scanAndLockForPut(key, hash, value);
V oldValue;
try {
HashEntry<K,V>[] tab = table;
int index = (tab.length - 1) & hash;
HashEntry<K,V> first = entryAt(tab, index);
for (HashEntry<K,V> e = first;;) {
if (e != null) {
K k;
if ((k = e.key) == key || (e.hash == hash && key.equals(k))) {
oldValue = e.value;
if (!onlyIfAbsent) {
e.value = value;
++modCount;
}
break;
}
e = e.next;
} else {
if (node != null)
node.setNext(first);
else
node = new HashEntry<K,V>(hash, key, value, first);
int c = count + 1;
if (c > threshold && tab.length < MAXIMUM_CAPACITY)
rehash(node);
else
setEntryAt(tab, index, node);
++modCount;
count = c;
oldValue = null;
break;
}
}
} finally {
unlock();
}
return oldValue;
}
ConcurrentHashMap
的迭代器主要包括以下几个步骤:
HashEntry
迭代器。HashEntry
链表中的节点。”`java
public Iterator
final class EntryIterator extends HashIterator implements Iterator
abstract class HashIterator {
int nextSegmentIndex;
int nextTableIndex;
HashEntry
HashIterator() {
nextSegmentIndex = segments.length - 1;
nextTableIndex = -1;
advance();
}
final void advance() {
if (nextEntry != null && (nextEntry = nextEntry.next) != null)
return;
while (nextTableIndex >= 0) {
if ((nextEntry = entryAt(currentTable, nextTableIndex--)) != null)
return;
}
while (nextSegmentIndex >= 0) {
Segment<K,V> seg = segmentAt(segments, nextSegmentIndex--);
if (seg != null && (currentTable = seg.table) != null
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。