在學習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
學習
大概搜索了一下了解到如下的知識(不保證正確):優化
[
不敢再深挖了,感受是個大坑。。ui
總結:ConcurrentHashMap
中針對table
數組的Unsafe
訪問和賦值的意義應該是在於越過jvm對數組操做的包裝,進而達到優化性能的目的。指針
以上爲拋磚引玉。。code
參考連接:
知乎-請問Java數組的length行爲是如何實現的?orm