1.类的定义
public class ConcurrentHashMap extends AbstractMap implements ConcurrentMap, Serializable
由上面可以看出,ConcurrentHashMap是实现了ConcurrentMap接口。ConcurrentMap接口定义可支持并发,NavigableMap接口定义可支持导航,sortedMap接口定义可支持排序。
2.类的结构
ConcurrentHashMap内部包含了多个内部类,其中最重要的就是Segment和HashEntry类。
HashEntry
HashEntry同HashMap中的Entry一样,每个HashEntry是一个节点,保持key,value,和下一个节点。
Segment
Segment是ConcurrentHashMap非常重要的内部类,ConcurrentHashMap保持了一个Segment数组,所有的数据都保存在segment中。ConcurrentHashMap通过N个Segment把数据分成N块,而每块之间互不影响。所以理论上可以同时并行的执行N个加锁的操作,这就是ConcurrentHashMap并发的基础。
3.构造函数
public ConcurrentHashMap(int initialCapacity, float loadFactor) {
this(initialCapacity, loadFactor, DEFAULT_CONCURRENCY_LEVEL);
}
public ConcurrentHashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
}
public ConcurrentHashMap() {
this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
}
DEFAULT_INITIAL_CAPACITY:默认初始容量
DEFAULT_LOAD_FACTOR:默认加载因子
DEFAULT_CONCURRENCY_LEVEL:表示有几个segment
3.1put(K,V)
public V put(K key, V value) {
if (value == null)
throw new NullPointerException();
int hash = hash(key.hashCode());
return segmentFor(hash).put(key, hash, value, false);
}
ConcurrentHashMap的put方法内部只是根据key的hash值找到对应的Segment.
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 = 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();
}
}
可以看出首先是要加锁;然后读取count值,count记录着segment中元素HashEntry的个数,用volatile修饰的;接着判断增加之后元数数量是否超过阈值,如果超过的话提前扩容。
3.2remove(Object)
public V remove(Object key) {
int hash = hash(key.hashCode());
return segmentFor(hash).remove(key, hash, null);
}
/**
* Remove; match on key only if value null, else match both.
*/
V remove(Object key, int hash, Object value) {
//由于remove是结构性修改,所以第一步便是lock
lock();
try {
//读取count值,此处是利用volatile变量的内存可见性来保证读线程能够及时的读取到最新值(后面会单独介绍)
int c = count - 1;
//是根据key的hashCode找到该节点对应的桶
HashEntry[] tab = table;
int index = hash & (tab.length - 1);
HashEntry first = 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;
//如果value==null,则无需关心节点的值是否与指定值相同,否则只有在两者相同情况才可删除
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();
}
}
在删除一个节点时,为了不影响正在遍历链表的线程,采用复制方式,而并不是直接移除带删除点的结点。
3.3get(Object)
public V get(Object key) {
int hash = hash(key.hashCode());
return segmentFor(hash).get(key, hash);
}
ConcurrentHashMap的get()方法和put()方法一样,都依赖于Segment的get()方法。
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;
}
/**
* Returns properly casted first entry of bin for given hash.
*/
HashEntry getFirst(int hash) {
HashEntry[] tab = table;
return tab[hash & (tab.length - 1)];
}
/**
* Reads value field of an entry under lock. Called if value
* field ever appears to be null. This is possible only if a
* compiler happens to reorder a HashEntry initialization with
* its table assignment, which is legal under memory model
* but is not known to ever occur.
*/
V readValueUnderLock(HashEntry e) {
lock();
try {
return e.value;
} finally {
unlock();
}
}