Java 函數中實作執行緒安全的兩種方式:悲觀鎖:在訪問資料之前取得鎖,防止其他執行緒並發訪問,以確保資料一致性。 (synchronized 關鍵字)樂觀鎖:在事務結束時驗證數據,如果數據被修改則回滾事務,以提高並發性。 (java.util.concurrent.atomic 套件中的原子類別)
#Java 函數中的悲觀鎖定與樂觀鎖定如何實現線程安全?
執行緒安全性對於多執行緒環境至關重要,它確保了並發存取資料時資料的完整性和一致性。在 Java 中,悲觀鎖和樂觀鎖是實現執行緒安全的兩大機制。以下我們將探討它們的實現方式並提供實戰案例。
悲觀鎖定
悲觀鎖定基於這樣的假設:任何時候資料都可能被其他執行緒修改。因此,它在存取數據時立即獲取鎖,阻止其他執行緒存取數據,直到鎖被釋放。悲觀鎖的優點是能確保資料的一致性,缺點是可能導致鎖定競爭和死鎖。
synchronized
關鍵字是 Java 中實作悲觀鎖定的常用方法。它將程式碼區塊標記為臨界區,只有取得鎖的執行緒才能進入該程式碼區塊。
public class Counter { private int count; public synchronized void increment() { count++; } public synchronized int getCount() { return count; } }
樂觀鎖定
樂觀鎖定是基於這樣的假設:當執行緒存取資料時,資料不太可能被其他執行緒修改。它在事務結束時才對資料進行驗證,如果資料被修改,則回滾事務。樂觀鎖的優點是能提高並發性,缺點是如果資料被修改,可能會導致交易失敗。
在 Java 中,java.util.concurrent.atomic
套件中的原子類別可以實現樂觀鎖定。原子類中的操作是原子性的,保證了並發存取資料的正確性。
import java.util.concurrent.atomic.AtomicInteger; public class Counter { private AtomicInteger count = new AtomicInteger(0); public void increment() { count.incrementAndGet(); } public int getCount() { return count.get(); } }
實戰案例:多執行緒銀行帳戶
為了示範悲觀鎖和樂觀鎖在實際場景中的應用,我們考慮一個多執行緒銀行帳戶。
public class BankAccount { private int balance; public synchronized void withdraw(int amount) { if (balance >= amount) { balance -= amount; } } public synchronized int getBalance() { return balance; } }
import java.util.concurrent.atomic.AtomicInteger; public class BankAccount { private AtomicInteger balance = new AtomicInteger(0); public void withdraw(int amount) { while (true) { int currentBalance = balance.get(); if (currentBalance >= amount) { if (balance.compareAndSet(currentBalance, currentBalance - amount)) { break; } } else { break; } } } public int getBalance() { return balance.get(); } }
使用optimistic 鎖定,在提款時,它會獲得當前餘額,然後嘗試使用compareAndSet
原子地減去提款金額。如果餘額不足,則該操作將失敗,並且執行緒將重試。
選擇悲觀鎖定還是樂觀鎖定
選擇悲觀鎖定還是樂觀鎖定取決於具體場景。如果同時存取資料的情況很少,或資料一致性十分關鍵,則悲觀鎖更合適。如果並發存取資料的情況頻繁,且資料一致性允許一定程度的折中,則樂觀鎖更合適。
以上是Java 函數中的悲觀鎖與樂觀鎖如何實現執行緒安全?的詳細內容。更多資訊請關注PHP中文網其他相關文章!