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

java?ReentrantLock并發(fā)鎖使用詳解

 更新時間:2022年10月12日 17:09:21   作者:Jony_zhang  
這篇文章主要為大家介紹了java?ReentrantLock并發(fā)鎖使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

一、ReentrantLock是什么

ReentrantLock是一種基于AQS框架的應(yīng)用實(shí)現(xiàn),是JDK中的一種線程并發(fā)訪問的同步手段,它的功能類似于synchronized是一種互斥鎖,可以保證線程安全。

相對于 synchronized, ReentrantLock具備如下特點(diǎn):

  • 可中斷
  • 可以設(shè)置超時時間
  • 可以設(shè)置為公平鎖
  • 支持多個條件變量
  • 與 synchronized 一樣,都支持可重入

進(jìn)入源碼可以看到,其實(shí)現(xiàn)了公平鎖和非公平鎖

內(nèi)部實(shí)現(xiàn)了加鎖的操作,并且支持重入鎖。不用我們再重寫

解鎖操作

1-1、ReentrantLock和synchronized區(qū)別

synchronized和ReentrantLock的區(qū)別:

  • synchronized是JVM層次的鎖實(shí)現(xiàn),ReentrantLock是JDK層次的鎖實(shí)現(xiàn);
  • synchronized的鎖狀態(tài)是無法在代碼中直接判斷的,但是ReentrantLock可以通過ReentrantLock#isLocked判斷;
  • synchronized是非公平鎖,ReentrantLock是可以是公平也可以是非公平的;
  • synchronized是不可以被中斷的,而ReentrantLock#lockInterruptibly方法是可以被中斷的;
  • 在發(fā)生異常時synchronized會自動釋放鎖,而ReentrantLock需要開發(fā)者在finally塊中顯示釋放鎖;
  • ReentrantLock獲取鎖的形式有多種:如立即返回是否成功的tryLock(),以及等待指定時長的獲取,更加靈活;
  • synchronized在特定的情況下對于已經(jīng)在等待的線程是后來的線程先獲得鎖(回顧一下sychronized的喚醒策略),而ReentrantLock對于已經(jīng)在等待的線程是先來的線程先獲得鎖;

1-2、ReentrantLock的使用

1-2-1、ReentrantLock同步執(zhí)行,類似synchronized

使用ReentrantLock需要注意的是:一定要在finally中進(jìn)行解鎖,方式業(yè)務(wù)拋出異常,無法解鎖

public class ReentrantLockDemo {
    private static  int sum = 0;
    private static ReentrantLock lock=new ReentrantLock();
    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 3; i++) {
            Thread thread = new Thread(()->{
                //加鎖
                lock.lock();
                try {
                    // 臨界區(qū)代碼
                    // TODO 業(yè)務(wù)邏輯:讀寫操作不能保證線程安全
                    for (int j = 0; j < 10000; j++) {
                        sum++;
                    }
                } finally {
                    // 解鎖--一定要在finally中解鎖,防止業(yè)務(wù)代碼異常,無法釋放鎖
                    lock.unlock();
                }
            });
            thread.start();
        }
        Thread.sleep(2000);
        System.out.println(sum);
    }
}

測試結(jié)果:

1-2-2、可重入鎖

可重入鎖就是 A(加鎖)-->調(diào)用--->B(加鎖)-->調(diào)用-->C(加鎖),從A到C即使B/C都有加鎖,也可以進(jìn)入

@Slf4j
public class ReentrantLockDemo2 {
    public static ReentrantLock lock = new ReentrantLock();
    public static void main(String[] args) {
        method1();
    }
    public static void method1() {
        lock.lock();
        try {
            log.debug("execute method1");
            method2();
        } finally {
            lock.unlock();
        }
    }
    public static void method2() {
        lock.lock();
        try {
            log.debug("execute method2");
            method3();
        } finally {
            lock.unlock();
        }
    }
    public static void method3() {
        lock.lock();
        try {
            log.debug("execute method3");
        } finally {
            lock.unlock();
        }
    }
}

執(zhí)行結(jié)果:

1-2-3、鎖中斷

可以使用lockInterruptibly來進(jìn)行鎖中斷

lockInterruptibly()方法能夠中斷等待獲取鎖的線程。當(dāng)兩個線程同時通過lock.lockInterruptibly()獲取某個鎖時,假若此時線程A獲取到了鎖,而線程B只有等待,那么對線程B調(diào)用threadB.interrupt()方法能夠中斷線程B的等待過程。

public class ReentrantLockDemo3 {
    public static void main(String[] args) {
        ReentrantLock lock = new ReentrantLock();
        Thread t1 = new Thread(() -> {
            log.debug("t1啟動...");
            try {
                lock.lockInterruptibly();
                try {
                    log.debug("t1獲得了鎖");
                } finally {
                    lock.unlock();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
                log.debug("t1等鎖的過程中被中斷");
            }
        }, "t1");
        lock.lock();
        try {
            log.debug("main線程獲得了鎖");
            t1.start();
            //先讓線程t1執(zhí)行
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            t1.interrupt();
            log.debug("線程t1執(zhí)行中斷");
        } finally {
            lock.unlock();
        }
    }
}

執(zhí)行結(jié)果:

1-2-4、獲得鎖超時失敗

可以讓線程等待指定的時間,如果還未獲取鎖則進(jìn)行失敗處理。

如下代碼,首先讓主線程獲得鎖,然后讓子線程啟動嘗試獲取鎖,但是由于主線程獲取鎖之后,讓線程等待了2秒,而子線程獲得鎖的超時時間只有1秒,如果未獲得鎖,則進(jìn)行return失敗處理

public class ReentrantLockDemo4 {
    public static void main(String[] args) {
        ReentrantLock lock = new ReentrantLock();
        Thread t1 = new Thread(() -> {
            log.debug("t1啟動...");
            //超時
            try {
                if (!lock.tryLock(1, TimeUnit.SECONDS)) {
                    log.debug("等待 1s 后獲取鎖失敗,返回");
                    return;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
                return;
            }
            try {
                log.debug("t1獲得了鎖");
            } finally {
                lock.unlock();
            }
        }, "t1");
        lock.lock();
        try {
            log.debug("main線程獲得了鎖");
            t1.start();
            //先讓線程t1執(zhí)行
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } finally {
            lock.unlock();
        }
    }
}

執(zhí)行結(jié)果:

1-2-5、公平鎖

ReentrantLock 默認(rèn)是不公平的

首先啟動500次for循環(huán)創(chuàng)建500個線程,然后進(jìn)行加鎖操作,并同時啟動了。這樣這500個線程就依次排隊(duì)等待加鎖的處理

下面500個線程也是等待加鎖操作

如果使用公平鎖,下面500的線程只有等上面500個線程運(yùn)行完成之后才能獲得鎖。

@Slf4j
public class ReentrantLockDemo5 {
    public static void main(String[] args) throws InterruptedException {
        ReentrantLock lock = new ReentrantLock(true); //公平鎖
        for (int i = 0; i < 500; i++) {
            new Thread(() -> {
                lock.lock();
                try {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    log.debug(Thread.currentThread().getName() + " running...");
                } finally {
                    lock.unlock();
                }
            }, "t" + i).start();
        }
        // 1s 之后去爭搶鎖
        Thread.sleep(1000);
        for (int i = 0; i < 500; i++) {
            new Thread(() -> {
                lock.lock();
                try {
                    log.debug(Thread.currentThread().getName() + " running...");
                } finally {
                    lock.unlock();
                }
            }, "強(qiáng)行插入" + i).start();
        }
    }
}

測試結(jié)果(后進(jìn)入的線程都在等待排隊(duì))

使用非公平鎖的情況下,就可以看到下面500線程有些線程就可以搶占鎖了

那ReentrantLock為什么默認(rèn)使用非公平鎖呢?實(shí)際上就是為了提高性能,如果使用公平鎖,當(dāng)前鎖對象釋放之后,還需要去隊(duì)列中獲取第一個排隊(duì)的線程,然后進(jìn)行加鎖處理。而非公平鎖,可能再當(dāng)前對象釋放鎖之后,正好有新的線程在獲取鎖,這樣就可以直接進(jìn)行加鎖操作,不必再去隊(duì)列中讀取。

以上就是java ReentrantLock并發(fā)鎖使用詳解的詳細(xì)內(nèi)容,更多關(guān)于java ReentrantLock并發(fā)鎖的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • JavaGUI界面實(shí)現(xiàn)頁面跳轉(zhuǎn)方法

    JavaGUI界面實(shí)現(xiàn)頁面跳轉(zhuǎn)方法

    這篇文章主要給大家介紹了關(guān)于JavaGUI界面實(shí)現(xiàn)頁面跳轉(zhuǎn)的相關(guān)資料, GUI是指圖形用戶界面,指采用圖形方式顯示的計(jì)算機(jī)操作用戶界面,需要的朋友可以參考下
    2023-07-07
  • 在java中使用SPI創(chuàng)建可擴(kuò)展的應(yīng)用程序操作

    在java中使用SPI創(chuàng)建可擴(kuò)展的應(yīng)用程序操作

    這篇文章主要介紹了在java中使用SPI創(chuàng)建可擴(kuò)展的應(yīng)用程序操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • Java字符串轉(zhuǎn)成二進(jìn)制碼的方法

    Java字符串轉(zhuǎn)成二進(jìn)制碼的方法

    這篇文章主要為大家詳細(xì)介紹了Java字符串轉(zhuǎn)成二進(jìn)制碼的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一
    2017-05-05
  • java實(shí)現(xiàn)gif動畫效果(java顯示動態(tài)圖片)

    java實(shí)現(xiàn)gif動畫效果(java顯示動態(tài)圖片)

    這篇文章主要介紹了java實(shí)現(xiàn)gif動畫效果示例(java顯示動態(tài)圖片),需要的朋友可以參考下
    2014-04-04
  • SpringBoot之webflux全面解析

    SpringBoot之webflux全面解析

    這篇文章主要介紹了SpringBoot之webflux全面解析,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • 基于SpringCloud手寫一個簡易版Sentinel

    基于SpringCloud手寫一個簡易版Sentinel

    SpringCloud Alibaba Sentinel是當(dāng)前最為流行一種熔斷降級框架,簡單易用的方式可以快速幫助我們實(shí)現(xiàn)服務(wù)的限流和降級,保證服務(wù)的穩(wěn)定性。
    2021-05-05
  • springBoot?啟動指定配置文件環(huán)境多種方案(最新推薦)

    springBoot?啟動指定配置文件環(huán)境多種方案(最新推薦)

    springBoot?啟動指定配置文件環(huán)境理論上是有多種方案的,一般都是結(jié)合我們的實(shí)際業(yè)務(wù)選擇不同的方案,比如,有pom.xml文件指定、maven命令行指定、配置文件指定、啟動jar包時指定等方案,今天我們一一分享一下,需要的朋友可以參考下
    2023-09-09
  • SpringBoot整合POI實(shí)現(xiàn)Excel文件讀寫操作

    SpringBoot整合POI實(shí)現(xiàn)Excel文件讀寫操作

    EasyExcel是一個基于Java的、快速、簡潔、解決大文件內(nèi)存溢出的Excel處理工具,這篇文章主要介紹了SpringBoot整合POI實(shí)現(xiàn)Excel文件讀寫操作,首先準(zhǔn)備環(huán)境進(jìn)行一系列操作,本文給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2023-10-10
  • Spring?AI聊天功能開發(fā)步驟

    Spring?AI聊天功能開發(fā)步驟

    本文給大家介紹Spring?AI聊天功能開發(fā)步驟,首先引入依賴,繼承父版本的springboot依賴,最好是比較新的依賴,結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2024-04-04
  • 什么是Spring Boot

    什么是Spring Boot

    Spring是一個非常受歡迎的Java框架,它用于構(gòu)建web和企業(yè)應(yīng)用。本文介紹將各種Spring的配置方式,幫助您了解配置Spring應(yīng)用的復(fù)雜性
    2017-08-08

最新評論