最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中鎖的類型詳解

 更新時間:2025年10月20日 16:47:22   作者:programer_33  
本文介紹了Java鎖的多種分類,包括公平鎖與非公平鎖、獨占鎖與共享鎖、悲觀鎖與樂觀鎖,以及可重入鎖與不可重入鎖,并分析了各自的實現(xiàn)方式、優(yōu)缺點及適用場景,幫助選擇適合的并發(fā)控制機制,感興趣的朋友跟隨小編一起看看吧

按照鎖的特性分類

公平性分類

公平鎖(Fair lock)

公平鎖指多個線程按照申請鎖的順序依次獲取鎖,遵循先到先得的原則,避免線程饑餓現(xiàn)象。在Java中,公平鎖通常通過ReentrantLockReentrantReadWriteLock的構(gòu)造函數(shù)指定公平策略實現(xiàn)。

ReentrantLock的公平模式
通過構(gòu)造函數(shù)傳入true啟用公平鎖:

ReentrantLock fairLock = new ReentrantLock(true); // true表示公平鎖

公平鎖會維護一個線程等待隊列,按請求順序分配鎖,但性能略低于非公平鎖。

ReentrantReadWriteLock的公平模式
類似ReentrantLock,通過構(gòu)造函數(shù)指定公平性:

ReentrantReadWriteLock fairReadWriteLock = new ReentrantReadWriteLock(true);

讀寫鎖的公平模式下,讀鎖和寫鎖的分配均遵循請求順序。

Semaphore的公平模式
信號量也可通過構(gòu)造函數(shù)啟用公平策略:

Semaphore fairSemaphore = new Semaphore(permits, true); // true表示公平

公平模式下,線程按申請許可證的順序獲取資源。

注意事項
  • 性能權(quán)衡:公平鎖減少線程饑餓但增加上下文切換開銷,非公平鎖吞吐量更高。
  • 默認(rèn)行為ReentrantLockSemaphore默認(rèn)是非公平鎖,需顯式聲明公平策略。
  • 適用場景:嚴(yán)格順序需求或避免饑餓時使用公平鎖,高并發(fā)場景優(yōu)先考慮非公平鎖。
示例代碼
// 公平鎖示例
ReentrantLock lock = new ReentrantLock(true);
lock.lock();
try {
    // 臨界區(qū)代碼
} finally {
    lock.unlock();
}

非公平鎖(Non-fair-lock)

它不保證線程獲取鎖的順序與請求鎖的順序一致。線程可以在鎖被釋放時直接嘗試獲取鎖,而不考慮是否有其他線程已經(jīng)在等待隊列中。

實現(xiàn)方式

在Java中,ReentrantLock類默認(rèn)使用非公平鎖策略。可以通過以下代碼顯式創(chuàng)建非公平鎖:

ReentrantLock lock = new ReentrantLock(false); // false表示非公平鎖
特點

非公平鎖允許新請求鎖的線程插隊,即使有其他線程在等待隊列中。這種機制減少了線程切換的開銷,提高了吞吐量,但可能導(dǎo)致某些線程長時間無法獲取鎖。

優(yōu)點

  • 減少線程切換,提高性能
  • 在高并發(fā)場景下吞吐量更高

缺點

  • 可能導(dǎo)致某些線程饑餓
  • 無法保證公平性
使用場景
  • 鎖持有時間較短
  • 線程競爭不激烈
  • 對吞吐量要求高于公平性要求
與公平鎖的對比
// 非公平鎖
ReentrantLock nonFairLock = new ReentrantLock(false);
// 公平鎖
ReentrantLock fairLock = new ReentrantLock(true);

非公平鎖的性能通常優(yōu)于公平鎖,因為減少了線程切換的開銷。但在要求嚴(yán)格的公平性場景下,應(yīng)該使用公平鎖。

非公平鎖的底層實現(xiàn)

非公平鎖通過AQS(AbstractQueuedSynchronizer)實現(xiàn)。當(dāng)線程嘗試獲取鎖時,會先嘗試直接獲取,失敗后才進入等待隊列:

final boolean nonfairTryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {
        if (compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    else if (current == getExclusiveOwnerThread()) {
        int nextc = c + acquires;
        if (nextc < 0) // overflow
            throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    return false;
}

排他性分類

獨占鎖(Exclusive lock)

獨占鎖(Exclusive Lock)是一種同步機制,同一時間只允許一個線程持有鎖,其他線程必須等待鎖釋放后才能獲取。Java 中主要通過 synchronized 關(guān)鍵字和 ReentrantLock 類實現(xiàn)獨占鎖。

使用synchronized實現(xiàn)獨占鎖

synchronized 是 Java 內(nèi)置的獨占鎖機制,可以修飾方法或代碼塊。

方法級別鎖

public synchronized void exclusiveMethod() {
    // 臨界區(qū)代碼
}

代碼塊級別鎖

public void exclusiveBlock() {
    synchronized (this) {
        // 臨界區(qū)代碼
    }
}

特點

  • 自動釋放鎖:線程執(zhí)行完同步代碼或發(fā)生異常時,鎖會自動釋放。
  • 可重入性:同一線程可重復(fù)獲取已持有的鎖。
使用ReentrantLock實現(xiàn)獨占鎖

ReentrantLockjava.util.concurrent.locks 包下的顯式鎖實現(xiàn),提供更靈活的鎖控制。

基本用法

private final ReentrantLock lock = new ReentrantLock();
public void performTask() {
    lock.lock(); // 獲取鎖
    try {
        // 臨界區(qū)代碼
    } finally {
        lock.unlock(); // 確保鎖釋放
    }
}

高級功能

可中斷鎖

lock.lockInterruptibly(); // 響應(yīng)中斷的鎖獲取

嘗試獲取鎖

if (lock.tryLock(1, TimeUnit.SECONDS)) { // 嘗試在指定時間內(nèi)獲取鎖
    try {
        // 臨界區(qū)代碼
    } finally {
        lock.unlock();
    }
}

公平鎖

ReentrantLock fairLock = new ReentrantLock(true); // 公平鎖
應(yīng)用場景
  1. 資源互斥訪問
    如單例模式的雙重檢查鎖、共享變量的線程安全操作。
  2. 寫操作保護
    在讀寫鎖(ReadWriteLock)中,寫鎖是獨占鎖,確保寫操作原子性。
注意事項
  • 避免死鎖:確保鎖的獲取和釋放成對出現(xiàn),尤其是異常場景。
  • 性能考量:高并發(fā)場景下,ReentrantLock 的靈活性可能優(yōu)于 synchronized,但需手動管理鎖釋放。

通過合理選擇 synchronizedReentrantLock,可以高效實現(xiàn)線程安全的獨占訪問控制。

共享鎖 (Shared lock)

共享鎖(Shared Lock)是一種允許多個線程同時讀取資源,但禁止寫入的鎖機制。與排他鎖(Exclusive Lock)互斥的特性不同,共享鎖適用于讀多寫少的場景,能有效提高并發(fā)性能。

Java中主要通過ReadWriteLock接口及其實現(xiàn)類ReentrantReadWriteLock實現(xiàn)共享鎖:

  • 讀鎖(共享鎖):通過readLock()方法獲取,允許多個線程同時持有。
  • 寫鎖(排他鎖):通過writeLock()方法獲取,同一時間僅允許一個線程持有。
ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock(); // 共享鎖
ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock(); // 排他鎖

使用場景

  1. 緩存系統(tǒng):多個線程可并發(fā)讀取緩存數(shù)據(jù),寫入時需獨占。
  2. 資源池管理:如數(shù)據(jù)庫連接池的讀取操作。
// 示例:使用共享鎖實現(xiàn)線程安全的緩存
class Cache<K, V> {
    private final Map<K, V> map = new HashMap<>();
    private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
    public V get(K key) {
        rwLock.readLock().lock();
        try {
            return map.get(key);
        } finally {
            rwLock.readLock().unlock();
        }
    }
    public void put(K key, V value) {
        rwLock.writeLock().lock();
        try {
            map.put(key, value);
        } finally {
            rwLock.writeLock().unlock();
        }
    }
}

注意事項

  • 鎖升級問題:持有讀鎖時嘗試獲取寫鎖會導(dǎo)致死鎖,需先釋放讀鎖。
  • 公平性選擇ReentrantReadWriteLock支持公平/非公平模式,非公平模式吞吐量更高。

共享鎖與同步代碼塊的對比

特性共享鎖(ReadWriteLock)synchronized
并發(fā)性讀操作并發(fā),寫操作互斥完全互斥
靈活性可分離讀/寫鎖單一鎖機制

其他共享鎖實現(xiàn)

  • StampedLock:Java 8引入,支持樂觀讀鎖,適用于讀操作遠(yuǎn)多于寫的場景。
StampedLock stampedLock = new StampedLock();
long stamp = stampedLock.tryOptimisticRead(); // 樂觀讀鎖
if (!stampedLock.validate(stamp)) {
    stamp = stampedLock.readLock(); // 退化為悲觀讀鎖
}

獲取方式分類

悲觀鎖(Pessimistic lock)

悲觀鎖是一種并發(fā)控制機制,假設(shè)多線程并發(fā)訪問共享資源時大概率會發(fā)生沖突,因此在訪問數(shù)據(jù)前會先加鎖,確保其他線程無法同時修改。適用于寫操作頻繁的場景。

實現(xiàn)方式

synchronized 關(guān)鍵字

通過synchronized修飾方法或代碼塊,實現(xiàn)隱式鎖:

public synchronized void updateData() {
    // 臨界區(qū)代碼
}

或使用代碼塊鎖定特定對象:

public void updateData() {
    synchronized (this) { // 鎖住當(dāng)前對象
        // 臨界區(qū)代碼
    }
}
ReentrantLock

java.util.concurrent.locks.ReentrantLock提供更靈活的顯式鎖:

private final ReentrantLock lock = new ReentrantLock();
public void updateData() {
    lock.lock(); // 手動加鎖
    try {
        // 臨界區(qū)代碼
    } finally {
        lock.unlock(); // 必須手動釋放
    }
}

數(shù)據(jù)庫悲觀鎖

在JDBC中可通過SQL語句實現(xiàn):

  • SELECT ... FOR UPDATE(MySQL/Oracle):
Connection conn = ...;
try {
    conn.setAutoCommit(false);
    PreparedStatement ps = conn.prepareStatement(
        "SELECT * FROM accounts WHERE id = ? FOR UPDATE"
    );
    ps.setInt(1, accountId);
    ResultSet rs = ps.executeQuery();
    // 修改數(shù)據(jù)后提交
    conn.commit();
} catch (SQLException e) {
    conn.rollback();
}

注意事項

  • 死鎖風(fēng)險:多個線程互相持有對方所需鎖時會導(dǎo)致死鎖,需設(shè)計合理的加鎖順序。
  • 性能開銷:頻繁加鎖可能降低系統(tǒng)吞吐量,讀多寫少的場景建議考慮樂觀鎖。
  • 鎖粒度:盡量縮小鎖范圍(如鎖定行而非整表)以減少阻塞。

適用場景

  • 數(shù)據(jù)競爭激烈的寫操作。
  • 需要保證強一致性的業(yè)務(wù)邏輯(如支付系統(tǒng)扣款)。

樂觀鎖 (Optimistic lock)

樂觀鎖是一種并發(fā)控制機制,假設(shè)多線程操作共享資源時不會發(fā)生沖突,因此在操作前不加鎖,而是在提交更新時檢查資源是否被其他線程修改。如果未被修改,則提交成功;否則,根據(jù)策略(重試、報錯等)處理沖突。樂觀鎖適用于讀多寫少的場景,減少鎖競爭的開銷

樂觀鎖的實現(xiàn)方式

1. 版本號機制
在數(shù)據(jù)表中增加一個版本號字段(如 version),每次更新時比對版本號。若版本號匹配,則更新數(shù)據(jù)并遞增版本號;否則視為沖突。

示例代碼(基于數(shù)據(jù)庫)

// 假設(shè)有一個實體類
public class Product {
    private Long id;
    private String name;
    private int version; // 樂觀鎖版本號
}
// 更新邏輯
@Transactional
public void updateProduct(Long id, String newName) {
    Product product = productDao.selectById(id);
    product.setName(newName);
    int updated = productDao.updateWithVersion(product);
    if (updated == 0) {
        throw new OptimisticLockException("更新失敗,數(shù)據(jù)已被修改");
    }
}

對應(yīng)的 SQL 語句示例:

UPDATE product SET name = #{newName}, version = version + 1 
WHERE id = #{id} AND version = #{oldVersion};

2. CAS(Compare-And-Swap)
通過原子操作(如 AtomicInteger)實現(xiàn)樂觀鎖,適用于單機或多線程環(huán)境。

示例代碼(基于 AtomicInteger

private AtomicInteger counter = new AtomicInteger(0);
public void increment() {
    int oldValue, newValue;
    do {
        oldValue = counter.get();
        newValue = oldValue + 1;
    } while (!counter.compareAndSet(oldValue, newValue));
}

優(yōu)點

  • 無鎖競爭,提高吞吐量。
  • 避免死鎖問題。

缺點

  • 沖突頻繁時需重試,可能降低性能。
  • 不保證操作原子性,需結(jié)合事務(wù)或其他機制。

適用場景

  • 讀多寫少的高并發(fā)場景(如商品庫存、點贊計數(shù))。
  • 沖突概率較低的業(yè)務(wù)邏輯。

注意事項

  • 版本號需為整型或時間戳,確保可比較性。
  • 分布式環(huán)境中需結(jié)合分布式鎖或數(shù)據(jù)庫唯一約束。

狀態(tài)分類

可重入鎖 (Reentrant lock)

可重入鎖(ReentrantLock)是Java中一種顯式鎖機制,屬于java.util.concurrent.locks包。與synchronized關(guān)鍵字相比,它提供更靈活的鎖操作,支持公平鎖、非公平鎖、可中斷鎖等待等特性。

核心特性

  • 可重入性
  • 同一線程可以多次獲取同一把鎖,避免死鎖。每次獲取鎖后需對應(yīng)釋放,通常通過計數(shù)器實現(xiàn)。
  • 公平性選擇
  • 通過構(gòu)造函數(shù)指定公平鎖(fair=true)或非公平鎖(默認(rèn))。公平鎖按請求順序分配,非公平鎖允許插隊。
  • 條件變量(Condition)
  • 通過newCondition()創(chuàng)建多個條件隊列,實現(xiàn)精細(xì)化的線程等待/喚醒機制,類似wait()notify()。

基本用法

ReentrantLock lock = new ReentrantLock(); // 非公平鎖
lock.lock(); // 獲取鎖
try {
    // 臨界區(qū)代碼
} finally {
    lock.unlock(); // 確保鎖釋放
}

高級功能

1. 嘗試獲取鎖
  • tryLock():立即返回是否成功獲取鎖。
  • tryLock(long timeout, TimeUnit unit):在指定時間內(nèi)嘗試獲取鎖。
if (lock.tryLock(1, TimeUnit.SECONDS)) {
    try {
        // 操作臨界區(qū)
    } finally {
        lock.unlock();
    }
} else {
    // 處理超時邏輯
}
2. 可中斷鎖

lockInterruptibly()允許在等待鎖時響應(yīng)中斷,避免死等。

try {
    lock.lockInterruptibly();
    // 臨界區(qū)代碼
} catch (InterruptedException e) {
    Thread.currentThread().interrupt(); // 恢復(fù)中斷狀態(tài)
} finally {
    if (lock.isHeldByCurrentThread()) {
        lock.unlock();
    }
}
3. 公平鎖示例
ReentrantLock fairLock = new ReentrantLock(true); // 公平鎖
fairLock.lock();
try {
    // 公平鎖保護的代碼
} finally {
    fairLock.unlock();
}

與synchronized對比

特性ReentrantLocksynchronized
鎖獲取方式顯式調(diào)用lock()/unlock()隱式(代碼塊/方法)
公平性支持配置非公平
可中斷支持不支持
條件變量支持多個Condition單一wait()/notify()
性能高競爭時更優(yōu)低競爭時更優(yōu)

注意事項

  • 必須在finally塊中釋放鎖,避免異常導(dǎo)致鎖泄漏。
  • 避免嵌套過多鎖操作,可能導(dǎo)致邏輯復(fù)雜化。
  • 公平鎖可能降低吞吐量,需根據(jù)場景權(quán)衡。

通過合理使用ReentrantLock,可以更靈活地控制多線程并發(fā),尤其適用于需要復(fù)雜同步策略的場景。

不可重入鎖 (Non-reentrant lock)

不可重入鎖(Non-Reentrant Lock)是一種線程同步機制,特點是同一線程在持有鎖的情況下,若再次嘗試獲取該鎖,會導(dǎo)致線程阻塞或死鎖。與可重入鎖(如 ReentrantLock)不同,不可重入鎖不記錄持有線程的重復(fù)獲取次數(shù)。

不可重入鎖通常通過以下方式實現(xiàn):

  • 鎖狀態(tài)標(biāo)記:使用一個布爾變量(如 isLocked)表示鎖是否被占用。
  • 線程檢查:獲取鎖時,若鎖已被占用(無論是否當(dāng)前線程持有),均會阻塞。

以下是一個簡單的不可重入鎖實現(xiàn)示例:

public class NonReentrantLock {
    private boolean isLocked = false;
    public synchronized void lock() throws InterruptedException {
        while (isLocked) {
            wait(); // 若鎖被占用,當(dāng)前線程等待
        }
        isLocked = true; // 獲取鎖
    }
    public synchronized void unlock() {
        isLocked = false;
        notify(); // 喚醒等待線程
    }
}

不可重入鎖的問題

死鎖風(fēng)險:若線程在持有鎖時重復(fù)調(diào)用 lock(),會導(dǎo)致自身阻塞。

NonReentrantLock lock = new NonReentrantLock();
lock.lock();
lock.lock(); // 線程在此處永久阻塞

靈活性不足:無法支持遞歸調(diào)用或嵌套同步代碼塊。

應(yīng)用場景

  • 簡單同步需求:僅需基礎(chǔ)互斥且無嵌套鎖的場景。
  • 資源限制:明確要求防止同一線程重復(fù)獲取鎖的情況。

不可重入鎖與可重入鎖的對比

特性不可重入鎖可重入鎖(如 ReentrantLock
同一線程重復(fù)獲取導(dǎo)致阻塞/死鎖允許,記錄重入次數(shù)
實現(xiàn)復(fù)雜度簡單需維護持有線程和計數(shù)器
適用場景無嵌套鎖的簡單同步遞歸調(diào)用或復(fù)雜同步邏輯

注意事項

  • 避免在不可重入鎖保護的代碼中調(diào)用可能再次獲取鎖的方法。
  • 若需嵌套鎖,應(yīng)使用 ReentrantLocksynchronized(Java 內(nèi)置的可重入鎖)。

到此這篇關(guān)于Java中鎖的類型詳解的文章就介紹到這了,更多相關(guān)java 鎖類型內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 淺談Java方法調(diào)用的優(yōu)先級問題

    淺談Java方法調(diào)用的優(yōu)先級問題

    這篇文章主要介紹了淺談Java方法調(diào)用的優(yōu)先級問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-10-10
  • Mybatis中collection和association的使用區(qū)別詳解

    Mybatis中collection和association的使用區(qū)別詳解

    這篇文章主要介紹了Mybatis中collection和association的使用區(qū)別詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-11-11
  • IDEA中的.iml文件和.idea文件的作用及意義

    IDEA中的.iml文件和.idea文件的作用及意義

    iml是 項目標(biāo)識文件,每一個模塊都有一個iml文件,存儲模塊的相關(guān)信息,跟eclipse的project文件是一樣的功能,這篇文章主要介紹了IDEA中的.iml文件和.idea文件的作用,需要的朋友可以參考下
    2023-09-09
  • Eclipse導(dǎo)出安卓apk文件的圖文教程

    Eclipse導(dǎo)出安卓apk文件的圖文教程

    這篇文章主要為大家詳細(xì)介紹了Eclipse導(dǎo)出安卓apk文件的圖文教程,以圖文結(jié)合的方式為大家分享了Eclipse是如何導(dǎo)出安卓apk文件的步驟,感興趣的小伙伴們可以參考一下
    2016-06-06
  • Git在IDEA中合并多個commit為一個

    Git在IDEA中合并多個commit為一個

    文章介紹了兩種情況下的commit合并方法:未提交到遠(yuǎn)程分支和已經(jīng)提交到遠(yuǎn)程分支,對于未提交的,通過reset和push操作即可;對于已提交的,使用rebase操作將多個commit合并為一個,然后強制push
    2025-10-10
  • IntelliJ IDEA 2020.1 EAP4 發(fā)布,重命名/更改簽名新功能一覽

    IntelliJ IDEA 2020.1 EAP4 發(fā)布,重命名/更改簽名新功能一覽

    這篇文章主要介紹了IntelliJ IDEA 2020.1 EAP4 發(fā)布,重命名/更改簽名新功能,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-04-04
  • RabbitMQ 避免消息重復(fù)消費的方法

    RabbitMQ 避免消息重復(fù)消費的方法

    消費者端實現(xiàn)冪等性,意味著消息永遠(yuǎn)不會消費多次,即使收到了多條一樣的消息,這篇文章給大家分享RabbitMQ 避免消息重復(fù)消費的方法,感興趣的朋友一起看看吧
    2024-03-03
  • spring?boot集成p6spy的最佳實踐

    spring?boot集成p6spy的最佳實踐

    這篇文章主要介紹了spring?boot集成p6spy的最佳實踐-p6spy-spring-boot-starter的項目案例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步
    2022-02-02
  • Java中BeanMap的使用方法

    Java中BeanMap的使用方法

    這篇文章主要介紹了Java中BeanMap的使用方法,BeanMap來源于spring 框架,可以將一般的類轉(zhuǎn)為 Map 結(jié)構(gòu)存儲,基于Map的JavaBean視圖,默認(rèn)的鍵集是所有屬性名稱的聯(lián)合,需要的朋友可以參考下
    2024-01-01
  • 關(guān)于SpringMVC對Restful風(fēng)格的支持詳解

    關(guān)于SpringMVC對Restful風(fēng)格的支持詳解

    Restful就是一個資源定位及資源操作的風(fēng)格,不是標(biāo)準(zhǔn)也不是協(xié)議,只是一種風(fēng)格,是對http協(xié)議的詮釋,下面這篇文章主要給大家介紹了關(guān)于SpringMVC對Restful風(fēng)格支持的相關(guān)資料,需要的朋友可以參考下
    2022-01-01

最新評論

星子县| 天门市| 离岛区| 洞头县| 十堰市| 曲松县| 金门县| 宁陵县| 济阳县| 咸宁市| 安阳市| 和田县| 兴山县| 九龙坡区| 雷州市| 乐昌市| 常熟市| 通城县| 武宁县| 桂平市| 佳木斯市| 徐汇区| 攀枝花市| 鹤壁市| 铅山县| 晴隆县| 醴陵市| 河东区| 秭归县| 利川市| 高雄市| 会昌县| 舒城县| 潮州市| 拉萨市| 忻州市| 平泉县| 阿尔山市| 桐庐县| 建始县| 信阳市|