3 回答

TA貢獻2041條經(jīng)驗 獲得超4個贊
i++
在Java中可能不是原子的,因為原子性是一個特殊的要求,在大多數(shù)用途中都不存在i++
。該要求具有顯著的開銷:使增量操作成為原子的成本很高; 它涉及在普通增量中不需要存在的軟件和硬件級別的同步。
您可以將i++
應(yīng)該設(shè)計和記錄的參數(shù)設(shè)置為專門執(zhí)行原子增量,以便使用執(zhí)行非原子增量i = i + 1
。但是,這會破壞Java,C和C ++之間的“文化兼容性”。同樣,它會刪除一個方便的符號,熟悉類C語言的程序員認(rèn)為這是理所當(dāng)然的,賦予它一個特殊的含義,僅適用于有限的情況。
基本的C或C ++代碼就像for (i = 0; i < LIMIT; i++)
轉(zhuǎn)換為Java一樣for (i = 0; i < LIMIT; i = i + 1)
; 因為使用原子是不合適的i++
。更糟糕的是,程序員從C語言或其他類C語言到Java都會使用i++
,導(dǎo)致不必要地使用原子指令。
即使在機器指令集級別,由于性能原因,增量類型操作通常也不是原子的。在x86中,必須使用特殊指令“l(fā)ock prefix”來使inc
指令成為原子:出于與上述相同的原因。如果inc
總是原子的,那么當(dāng)需要非原子公司時,它永遠不會被使用; 程序員和編譯器會生成加載,添加1和存儲的代碼,因為它會更快。
在一些指令集架構(gòu)中,沒有原子inc
或根本沒有inc
; 要在MIPS上執(zhí)行原子公司,你必須編寫一個使用ll
and sc
:load-linked和store-conditional 的軟件循環(huán)。加載鏈接讀取單詞,如果單詞未更改,則store-conditional存儲新值,否則失?。z測到并導(dǎo)致重新嘗試)。

TA貢獻1811條經(jīng)驗 獲得超5個贊
i++ 涉及兩個操作:
讀取當(dāng)前值 i
遞增值并將其分配給 i
當(dāng)兩個線程i++同時對同一個變量執(zhí)行時,它們可能都獲得相同的當(dāng)前值i,然后遞增并設(shè)置為i+1,因此您將獲得單個增量而不是兩個。
示例:
int i = 5;
Thread 1 : i++;
// reads value 5
Thread 2 : i++;
// reads value 5
Thread 1 : // increments i to 6
Thread 2 : // increments i to 6
// i == 6 instead of 7

TA貢獻1799條經(jīng)驗 獲得超8個贊
為什么i ++在Java中不是原子的?
讓我們將增量操作分解為多個語句:
線程1和2:
從內(nèi)存中獲取總值
將1添加到值
寫回內(nèi)存
如果沒有同步,那么讓我們說線程1讀取值3并將其增加到4,但是沒有寫回來。此時,發(fā)生上下文切換。線程2讀取值3,遞增它并發(fā)生上下文切換。雖然兩個線程都增加了總值,但仍然是4 - 競爭條件
添加回答
舉報