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

Java中的Lock使用實(shí)例詳解

 更新時間:2026年03月31日 10:43:05   作者:Arva?.  
在多線程編程中,鎖是保證數(shù)據(jù)一致性的關(guān)鍵工具,Java從JDK1.5開始提供了java.util.concurrent.locks包,其中的Lock接口及其實(shí)現(xiàn)類比傳統(tǒng)的synchronized更加強(qiáng)大和靈活,這篇文章主要介紹了Java中Lock使用的相關(guān)資料,需要的朋友可以參考下

1. 為什么需要 Lock?(從 synchronized 說起)

synchronized 的局限性:
synchronized 用起來很簡單,但它有一些“笨拙”的地方:

  • 鎖的獲取和釋放是固定的:線程進(jìn)入 synchronized 塊時獲取鎖,退出時(無論是正常退出還是異常退出)自動釋放鎖。你無法手動控制。
  • 不可中斷:如果一個線程在等待鎖,它會一直等下去,不能被中斷。
  • 非公平鎖:默認(rèn)情況下,等待的線程們不是按先來后到的順序獲取鎖的,可能會“插隊”。
  • 只有一個條件隊列:等待和通知用的是 wait()notify(),不夠靈活。

為了解決這些“笨拙”的問題,Java 在 1.5 版本引入了 java.util.concurrent.locks.Lock 接口。

2. Lock 是什么?

  • Lock 像一個需要你用鑰匙開閉的密碼鎖或指紋鎖:你可以自己決定什么時候上鎖,什么時候解鎖。功能強(qiáng)大,可以設(shè)置密碼(嘗試獲取鎖)、設(shè)置超時時間等,但需要你自己管理鑰匙,別弄丟了。

3. Lock 的核心方法

Lock 接口最主要的方法有以下幾個:

  1. lock(): 獲取鎖。如果鎖被其他線程占用,則當(dāng)前線程會一直等待,直到拿到鎖為止。這是最基礎(chǔ)的用法。
  2. unlock(): 釋放鎖非常重要! 你必須手動調(diào)用,通常放在 finally 塊中以確保一定會被執(zhí)行,防止死鎖。
  3. tryLock(): 嘗試獲取鎖。它不會像 lock() 那樣死等。如果能拿到鎖,就返回 true;如果拿不到,就立刻返回 false。這給了你“搶不到就去做別的事”的可能性。
  4. tryLock(long time, TimeUnit unit): 帶超時的嘗試獲取鎖。在指定的時間內(nèi)嘗試獲取鎖,獲取成功則返回 true,超時后還獲取不到則返回 false。這個方法非常實(shí)用,可以避免線程無限期等待。
  5. lockInterruptibly(): 可中斷地獲取鎖。在等待鎖的過程中,線程可以被中斷(調(diào)用 interrupt() 方法)。

4. 最常用的實(shí)現(xiàn)類:ReentrantLock

ReentrantLockLock 接口最主要、最常用的實(shí)現(xiàn)類。它的名字叫“可重入鎖”,意思是同一個線程可以多次獲取同一把鎖而不會把自己鎖死(和 synchronized 一樣)。

基礎(chǔ)使用模板

使用 Lock 有一個固定的“套路”,以確保鎖一定能被釋放:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockExample {
    // 1. 創(chuàng)建一個 Lock 實(shí)例,通常是 ReentrantLock
    private final Lock lock = new ReentrantLock();
    public void safeMethod() {
        // 2. 在操作共享資源前,獲取鎖
        lock.lock();
        try {
            // 3. 在這里執(zhí)行需要線程安全的代碼(臨界區(qū)代碼)
            // ... 比如修改一個共享變量
            System.out.println(Thread.currentThread().getName() + " 拿到了鎖");
        } finally {
            // 4. 在 finally 塊中釋放鎖,確保無論發(fā)生什么異常,鎖都會被釋放
            lock.unlock();
            System.out.println(Thread.currentThread().getName() + " 釋放了鎖");
        }
    }
}

關(guān)鍵點(diǎn): lock.unlock() 一定要放在 finally 塊里!否則如果臨界區(qū)代碼發(fā)生異常,鎖可能永遠(yuǎn)無法釋放,導(dǎo)致其他線程全部“餓死”。

高級用法示例:tryLock

public void tryLockExample() {
    if (lock.tryLock()) { // 嘗試獲取鎖
        try {
            // 成功拿到鎖,執(zhí)行任務(wù)
            System.out.println(Thread.currentThread().getName() + " 成功獲取鎖,執(zhí)行任務(wù)...");
            Thread.sleep(1000); // 模擬任務(wù)執(zhí)行時間
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    } else {
        // 沒拿到鎖,去做別的事情
        System.out.println(Thread.currentThread().getName() + " 獲取鎖失敗,去執(zhí)行其他任務(wù)了...");
    }
}

ReentrantLock基于AQS,AQS有tryAcquire(),所以ReentrantLock有tryLock()嘗試加鎖

5. Lock 的另一個強(qiáng)大功能:條件(Condition)

synchronized 的等待/通知

synchronized 中,我們是這樣讓線程等待和喚醒的:

synchronized (obj) {
    while (條件不滿足) {
        obj.wait();  // 線程等待
    }
    // 執(zhí)行任務(wù)...
}
// 另一個線程中
synchronized (obj) {
    obj.notify();  // 喚醒一個等待的線程
    // 或者 obj.notifyAll(); 喚醒所有等待的線程
}

問題:所有線程都在同一個"等待隊列"里,我們無法精確控制喚醒哪種線程。

Condition 就像"專門的等待室"

想象一個餐廳:

  • synchronized:只有一個大的"等候區(qū)",所有客人都擠在一起
  • Condition:有多個專門的"等候室"
    • notFull:等待"桌子有空位"的生產(chǎn)者等候室
    • notEmpty:等待"有菜可吃"的消費(fèi)者等候室

代碼對比理解

import java.util.concurrent.locks.*;
public class Restaurant {
    private final Lock lock = new ReentrantLock();
    // 創(chuàng)建兩個專門的"等候室"
    private final Condition notFull = lock.newCondition();  // "桌子有空位"等候室
    private final Condition notEmpty = lock.newCondition(); // "有菜可吃"等候室
    private int foodCount = 0;
    private final int MAX_FOOD = 5;
    // 廚師(生產(chǎn)者):做菜
    public void cook() throws InterruptedException {
        lock.lock();
        try {
            while (foodCount == MAX_FOOD) {
                System.out.println("廚房滿了,廚師在notFull等候室等待...");
                notFull.await();  // 如果廚房滿了,就去"桌子有空位"等候室等待
            }
            // 做菜
            foodCount++;
            System.out.println("廚師做了一道菜,現(xiàn)在有 " + foodCount + " 道菜");
            // 通知在"有菜可吃"等候室等待的客人
            notEmpty.signal();
        } finally {
            lock.unlock();
        }
    }
    // 客人(消費(fèi)者):吃菜
    public void eat() throws InterruptedException {
        lock.lock();
        try {
            while (foodCount == 0) {
                System.out.println("沒菜了,客人在notEmpty等候室等待...");
                notEmpty.await();  // 如果沒菜了,就去"有菜可吃"等候室等待
            }
            // 吃菜
            foodCount--;
            System.out.println("客人吃了一道菜,還剩 " + foodCount + " 道菜");
            // 通知在"桌子有空位"等候室等待的廚師
            notFull.signal();
        } finally {
            lock.unlock();
        }
    }
}

synchronized 配合 wait()notify() 可以實(shí)現(xiàn)線程間的等待/通知機(jī)制。Lock 也有對應(yīng)的、但更強(qiáng)大的功能,那就是 Condition。

你可以通過 LocknewCondition() 方法創(chuàng)建一個 Condition 對象。一個 Lock 可以創(chuàng)建多個 Condition,這意味著你可以有多個等待隊列,實(shí)現(xiàn)更精細(xì)的線程控制。

  • await(): 類似 Object.wait(),讓當(dāng)前線程等待。
  • signal(): 類似 Object.notify(),喚醒一個在此 Condition 上等待的線程。
  • signalAll(): 類似 Object.notifyAll(),喚醒所有在此 Condition 上等待的線程。

經(jīng)典場景:生產(chǎn)者-消費(fèi)者模型
你可以創(chuàng)建兩個 Condition:notFull(隊列未滿)和 notEmpty(隊列未空)。

  • 生產(chǎn)者往隊列放東西前,如果隊列滿了,就在 notFull 上等待;放完之后,就喚醒在 notEmpty 上等待的消費(fèi)者。
  • 消費(fèi)者從隊列拿東西前,如果隊列空了,就在 notEmpty 上等待;拿完之后,就喚醒在 notFull 上等待的生產(chǎn)者。

這樣比單一的 wait()/notify() 更清晰,不容易出錯。

6. 公平鎖 vs 非公平鎖

在創(chuàng)建 ReentrantLock 時,可以傳入一個 boolean 參數(shù)來指定是否是公平鎖:

  • new ReentrantLock(true): 公平鎖。線程們按申請鎖的先后順序來獲取鎖,先到先得。
  • new ReentrantLock(false): 非公平鎖(默認(rèn))。允許“插隊”,后申請的線程可能比先申請的線程先拿到鎖。
    AQS先進(jìn)先出的隊列為實(shí)現(xiàn)公平鎖奠定了基礎(chǔ)。ReeentrantLock中有一個FairSync和NonfairSync的子類,他們都重寫了AQS的tryAcquire()方法,F(xiàn)airSync是依賴了AQS的隊列結(jié)構(gòu),實(shí)現(xiàn)了先來先獲取鎖的操作。NonfairSync就允許新線程插隊搶鎖。

優(yōu)缺點(diǎn):

  • 公平鎖:優(yōu)點(diǎn)是不會產(chǎn)生線程饑餓(某個線程永遠(yuǎn)拿不到鎖)。缺點(diǎn)是吞吐量低,性能開銷大。
  • 非公平鎖:優(yōu)點(diǎn)是吞吐率高(減少了線程切換的開銷)。缺點(diǎn)是可能導(dǎo)致線程饑餓。

在絕大多數(shù)情況下,使用默認(rèn)的非公平鎖即可,因為性能更好。

7. 總結(jié):Lock 和 synchronized 如何選擇?

特性synchronizedLock
本質(zhì)Java 語言關(guān)鍵字,內(nèi)置的是一個接口,需要手動實(shí)例化
用法簡單,自動加鎖解鎖靈活,手動控制,需配合 try-finally
可中斷是 (lockInterruptibly)
超時獲取是 (tryLock(long, TimeUnit))
公平性非公平兩者都可選(默認(rèn)非公平)
** Condition **單一多個

選擇建議:

  • 優(yōu)先使用 synchronized:如果你的需求很簡單,用 synchronized 就足夠了。因為它寫起來更簡潔,不容易出錯(不會忘記釋放鎖),并且 JVM 對其有持續(xù)的優(yōu)化。
  • 當(dāng)需要以下高級功能時,才使用 Lock
    • 需要嘗試獲取鎖tryLock)。
    • 需要可中斷的鎖。
    • 需要超時獲取鎖。
    • 需要實(shí)現(xiàn)公平鎖。
    • 需要多個 Condition 來實(shí)現(xiàn)復(fù)雜的線程協(xié)作(比如復(fù)雜的生產(chǎn)者-消費(fèi)者模型)。

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

相關(guān)文章

  • IDEA 去除 mybatis.xml 文件黃色警告的圖文教程

    IDEA 去除 mybatis.xml 文件黃色警告的圖文教程

    這篇文章主要介紹了IDEA 去除 mybatis.xml 文件黃色警告的方法,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-07-07
  • java 單例模式和工廠模式實(shí)例詳解

    java 單例模式和工廠模式實(shí)例詳解

    這篇文章主要介紹了Java設(shè)計模式編程中的單例模式和簡單工廠模式以及實(shí)例,使用設(shè)計模式編寫代碼有利于團(tuán)隊協(xié)作時程序的維護(hù),需要的朋友可以參考下
    2017-04-04
  • Java源碼解析之接口Collection

    Java源碼解析之接口Collection

    Collection是List、Queue和set的超集,它直接繼承于Iterable,也就是說所有的Collection集合類都支持foreach循環(huán).除此之外呢,Collection也是面向接口編程的典范,它可以在多種實(shí)現(xiàn)類間轉(zhuǎn)換,這就是面向?qū)ο缶幊痰膮柡χ?接下來就隨著小編一起去看看吧,需要的朋友可以參考下
    2021-05-05
  • 老生常談java路徑中的反斜杠和斜杠的區(qū)別

    老生常談java路徑中的反斜杠和斜杠的區(qū)別

    下面小編就為大家?guī)硪黄仙U刯ava路徑中的反斜杠和斜杠的區(qū)別。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-04-04
  • 了解java中的Clojure如何抽象并發(fā)性和共享狀態(tài)

    了解java中的Clojure如何抽象并發(fā)性和共享狀態(tài)

    Clojure是一種運(yùn)行在Java平臺上的 Lisp 方言,Lisp是一種以表達(dá)性和功能強(qiáng)大著稱的編程語言,但人們通常認(rèn)為它不太適合應(yīng)用于一般情況,而Clojure的出現(xiàn)徹底改變了這一現(xiàn)狀。,需要的朋友可以參考下
    2019-06-06
  • Vue3源碼解讀effectScope API及實(shí)現(xiàn)原理

    Vue3源碼解讀effectScope API及實(shí)現(xiàn)原理

    這篇文章主要為大家介紹了Vue3源碼解讀effectScope API及實(shí)現(xiàn)原理,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • 使用Spring的StopWatch實(shí)現(xiàn)代碼性能監(jiān)控的方法詳解

    使用Spring的StopWatch實(shí)現(xiàn)代碼性能監(jiān)控的方法詳解

    在開發(fā)過程中,偶爾還是需要分析代碼的執(zhí)行時間,Spring 框架提供了一個方便的工具類 StopWatch,本文將介紹 StopWatch 的基本用法,并通過示例演示如何在項目中使用 StopWatch 進(jìn)行代碼性能監(jiān)控
    2023-12-12
  • 基于Nacos實(shí)現(xiàn)Spring Cloud Gateway實(shí)現(xiàn)動態(tài)路由的方法

    基于Nacos實(shí)現(xiàn)Spring Cloud Gateway實(shí)現(xiàn)動態(tài)路由的方法

    這篇文章主要介紹了基于Nacos實(shí)現(xiàn)Spring Cloud Gateway實(shí)現(xiàn)動態(tài)路由的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • Java多線程輪流打印ABC的四種實(shí)現(xiàn)方式

    Java多線程輪流打印ABC的四種實(shí)現(xiàn)方式

    在Java中實(shí)現(xiàn)多線程輪流打印ABC的操作是一種常見的并發(fā)編程練習(xí),它展示了如何利用多線程提高程序執(zhí)行的效率和并行性,本文將深入探討如何用Java實(shí)現(xiàn)這一任務(wù),需要的朋友可以參考下
    2025-08-08
  • struts2中通過json傳值解決亂碼問題的實(shí)現(xiàn)方法

    struts2中通過json傳值解決亂碼問題的實(shí)現(xiàn)方法

    這篇文章主要介紹了struts2中通過json傳值解決亂碼問題的實(shí)現(xiàn)方法,涉及js編碼及java解碼的相關(guān)操作技巧,需要的朋友可以參考下
    2016-06-06

最新評論

东乌珠穆沁旗| 乌拉特中旗| 蛟河市| 华亭县| 汝阳县| 永登县| 宜春市| 邮箱| 彭州市| 新民市| 扎鲁特旗| 开阳县| 定襄县| 固镇县| 措勤县| 荆州市| 枣庄市| 资溪县| 镇原县| 阿克苏市| 蕲春县| 防城港市| 岱山县| 丽江市| 杭锦旗| 浦北县| 花莲县| 湖口县| 罗田县| 郯城县| 龙南县| 新昌县| 专栏| 邵武市| 前郭尔| 镇坪县| 左权县| 明溪县| 富民县| 昂仁县| 民丰县|