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

Java中的可重入鎖ReentrantLock簡析

 更新時間:2023年12月16日 09:23:38   作者:小晨想好好學(xué)習(xí)  
這篇文章主要介紹了Java中的可重入鎖ReentrantLock簡析,可重入是指同一個線程如果首次獲得了這把鎖,那么因為它是這把鎖的擁有者,因此有權(quán)利再次獲取這把鎖如果是不可重入鎖,那么第二次獲得鎖時,自己也會被鎖擋住,需要的朋友可以參考下

可重入鎖ReentrantLock

相對于 synchronized 它具備如下特點

  • 可中斷
  • 可以設(shè)置超時時間
  • 可以設(shè)置為公平鎖
  • 支持多個條件變量
    與 synchronized 一樣,都支持可重入
//基本語法
    // 獲取鎖
    reentrantLock.lock();
    try{
        // 臨界區(qū)
    } finally{
        // 釋放鎖
        reentrantLock.unlock();
    }

1、可重入

可重入是指同一個線程如果首次獲得了這把鎖,那么因為它是這把鎖的擁有者,因此有權(quán)利再次獲取這把鎖 如果是不可重入鎖,那么第二次獲得鎖時,自己也會被鎖擋住

@Slf4j(topic = "c.TestReentrant")
public class TestReentrant {
    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();
        }
    }
}

由結(jié)果可以證明:ReentrantLock 是可重入的

在這里插入圖片描述

2、可打斷

舉例說明:

@Slf4j(topic = "c.TestInterrupt")
public class TestInterrupt {
    public static void main(String[] args) {
        test1();
    }
    private static void test1() {
        ReentrantLock lock = new ReentrantLock();
        Thread t1 = new Thread(() -> {
            log.debug("啟動...");
            try {
                lock.lockInterruptibly();
            } catch (InterruptedException e) {
                e.printStackTrace();
                log.debug("等鎖的過程中被打斷");
                return;
            }
            try {
                log.debug("獲得了鎖");
            } finally {
                lock.unlock();
            }
        }, "t1");
        lock.lock();
        log.debug("獲得了鎖");
        t1.start();
        try {
            sleep(1);
            t1.interrupt();
            log.debug("執(zhí)行打斷");
        } finally {
            lock.unlock();
        }
    }
}

由結(jié)果可以看到,main線程獲取到了鎖,t1線程嘗試去獲取鎖,然后main線程打斷t1線程嘗試獲取鎖的過程

在這里插入圖片描述

注意如果是不可中斷模式,那么即使使用了 interrupt 也不會讓等待中斷

@Slf4j(topic = "c.TestInterrupt")
public class TestInterrupt {
    public static void main(String[] args) {
        test2();
    }
    private static void test2() {
        ReentrantLock lock = new ReentrantLock();
        Thread t1 = new Thread(() -> {
            log.debug("啟動...");
            lock.lock();
            try {
                log.debug("獲得了鎖");
            } finally {
                lock.unlock();
            }
        }, "t1");
        lock.lock();
        log.debug("獲得了鎖");
        t1.start();
        try {
            sleep(1);
            t1.interrupt();
            log.debug("執(zhí)行打斷");
            sleep(1);
        } finally {
            log.debug("釋放了鎖");
            lock.unlock();
        }
    }
}

可以看到t1被主線程打斷后,并沒異常拋出錯誤,而是正常執(zhí)行

在這里插入圖片描述

3、鎖超時

1) 立即失敗的場景

public class TestTimeout {
    public static void main(String[] args) {
        test2();
    }
    private static void test2() {
        ReentrantLock lock = new ReentrantLock();
        Thread t1 = new Thread(() -> {
            log.debug("啟動...");
            if (!lock.tryLock()) {
                 log.debug("獲取立刻失敗,返回");
                return;
            }
            try {
                log.debug("獲得了鎖");
            } finally {
                lock.unlock();
            }
        }, "t1");
        lock.lock();
        log.debug("獲得了鎖");
        t1.start();
        try {
            sleep(2);
        } finally {
            lock.unlock();
        }
    }
}

main線程首先獲取到了鎖,t1線程嘗試去獲取鎖的時候就會立即失敗

在這里插入圖片描述

2)超時失敗

public class TestTimeout {
    public static void main(String[] args) {
        test1();
    }
    private static void test1() {
        ReentrantLock lock = new ReentrantLock();
        Thread t1 = new Thread(() -> {
            log.debug("啟動...");
            try {
                if (!lock.tryLock(1, TimeUnit.SECONDS)) {
                    log.debug("獲取等待 1s 后失敗,返回");
                    return;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            try {
                log.debug("獲得了鎖");
            } finally {
                lock.unlock();
            }
        }, "t1");
        lock.lock();
        log.debug("獲得了鎖");
        t1.start();
        try {
            sleep(2);
        } finally {
            lock.unlock();
        }
    }
}

由結(jié)果可以判斷t1線程在嘗試獲取鎖時,阻塞了一秒鐘,一秒后還是沒有獲取到鎖,則返回false

在這里插入圖片描述

4、公平鎖

公平鎖是指多個線程按照申請鎖的順序來獲取鎖,ReentrantLock 默認(rèn)是不公平的

demo演示證明:ReentrantLock 默認(rèn)是不公平的

public class TestFair {
    public static void main(String[] args) throws InterruptedException {
        ReentrantLock lock = new ReentrantLock(false);
        lock.lock();
        for (int i = 0; i < 20; i++) {
            new Thread(() -> {
                lock.lock();
                try {
                    System.out.println(Thread.currentThread().getName() + " running...");
                } finally {
                    lock.unlock();
                }
            }, "t" + i).start();
        }
// 1s 之后去爭搶鎖
        Thread.sleep(1000);
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                lock.lock();
                try {
                    System.out.println(Thread.currentThread().getName() + " running...");
                } finally {
                    lock.unlock();
                }
            }, "強(qiáng)行插入").start();
        }
        lock.unlock();
    }
}

按道理說,500個線程是先啟動的,應(yīng)該先獲取到鎖,但是實際情況,強(qiáng)制插入線程中途就獲取到鎖了

在這里插入圖片描述

5、條件變量

synchronized 中也有條件變量,就是我們講原理時那個 waitSet 休息室,當(dāng)條件不滿足時進(jìn)入 waitSet 等待 ReentrantLock 的條件變量比 synchronized 強(qiáng)大之處在于,它是支持多個條件變量的,這就好比

  • synchronized 是那些不滿足條件的線程都在一間休息室等消息
  • 而 ReentrantLock 支持多間休息室,有專門等煙的休息室、專門等早餐的休息室、喚醒時也是按休息室來喚醒

使用要點:

  • await 前需要獲得鎖
  • await 執(zhí)行后,會釋放鎖,進(jìn)入 conditionObject 等待
  • await 的線程被喚醒(或打斷、或超時)取重新競爭 lock 鎖
  • 競爭 lock 鎖成功后,從 await 后繼續(xù)執(zhí)行
@Slf4j(topic = "c.TestCondition")
public class TestCondition {
    static ReentrantLock lock = new ReentrantLock();
    static Condition waitCigaretteQueue = lock.newCondition();
    static Condition waitbreakfastQueue = lock.newCondition();
    static volatile boolean hasCigrette = false;
    static volatile boolean hasBreakfast = false;
    public static void main(String[] args) {
        new Thread(() -> {
            try {
                lock.lock();
                log.debug("準(zhǔn)備工作,看看有沒有煙: {}", hasCigrette);
                while (!hasCigrette) {
                    log.debug("準(zhǔn)備工作,看看有沒有煙: {}", hasCigrette);
                    try {
                    	// 釋放鎖,并在該條件變量上等待
                        waitCigaretteQueue.await(); 
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                log.debug("等到了它的煙");
            } finally {
                lock.unlock();
            }
        }).start();
        new Thread(() -> {
            try {
                lock.lock();
                log.debug("準(zhǔn)備工作,看看有沒有早餐: {}", hasBreakfast);
                while (!hasBreakfast) {
                    log.debug("準(zhǔn)備工作,看看有沒有早餐: {}", hasBreakfast);
                    try {
                        waitbreakfastQueue.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                log.debug("等到了它的早餐");
            } finally {
                lock.unlock();
            }
        }).start();
        sleep(1);
        sendBreakfast();
        sleep(1);
        sendCigarette();
    }
    private static void sendCigarette() {
        lock.lock();
        try {
            log.debug("送煙來了");
            hasCigrette = true;
            waitCigaretteQueue.signal();
        } finally {
            lock.unlock();
        }
    }
    private static void sendBreakfast() {
        lock.lock();
        try {
            log.debug("送早餐來了");
            hasBreakfast = true;
            waitbreakfastQueue.signal();
        } finally {
            lock.unlock();
        }
    }
}

在這里插入圖片描述

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

相關(guān)文章

  • mybatis使用foreach語句實現(xiàn)IN查詢(三種)

    mybatis使用foreach語句實現(xiàn)IN查詢(三種)

    這篇文章主要介紹了mybatis使用foreach語句實現(xiàn)IN查詢(三種),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • Java裝飾者模式的深入了解

    Java裝飾者模式的深入了解

    這篇文章主要為大家介紹了Java裝飾者模式,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-01-01
  • MyBatis動態(tài)sql查詢及多參數(shù)查詢方式

    MyBatis動態(tài)sql查詢及多參數(shù)查詢方式

    這篇文章主要介紹了MyBatis動態(tài)sql查詢及多參數(shù)查詢方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • springcloud本地調(diào)試feign調(diào)用出現(xiàn)的詭異404問題及解決

    springcloud本地調(diào)試feign調(diào)用出現(xiàn)的詭異404問題及解決

    這篇文章主要介紹了springcloud本地調(diào)試feign調(diào)用出現(xiàn)的詭異404問題及解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Java將CSV的數(shù)據(jù)發(fā)送到kafka的示例

    Java將CSV的數(shù)據(jù)發(fā)送到kafka的示例

    這篇文章主要介紹了Java將CSV的數(shù)據(jù)發(fā)送到kafka得示例,幫助大家更好得理解和使用Java,感興趣的朋友可以了解下
    2020-11-11
  • SpringBoot中@ComponentScan注解過濾排除不加載某個類的3種方法

    SpringBoot中@ComponentScan注解過濾排除不加載某個類的3種方法

    這篇文章主要給大家介紹了關(guān)于SpringBoot中@ComponentScan注解過濾排除不加載某個類的3種方法,文中通過實例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用SpringBoot具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2023-07-07
  • EasyExcel實現(xiàn)讀取excel中的日期單元格并自動判定終止讀取

    EasyExcel實現(xiàn)讀取excel中的日期單元格并自動判定終止讀取

    這篇文章主要為大家詳細(xì)介紹了EasyExcel如何實現(xiàn)讀取excel中的日期單元格并自動判定終止讀取,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-11-11
  • Java中的List集合初始化及常見方法解析

    Java中的List集合初始化及常見方法解析

    這篇文章主要介紹了Java中的List集合初始化及常見方法解析,List集合的特點是元素有序可重復(fù),只要是帶集合、數(shù)組的都叫有序,因若無序就不會存在有下標(biāo),本文來講一下List集合初始化及常見方法,需要的朋友可以參考下
    2023-10-10
  • Java中使用opencv的問題

    Java中使用opencv的問題

    這篇文章主要介紹了Java中使用opencv的問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • Java讀寫ini文件代碼示例

    Java讀寫ini文件代碼示例

    這篇文章主要介紹了Java讀寫ini文件代碼示例,分享了相關(guān)代碼示例及相關(guān)注釋,小編覺得還是挺不錯的,具有一定借鑒價值,需要的朋友可以參考下
    2018-02-02

最新評論