Java并發基礎:原子類之AtomicBoolean全面解析

Java并發基礎:原子類之AtomicBoolean全面解析 - 程序員古德

本文概要

AtomicBoolean類優點在于能夠確保布爾值在多線程環境下的原子性操作,避免了繁瑣的同步措施,它提供了高效的非阻塞算法實現,可以大大提成程序的并發性能,AtomicBoolean的API設計非常簡單易用。

AtomicBoolean核心概念

AtomicBooleanjava.util.concurrent.atomic中的一個類,它提供了一個原子性的布爾值,這個布爾值的讀取和設置是線程安全的,不會發生線程間的沖突。

模擬一個業務場景來說明AtomicBoolean的作用,假設,有一個電商平臺系統,其中一個功能是管理促銷活動的開啟和關閉狀態,促銷活動可能由多個線程或服務同時訪問和修改其狀態,比如一個線程可能負責定時檢查促銷活動的結束時間并在時間到達時關閉活動,而另一個線程可能負責實時接收運營人員的操作指令來手動開啟或關閉活動。

為了確保這兩個線程能夠正確地更新和讀取促銷活動的開啟狀態,而不發生數據不一致的情況,可以使用 AtomicBoolean 控制這個狀態:

  1. 當運營人員通過后臺界面開啟活動時,負責接收操作指令的線程會將 AtomicBoolean 設置為 true
  2. 當促銷活動自然結束或運營人員手動關閉活動時,相應的線程會將 AtomicBoolean 設置為 false
  3. 同時,其他任何需要讀取活動狀態的線程,如前端展示促銷活動的頁面,都可以安全地讀取這個 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來控制服務的狀態,startServicestopService方法分別用于開啟和關閉服務,它們通過調用AtomicBooleanset方法來設置狀態,isServiceRunning方法返回當前服務的運行狀態,它通過調用AtomicBooleanget方法來獲取狀態。

ClientThread類是一個線程類,它模擬客戶端請求服務的行為,在run方法中,它調用服務的clientRequest方法,該方法根據服務的運行狀態來處理請求。

AtomicBoolean核心API

AtomicBoolean類是Java的java.util.concurrent.atomic包中的一個原子類,用于對布爾值進行原子操作,以下是AtomicBoolean類中主要方法的含義:

  1. AtomicBoolean(boolean initialValue)
    • 構造函數,用于創建一個具有給定初始值的AtomicBoolean實例。
  2. boolean get()
    • 獲取當前值,此方法以原子方式讀取AtomicBoolean實例的當前值,并返回它。
  3. void set(boolean newValue)
    • 設置新值,此方法以原子方式設置AtomicBoolean實例的值。
  4. boolean compareAndSet(boolean expect, boolean update)
    • 如果當前值與預期值expect相等,則以原子方式將該值設置為update,并返回true;否則返回false,這是一個條件原子更新操作,常用于實現無鎖算法或數據結構。
  5. boolean getAndSet(boolean newValue)
    • 以原子方式設置AtomicBoolean的值為newValue,并返回舊值,這個方法可以用于實現一些需要知道舊值的同時更新為新值的場景。
  6. boolean weakCompareAndSet(boolean expect, boolean update)
    • compareAndSet方法類似,但允許更大的并發性,可能會失敗更多(即返回false),即使在當前值與預期值相同的情況下也是如此,這個方法通常用于循環中,直到成功為止。不過,由于它可能“失敗更多”,因此它通常比compareAndSet更快。
  7. String toString()
    • 返回AtomicBoolean實例的當前值的字符串表示形式("true""false")。
  8. int hashCode()
    • 返回該AtomicBoolean實例的哈希碼值。
  9. boolean equals(Object obj)
    • 檢查此AtomicBoolean實例與另一個對象是否相等。如果對象也是一個AtomicBoolean實例,并且兩個實例的當前值相同,則返回true;否則返回false

AtomicBoolean技術原理

AtomicBooleanjava.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); }}
}

從上述代碼可以看出:

  1. value變量使用了volatile關鍵字,保證了多線程環境下的內存可見性和禁止指令重排序。
  2. 提供了如compareAndSet()getAndSet()等原子操作方法,這些方法底層通過Unsafe類提供的CAS操作實現,能在硬件層面保證操作的原子性,即在同一時間只有一個線程能修改value值,不會出現競態條件
  3. Boolean值被轉換為int值進行存儲和操作,這是因為JVM無法直接對boolean類型進行CAS操作,而對int類型可以。

自我總結

Java并發基礎:原子類之AtomicBoolean全面解析 - 程序員古德

AtomicBoolean類的優點在于原子性操作,可確保在多線程環境中對布爾值的讀取和設置不會產生競態條件,同時,它的性能通常優于使用synchronized的代碼,因為它避免了線程阻塞和上下文切換的開銷。同時,AtomicBoolean還提供了豐富的API,如compareAndSetgetAndSet等。但是,雖然AtomicBoolean提供了原子性保證但它卻無法解決并發中的可見性和有序性問題,這里需要特別注意。

關注我,每天學習互聯網編程技術 - 程序員古德

END!
END!
END!

往期回顧

精品文章

Java并發基礎:concurrent Flow API全面解析

Java并發基礎:CopyOnWriteArraySet全面解析

Java并發基礎:ConcurrentSkipListMap全面解析

Java并發基礎:ConcurrentSkipListSet全面解析!

Java并發基礎:SynchronousQueue全面解析!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/696155.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/696155.shtml
英文地址,請注明出處:http://en.pswp.cn/news/696155.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

P1024 [NOIP2001 提高組] 一元三次方程求解

P1024 [NOIP2001 提高組] 一元三次方程求解 純代碼記錄 #include <iostream> #include <math.h> using namespace std; double a,b,c,d; double res[3];//用于存放三個解 int resCount;inline double F(double x)//三次函數 {return a*pow(x,3)b*pow(x,2)c*xd; }//…

web前端開發this指向問題

? 函數內部中的 this 指向誰&#xff0c;不是在函數定義時決定的&#xff0c;而是在函數第一次調用并執行的時候決定的 1. call 方法 語法&#xff1a;函數名.call(調用者, 參數1, …) 作用&#xff1a;函數被借用時&#xff0c;會立即執行&#xff0c;并且函數體內的this會…

Facebook Horizon:探索虛擬現實中的社交空間

隨著科技的不斷進步&#xff0c;虛擬現實&#xff08;VR&#xff09;技術正成為社交互動和娛樂體驗的新前沿。在這個數字時代&#xff0c;Facebook作為全球最大的社交媒體平臺之一&#xff0c;正在引領虛擬社交的新時代&#xff0c;其推出的虛擬社交平臺Facebook Horizon成為了…

Tomcat線程池原理(下篇:工作原理)

文章目錄 前言正文一、執行線程的基本流程1.1 JUC中的線程池執行線程1.2 Tomcat 中線程池執行線程 二、被改造的阻塞隊列2.1 TaskQueue的 offer(...)2.2 TaskQueue的 force(...) 三、總結 前言 Tomcat 線程池&#xff0c;是依據 JUC 中的線程池 ThreadPoolExecutor 重新自定義…

深入理解C語言(5):程序環境和預處理詳解

文章主題&#xff1a;程序環境和預處理詳解&#x1f30f;所屬專欄&#xff1a;深入理解C語言&#x1f4d4;作者簡介&#xff1a;更新有關深入理解C語言知識的博主一枚&#xff0c;記錄分享自己對C語言的深入解讀。&#x1f606;個人主頁&#xff1a;[?]的個人主頁&#x1f3c4…

Imagewheel私人圖床搭建結合內網穿透實現無公網IP遠程訪問教程

文章目錄 1.前言2. Imagewheel網站搭建2.1. Imagewheel下載和安裝2.2. Imagewheel網頁測試2.3.cpolar的安裝和注冊 3.本地網頁發布3.1.Cpolar臨時數據隧道3.2.Cpolar穩定隧道&#xff08;云端設置&#xff09;3.3.Cpolar穩定隧道&#xff08;本地設置&#xff09; 4.公網訪問測…

flutter 文件上傳組件和大文件分片上傳

文件分片上傳 資料 https://www.cnblogs.com/caijinglong/p/11558389.html 使用分段上傳來上傳和復制對象 - Amazon Simple Storage Service 因為公司使用的是亞馬遜的s3桶 下面是查閱資料獲得的 亞馬遜s3桶的文件上傳分片 分段上分為三個步驟&#xff1a;開始上傳、上傳對…

CSP-J 2023 T3 一元二次方程

文章目錄 題目題目背景題目描述輸入格式輸出格式樣例 #1樣例輸入 #1樣例輸出 #1 提示 題目傳送門題解思路總代碼 提交結果尾聲 題目 題目背景 眾所周知&#xff0c;對一元二次方程 a x 2 b x c 0 , ( a ≠ 0 ) ax ^ 2 bx c 0, (a \neq 0) ax2bxc0,(a0)&#xff0c;可…

STM32G030C8T6:定時器1ms中斷(以64MHz外部晶振為例)

本專欄記錄STM32開發各個功能的詳細過程&#xff0c;方便自己后續查看&#xff0c;當然也供正在入門STM32單片機的兄弟們參考&#xff1b; 本小節的目標是&#xff0c;系統主頻64 MHZ,采用高速外部晶振&#xff0c;通過定時器3 每秒中斷控制 PB9 引腳輸出高低電平&#xff0c;從…

20240222作業

完善對話框&#xff0c;點擊登錄對話框&#xff0c;如果賬號和密碼匹配&#xff0c;則彈出信息對話框&#xff0c;給出提示“登錄成功"&#xff0c;提供一個Ok按鈕&#xff0c;用戶點擊OK后&#xff0c;關閉登錄界面&#xff0c;跳轉到其他界面 如果賬號和密碼不匹配&…

Java基礎-注解

注解 注解是用來干什么的它有什么作用注解的常見分類內置注解Override注解定義 Deprecated注解定義 SuppressWarnings注解定義 元注解Target注解定義ElementType Retention&&RetentionTarget注解定義RetentionPolicy Documented注解定義 Inherited注解定義用法 Repeata…

低代碼開發:推動互聯網企業數字化轉型的關鍵因素

聯網行業作為我國數字經濟發展的核心驅動力&#xff0c;在推動國家數字化轉型中扮演著至關重要的角色。與其他傳統行業相比&#xff0c;互聯網企業面臨更加緊迫的數字化轉型需求&#xff0c;因為它們需要不斷適應快速變化的市場環境和技術趨勢。 然而&#xff0c;由于互聯網企業…

深入理解APDU協議與Java開發

1. 什么是APDU&#xff1f; APDU&#xff0c;即應用協議數據單元&#xff08;Application Protocol Data Unit&#xff09;&#xff0c;是一種在智能卡與卡片讀卡器之間進行通信的協議。APDU定義了在交互中傳輸的數據格式和規則&#xff0c;允許讀卡器發送指令并接收響應。 2…

MFC 皮膚庫配置

1.創建MFC 對話框 2.添加皮膚資源 添加資源 添加頭文件 關閉SDL檢測 添加靜態庫文件 修改字符集 添加頭文件 將皮膚中的ssk文件加載到初始化實例中 > 運行即可

springboot 的 websocket 里面使用 @Autowired 注入 service 或 bean 時,報空指針異常

直接上解決方案&#xff1a; 在你的WebSocketServer服務器中 public static MessageService messageService; //要注入的類// 注入的時候&#xff0c;給類的 service 注入Autowiredpublic void setChatService(MessageService messageService) {WebSocketServer.messageSer…

【寸鐵的刷題筆記】樹、dfs、bfs、回溯、遞歸(一)

【寸鐵的刷題筆記】樹、dfs、bfs、回溯、遞歸(一) 大家好 我是寸鐵&#x1f44a; 總結了一篇刷題關于樹、dfs、bfs、回溯、遞歸的文章? 喜歡的小伙伴可以點點關注 &#x1f49d; 105. 從前序與中序遍歷序列構造二叉樹 模擬分析圖 代碼實現 /*** Definition for a binary tre…

HarmonyOS—添加/刪除Module

Module是應用/服務的基本功能單元&#xff0c;包含了源代碼、資源文件、第三方庫及應用/服務配置文件&#xff0c;每一個Module都可以獨立進行編譯和運行。一個HarmonyOS應用/服務通常會包含一個或多個Module&#xff0c;因此&#xff0c;可以在工程中創建多個Module&#xff0…

如何利用內網穿透工具在企業微信開發者中心實現本地接口服務回調

文章目錄 1. Windows安裝Cpolar2. 創建Cpolar域名3. 創建企業微信應用4. 定義回調本地接口5. 回調和可信域名接口校驗6. 設置固定Cpolar域名7. 使用固定域名校驗 企業微信開發者在應用的開發測試階段&#xff0c;應用服務通常是部署在開發環境&#xff0c;在有數據回調的開發場…

SQL查詢每個類別價格前3的數據

SELECTproduct_id,category,price FROM (SELECTproduct_id,category,price,ROW_NUMBER() OVER (PARTITION BY category ORDER BY price) AS rankFROMyour_products_table ) AS ranked_products WHERErank < 3;DENSE_RANK() 和 ROW_NUMBER() 是窗口函數&#xff08;Window Fu…

前端知識復習

1.symbol類型 Symbol 是 ECMAScript 6 中引入的一種新的基本數據類型&#xff0c;它表示獨一無二的值。Symbol 值是通過 Symbol() 函數創建的。 Symbol 值具有以下特點&#xff1a; 獨一無二性&#xff08;唯一性&#xff09;&#xff1a;每個通過 Symbol() 函數創建的 Symb…