本文概要
AtomicBoolean
類優點在于能夠確保布爾值在多線程環境下的原子性操作,避免了繁瑣的同步措施,它提供了高效的非阻塞算法實現,可以大大提成程序的并發性能,AtomicBoolean
的API設計非常簡單易用。
AtomicBoolean核心概念
AtomicBoolean
是java.util.concurrent.atomic
中的一個類,它提供了一個原子性的布爾值,這個布爾值的讀取和設置是線程安全的,不會發生線程間的沖突。
模擬一個業務場景來說明AtomicBoolean
的作用,假設,有一個電商平臺系統,其中一個功能是管理促銷活動的開啟和關閉狀態,促銷活動可能由多個線程或服務同時訪問和修改其狀態,比如一個線程可能負責定時檢查促銷活動的結束時間并在時間到達時關閉活動,而另一個線程可能負責實時接收運營人員的操作指令來手動開啟或關閉活動。
為了確保這兩個線程能夠正確地更新和讀取促銷活動的開啟狀態,而不發生數據不一致的情況,可以使用 AtomicBoolean
控制這個狀態:
- 當運營人員通過后臺界面開啟活動時,負責接收操作指令的線程會將
AtomicBoolean
設置為true
。 - 當促銷活動自然結束或運營人員手動關閉活動時,相應的線程會將
AtomicBoolean
設置為false
。 - 同時,其他任何需要讀取活動狀態的線程,如前端展示促銷活動的頁面,都可以安全地讀取這個
AtomicBoolean
的值,而不用擔心讀到的是一個正在被其他線程修改的中間狀態。
AtomicBoolean
類主要用來解決并發編程中的線程安全問題,特別是在需要對一個共享布爾變量進行原子性讀取和修改的場景中,它的內部使用了硬件級別的原子操作來保證對布爾值的讀取和設置是線程安全的,因此,在多線程環境中,當一個線程正在修改AtomicBoolean
的值時,其他線程無法同時修改它,必須等待當前線程的操作完成后才能繼續。
AtomicBoolean使用案例
下面是一個簡單的Java代碼示例,演示了如何使用AtomicBoolean
類,這實例將創建一個模擬的服務,使用一個AtomicBoolean
來控制其狀態(開啟或關閉),并通過多個線程來模擬客戶端的調用,如下代碼案例:
import java.util.concurrent.atomic.AtomicBoolean; // Service類使用AtomicBoolean來控制其狀態
public class AtomicService { private AtomicBoolean isRunning = new AtomicBoolean(false); // 開啟服務 public void startService() { isRunning.set(true); System.out.println("Service started."); } // 關閉服務 public void stopService() { isRunning.set(false); System.out.println("Service stopped."); } // 檢查服務是否正在運行 public boolean isServiceRunning() { return isRunning.get(); } // 客戶端調用服務的模擬方法 public void clientRequest() { if (isServiceRunning()) { System.out.println("Client request processed successfully as the service is running."); } else { System.out.println("Client request failed as the service is not running."); } }
} // 客戶端線程,模擬多個客戶端同時請求服務
class ClientThread extends Thread { private AtomicService service; public ClientThread(AtomicService service) { this.service = service; } @Override public void run() { service.clientRequest(); }
} // 主類,包含main方法,用于啟動示例
public class AtomicBooleanDemo { public static void main(String[] args) throws InterruptedException { AtomicService atomicService = new AtomicService(); // 開啟服務 atomicService.startService(); // 創建并啟動多個客戶端線程 Thread client1 = new ClientThread(atomicService); Thread client2 = new ClientThread(atomicService); client1.start(); client2.start(); client1.join(); // 等待線程執行完成 client2.join(); // 等待線程執行完成 // 關閉服務 atomicService.stopService(); // 再次嘗試通過客戶端線程請求服務,應該會失敗 Thread client3 = new ClientThread(atomicService); client3.start(); client3.join(); // 等待線程執行完成 }
}
上面代碼中,AtomicService
類使用一個AtomicBoolean
成員變量isRunning
來控制服務的狀態,startService
和stopService
方法分別用于開啟和關閉服務,它們通過調用AtomicBoolean
的set
方法來設置狀態,isServiceRunning
方法返回當前服務的運行狀態,它通過調用AtomicBoolean
的get
方法來獲取狀態。
ClientThread
類是一個線程類,它模擬客戶端請求服務的行為,在run
方法中,它調用服務的clientRequest
方法,該方法根據服務的運行狀態來處理請求。
AtomicBoolean核心API
AtomicBoolean
類是Java的java.util.concurrent.atomic
包中的一個原子類,用于對布爾值進行原子操作,以下是AtomicBoolean
類中主要方法的含義:
AtomicBoolean(boolean initialValue)
- 構造函數,用于創建一個具有給定初始值的
AtomicBoolean
實例。
- 構造函數,用于創建一個具有給定初始值的
boolean get()
- 獲取當前值,此方法以原子方式讀取
AtomicBoolean
實例的當前值,并返回它。
- 獲取當前值,此方法以原子方式讀取
void set(boolean newValue)
- 設置新值,此方法以原子方式設置
AtomicBoolean
實例的值。
- 設置新值,此方法以原子方式設置
boolean compareAndSet(boolean expect, boolean update)
- 如果當前值與預期值
expect
相等,則以原子方式將該值設置為update
,并返回true
;否則返回false
,這是一個條件原子更新操作,常用于實現無鎖算法或數據結構。
- 如果當前值與預期值
boolean getAndSet(boolean newValue)
- 以原子方式設置
AtomicBoolean
的值為newValue
,并返回舊值,這個方法可以用于實現一些需要知道舊值的同時更新為新值的場景。
- 以原子方式設置
boolean weakCompareAndSet(boolean expect, boolean update)
- 與
compareAndSet
方法類似,但允許更大的并發性,可能會失敗更多(即返回false
),即使在當前值與預期值相同的情況下也是如此,這個方法通常用于循環中,直到成功為止。不過,由于它可能“失敗更多”,因此它通常比compareAndSet
更快。
- 與
String toString()
- 返回
AtomicBoolean
實例的當前值的字符串表示形式("true"
或"false"
)。
- 返回
int hashCode()
- 返回該
AtomicBoolean
實例的哈希碼值。
- 返回該
boolean equals(Object obj)
- 檢查此
AtomicBoolean
實例與另一個對象是否相等。如果對象也是一個AtomicBoolean
實例,并且兩個實例的當前值相同,則返回true
;否則返回false
。
- 檢查此
AtomicBoolean技術原理
AtomicBoolean
是 java.util.concurrent.atomic
中的一個類,它提供了線程安全的方式來操作布爾值,它可以確保多個線程對同一個布爾值的操作是原子的,并且對這個布爾值的操作任何時候都只能由一個線程執行。
實現原理
AtomicBoolean
的實現基于硬件級別的原子操作,它使用Java的Unsafe
類來直接訪問內存,并執行底層的原子操作。
Unsafe
類提供了一些可以直接操作內存的低級方法,包括原子性的比較和交換(compare-and-swap,CAS)操作,CAS是一種無鎖算法,它包含三個操作數——內存位置(V)、預期原值(A)和新值(B),CAS會檢查內存位置V的值是否與預期原值A相等,如果是,則將該位置的值設置為新值B,這個過程是原子的,也就是說,在這個操作進行期間,不會有其他線程能夠改變內存位置V的值。
AtomicBoolean
的內部實現中,布爾值被存儲在一個volatile
修飾的字段中,以確保所有線程都能看到最新的值,volatile
關鍵字保證了內存可見性和禁止指令重排序。
底層算法
AtomicBoolean
類中的主要方法是 get()
, set()
, compareAndSet()
, getAndSet()
, lazySet()
, 和 weakCompareAndSet()
,這些核心方法都使用了底層的 CAS 操作來實現原子性,如下:
get()
方法,直接返回當前存儲的布爾值。set(boolean newValue)
方法,使用Unsafe
類的putOrderedObject()
方法來設置新的布爾值,雖然這個方法名看起來可能不是原子的,但實際上對于布爾值這種單個字段的寫入,它是原子的,不過,set()
操作本身并不保證其他線程的立即可見性,但在后續的讀取操作中,由于volatile
關鍵字的存在,會保證讀取到的是最新的值。compareAndSet(boolean expect, boolean update)
方法,這是一個典型的 CAS 操作,它首先檢查當前值是否與期望的值相等,如果是,則更新為新值,這個過程是原子的。getAndSet(boolean newValue)
方法,這個方法會設置新的值,并返回舊的值,它內部也是通過 CAS 操作來實現的。
雖然 AtomicBoolean
的實現基于 CAS,但它并不是鎖或者同步原語,它使用了一種稱為無鎖編程的技術,通過避免使用傳統的鎖機制來減少線程間的競爭和阻塞,從而提高并發性能。
小總結:AtomicBoolean
是通過底層硬件支持的原子操作和 Java 內存模型中的 volatile
關鍵字來實現線程安全的布爾值操作的,通過它,可以用來實現各種無鎖的數據結構和算法。
核心代碼實現
public class AtomicBoolean implements java.io.Serializable {private static final long serialVersionUID = 6214790243416807050L;// 使用volatile修飾符確保可見性和有序性private volatile int value;// 將value轉換為布爾值private static final boolean BOOLEAN_TRUE = true;private static final int INT_TRUE = 1;// 構造函數public AtomicBoolean(boolean initialValue) {value = initialValue ? 1 : 0;}// 默認構造函數,默認值為falsepublic AtomicBoolean() {this(false);}// 原子性的設置值public final boolean getAndSet(boolean newValue) {return unsafe.getAndSetInt(this, valueOffset, newValue ? 1 : 0);}// 原子性的比較并交換public final boolean compareAndSet(boolean expect, boolean update) {return unsafe.compareAndSwapInt(this, valueOffset, expect ? 1 : 0, update ? 1 : 0);}// 獲取當前值public final boolean get() {return value != 0;}// Unsafe類的操作private static final sun.misc.Unsafe unsafe =sun.misc.Unsafe.getUnsafe();private static final long valueOffset;static {try {valueOffset = unsafe.objectFieldOffset(AtomicBoolean.class.getDeclaredField("value"));} catch (Exception ex) { throw new Error(ex); }}
}
從上述代碼可以看出:
value
變量使用了volatile
關鍵字,保證了多線程環境下的內存可見性和禁止指令重排序。- 提供了如
compareAndSet()
、getAndSet()
等原子操作方法,這些方法底層通過Unsafe
類提供的CAS
操作實現,能在硬件層面保證操作的原子性,即在同一時間只有一個線程能修改value值,不會出現競態條件。 - Boolean值被轉換為int值進行存儲和操作,這是因為JVM無法直接對boolean類型進行CAS操作,而對int類型可以。
自我總結
AtomicBoolean
類的優點在于原子性操作,可確保在多線程環境中對布爾值的讀取和設置不會產生競態條件,同時,它的性能通常優于使用synchronized
的代碼,因為它避免了線程阻塞和上下文切換的開銷。同時,AtomicBoolean
還提供了豐富的API,如compareAndSet
和getAndSet
等。但是,雖然AtomicBoolean
提供了原子性保證,但它卻無法解決并發中的可見性和有序性問題,這里需要特別注意。
END!
END!
END!
往期回顧
精品文章
Java并發基礎:concurrent Flow API全面解析
Java并發基礎:CopyOnWriteArraySet全面解析
Java并發基礎:ConcurrentSkipListMap全面解析
Java并發基礎:ConcurrentSkipListSet全面解析!
Java并發基礎:SynchronousQueue全面解析!