您当前的位置:网站首页>斯德哥尔摩,解-中兴5G蓝图,以健康的产业生态推动商用成功

斯德哥尔摩,解-中兴5G蓝图,以健康的产业生态推动商用成功

2019-05-20 07:54:22 投稿作者:admin 围观人数:211 评论人数:0次
作者:HongJie
来历:https://javadoop.com流量君/post/hashmap

Java7中的 HashMap 和 ConcurrentHa沈阳市天气预报shMap 全解析

Java8 HashMap

Java8 对 HashMap 进行了一些修正,最大的不同便是利用了红黑树,所以五粮醇其由 数组+链表+红黑树 组成。

依据 Java7 HashMap 的介绍,咱们知道,查找的时分,依据 hash 值咱们能够快速定位到数组的详细下标,可是之后的话,需求顺着链表一个个比较下去才干找到咱们需求的,时刻杂乱度取决于链表的长度,为 O(n斯德哥尔摩,解-中兴5G蓝图,以健康的工业生态推进商用成功)

为了下降这部分的开支,在 Java8 中,当链表中的元素到达了 8 个时,会将链表转化为红黑树,在这些方位进行查找的时分能够下降时刻杂乱度为 O(logN)

来一张图简略暗示一下吧:

留意,上图是暗示图,首要是描绘结构,不会到达这个状况的,由于这么多数据的时分早就扩容了。

下面,咱们仍是用代码来介绍吧,个人感觉,Java8 的源模拟游戏码可读性要差一些,不过精简一些。

Java7 中运用 Entry 来代表每个 HashMap 中的数据节点,Java8 中运用 Node,根本没有差异,都是 key,value,hash 和 next 这四个特点,不过,Node 只能用于链表的状况,红黑树的状况需求运用 TreeNode

咱们依据数组元素中,第一个节点数据类型是 Node 仍是 TreeNode 来判别该方位下是链表仍是红黑树的。

put 进程剖析

和 Java7 略微有点不相同的当地便是,Java7 是先扩容后刺进新值的,Java8 先插值再扩容,不过这个不重要。

数组扩容

resize() 办法用于初始化数组数组扩容,每次扩容后,容量为本来的 2 倍,并进行数大乐透杀号据搬迁。

get 进程摩根剖析

相关于 put 来说,get 真的太简略了。

  1. 核算 key 的 hash 值,依据 h埃森哲ash 值找到对应数组下标: hash & (length-1)
  2. 判别数组该方位处的元素是否刚好便是咱们要找的,假如不是,走第三步
  3. 判别该元素类型是否是 TreeNode,假如是,用红黑树的办法取数据,假如不是,走第四步
  4. 遍历链谢表,直到找到持平(==或equals)的 key
public V get(Object key) {
Node e;
return (e = getNode(hash(key), key)) == null ? null : e.value;
}

Java8 ConcurrentHashMap

Java7 中完成的 ConcurrentHashMap 说实话仍是比较杂乱的,Java8 对 ConcurrentHashMap 进行了比较大的改动。主张读者能够参阅 Java8 中 HashMap 相关于 Java7 HashMap 的改动,关于 ConcurrentHashMap,Java8 也引入了红黑树。

说实话,Java8 ConcurrentHashMap 源码诚心不简略,最难的在于扩容,数据搬迁操作不简单看懂。

咱们先用一个暗示图来描绘下其结构:

结构上和 Java8 的 HashMap 根本上相同,不过它要确保线程安全性,所以在源码上的确要杂乱一些。

初始化

这个初始化办法有点意思,经过供给初始容量,核算了 sizeCtl,sizeCtl = 【 (1.5 * initialCapacity +谢梦媛英标发音全集 1),然后向上取最近的 2 的 n 次方】。如 initialCapacity 为 10,那么得到 sizeCtl 为 16,假如 initialCapacity 为 11,得到 sizeCtl 为 32。

sizeCt洗浴服务l 这个特点运用的场景许多,不过只需跟着文章的思路来,就不会被它搞晕了。

假如你爱折腾,也能够看下另一个有三个参数的结构办法,这儿我就不说了,大部分时分,咱们会运用无参结构函数进行实例化,我华为售后们也依照这个思路来进行源码剖析吧。

put 进程剖析

细心地一行一行代码看下去tour:

public V put(K key, V value) {
return putVal(key,租个女友回家春节 value, false);
}

put 的主流程看完了,可是至少留下了几个问题,第一个是初始化,第二个是扩容,第三个是协助数据搬迁,这些咱们都会在后边进行逐个介绍。

初始化数组:initTable

这个比较简略,首要便是初始化一个适宜巨细的数组,然后会设置 sizeCtl。

初始化办法中的并发问题是经过对 sizeCtl 进行一个 CAS 操作来操控的。

链表转红黑树: treeifyBin

前面咱们在 put 源码剖析也说过,treeifyBin 不必定就会进行红黑树转化,也或许是只是做数组扩容。咱们仍是进行源码剖析吧。

扩容:tryPresize

假如说 Java8 ConcurrentHashMap 的源码不简略,那么说的便是扩容操作和搬迁操作。

这个办法要完完全全看懂还需求看之后的 transfer 办法,读者应该提早知道这点。

这儿的扩容也是做翻倍扩容的,扩容后数组容量为本来的 2 倍。

这个办法的中心在于 sizeCtl 值的操作,首要将其设置为一个负数,然后履行 transfer(tab, null),再下一黄维德个循环将 sizeCtl 加 1,并履行 transfer(tab, nt),之后或许是持续 sizeCtl 加 1,并履行 transfer(tab, nt)。

所以,或许的操作便是履行 1 次 transfer(tab, null) + 屡次 transfer(tab, nt),这儿怎样完毕循环的需求看完 transfer 源码才清楚。

数据搬迁:transfer

下面这个办法很点长,将本来的 tab 数组的元素搬迁到新的 nextTab 数组中。

尽管咱们之前说的 tryPresize 办法中屡次调用 transfer 不触及多线程,可是这个 transfer 办法能够在其他当地被调用,典型地,咱们之前在说 put 办法的时分就说过了,请往上看 put 办法,是不是有个当地调用了 helpTransfer 办法,helpTransfer 办法会调用 transfer 办法的。

此办法支撑多线程履行,外围调用此by办法的时分,会确保第一个建议数据搬迁的线程,nextTab杨树鹏 参数为 null,之后再调用此办法的时分,nextTab 不会为 null。

阅览源码之前,先要了解并发操作的机制。原数组长度为 n,所以咱们有 n 个搬迁使命,让每个线程每次担任一个小使命是最简略的,每做完一个使命再检测是否有其他没做完的使命,协助搬迁就能够了,而 Doug Lea 运用了一个 stride,简略了解便是步长,每个线程每次担任搬迁其间的一部分,如每次搬迁 16 个斯德哥尔摩,解-中兴5G蓝图,以健康的工业生态推进商用成功小使命。所以,咱们就需求一个大局的调度者来组织哪个线程履行哪几个使命,这个便是特点 transferIndex 的效果。

第一个建议数据搬迁的线程会将 transferIndex 指向原数组最终的方位,然后从后往前的 stride 个使命归于第一个线程,然后将 transferIndex 指向新的方位,再往前的 stride 个使命归于第二个线程,依此类推。当然,这儿说的第二个线程不是真的必定指代了第二个线程,也能够是同一个线程,这个读者应该能了解吧。其斯德哥尔摩,解-中兴5G蓝图,以健康的工业生态推进商用成功实便是将爱之奇观一个大的搬迁使命分为了一个个使命包。

说到底,斯德哥尔摩,解-中兴5G蓝图,以健康的工业生态推进商用成功transfer 这个办法并没有完成一切的搬迁使命,每次调用这个办法只完成了 transferIndex 往前 stride 个方位的搬迁作业,其他的需求由外围来操控。

这个时分,再回去细心看 tryPresize 办法或许就会愈加明晰一些了。

get 进程剖析

get 办法历来都是最简略的,这儿也不破例:

  1. 核算 hash 值
  2. 依据 hash 值找到数组对应方位: (n - 1) & h
  3. 依据该方位处结点性质进行相应查找
  • 假如该方位为 null,那么直接回来 null斯德哥尔摩,解-中兴5G蓝图,以健康的工业生态推进商用成功 就能够了
  • 假如该方位处的节点刚好便是咱们需求的,回来该节点的值即可
  • 假如该方位节点的 hash 值小于 0,阐明正在扩容,或者是红黑树,后边咱们再介绍 find 办法
  • 假如以上 3 条都不满意,那便是链表,进行遍历比对即可

简略说一句,此办法的大部分内容都很简略,只要正好碰到扩容的状况,ForwardingNode.find(int h, Object k) 略微杂乱一斯德哥尔摩,解-中兴5G蓝图,以健康的工业生态推进商用成功些,不过在了解了数据搬迁的进程后,这个也就不难了,所以限于篇幅这儿也不打开说了。

总结

其实也不是很难嘛,尽管没有像之前的 AQS 和线程池相同一行一行源码进行剖析,但仍是把一切初学者或许会模糊的当地都进行了深化的介绍,只需是略微有点根底的读者,应该是很简单就能看懂 HashMap 和 ConcurrentHashMap 源码了。

看源码不算是意图吧,深化地了解 Doug 斯德哥尔摩,解-中兴5G蓝图,以健康的工业生态推进商用成功Lea 的规划思路,我觉得还挺风趣的,大师便是大师,代码写得真的是好啊。

我发现许多人都认为我写博客首要是源码剖析,说真的,我关于源码剖析没有那么大热心,首要都是为了用源码说事算了,或许之后的文章仍是会有比较河池多的源码剖析成分,我们该怎样看就怎样看吧。

不要脸地自认为本文的质量仍是挺高的,信息量比较大,假如你觉得有写得欠好的当地,或者说看完本文你仍是没看懂它们,那么请提出来~

Java7中的 HashMap 和 沦为ConcurrentHashMap 全解析

the end
中兴5G蓝图,以健康的产业生态推动商用成功