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

Java中ReentrantLock4種常見的坑

 更新時間:2022年05月20日 08:49:53   作者:??Java中文社群????  
本文主要介紹了Java中ReentrantLock?4種常見的坑,ReentrantLock默認情況下為非公平鎖,下文關(guān)于其更多詳情需要的小伙伴可以參考一下

前言

JDK 1.5 之前 synchronized 的性能是比較低的,但在 JDK 1.5 中,官方推出一個重量級功能 Lock,一舉改變了 Java 中鎖的格局。JDK 1.5 之前當(dāng)我們談到鎖時,只能使用內(nèi)置鎖 synchronized,但如今我們鎖的實現(xiàn)又多了一種顯式鎖 Lock。

前面的文章我們已經(jīng)介紹了 synchronized,詳見以下列表:

淺談synchronized加鎖this和class的區(qū)別

Java中的synchronized 優(yōu)化方法之鎖膨脹機制

Java中synchronized 的4個優(yōu)化技巧

所以本文咱們重點來看 Lock。

Lock 簡介

Lock 是一個頂級接口,它的所有方法如下圖所示: 

 它的子類列表如下: 

 我們通常會使用 ReentrantLock 來定義其實例,它們之間的關(guān)聯(lián)如下圖所示:

PS:Sync 是同步鎖的意思,F(xiàn)airSync 是公平鎖,NonfairSync 是非公平鎖。

ReentrantLock 使用

學(xué)習(xí)任何一項技能都是先從使用開始的,所以我們也不例外,咱們先來看下 ReentrantLock 的基礎(chǔ)使用:

public class LockExample {
    // 創(chuàng)建鎖對象
    private final ReentrantLock lock = new ReentrantLock();
    public void method() {
        // 加鎖操作
        lock.lock();
        try {
            // 業(yè)務(wù)代碼......
        } finally {
            // 釋放鎖
            lock.unlock();
        }
    }
}

ReentrantLock 在創(chuàng)建之后,有兩個關(guān)鍵性的操作:

  • 加鎖操作:lock()
  • 釋放鎖操作:unlock()

ReentrantLock 中的坑

1.ReentrantLock 默認為非公平鎖

很多人會認為(尤其是新手朋友),ReentrantLock 默認的實現(xiàn)是公平鎖,其實并非如此,ReentrantLock 默認情況下為非公平鎖(這主要是出于性能方面的考慮),

比如下面這段代碼:

import java.util.concurrent.locks.ReentrantLock;
public class LockExample {
    // 創(chuàng)建鎖對象
    private static final ReentrantLock lock = new ReentrantLock();
    public static void main(String[] args) {
        // 定義線程任務(wù)
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                // 加鎖
                lock.lock();
                try {
                    // 打印執(zhí)行線程的名字
                    System.out.println("線程:" + Thread.currentThread().getName());
                } finally {
                    // 釋放鎖
                    lock.unlock();
                }
            }
        };
        // 創(chuàng)建多個線程
        for (int i = 0; i < 10; i++) {
            new Thread(runnable).start();
        }
    }
}

以上程序的執(zhí)行結(jié)果如下: 

 從上述執(zhí)行的結(jié)果可以看出,ReentrantLock 默認情況下為非公平鎖。因為線程的名稱是根據(jù)創(chuàng)建的先后順序遞增的,所以如果是公平鎖,那么線程的執(zhí)行應(yīng)該是有序遞增的,但從上述的結(jié)果可以看出,線程的執(zhí)行和打印是無序的,這說明 ReentrantLock 默認情況下為非公平鎖。

想要將 ReentrantLock 設(shè)置為公平鎖也很簡單,只需要在創(chuàng)建 ReentrantLock 時,設(shè)置一個 true 的構(gòu)造參數(shù)就可以了,如下代碼所示:

import java.util.concurrent.locks.ReentrantLock;
public class LockExample {
    // 創(chuàng)建鎖對象(公平鎖)
    private static final ReentrantLock lock = new ReentrantLock(true);
    public static void main(String[] args) {
        // 定義線程任務(wù)
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                // 加鎖
                lock.lock();
                try {
                    // 打印執(zhí)行線程的名字
                    System.out.println("線程:" + Thread.currentThread().getName());
                } finally {
                    // 釋放鎖
                    lock.unlock();
                }
            }
        };
        // 創(chuàng)建多個線程
        for (int i = 0; i < 10; i++) {
            new Thread(runnable).start();
        }
    }
}

以上程序的執(zhí)行結(jié)果如下: 

從上述結(jié)果可以看出,當(dāng)我們顯式的給 ReentrantLock 設(shè)置了 true 的構(gòu)造參數(shù)之后,ReentrantLock 就變成了公平鎖,線程獲取鎖的順序也變成有序的了。

其實從 ReentrantLock 的源碼我們也可以看出它究竟是公平鎖還是非公平鎖,ReentrantLock 部分源碼實現(xiàn)如下:

 public ReentrantLock() {
     sync = new NonfairSync();
 }
public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

從上述源碼中可以看出,默認情況下 ReentrantLock 會創(chuàng)建一個非公平鎖,如果在創(chuàng)建時顯式的設(shè)置構(gòu)造參數(shù)的值為 true 時,它就會創(chuàng)建一個公平鎖。

2.在 finally 中釋放鎖

使用 ReentrantLock 時一定要記得釋放鎖,否則就會導(dǎo)致該鎖一直被占用,其他使用該鎖的線程則會永久的等待下去,所以我們在使用 ReentrantLock 時,一定要在 finally 中釋放鎖,這樣就可以保證鎖一定會被釋放。

反例

import java.util.concurrent.locks.ReentrantLock;
public class LockExample {
    // 創(chuàng)建鎖對象
    private static final ReentrantLock lock = new ReentrantLock();
    public static void main(String[] args) {
        // 加鎖操作
        lock.lock();
        System.out.println("Hello,ReentrantLock.");
        // 此處會報異常,導(dǎo)致鎖不能正常釋放
        int number = 1 / 0;
        // 釋放鎖
        lock.unlock();
        System.out.println("鎖釋放成功!");
    }
}

以上程序的執(zhí)行結(jié)果如下: 

 從上述結(jié)果可以看出,當(dāng)出現(xiàn)異常時鎖未被正常釋放,這樣就會導(dǎo)致其他使用該鎖的線程永久的處于等待狀態(tài)。

正例

import java.util.concurrent.locks.ReentrantLock;
public class LockExample {
    // 創(chuàng)建鎖對象
    private static final ReentrantLock lock = new ReentrantLock();
    public static void main(String[] args) {
        // 加鎖操作
        lock.lock();
        try {
            System.out.println("Hello,ReentrantLock.");
            // 此處會報異常
            int number = 1 / 0;
        } finally {
            // 釋放鎖
            lock.unlock();
            System.out.println("鎖釋放成功!");
        }
    }
}

以上程序的執(zhí)行結(jié)果如下: 

 從上述結(jié)果可以看出,雖然方法中出現(xiàn)了異常情況,但并不影響 ReentrantLock 鎖的釋放操作,這樣其他使用此鎖的線程就可以正常獲取并運行了。

3.鎖不能被釋放多次

lock 操作的次數(shù)和 unlock 操作的次數(shù)必須一一對應(yīng),且不能出現(xiàn)一個鎖被釋放多次的情況,因為這樣就會導(dǎo)致程序報錯。

反例

一次 lock 對應(yīng)了兩次 unlock 操作,導(dǎo)致程序報錯并終止執(zhí)行,示例代碼如下:

import java.util.concurrent.locks.ReentrantLock;
public class LockExample {
    // 創(chuàng)建鎖對象
    private static final ReentrantLock lock = new ReentrantLock();
    public static void main(String[] args) {
        // 加鎖操作
        lock.lock();

        // 第一次釋放鎖
        try {
            System.out.println("執(zhí)行業(yè)務(wù) 1~");
            // 業(yè)務(wù)代碼 1......
        } finally {
            // 釋放鎖
            lock.unlock();
            System.out.println("鎖釋鎖");
        }

        // 第二次釋放鎖
        try {
            System.out.println("執(zhí)行業(yè)務(wù) 2~");
            // 業(yè)務(wù)代碼 2......
        } finally {
            // 釋放鎖
            lock.unlock();
            System.out.println("鎖釋鎖");
        }
        // 最后的打印操作
        System.out.println("程序執(zhí)行完成.");
    }
}

以上程序的執(zhí)行結(jié)果如下: 

 從上述結(jié)果可以看出,執(zhí)行第 2 個 unlock 時,程序報錯并終止執(zhí)行了,導(dǎo)致異常之后的代碼都未正常執(zhí)行。

4.lock 不要放在 try 代碼內(nèi)

在使用 ReentrantLock 時,需要注意不要將加鎖操作放在 try 代碼中,這樣會導(dǎo)致未加鎖成功就執(zhí)行了釋放鎖的操作,從而導(dǎo)致程序執(zhí)行異常。

反例

import java.util.concurrent.locks.ReentrantLock;
public class LockExample {
    // 創(chuàng)建鎖對象
    private static final ReentrantLock lock = new ReentrantLock();
    public static void main(String[] args) {
        try {
            // 此處異常
            int num = 1 / 0;
            // 加鎖操作
            lock.lock();
        } finally {
            // 釋放鎖
            lock.unlock();
            System.out.println("鎖釋鎖");
        }
        System.out.println("程序執(zhí)行完成.");
    }
}

以上程序的執(zhí)行結(jié)果如下: 

 從上述結(jié)果可以看出,如果將加鎖操作放在 try 代碼中,可能會導(dǎo)致兩個問題:

  • 未加鎖成功就執(zhí)行了釋放鎖的操作,從而導(dǎo)致了新的異常;
  • 釋放鎖的異常會覆蓋程序原有的異常,從而增加了排查問題的難度。

總結(jié)

本文介紹了 Java 中的顯式鎖 Lock 及其子類 ReentrantLock 的使用和注意事項,Lock 在 Java 中占據(jù)了鎖的半壁江山,但在使用時卻要注意 4 個問題:

  • 默認情況下 ReentrantLock 為非公平鎖而非公平鎖;
  • 加鎖次數(shù)和釋放鎖次數(shù)一定要保持一致,否則會導(dǎo)致線程阻塞或程序異常;
  • 加鎖操作一定要放在 try 代碼之前,這樣可以避免未加鎖成功又釋放鎖的異常;
  • 釋放鎖一定要放在 finally 中,否則會導(dǎo)致線程阻塞。

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

相關(guān)文章

  • java 實現(xiàn)定時的方法及實例代碼

    java 實現(xiàn)定時的方法及實例代碼

    這篇文章主要介紹了java 定時任務(wù)詳細介紹及實例代碼的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • Springboot消除switch-case過程解析

    Springboot消除switch-case過程解析

    這篇文章主要介紹了Springboot消除switch-case過程解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-10-10
  • 大話Java混合運算規(guī)則

    大話Java混合運算規(guī)則

    這篇文章主要介紹了大話Java混合運算規(guī)則,小編覺得挺不錯的,在這里分享給大家,需要的朋友可以了解下。
    2017-10-10
  • 推薦一款I(lǐng)ntelliJ IDEA提示快捷鍵的Key Promoter X插件

    推薦一款I(lǐng)ntelliJ IDEA提示快捷鍵的Key Promoter X插件

    今天小編就為大家分享一篇關(guān)于IntelliJ IDEA提示快捷鍵的Key Promoter X插件,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-10-10
  • 詳解Javascript判斷Crontab表達式是否合法

    詳解Javascript判斷Crontab表達式是否合法

    這篇文章主要介紹了詳解Javascript判斷Crontab表達式是否合法的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • 關(guān)于java入門與java開發(fā)環(huán)境配置詳細教程

    關(guān)于java入門與java開發(fā)環(huán)境配置詳細教程

    這篇文章主要介紹了關(guān)于java入門與java開發(fā)環(huán)境配置詳細教程,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-03-03
  • Java 字符串連接的性能問題分析

    Java 字符串連接的性能問題分析

    這篇文章主要介紹了Java 字符串連接的性能問題分析的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • 使用springboot每日推送早安問候語到用戶微信的全過程

    使用springboot每日推送早安問候語到用戶微信的全過程

    近期網(wǎng)上又出現(xiàn)一股給女朋友做微信公眾號推送的潮流,所以這篇文章主要給大家介紹了關(guān)于如何使用springboot每日推送早安問候語到用戶微信的相關(guān)資料,文中通過圖文以及實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-11-11
  • 從Spring遷移到Spring Boot的方法步驟

    從Spring遷移到Spring Boot的方法步驟

    這篇文章主要介紹了從Spring遷移到Spring Boot的方法步驟,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • java實現(xiàn)圖片上插入文字并保存

    java實現(xiàn)圖片上插入文字并保存

    這篇文章主要為大家詳細介紹了java實現(xiàn)圖片上插入文字并保存,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-06-06

最新評論

永仁县| 玉田县| 白城市| 光山县| 三台县| 定州市| 高雄市| 绩溪县| 泸定县| 晋城| 武夷山市| 鹿邑县| 霍林郭勒市| 鹤庆县| 娱乐| 合水县| 望谟县| 无极县| 黔东| 喀喇沁旗| 丁青县| 奇台县| 淳化县| 遂川县| 辽阳县| 谢通门县| 长汀县| 呈贡县| 丰顺县| 邯郸市| 济宁市| 酒泉市| 伊吾县| 海南省| 阜城县| 农安县| 乐昌市| 中卫市| 登封市| 柳河县| 新巴尔虎左旗|