[英]What does "atomic" mean in programming?
在有效的 Java 書中,它指出:
語言規范保證讀取或寫入變量是原子的,除非變量的類型為
long
或double
[JLS, 17.4.7]。
在 Java 編程或一般編程的上下文中,“原子”是什么意思?
這是一個例子:假設foo
是一個long
類型的變量,那么以下操作不是原子操作(在 Java 中):
foo = 65465498L;
實際上,變量是使用兩個單獨的操作寫入的:一個是寫入前 32 位,第二個是寫入后 32 位。 這意味着另一個線程可能會讀取foo
的值,並查看中間狀態。
使操作原子化包括使用同步機制以確保操作從任何其他線程被視為單個原子(即不可拆分成部分)操作。 這意味着任何其他線程,一旦操作成為原子,要么在賦值之前,要么在賦值之后看到foo
的值。 但絕不是中間值。
一個簡單的方法是使變量 volatile :
private volatile long foo;
或者同步對變量的每次訪問:
public synchronized void setFoo(long value) {
this.foo = value;
}
public synchronized long getFoo() {
return this.foo;
}
// no other use of foo outside of these two methods, unless also synchronized
或者用AtomicLong
替換它:
private AtomicLong foo;
“原子操作”是指從所有其他線程的角度來看似乎是瞬時的操作。 當保證適用時,您無需擔心部分完成的操作。
它是“在系統的其余部分看來是立即發生的”,並且屬於計算過程中的線性化分類。 進一步引用該鏈接文章:
原子性是與並發進程隔離的保證。 此外,原子操作通常有一個成功或失敗的定義——它們要么成功地改變系統的狀態,要么沒有明顯的影響。
因此,例如,在數據庫系統的上下文中,可以有“原子提交”,這意味着您可以將更新的變更集推送到關系數據庫,這些變更要么全部提交,要么根本不提交發生故障時,這樣數據不會損壞,並且鎖和/或隊列的后果,下一個操作將是不同的寫入或讀取,但僅在事后。 在變量和線程的上下文中,這與應用於內存的情況大致相同。
你的報價亮點:這並不需要指望在所有情況下的行為。
剛剛發現一篇Atomic vs. Non-Atomic Operations對我很有幫助。
“如果一個操作相對於其他線程在單個步驟中完成,那么作用於共享內存的操作就是原子的。
當在共享內存上執行原子存儲時,沒有其他線程可以觀察到修改半完成。
當對共享變量執行原子加載時,它會讀取單個時刻出現的整個值。”
如果您有多個線程執行以下代碼中的 m1 和 m2 方法:
class SomeClass {
private int i = 0;
public void m1() { i = 5; }
public int m2() { return i; }
}
您可以保證任何調用m2
線程都將讀取 0 或 5。
另一方面,使用此代碼(其中i
很長):
class SomeClass {
private long i = 0;
public void m1() { i = 1234567890L; }
public long m2() { return i; }
}
調用m2
的線程可以讀取 0、1234567890L 或其他一些隨機值,因為語句i = 1234567890L
不能保證long
是原子的(JVM 可以在兩個操作和一個線程中寫入前 32 位和后 32 位)可能會觀察到i
介於兩者之間)。
在Java中,除long和double之外的所有類型的字段讀寫都是原子發生的,如果字段是用volatile修飾符聲明的,那么long和double也是原子讀寫的。 也就是說,我們 100% 得到了那里發生了什么,或者那里發生了什么,變量中也不可能有任何中間結果。
簡單來說,原子意味着操作要么完成,要么不完成。 其他線程或 CPU 不會在操作中間捕獲它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.