欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java使用重入鎖實(shí)現(xiàn)線程同步的示例代碼

 更新時間:2025年07月07日 09:28:36   作者:Katie。  
在多線程環(huán)境中,為保證對共享資源的安全訪問,常用的同步手段是 synchronized 關(guān)鍵字,但 synchronized 存在局限,本項(xiàng)目旨在通過示例演示如何使用 ReentrantLock 實(shí)現(xiàn)線程同步,替代 synchronized,并展示其高級功能,需要的朋友可以參考下

一、項(xiàng)目背景詳細(xì)介紹

在多線程環(huán)境中,為保證對共享資源的安全訪問,常用的同步手段是 synchronized 關(guān)鍵字。但 synchronized 存在以下局限:

  • 靈活性較低:不能嘗試超時獲取鎖,也無法中斷獲取鎖的線程;
  • 可見性:無法查看當(dāng)前鎖是否被占用或等待隊(duì)列情況;
  • 公平性控制:無法直接控制鎖的公平或非公平策略。

Java 5 引入了更強(qiáng)大的 java.util.concurrent.locks 包,其中的 ReentrantLock(可重入鎖)在功能和性能上均優(yōu)于內(nèi)置鎖。它提供:

  • 嘗試獲取鎖tryLock()、tryLock(timeout, unit)
  • 可中斷的鎖獲取lockInterruptibly()
  • 公平鎖:通過構(gòu)造函數(shù)選擇公平或非公平策略
  • 監(jiān)視器查詢getHoldCount()isLocked()、getQueueLength() 等方法

本項(xiàng)目旨在通過示例演示如何使用 ReentrantLock 實(shí)現(xiàn)線程同步,替代 synchronized,并展示其高級功能,如超時嘗試獲取鎖、公平策略和中斷響應(yīng)。

二、項(xiàng)目需求詳細(xì)介紹

基本互斥訪問

  • 使用 ReentrantLock 替代 synchronized,在多個線程間安全地更新同一共享變量或數(shù)據(jù)結(jié)構(gòu);
  • 提供示例:多線程對同一計數(shù)器或共享列表進(jìn)行增刪操作。

超時獲取鎖

  • 演示 tryLock(long timeout, TimeUnit unit) 用法,當(dāng)鎖長時間被占用時拋出或走備用邏輯;

可中斷鎖獲取

  • 演示 lockInterruptibly(),在等待鎖期間響應(yīng)中斷,避免因鎖阻塞導(dǎo)致的無法取消;

公平鎖與非公平鎖

  • 對比默認(rèn)(非公平)鎖和通過 new ReentrantLock(true) 創(chuàng)建的公平鎖在高并發(fā)場景下的性能及線程調(diào)度差異;

鎖狀態(tài)監(jiān)控

  • 使用 getHoldCount()getQueueLength()、hasQueuedThreads() 等方法,實(shí)時查詢鎖的占用與等待情況,打印日志監(jiān)控;

示例應(yīng)用

  • 實(shí)現(xiàn)一個帶超時和中斷功能的共享資源訪問類 SharedResource;
  • 編寫多線程測試,模擬高并發(fā)下的鎖獲取、超時回退和中斷場景;

配置可控

  • 通過構(gòu)造參數(shù)或配置文件動態(tài)切換公平性、超時閾值等;

文檔與示例

  • 在 README 中給出代碼調(diào)用示例及注意事項(xiàng);
  • 對比 synchronizedReentrantLock 的使用差異。

三、相關(guān)技術(shù)詳細(xì)介紹

java.util.concurrent.locks.ReentrantLock

  • 基本方法lock()、unlock()lockInterruptibly()、tryLock()tryLock(timeout, unit);
  • 構(gòu)造參數(shù)new ReentrantLock()(非公平鎖)、new ReentrantLock(true)(公平鎖);

Condition 接口

  • 通過 lock.newCondition() 創(chuàng)建條件變量,替代 wait/notify,支持多條件隊(duì)列;
  • 方法:await()、signal()signalAll();

鎖監(jiān)控與診斷

  • getHoldCount():返回當(dāng)前線程重入次數(shù);
  • isLocked():鎖是否被任意線程占用;
  • hasQueuedThreads()getQueueLength():等待鎖的線程信息;

中斷與超時

  • lockInterruptibly() 在鎖等待時可響應(yīng)中斷;
  • tryLock(timeout, unit) 在指定時長內(nèi)等待,超時后返回 false;

多線程測試

  • 使用 ExecutorService 啟動多個線程;
  • 使用 CountDownLatchCyclicBarrier 協(xié)調(diào)線程啟動同步測試;
  • 記錄鎖獲取次數(shù)與失敗次數(shù)進(jìn)行統(tǒng)計。

四、實(shí)現(xiàn)思路詳細(xì)介紹

SharedResource 類設(shè)計

  • 內(nèi)部包含 private final ReentrantLock lock; 和可選的 Condition;
  • 提供方法:
void safeIncrement() { lock.lock(); try { /* 更新共享計數(shù) */ } finally { lock.unlock(); } }
boolean trySafeIncrement(long timeout, TimeUnit unit) { if (lock.tryLock(timeout, unit)) { try { ... } finally { lock.unlock(); } } else { /* 超時邏輯 */ } }
void interruptibleAccess() throws InterruptedException { lock.lockInterruptibly(); try { ... } finally { lock.unlock(); } }
  • 若需要多個條件,可創(chuàng)建 Condition notEmpty、notFull 并在方法中配合使用。

公平與非公平鎖對比

  • 在測試中構(gòu)造兩種 SharedResource,公平鎖與非公平鎖,分別運(yùn)行相同并發(fā)測試,比較吞吐量與線程饑餓情況。

監(jiān)控鎖狀態(tài)

  • 在方法中或監(jiān)控線程里定期調(diào)用 lock.getQueueLength()lock.hasQueuedThreads() 并打印,觀察等待線程數(shù);
  • 結(jié)合 lock.getHoldCount() 了解重入深度。

多線程測試

  • 使用 ExecutorService 和多個工作線程不斷調(diào)用不同模式的方法;
  • 使用 CountDownLatch 保證開始同步,使用 AtomicInteger 統(tǒng)計成功與超時/中斷次數(shù);

文檔示例

  • 在 README 中說明各模式使用場景和注意事項(xiàng),例如必須在 finally 塊中 unlock(),避免死鎖。
/*
 * =====================================================
 * File: SharedResource.java
 * 共享資源類,使用 ReentrantLock 實(shí)現(xiàn)多種同步策略
 * =====================================================
 */
package com.example.lock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class SharedResource {
    private int counter = 0;
    private final ReentrantLock lock;
    private final Condition notZero;

    /**
     * 構(gòu)造函數(shù):可指定是否公平鎖
     */
    public SharedResource(boolean fair) {
        this.lock = new ReentrantLock(fair);
        this.notZero = lock.newCondition();
    }

    /**
     * 基本互斥:安全地遞增 counter
     */
    public void safeIncrement() {
        lock.lock();
        try {
            counter++;
            System.out.printf("%s incremented to %d%n",
                Thread.currentThread().getName(), counter);
            notZero.signalAll();
        } finally {
            lock.unlock();
        }
    }

    /**
     * 帶超時嘗試獲取鎖的遞增
     */
    public boolean trySafeIncrement(long timeout, TimeUnit unit) {
        boolean acquired = false;
        try {
            acquired = lock.tryLock(timeout, unit);
            if (acquired) {
                counter++;
                System.out.printf("%s timed increment to %d%n",
                    Thread.currentThread().getName(), counter);
                notZero.signalAll();
                return true;
            } else {
                System.out.printf("%s failed to acquire lock in %d %s%n",
                    Thread.currentThread().getName(), timeout, unit);
                return false;
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            System.out.printf("%s interrupted while waiting%n",
                Thread.currentThread().getName());
            return false;
        } finally {
            if (acquired) lock.unlock();
        }
    }

    /**
     * 可中斷地獲取鎖并等待 counter > 0 后消費(fèi)
     */
    public int interruptibleConsume() throws InterruptedException {
        lock.lockInterruptibly();
        try {
            while (counter == 0) {
                System.out.printf("%s waiting for counter > 0%n",
                    Thread.currentThread().getName());
                notZero.await();
            }
            counter--;
            System.out.printf("%s consumed to %d%n",
                Thread.currentThread().getName(), counter);
            return counter;
        } finally {
            lock.unlock();
        }
    }

    /**
     * 監(jiān)控方法:打印當(dāng)前鎖狀態(tài)
     */
    public void printLockStatus() {
        System.out.printf("Lock held by thread: %s, holdCount=%d, queuedThreads=%d%n",
            lock.isLocked() && lock.isHeldByCurrentThread()
                ? Thread.currentThread().getName()
                : "other",
            lock.getHoldCount(),
            lock.getQueueLength());
    }
}


/*
 * =====================================================
 * File: LockDemo.java
 * 演示:多線程調(diào)用 SharedResource 不同方法
 * =====================================================
 */
package com.example.lock;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

public class LockDemo {
    public static void main(String[] args) throws InterruptedException {
        SharedResource fairResource = new SharedResource(true);
        SharedResource unfairResource = new SharedResource(false);

        ExecutorService exec = Executors.newFixedThreadPool(6);
        CountDownLatch startLatch = new CountDownLatch(1);
        AtomicInteger successCount = new AtomicInteger(0);
        AtomicInteger failCount = new AtomicInteger(0);

        // 創(chuàng)建 2 個常規(guī)增量任務(wù)
        for (int i = 0; i < 2; i++) {
            exec.submit(() -> {
                await(startLatch);
                fairResource.safeIncrement();
            });
        }

        // 創(chuàng)建 2 個帶超時嘗試鎖任務(wù)
        for (int i = 0; i < 2; i++) {
            exec.submit(() -> {
                await(startLatch);
                if (fairResource.trySafeIncrement(500, TimeUnit.MILLISECONDS)) {
                    successCount.incrementAndGet();
                } else {
                    failCount.incrementAndGet();
                }
            });
        }

        // 創(chuàng)建 2 個可中斷消費(fèi)任務(wù)
        for (int i = 0; i < 2; i++) {
            exec.submit(() -> {
                await(startLatch);
                try {
                    unfairResource.interruptibleConsume();
                } catch (InterruptedException e) {
                    System.out.printf("%s interrupted%n",
                        Thread.currentThread().getName());
                }
            });
        }

        // 啟動所有任務(wù)
        startLatch.countDown();

        // 等待一段時間后中斷消費(fèi)任務(wù)
        Thread.sleep(1000);
        exec.shutdownNow();
        exec.awaitTermination(5, TimeUnit.SECONDS);

        System.out.printf("TryLock successes: %d, failures: %d%n",
            successCount.get(), failCount.get());
    }

    private static void await(CountDownLatch latch) {
        try {
            latch.await();
        } catch (InterruptedException ignored) {}
    }
}

代碼詳細(xì)解讀

SharedResource

  • safeIncrement():使用 lock.lock()unlock() 實(shí)現(xiàn)基本互斥,并在 notZero 條件上喚醒等待的消費(fèi)者。
  • trySafeIncrement(timeout, unit):使用 tryLock(timeout, unit) 帶超時嘗試獲取鎖,超時后返回失敗邏輯。
  • interruptibleConsume():使用 lock.lockInterruptibly(),在等待中可響應(yīng)中斷,配合 notZero.await() 等待條件。
  • printLockStatus():演示查詢鎖狀態(tài)的方法,包括持有計數(shù)和等待隊(duì)列長度。

LockDemo

使用 ExecutorService 啟動 6 個線程:

  • 2 個調(diào)用 safeIncrement();
  • 2 個調(diào)用 trySafeIncrement(500ms),統(tǒng)計成功與失敗次數(shù);
  • 2 個調(diào)用 interruptibleConsume(),并在主線程中斷它們,演示可中斷鎖獲??;
  • 使用 CountDownLatch 保證所有線程同時開始。
  • 程序運(yùn)行 1 秒后調(diào)用 shutdownNow() 中斷消費(fèi)任務(wù),并打印 tryLock 的統(tǒng)計結(jié)果。

項(xiàng)目詳細(xì)總結(jié)

本示例通過 ReentrantLock 展示了:

  • 基本互斥:與 synchronized 類似,但可以更靈活地控制鎖釋放時機(jī)。
  • 超時獲取鎖tryLock(timeout, unit) 避免長時間阻塞,方便實(shí)現(xiàn)備用邏輯。
  • 可中斷鎖lockInterruptibly() 在等待鎖時響應(yīng)中斷,提高了取消能力。
  • 公平與非公平:可通過構(gòu)造函數(shù)選擇公平策略,避免線程饑餓。
  • 鎖監(jiān)控getHoldCount()getQueueLength() 等方法便于在運(yùn)行時診斷鎖狀態(tài)。

項(xiàng)目常見問題及解答

為何要在 finallyunlock()?
避免在執(zhí)行過程中拋出異常導(dǎo)致鎖未釋放,進(jìn)而引發(fā)死鎖。

tryLock 獲不到鎖后還能重試嗎?
可以在代碼中判斷失敗后循環(huán)調(diào)用,或結(jié)合退避機(jī)制重試。

公平鎖性能更差嗎?
是的,公平鎖會增加上下文切換成本,一般在需要嚴(yán)格順序時使用,否則推薦默認(rèn)非公平鎖。

lockInterruptibly 如何正確處理中斷?
調(diào)用方法需聲明 throws InterruptedException,在捕獲后可執(zhí)行清理邏輯或直接結(jié)束任務(wù)。

如何監(jiān)控生產(chǎn)環(huán)境中的鎖競爭?
利用 lock.getQueueLength() 和日志定期采集,或結(jié)合 APM 工具監(jiān)控線程等待情況。

擴(kuò)展方向與性能優(yōu)化

Condition 多隊(duì)列
使用多個 Condition 實(shí)現(xiàn)更精細(xì)的等待/喚醒控制,例如生產(chǎn)者—消費(fèi)者的 notFull / notEmpty。

鎖分段
對大數(shù)據(jù)結(jié)構(gòu)進(jìn)行分段加鎖(類似 ConcurrentHashMap),降低鎖粒度提升并發(fā)度。

公平性調(diào)優(yōu)
在高并發(fā)場景下考慮非公平鎖與超時重試結(jié)合,避免嚴(yán)格公平帶來的吞吐下降。

鎖剝離
當(dāng)只有讀操作時,可使用 ReadWriteLock 切換到無阻塞讀鎖,提高并發(fā)讀性能。

可視化診斷
集成到監(jiān)控平臺或定制 Web 界面,實(shí)時展示鎖爭用、隊(duì)列長度和線程等待圖。

以上就是Java使用重入鎖實(shí)現(xiàn)線程同步的示例代碼的詳細(xì)內(nèi)容,更多關(guān)于Java重入鎖線程同步的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 解析Java Class 文件過程

    解析Java Class 文件過程

    class文件全名稱為Java class文件,主要在平臺無關(guān)性和網(wǎng)絡(luò)移動性方面使Java更適合網(wǎng)絡(luò)。它在平臺無關(guān)性方面的任務(wù)是:為Java程序提供獨(dú)立于底層主機(jī)平臺的二進(jìn)制形式的服務(wù)。下面我們來詳細(xì)解讀下它吧
    2019-05-05
  • 詳解java爬蟲jsoup解析多空格class數(shù)據(jù)

    詳解java爬蟲jsoup解析多空格class數(shù)據(jù)

    在本篇內(nèi)容中小編給大家分享了java爬蟲jsoup怎么解析多空格class數(shù)據(jù)的方法和技巧,需要的朋友們跟著學(xué)習(xí)下。
    2018-12-12
  • Java實(shí)現(xiàn)圖片轉(zhuǎn)換PDF文件的示例代碼

    Java實(shí)現(xiàn)圖片轉(zhuǎn)換PDF文件的示例代碼

    這篇文章主要介紹了Java實(shí)現(xiàn)圖片轉(zhuǎn)換PDF文件的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • Java字符編碼原理(動力節(jié)點(diǎn)Java學(xué)院整理)

    Java字符編碼原理(動力節(jié)點(diǎn)Java學(xué)院整理)

    Java開發(fā)中,常常會遇到亂碼的問題,一旦遇到這種問題,常常比較煩惱,大家都不想承認(rèn)是自己的代碼問題,其實(shí)搞明白編碼的本質(zhì)過程就簡單多了,接下來小編給大家?guī)韏ava字符編碼原理,要求看看吧
    2017-04-04
  • SpringBoot+Mybatis項(xiàng)目使用Redis做Mybatis的二級緩存的方法

    SpringBoot+Mybatis項(xiàng)目使用Redis做Mybatis的二級緩存的方法

    本篇文章主要介紹了SpringBoot+Mybatis項(xiàng)目使用Redis做Mybatis的二級緩存的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • 使用IDEA直接連接MySQL數(shù)據(jù)庫的方法

    使用IDEA直接連接MySQL數(shù)據(jù)庫的方法

    這篇文章主要介紹了如何使用IDEA直接連接MySQL數(shù)據(jù)庫,首先需要新建一個空項(xiàng)目,第一次連接 需要先下載驅(qū)動,文中給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2024-04-04
  • Java PhantomJs完成html圖片輸出功能

    Java PhantomJs完成html圖片輸出功能

    給大家?guī)硪黄P(guān)于用Java PhantomJs完成html圖片輸出功能的教學(xué)內(nèi)容,有興趣的朋友學(xué)習(xí)參考下吧。
    2017-12-12
  • java解析xml之jdom解析xml示例分享

    java解析xml之jdom解析xml示例分享

    JDOM是專門為Java打造的API,JDOM采用了Java中的Collection架構(gòu)來封裝集合,是Java愛好者更加熟悉的模式,下面看使用示例
    2014-01-01
  • Java正則表達(dá)式的替換和分組功能

    Java正則表達(dá)式的替換和分組功能

    這篇文章主要給大家介紹了關(guān)于Java正則表達(dá)式的替換和分組功能的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • 后端java壓縮圖片超詳細(xì)圖文教程

    后端java壓縮圖片超詳細(xì)圖文教程

    這篇文章主要給大家介紹了關(guān)于后端java壓縮圖片的相關(guān)資料,片壓縮是一種廣泛采用的技術(shù),它不僅能顯著減小文件大小,釋放更多存儲空間,還能提升圖片加載速度,避免長時間等待,需要的朋友可以參考下
    2024-04-04

最新評論