前言:
而今同学们对“初始化数组为什么不能用n”大概比较关怀,姐妹们都想要剖析一些“初始化数组为什么不能用n”的相关文章。那么小编同时在网摘上搜集了一些对于“初始化数组为什么不能用n””的相关内容,希望大家能喜欢,小伙伴们一起来学习一下吧!1.initTable方法
ConcurrentHashMap在插入数据时,如果数组为空,则会先进行初始化操作
初始化调用initTable方法来完成,方法中使用了CAS机制和双层检查机制来解决线程安全问题
初始化的时候会判断sizeCtl的值,保证只能有一个线程执行初始化操作,其他的线程使用yield的方式来自旋等待
private final Node<K,V>[] initTable() { Node<K,V>[] tab; int sc; //创建tab并使用table赋值 //判断tab是否已经初始化,有的话直接跳过,返回tab即可 //tab没有初始化的话则需要则进入循环中进行初始化操作,直到tab初始化完成 while ((tab = table) == null || tab.length == 0) { //使用sizeCtl给sc赋值,在没有初始化的情况下sizeCtl默认为0,进入else里面,else里面需要将sc的值修改为小于0,防止其他线程进入 //其他线程如果sc小于0,则线程会进行让步,进入自旋状态 //只有第一个线程初始化成功后,则跳出循环 if ((sc = sizeCtl) < 0) Thread.yield(); //else选项,第一个线程进入是sc为0,进入该分支 //首先通过CAS对sc的值进行判断并尝试修改为-1,如果成功则进入分支 //如果有两个线程同时跑到此处,因为compareAndSetInt是原子性的,只能有一个线程修改成功 //修改失败的线程继续执行循环,第二次循环时sc已经置为-1了,线程进入自旋等待 else if (U.compareAndSetInt(this, SIZECTL, sc, -1)) { try { //双层检查机制,第一个线程进来初始化时正常执行 //初始化线程完成之后,退出该逻辑,在sc > 0的情况下,自旋线程可能会进入到此处 //进入后再次判断table是否已经初始化,此时初始化已经完成,跳过后面的逻辑 if ((tab = table) == null || tab.length == 0) { //获取初始容量,如果在构造方法中没有传入初始容量,则默认为DEFAULT_CAPACITY的值16 int n = (sc > 0) ? sc : DEFAULT_CAPACITY; //使用n创建Node数组 Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n]; //将创建的数组赋值为table table = tab = nt; //计算sc为容量的3/4 sc = n - (n >>> 2); } } finally { //将sc的值赋值给sizeCtl sizeCtl = sc; } break; } } return tab; }
版权声明:
本站文章均来自互联网搜集,如有侵犯您的权益,请联系我们删除,谢谢。
标签: #初始化数组为什么不能用n