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

在學習ConcurrentHashMap時發現,源碼中對table數組的元素進行操做時,使用了三個封裝好的原子操做方法,以下:java

/* ---------------- 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 <K,V> Node<K,V> tabAt(Node<K,V>[] tab, int i) {
    return (Node<K,V>)U.getObjectAcquire(tab, ((long)i << ASHIFT) + ABASE);
}

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

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

casTabAt這個方法咱們能夠很清晰地明白它封裝了對於數組元素的cas操做,可是另外兩個方法的意義如何理解呢?數組

源碼的做者使用Unsafe直接經過數組內存地址以及索引偏移量去訪問和修改數組元素的值,和咱們直接使用java代碼訪問(arr[i])、賦值(arr[i] = x )有什麼區別呢?jvm

請教了成哥(同事)後獲得了一個重要的點:數組越界異常ArrayIndexOutOfBoundsException性能

若是java中的數組和c同樣,僅僅是一個指針的話,那麼也許經過arr[i]訪問和經過內存地址訪問不會有什麼區別,可是因爲ArrayIndexOutOfBoundsException這個衆所周知的異常,咱們能夠推斷:java中的數組是通過了包裝的
另外一個能夠從側面印證的點是arr.length學習

大概搜索了一下了解到如下的知識(不保證正確):優化

  • jvm會爲數組對象動態建立Class類文件,其標識爲[
  • (HotSpot VM中)java對象的對象頭(Object header)內會有一段用於記錄數組長度的數據

不敢再深挖了,感受是個大坑。。ui

總結ConcurrentHashMap中針對table數組的Unsafe訪問和賦值的意義應該是在於越過jvm對數組操做的包裝,進而達到優化性能的目的。指針

以上爲拋磚引玉。。code

參考連接:
知乎-請問Java數組的length行爲是如何實現的?orm

相關文章
相關標籤/搜索