簡體   English   中英

Java中的Atomic Integer和Normal immutable Integer類有什么區別?

[英]What is the difference between Atomic Integer and Normal immutable Integer class in Java?

由於 Integer 類也是不可變類,我們知道不可變類是線程安全的,這是 Atomic Integer 的需要。 我很困惑 。 是不是不可變對象的讀寫不需要是原子的,而原子整數的讀寫是原子的。 這意味着原子類也是線程安全的。

當您需要確保只有一個線程可以更新 int 變量時,AtomicInteger 用於多線程環境。 優點是不需要外部同步,因為修改它的值的操作是以線程安全的方式執行的。

考慮以下代碼:

private int count;

public int updateCounter() {
   return ++count;
}

如果多個線程調用 updateCounter 方法,它們中的一些可能會收到相同的值。 ++count 操作不是原子操作的原因不僅僅是一個操作,而是由三個操作組成: read count, add 1 to it's value and write it back to it 多個調用線程可以看到該變量未修改為其最新值。

上面的代碼應該替換為:

private AtomicInteger count = new AtomicInteger(0);
public int updateCounter() {
    return count.incrementAndGet();
}

incrementAndGet方法保證自動遞增存儲的值並返回它的值,而不使用任何外部同步。

如果你的值永遠不會改變,你不必使用 AtomicInteger,使用 int 就足夠了。

AtomicInteger 是線程安全的(事實上,java.util.concurrent.atomic 包中的所有類都是線程安全的),而普通整數不是線程安全的。

當您在多線程環境中使用“整數”變量(以使其線程安全)時,您將需要“同步”和“易失性”關鍵字,而對於原子整數,您不需要“同步”和“易失性”作為原子整數的關鍵字負責線程安全。

另外,我會推薦以下關於同一主題的有用教程:http: //tutorials.jenkov.com/java-concurrency/compare-and-swap.html

有關“原子”包的更多信息,請參閱下面的 oracle 文檔: https ://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/package-summary.html

雖然根據定義,不可變對象是線程安全的,但可變對象也可以是線程安全的。

這正是Atomic...類( AtomicIntegerAtomicBoolean等)的目的。

各種...get......set...方法允許對象的線程安全訪問和變異。

毫不奇怪,該類是在java.util.concurrent包中聲明的。

您只需瀏覽java.util.concurrent.atomic包的API

一個小的類工具包,支持對單個變量進行無鎖線程安全編程。

考慮一個變量

int myInt = 3;

AtomicIntegermyInt

Integer3相關。

換句話說,你的變量是可變的並且可以改變它的值。 而值 3 是一個整數文字,一個常量,一個不可變的表達式。

整數是文字的對象表示,因此是不可變的,您基本上只能讀取它們。

AtomicIntegers 是這些值的容器。 您可以閱讀和設置它們。 與為變量賦值相同。 但與更改int變量的值不同,對AtomicInteger的操作是原子的。

例如,這不是原子的

if(myInt == 3) {
   myInt++; 
}

這是原子的

AtomicInteger myInt = new AtomicInteger(3);

//atomic
myInt.compareAndSet(3, 4);

我認為 AtomicInteger 和普通不可變 Integer 之間的主要區別將會顯現出來,一旦我們了解為什么即使是不可變 Integer 也不是線程安全的。

讓我們看一個例子。

假設,我們有一個int count = 5的值,它被兩個名為T1T2的不同線程共享,同時讀取和寫入。

我們知道,如果有任何值被重新分配給不可變對象,舊對象將保留在池中,而新對象將接管。

現在,當 T1 和 T2 將它們的值更新為 count 變量時,Java 可能會將這個值放入某個緩存中並在那里進行設置操作,我們不知道 JVM 何時會將更新后的值寫入主內存,所以可能會有其中一個線程可能會將值更新為完全過時的值。

這將我們帶到了volatile關鍵字。

Volatile - 這個關鍵字確保對任何變量的所有 I/O 操作都將在主內存上進行,以便所有線程都使用最新的值。

考慮一下,如果 1 個線程正在寫入,而其他所有線程都在讀取,那么 volatile 將解決我們的問題,但如果所有線程同時在同一個變量上讀寫,那么我們需要同步以確保線程安全。

volatile 關鍵字不能確保線程安全。

現在,為什么要使用 AtomicIntegers。 即使使用syncrhonized關鍵字來保證線程安全,count變量的實際更新操作也將是一個三步過程。

  1. 獲取計數變量的更新值
  2. 將值增加 1
  3. 將值設置為計數變量

這就是為什么一旦考慮到線程安全,更新普通整數的任何值以更新值需要稍長的時間。

**AtomicIntegers 通過一種稱為 Compare-And-Swap(CAS 方法)的優化無鎖算法進一步解決了線程安全和更快更新的問題。

它們以單步過程原子方式執行所有更新操作。 **

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM