ConurrentHashMap源码分析

本文详细解析了ConcurrentHashMap在JDK1.8中的实现原理,包括volatile关键字、CAS技术、synchronized关键字的运用,以及初始化、get、put、size等方法的线程安全处理。特别介绍了变树与扩容过程中的局部同步策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ConurrentHashMap源码分析

推荐阅读文章:Map大家族的那点事儿

在jdk1.8中ConcurrentHashMap所采用的线程安全技术有:

1.volatile 关键字 (核心)

/**
 * The array of bins. Lazily initialized upon first insertion.
 * Size is always a power of two. Accessed directly by iterators.
 */
 transient volatile Node<K,V>[] table;

2.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);
    }

3.synchronized 关键字 (次要、细粒度锁、且少量出现)

final V putVal(K key, V value, boolean onlyIfAbsent) {
	....
	synchronized (f) {
            ....
    }       
	....
}

初始化

通过cas与sizeCtl 变量的相互配合,来保证初始化时的线程安全

/**
 * Table initialization and resizing control.  When negative, the
 * table is being initialized or resized: -1 for initialization,
 * else -(1 + the number of active resizing threads).  Otherwise,
 * when table is null, holds the initial table size to use upon
 * creation, or 0 for default. After initialization, holds the
 * next element count value upon which to resize the table.
 */
 private transient volatile int sizeCtl;
/**
 * Initializes table, using the size recorded in sizeCtl.
 */
private final Node<K,V>[] initTable() {
    Node<K,V>[] tab; int sc;
    while ((tab = table) == null || tab.length == 0) {
        // sizeCtl小于0,这意味着已经有其他线程进行初始化了
        // 所以当前线程让出CPU时间片
        if ((sc = sizeCtl) < 0)
            Thread.yield(); // lost initialization race; just spin
        // 否则,通过CAS操作尝试修改sizeCtl
        else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
        	
            try {
                if ((tab = table) == null || tab.length == 0) {
                    // 默认构造函数,sizeCtl = 0,使用默认容量(16)进行初始化
                    // 否则,会根据sizeCtl进行初始化
                    int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
                    @SuppressWarnings("unchecked")
                    Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
                    table = tab = nt;
                    // 计算阈值,n的75%
                    sc = n - (n >>> 2);
                }
            } finally {
                // 阈值赋给sizeCtl
                sizeCtl = sc;
            }
            break;
        }
    }
    return tab;
}

get

get方法并未加锁,由于volatile关键的修饰,获取到的值一定是最新值,不存在线程安全问题。

/**
 * The array of bins. Lazily initialized upon first insertion.
 * Size is always a power of two. Accessed directly by iterators.
 */
 transient volatile Node<K,V>[] table;

put

在put操作过程中涉及扩容与转树问题,当达到预设的变树阙值时,ConcurrentHashMap将由原先的散列链表结构变成散列红黑树结构
变树与扩容的过程中通过局部synchronized 来保证线程安全

 /**
  * Replaces all linked nodes in bin at given index unless table is
  * too small, in which case resizes instead.
  */
  //变树过程
  private final void treeifyBin(Node<K,V>[] tab, int index) {
      Node<K,V> b; int n, sc;
       if (tab != null) {
           if ((n = tab.length) < MIN_TREEIFY_CAPACITY)
               tryPresize(n << 1);
           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));
                   }
               }
           }
       }
   }

size

Java 8声明了一个volatile变量baseCount用于记录元素的个数,对这个变量的修改操作是基于CAS的,每当插入元素或删除元素时都会调用addCount()函数进行计数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值