原創
1 背景
在學習并發的時候看到了ConcurrentLinkedQueue隊列的源碼,剛開始的時候是看網上的帖子,然后就到IDE里邊看源碼,發現offer()方法在1.7版的時候有過修改。
樓主的問題不是整個方法,而是其中的一截代碼“(t != (t = tail))”,有點發暈,t是個引用,而修改引用的時候不是都修改嗎?怎么還會判斷是否相等呢 ?
2 為了解決這個問題,寫個測試方法。如下:
publicclassReferTest {
publicstaticvoidmain(String[] args) {
ReferTest a =newReferTest();
booleanb= (a != (a =newReferTest()));
}
}
答案:b= true。
說明 a != a,這個就更暈了。在度娘和谷歌上都查不到什么有用的資料,關鍵是不好描述,引用不等于引用?
再往下樓主就猜測了,引用的東西一般都和棧有關,就想看看方法的字節碼指令。使用javap命令解釋了方法的字節碼指令。
有用的方法看main方法的指令,樓主沒有接觸過字節碼指令,所以找個指令集學學了一下。在這里解釋下指令的意義,在這里記錄一下。
注意引用1是在命令8的時候加載的a的值,而引用2是新的引用,為什么出現這種情況,原因是if_acmpeq指令是比較兩個棧頂的值是否一樣。
所以在"!="號的兩端的值需要加載到棧頂,而右邊是一個表達式,所以先加載左邊的值到棧頂然后再去執行右邊的表達式,表達式的結果放入棧頂,這個時候a引用1先加載,而表達式的結果會改變a變量的值,但是不會改變棧頂的值。
所以就出現不一致的情況了。
同理,通過這個方式可以判斷對應的引用是否改變了。
ps:跟同事講解的時候,又分析了 i=i++ 、 i=++i、i= i+1的字節碼,發現 i++ 使用的是iinc的命令,而i=i+1使用的是iadd指令。