完美世界面经准备

 Q:cas如果一直失败的解决方案:cas属于自旋锁,在1.6就引入了适应性自旋锁,(1.6是写死的  后面可以改变)通过比较自旋锁时间阈值(上一次该锁的自旋时间 还有当前状态所决定的)  来决定以下操作:超过阈值后 阻塞后续线程的。

Q:concurrenthashmap的实现:

在ConcurrentHashMap中通过一个Node<K,V>[]数组来保存添加到map中的键值对,而在同一个数组位置是通过链表和红黑树的形式来保存的。但是这个数组只有在第一次添加元素的时候才会初始化,否则只是初始化一个ConcurrentHashMap对象的话,只是设定了一个sizeCtl变量,这个变量用来判断对象的一些状态和是否需要扩容。

  第一次添加元素的时候,默认初期长度为16,当往map中继续添加元素的时候,通过hash值跟数组长度取与来决定放在数组的哪个位置,如果出现放在同一个位置的时候,优先以链表的形式存放,在同一个位置的个数又达到了8个以上,如果数组的长度还小于64的时候,则会扩容数组。如果数组的长度大于等于64了的话,在会将该节点的链表转换成树。

  通过扩容数组的方式来把这些节点给分散开。然后将这些元素复制到扩容后的新的数组中,同一个链表中的元素通过hash值和数组长度位来区分,是还是放在原来的位置还是放到扩容的长度的相同位置去 。在扩容完成之后,如果某个节点的是树,同时现在该节点的个数又小于等于6个了,则会将该树转为链表。

  取元素的时候,相对来说比较简单,通过计算hash来确定该元素在数组的哪个位置,然后在通过遍历链表或树来判断key和key的hash,取出value值。

       就是当数组某一个位置的节点个数大于8个,如果并且数组数目没有超过64的话就进行扩容,但是如果是超过64的话就进行红黑树的转换。扩容的时候一定要保证扩容后3/4.

       一般来说是通过Sizectl来判断当前hashmap的状态  阈值  大小是数组长度的3/4

sizectl = -1表示还没有初始化  sizectl = -(1+n)表示正在扩容

 

下面进行put方法的思考与分析:

  • 当添加一个键值对的时候,首先判断保存这些键值对的数组是否初始化了
  • 如果没有的话 进行初始化数组
  • 然后通过计算对象hash以及数组长度来计算出hash值,来确定放在数组哪一个位置
  • 如果这个位置为空则直接添加,如果不是空的话,则取出这个节点来
  • 如果取出的节点hash值是-1的话表示当前正在对这个数组进行扩容,将数据复制到新的数组,则当前线程前往帮助
  • 最后一种情况就是:啥都不是,通过synchronized来加锁,进行操作。
  • 然后判断当前节点是否为树还是链表  -2就是链表
  • 如果是链表则遍历整个链表,直到直到取出来的节点的key来个要放的key进行比较,如果key相等,并且key的hash值也相等的话,属于同一个键值对,可以进行覆盖,不然的话就加在尾部。
  • 如果是树的话 就调用函数puttreevalue方法添加到树中
  • 添加完成后 看是否需要转换为树。

下面就是对扩容的详细解释:treeifyBin  在put方法的详解中,我们可以看到,在同一个节点的个数超过8个的时候,会调用treeifyBin方法来看看是扩容还是转化为一棵树

  • 当数组长度小于64的时候,扩张数组长度一倍,否则的话把链表转为树
  • tryPresize
  •  一直扩容到的c小于等于sizeCtl或者数组长度大于最大长度的时候,则退出。
  • 在tryPresize方法中,并没有加锁,允许多个线程进入,如果数组正在扩张,则当前线程也去帮助扩容

下面就是对获取数据的详细解释:

* 相比put方法,get就很单纯了,支持并发操作,
     * 当key为null的时候回抛出NullPointerException的异常
     * get操作通过首先计算key的hash值来确定该元素放在数组的哪个位置
     * 然后遍历该位置的所有节点
     * 如果不存在的话返回null

 

扩展学习:首先学习一下CAS CAS全称是compareandswap 在原子包中经常使用CAS来实现原子操作。getandincresment

,cas底层是通过操作系统实现该功能 ,(cmpxchg查询当前处理器数量)从过添加前缀lock实现。

cas缺点:

  1. 循环时间开销很大:在执行底层函数getandaddint时候可以发现,循环等待执行的时候,会空转消耗cpu的资源。
  2. 只能操作一个共享变量,cas一次只能操作一个共享变量 对于多个共享变量组合的操作是无法使用cas的
  3. ABA问题 可以通过变量的版本号来区别    版本号可以写在同一内存中(前后   要后续处理)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值