Java多线程ConcurrentHashMap

Posted moxi-moxi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java多线程ConcurrentHashMap相关的知识,希望对你有一定的参考价值。

·首先来看Put()方法

final V putVal(K key, V value, boolean onlyIfAbsent) {
if (key == null || value == null) throw new NullPointerException();
//寻找hash值,spread方法的作用是再散列,与数学相关,不管,用处就是让hash值更加均匀
  int hash = spread(key.hashCode());
int binCount = 0;
for (Node<K,V>[] tab = table;;) {
Node<K,V> f; int n, i, fh;
if (tab == null || (n = tab.length) == 0)
//hashmap的特点,在放第一个值的时候才会对table进行初始化
*****************************************************************
//重要变量sizeCtl:
//负数:表示正在进行初始化或者扩容,为-1表示正在初始化,-n表示有n-1个线程正在进行扩容
//正数:0表示还没有被初始化,大于0的数,初始化或者是下一次扩容的阈值
private final Node<K,V>[] initTable() {
Node<K,V>[] tab; int sc;
while ((tab = table) == null || tab.length == 0) {
if ((sc = sizeCtl) < 0)
        //发现有其他线程正在初始化或者扩容,yield
Thread.yield(); // lost initialization race; just spin
      //自旋,对sc进行设值,表示正在初始化
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=0.75n(默认的阈值)
sc = n - (n >>> 2);
}
} finally {
sizeCtl = sc;
}
break;
}
}
return tab;
}

*****************************************************************
tab = initTable();
      //table数组上这个元素为null的时候,直接把新元素放置到数组里面
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
}
      //table数组不为空的时候
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,V> e = f;; ++binCount) {
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<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) {
          //到达树化阈值时由链表转为红黑树
if (binCount >= TREEIFY_THRESHOLD)
treeifyBin(tab, i);
if (oldVal != null)
return oldVal;
break;
}
}
}
addCount(1L, binCount);
return null;
}


技术图片

 

 相当于加索引,空间换时间


·阻塞队列

概念、生产者消费者模式
  当队列满的时候,插入元素线程被阻塞,直到队列不满
  当队列为空的时候,获取元素的线程被阻塞,直到队列非空

常用方法:
  插入方法、add、offer、阻塞方法put、超时退出offer(time)
  移除(拿)方法、remove、poll、阻塞方法take、超时退出poll(time)
  检查方法:element、peek

常见阻塞队列:接口BlockingQueue
  

技术图片

 

 

ArrayBlockingQueue:按照先进先出的原则,要求设定初始大小
LinkedBlockingQueue:按照先进先出原则,可以不设置初始大小
区别:ArrayBlockingQueue只有一个锁,直接插入元素
    LinkedBlockingQueue消费者生产者各有一个锁,需要经过一次转换
PriorityQueue:默认情况下,按照自然顺序排序,或者可以指定一个CompareTo()方法








以上是关于Java多线程ConcurrentHashMap的主要内容,如果未能解决你的问题,请参考以下文章

Java多线程ConcurrentHashMap

Java多线程工具包java.util.concurrent---ConcurrentHashMap

java多线程进阶ConcurrentHashMap

java多线程进阶ConcurrentHashMap

java面试问题分类

Java并发容器--ConcurrentHashMap