资讯专栏INFORMATION COLUMN

ConcurrentHashMap中tabAt、setTabAt方法的意义所在

GeekGhc / 3270人阅读

摘要:总结中针对数组的访问和赋值的意义应该是在于越过对数组操作的包装,进而达到优化性能的目的。以上为抛砖引玉。。参考链接知乎请问数组的行为是如何实现的

在学习ConcurrentHashMap时发现,源码中对table数组的元素进行操作时,使用了三个封装好的原子操作方法,如下:

/* ---------------- Table element access -------------- */

/*
 * Atomic access methods are used for table elements as well as
 * elements of in-progress next table while resizing.  All uses of
 * the tab arguments must be null checked by callers.  All callers
 * also paranoically precheck that tab"s length is not zero (or an
 * equivalent check), thus ensuring that any index argument taking
 * the form of a hash value anded with (length - 1) is a valid
 * index.  Note that, to be correct wrt arbitrary concurrency
 * errors by users, these checks must operate on local variables,
 * which accounts for some odd-looking inline assignments below.
 * Note that calls to setTabAt always occur within locked regions,
 * and so require only release ordering.
 */

@SuppressWarnings("unchecked")
static final  Node tabAt(Node[] tab, int i) {
    return (Node)U.getObjectAcquire(tab, ((long)i << ASHIFT) + ABASE);
}

static final  boolean casTabAt(Node[] tab, int i,
                                    Node c, Node v) {
    return U.compareAndSetObject(tab, ((long)i << ASHIFT) + ABASE, c, v);
}

static final  void setTabAt(Node[] tab, int i, Node v) {
    U.putObjectRelease(tab, ((long)i << ASHIFT) + ABASE, v);
}

casTabAt这个方法我们可以很清晰地明白它封装了对于数组元素的cas操作,但是另外两个方法的意义如何理解呢?

源码的作者使用Unsafe直接通过数组内存地址以及索引偏移量去访问和修改数组元素的值,和我们直接使用java代码访问(arr[i])、赋值(arr[i] = x )有什么区别呢?

请教了成哥(同事)后得到了一个重要的点:数组越界异常ArrayIndexOutOfBoundsException

如果java中的数组和c一样,仅仅是一个指针的话,那么也许通过arr[i]访问和通过内存地址访问不会有什么区别,但是由于ArrayIndexOutOfBoundsException这个众所周知的异常,我们可以推断:java中的数组是经过了包装的
另一个可以从侧面印证的点是arr.length

大概搜索了一下了解到以下的知识(不保证正确):

jvm会为数组对象动态创建Class类文件,其标识为[

(HotSpot VM中)java对象的对象头(Object header)内会有一段用于记录数组长度的数据

不敢再深挖了,感觉是个大坑。。

总结ConcurrentHashMap中针对table数组的Unsafe访问和赋值的意义应该是在于越过jvm对数组操作的包装,进而达到优化性能的目的。

以上为抛砖引玉。。

参考链接:
知乎-请问Java数组的length行为是如何实现的?

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/74339.html

相关文章

  • [学习笔记-Java集合-8] Map - ConcurrentHashMap 源码分析(二)

    摘要:那么,如果之后不是简单的操作,而是还有其它业务操作,之后才是,比如下面这样,这该怎么办呢其它业务操作这时候就没办法使用提供的方法了,只能业务自己来保证线程安全了,比如下面这样其它业务操作这样虽然不太友好,但是最起码能保证业务逻辑是正确的。 删除元素 删除元素跟添加元素一样,都是先找到元素所在的桶,然后采用分段锁的思想锁住整个桶,再进行操作。 public V remove(Objec...

    2501207950 评论0 收藏0
  • Kill_Java -- ConcurrentHashMap源码分析

    摘要:原因是它支持多线程进行扩容操作,而并没有加锁。多线程的情况下如果一个或多个线程正在对进行扩容操作,当前线程也要进入扩容的操作中。 KillCode系列 -- Java篇 原文发布在我的个人博客中killCode 因为JDK1.8 与 1.7 里对ConcurrentHashMap 有很多不同的更改以提高性能。所以特别找出类似的方面,进行分析。 1. 内部参数 //初始容积为 16 p...

    Karrdy 评论0 收藏0
  • Java多线程进阶(二四)—— J.U.C之collections框架:ConcurrentHash

    摘要:一扩容的基本思路中,最复杂的部分就是扩容数据迁移,涉及多线程的合作和。单线程注意这两种情况都是调用了方法,通过第二个入参进行区分表示扩容后的新数组,如果为,表示首次发起扩容。第二种情况下,是通过和移位运算来保证仅有一个线程能发起扩容。 showImg(https://segmentfault.com/img/bVbf0J0?w=1000&h=663); 本文首发于一世流云专栏:http...

    nidaye 评论0 收藏0
  • JDK源码那些事儿之并发ConcurrentHashMap下篇

    摘要:上一篇文章已经就进行了部分说明,介绍了其中涉及的常量和变量的含义,有些部分需要结合方法源码来理解,今天这篇文章就继续讲解并发前言本文主要介绍中的一些重要方法,结合上篇文章中的讲解部分进行更进一步的介绍回顾下上篇文章,我们应该已经知道的整体结 上一篇文章已经就ConcurrentHashMap进行了部分说明,介绍了其中涉及的常量和变量的含义,有些部分需要结合方法源码来理解,今天这篇文章就...

    Zack 评论0 收藏0
  • 趣谈ConcurrentHashMap

    摘要:最近准备面试,一谈到基础,大部分面试官上来就数据结构素质三连与区别,底层数据结构,为什么能保证线程安全。数组顺序存储,内存连续,查询快,插入删除效率稍微低,不过现在略有改善。而在开始,是由和的方式去实现高并发下的线程安全。 最近准备面试,一谈到java基础,大部分面试官上来就java数据结构素质三连:ArrayList与LinkedList区别,HashMap底层数据结构,Concur...

    Travis 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<