demo:
public static void main(String[] args) {
ConcurrentHashMap<Integer,Integer> map = new ConcurrentHashMap<>(); // 初始化
for (int i=0; i<=1000; i++) {
map.put(i,i); // 添加元素
}
System.out.println(map.get(11)); // 获取元素
}
常见问题:
1.ConcurrentHashMap如何实现线程安全
使用Node + CAS + Synchronized来保证线程安全。
写头node使用CAS不加锁,写链表或红黑树时只加锁头节点,因此可以并发写不同Node上的节点。
常量:
//
private static final int MAXIMUM_CAPACITY = 1 << 30;
//
private static final int DEFAULT_CAPACITY = 16;
//
static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
//
private static final int DEFAULT_CONCURRENCY_LEVEL = 16;
//
private static final float LOAD_FACTOR = 0.75f;
//
static final int TREEIFY_THRESHOLD = 8;
//
static final int UNTREEIFY_THRESHOLD = 6;
//
static final int MIN_TREEIFY_CAPACITY = 64;
//
private static final int MIN_TRANSFER_STRIDE = 16;
//
private static int RESIZE_STAMP_BITS = 16;
//
private static final int MAX_RESIZERS = (1 << (32 - RESIZE_STAMP_BITS)) - 1;
//
private static final int RESIZE_STAMP_SHIFT = 32 - RESIZE_STAMP_BITS;
//
static final int MOVED = -1; // hash for forwarding nodes
static final int TREEBIN = -2; // hash for roots of trees
static final int RESERVED = -3; // hash for transient reservations
static final int HASH_BITS = 0x7fffffff; // usable bits of normal node hash
属性:
//
transient volatile Node<K,V>[] table;
//
private transient volatile Node<K,V>[] nextTable;
//
private transient volatile long baseCount;
//
private transient volatile int sizeCtl;
//
private transient volatile int transferIndex;
//
private transient volatile int cellsBusy;
put():
public V put(K key, V value) {
return putVal(key, value, false);
}
final V putVal(K key, V value, boolean onlyIfAbsent) {
//key或value为null,抛异常
if (key == null || value == null) throw new NullPointerException();
//获取key的hash
int hash = spread(key.hashCode());
int binCount = 0;
//死循环
for (Node<K,V>[] tab = table;;) {
Node<K,V> f; int n, i, fh;
//1.若tab为空则初始化
if (tab == null || (n = tab.length) == 0)
tab = initTable();
· //2.若tabAt(tab, i = (n - 1) & hash))为空则CAS添加元素
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
if (casTabAt(tab, i, null,
new Node<K,V>(hash, key, value, null)))
break; // no lock when adding to empty bin
}
· //3.若正在扩容,则当前线程协助扩容
else if ((fh = f.hash) == MOVED)
tab = helpTransfer(tab, f);
· //4.若tabAt(tab, i = (n - 1) & hash))不为空,则synchronized的方式加锁
else {
V oldVal = null;
synchronized (f) {
if (tabAt(tab, i) == f) {
if (fh >= 0) {
binCount = 1;
for (Node<K,V> e = f;; ++binCount) {
K ek;
//key相同时,覆盖
if (e.hash == hash &&
((ek = e.key) == key ||
(ek != null && key.equals(ek)))) {
oldVal = e.val;
if (!onlyIfAbsent)
e.val = value;
break;
}
//key不相同时,追加到尾部
Node<K,V> pred = e;
if ((e = e.next) == null) {
pred.next = new Node<K,V>(hash, key,
value, null);
break;
}
}
}
//若为红黑树,则追加
else if (f instanceof TreeBin) {
Node<K,V> p;
binCount = 2;
if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,
value)) != null) {
oldVal = p.val;
if (!onlyIfAbsent)
p.val = value;
}
}
}
}
if (binCount != 0) {
//链表长度大于8,尝试转为红黑树
if (binCount >= TREEIFY_THRESHOLD)
//尝试调整为红黑树(若node数组长度小于64依然走扩容)
treeifyBin(tab, i);
if (oldVal != null)
return oldVal;
break;
}
}
}
addCount(1L, binCount);
return null;
}
//初始化
private final Node<K,V>[] initTable() {
Node<K,V>[] tab; int sc;
while ((tab = table) == null || tab.length == 0) {
//若sizeCtl<0,说明别的线程正在执行cas,当前线程让出时间片
if ((sc = sizeCtl) < 0)
Thread.yield(); // lost initialization race; just spin
//第一次put,有且只有一个线程将sizeCtl设置为-1,其它线程让出时间片
else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
try {
if ((tab = table) == null || tab.length == 0) {
int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
@SuppressWarnings("unchecked")
Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
table = tab = nt;
sc = n - (n >>> 2);
}
} finally {
sizeCtl = sc;
}
break;
}
}
return tab;
}
//指定位置的节点
static final <K,V> Node<K,V> tabAt(Node<K,V>[] tab, int i) {
return (Node<K,V>)U.getObjectVolatile(tab, ((long)i << ASHIFT) + ABASE);
}
//cas添加到指定位置元素
static final <K,V> boolean casTabAt(Node<K,V>[] tab, int i,
Node<K,V> c, Node<K,V> v) {
return U.compareAndSwapObject(tab, ((long)i << ASHIFT) + ABASE, c, v);
}
//尝试调整为红黑树(若node数组长度小于64依然走扩容)
private final void treeifyBin(Node<K,V>[] tab, int index) {
Node<K,V> b; int n, sc;
if (tab != null) {
//node数组长度小于64走扩容
if ((n = tab.length) < MIN_TREEIFY_CAPACITY)
tryPresize(n << 1);
//node数组长度大于等于64调整为红黑树
else if ((b = tabAt(tab, index)) != null && b.hash >= 0) {
synchronized (b) {
if (tabAt(tab, index) == b) {
TreeNode<K,V> hd = null, tl = null;
for (Node<K,V> e = b; e != null; e = e.next) {
TreeNode<K,V> p =
new TreeNode<K,V>(e.hash, e.key, e.val,
null, null);
if ((p.prev = tl) == null)
hd = p;
else
tl.next = p;
tl = p;
}
setTabAt(tab, index, new TreeBin<K,V>(hd));
}
}
}
}
}