溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

java并發編程中悲觀鎖和樂觀鎖是什么意思

發布時間:2021-12-24 09:57:26 來源:億速云 閱讀:116 作者:小新 欄目:云計算
# Java并發編程中悲觀鎖和樂觀鎖是什么意思

## 引言

在多線程并發編程中,保證數據的一致性和線程安全是核心挑戰。Java提供了多種鎖機制來解決并發問題,其中悲觀鎖和樂觀鎖是兩種最基礎且重要的并發控制策略。本文將深入探討這兩種鎖的概念、實現原理、典型應用場景以及它們的優缺點對比。

## 一、悲觀鎖的基本概念

### 1.1 什么是悲觀鎖

悲觀鎖(Pessimistic Locking)是一種"先獲取鎖,再訪問數據"的并發控制策略。其核心思想是:**假定并發沖突一定會發生**,因此在數據被訪問前就加鎖,確保同一時刻只有一個線程能操作數據。

### 1.2 典型實現方式

在Java中,悲觀鎖主要通過以下方式實現:

```java
// synchronized關鍵字實現
public synchronized void pessimisticMethod() {
    // 臨界區代碼
}

// ReentrantLock實現
private Lock lock = new ReentrantLock();

public void lockExample() {
    lock.lock();  // 獲取鎖
    try {
        // 臨界區代碼
    } finally {
        lock.unlock();  // 釋放鎖
    }
}

1.3 數據庫中的悲觀鎖

-- MySQL的SELECT...FOR UPDATE語句
BEGIN;
SELECT * FROM accounts WHERE id = 1 FOR UPDATE;
-- 更新操作
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
COMMIT;

二、樂觀鎖的基本概念

2.1 什么是樂觀鎖

樂觀鎖(Optimistic Locking)采用”先修改,再驗證”的策略。其核心假設是:并發沖突不常發生,因此允許多個線程同時讀取數據,但在更新時會檢查數據是否被其他線程修改過。

2.2 典型實現方式

2.2.1 版本號機制

// 偽代碼示例
public boolean updateWithOptimisticLock(Entity entity) {
    // 獲取當前版本號
    int currentVersion = entity.getVersion();
    
    // 執行更新操作,同時檢查版本號
    int updatedRows = executeUpdate(
        "UPDATE table SET field = ?, version = version + 1 " +
        "WHERE id = ? AND version = ?", 
        newValue, entity.getId(), currentVersion);
    
    return updatedRows > 0;
}

2.2.2 CAS操作

// AtomicInteger的CAS實現
AtomicInteger atomicInt = new AtomicInteger(0);

boolean success = atomicInt.compareAndSet(0, 1);  // 期望值0,新值1

2.3 數據庫中的樂觀鎖

-- 使用版本號的SQL示例
UPDATE products 
SET stock = stock - 1, version = version + 1
WHERE id = 100 AND version = 2;

三、兩種鎖的對比分析

3.1 性能對比

指標 悲觀鎖 樂觀鎖
并發讀 差(需要加鎖) 優秀(無需加鎖)
并發寫 串行執行 可能失敗但可重試
沖突頻率 高沖突場景適用 低沖突場景適用
系統開銷 上下文切換、鎖維護成本高 僅CAS或版本檢查,開銷低

3.2 適用場景對比

悲觀鎖適用場景: 1. 寫操作頻繁且沖突概率高 2. 臨界區代碼執行時間長 3. 需要保證強一致性的場景(如銀行轉賬)

樂觀鎖適用場景: 1. 讀多寫少的環境 2. 沖突概率低的場景 3. 需要高吞吐量的系統

四、Java中的具體實現

4.1 悲觀鎖實現細節

4.1.1 synchronized的底層原理

public synchronized void method() {
    // 方法體
}

對應的字節碼:

monitorenter
// 方法代碼
monitorexit

4.1.2 ReentrantLock的AQS實現

public class ReentrantLock implements Lock {
    private final Sync sync;
    abstract static class Sync extends AbstractQueuedSynchronizer {
        // 實現AQS的tryAcquire等方法
    }
}

4.2 樂觀鎖實現細節

4.2.1 Atomic類的實現

public class AtomicInteger extends Number {
    private volatile int value;
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    
    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }
}

4.2.2 LongAdder的分段優化

public void add(long x) {
    Cell[] as; long b, v; int m; Cell a;
    if ((as = cells) != null || !casBase(b = base, b + x)) {
        // 使用分段Cell減少競爭
    }
}

五、實際應用案例

5.1 悲觀鎖案例:庫存扣減

public class InventoryService {
    private int stock = 100;
    private final Object lock = new Object();
    
    public boolean deductStock(int quantity) {
        synchronized (lock) {
            if (stock >= quantity) {
                stock -= quantity;
                return true;
            }
            return false;
        }
    }
}

5.2 樂觀鎖案例:用戶積分更新

public class UserPointsService {
    public boolean addPoints(Long userId, int pointsToAdd) {
        User user = userDao.get(userId);
        int currentVersion = user.getVersion();
        user.setPoints(user.getPoints() + pointsToAdd);
        return userDao.updateWithVersion(user, currentVersion) > 0;
    }
}

六、高級話題

6.1 鎖升級與降級

// ReentrantReadWriteLock的鎖降級示例
public void lockDowngrade() {
    writeLock.lock();
    try {
        // 寫操作...
        readLock.lock();  // 鎖降級開始
    } finally {
        writeLock.unlock();  // 降級完成
    }
    // 仍持有讀鎖...
    readLock.unlock();
}

6.2 ABA問題及解決方案

// 使用AtomicStampedReference解決ABA問題
AtomicStampedReference<Integer> atomicRef = 
    new AtomicStampedReference<>(100, 0);

int[] stampHolder = new int[1];
int currentStamp = atomicRef.getStamp();
atomicRef.compareAndSet(100, 101, currentStamp, currentStamp + 1);

七、總結與最佳實踐

  1. 選擇標準:根據沖突概率、性能要求和業務場景選擇
  2. 混合使用:系統中可以同時存在兩種鎖機制
  3. 監控指標:關注鎖競爭率、CAS成功率等關鍵指標
  4. 避免誤區:不是所有場景都需要加鎖,有時無鎖數據結構更優

“并發控制沒有銀彈,理解每種策略的適用場景比掌握實現細節更重要。” —— Brian Goetz

參考資料

  1. 《Java并發編程實戰》
  2. Oracle官方Java文檔
  3. Java內存模型規范(JSR-133)

”`

注:本文實際約2300字,完整展開所有代碼示例和詳細解釋后可達2500字左右??筛鶕枰{整具體章節的深度。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女