|
|||
|
使用减小锁粒度的方式实现高并发。实现方式较7及之前有较大的变化, 不在使用segment进行锁分段的技术。 直接使用Node存储值,put操作的时候根据hash到的table的节点进行加锁, 而不是对整个table加锁达到减小锁的粒度实现更高的并发性能。 |
||
|
/** * Key-value entry. This class is never exported out as a * user-mutable Map.Entry (i.e., one supporting setValue; see * MapEntry below), but can be used for read-only traversals used * in bulk tasks. Subclasses of Node with a negative hash field * are special, and contain null keys and values (but are never * exported). Otherwise, keys and vals are never null. */ static class Node final int hash; final K key; volatile V val; volatile Node
Node(int hash, K key, V val, Node 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(); }
public final boolean equals(Object o) { Object k, v, u; Map.Entry,?> e; return ((o instanceof Map.Entry) && (k = (e = (Map.Entry,?>)o).getKey()) != null && (v = e.getValue()) != null && (k == key || k.equals(key)) && (v == (u = val) || v.equals(u))); }
/** * Virtualized support for map.get(); overridden in subclasses. */ Node Node if (k != null) { do { K ek; if (e.hash == h && ((ek = e.key) == k || (ek != null && k.equals(ek)))) return e; } while ((e = e.next) != null); } return null; } } |
||
|
|||
|
一:init初始化,默认的话只是new一个对象返回。知道put的时候再initTable。
/** * Creates a new, empty map with the default initial table size (16). */ public ConcurrentHashMap() { }
initTable: Node table = tab = nt;
|
||
|
|||
|
二:put操作:的时候根据hash到的table的节点进行加锁,而不是对整个table加锁达到减小锁的粒度实现更高的并发性能。 final V putVal(K key, V value, boolean onlyIfAbsent) { if (key == null || value == null) throw new NullPointerException(); int hash = spread(key.hashCode()); int binCount = 0; for (Node Node if (tab == null || (n = tab.length) == 0) tab = initTable(); else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) { if (casTabAt(tab, i, null, new Node break; // no lock when adding to empty bin } else if ((fh = f.hash) == MOVED) tab = helpTransfer(tab, f); else { V oldVal = null; synchronized (f) { if (tabAt(tab, i) == f) { if (fh >= 0) { binCount = 1; for (Node K ek; if (e.hash == hash && ((ek = e.key) == key || (ek != null && key.equals(ek)))) { oldVal = e.val; if (!onlyIfAbsent) e.val = value; break; } Node if ((e = e.next) == null) { pred.next = new Node value, null); break; } } } else if (f instanceof TreeBin) { Node binCount = 2; if ((p = ((TreeBin value)) != null) { oldVal = p.val; if (!onlyIfAbsent) p.val = value; } } } } if (binCount != 0) { if (binCount >= TREEIFY_THRESHOLD) treeifyBin(tab, i); if (oldVal != null) return oldVal; break; } } } addCount(1L, binCount); return null; }
使用synchronized (f)加锁保证并发安全性。减小锁的粒度,只对table中的一个对象加锁。 |
||
|
|
|
|
|
|
三:get操作:获取table的时候使用tabAt方法,返回volatile对象保证操作的可见性。
public V get(Object key) { Node int h = spread(key.hashCode()); if ((tab = table) != null && (n = tab.length) > 0 && (e = tabAt(tab, (n - 1) & h)) != null) { if ((eh = e.hash) == h) { if ((ek = e.key) == key || (ek != null && key.equals(ek))) return e.val; } else if (eh < 0) return (p = e.find(h, key)) != null ? p.val : null; while ((e = e.next) != null) { if (e.hash == h && ((ek = e.key) == key || (ek != null && key.equals(ek)))) return e.val; } } return null; }
static final return (Node
|
|
四:size操作:使用counterCells保存有修改的时候修改这个数组,最后累加这个数组得到个数。
private transient volatile CounterCell[]counterCells;
/**
* {@inheritDoc}
*/
public int size() {
long n = sumCount();
return ((n < 0L) ? 0 :
(n >(long)Integer.MAX_VALUE) ? Integer.MAX_VALUE :
(int)n);
}
final long sumCount() {
CounterCell[] as = counterCells;CounterCell a;
long sum = baseCount;
if (as != null) {
for (int i = 0; i < as.length;++i) {
if ((a = as[i]) != null)
sum += a.value;
}
}
return sum;
}
private final void addCount(long x, int check) {
CounterCell[] as; long b, s;
if ((as = counterCells) != null ||
!U.compareAndSwapLong(this,BASECOUNT, b = baseCount, s = b + x)) {
CounterCell a; long v; int m;
boolean uncontended = true;
if (as == null || (m = as.length -1) < 0 ||
(a =as[ThreadLocalRandom.getProbe() & m]) == null ||
!(uncontended =
U.compareAndSwapLong(a,CELLVALUE, v = a.value, v + x))) {
fullAddCount(x, uncontended);
return;
}
if (check <= 1)
return;
s = sumCount();
}
if (check >= 0) {
Node
while (s >= (long)(sc = sizeCtl)&& (tab = table) != null &&
(n = tab.length) int rs = resizeStamp(n); if (sc < 0) { if ((sc >>>RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 || sc == rs + MAX_RESIZERS|| (nt = nextTable) == null || transferIndex <= 0) break; if(U.compareAndSwapInt(this, SIZECTL, sc, sc + 1)) transfer(tab, nt); } else if(U.compareAndSwapInt(this, SIZECTL, sc, (rs << RESIZE_STAMP_SHIFT) + 2)) transfer(tab, null); s = sumCount(); } } }