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

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 默認是不公平的

demo演示證明:ReentrantLock 默認是不公平的

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();
                }
            }, "強行插入").start();
        }
        lock.unlock();
    }
}

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

在這里插入圖片描述

5、條件變量

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

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

使用要點:

  • await 前需要獲得鎖
  • await 執(zhí)行后,會釋放鎖,進入 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("準備工作,看看有沒有煙: {}", hasCigrette);
                while (!hasCigrette) {
                    log.debug("準備工作,看看有沒有煙: {}", hasCigrette);
                    try {
                    	// 釋放鎖,并在該條件變量上等待
                        waitCigaretteQueue.await(); 
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                log.debug("等到了它的煙");
            } finally {
                lock.unlock();
            }
        }).start();
        new Thread(() -> {
            try {
                lock.lock();
                log.debug("準備工作,看看有沒有早餐: {}", hasBreakfast);
                while (!hasBreakfast) {
                    log.debug("準備工作,看看有沒有早餐: {}", 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)文章

  • 使用Java實現(xiàn)HTTP和HTTPS代理服務(wù)詳解

    使用Java實現(xiàn)HTTP和HTTPS代理服務(wù)詳解

    這篇文章主要為大家詳細介紹了如何使用Java實現(xiàn)HTTP和HTTPS代理服務(wù),文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-04-04
  • Java編程泛型限定代碼分享

    Java編程泛型限定代碼分享

    這篇文章主要介紹了Java編程泛型限定的相關(guān)內(nèi)容,具有一定參考價值,需要的朋友可以了解下。
    2017-10-10
  • jdk1.8中的for循環(huán)問題記錄

    jdk1.8中的for循環(huán)問題記錄

    這篇文章主要介紹了jdk1.8中的for循環(huán)及jdk1.8 新特性之 forEach 循環(huán)遍歷問題,本文通過實例代碼給大家詳細講解,需要的朋友可以參考下
    2022-11-11
  • Spring Boot CLI安裝教程

    Spring Boot CLI安裝教程

    Spring Boot是一個命令行工具,用于使用Spring進行快速原型搭建。本文重點給大家介紹Spring Boot CLI安裝教程,感興趣的朋友參考下吧
    2017-08-08
  • Java項目實現(xiàn)定時任務(wù)的三種方法

    Java項目實現(xiàn)定時任務(wù)的三種方法

    Java開發(fā)過程中經(jīng)常會遇到使用定時任務(wù)的情況,比如在某個活動結(jié)束時,自動生成獲獎名單,導(dǎo)出excel等,下面這篇文章主要給大家介紹了關(guān)于Java項目實現(xiàn)定時任務(wù)的三種方法,需要的朋友可以參考下
    2022-06-06
  • Java Web實現(xiàn)自動登陸功能

    Java Web實現(xiàn)自動登陸功能

    這篇文章主要為大家詳細介紹了Java Web實現(xiàn)自動登陸功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • Java常見面試題之final在java中的作用是什么

    Java常見面試題之final在java中的作用是什么

    這篇文章主要介紹了Java常見面試題之final在java中的作用是什么,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-01-01
  • 100-200之間所有素數(shù)求和程序代碼(二個版本)

    100-200之間所有素數(shù)求和程序代碼(二個版本)

    寫一個求100-200之間素數(shù),并求和的程序,大家參考使用吧
    2013-11-11
  • SpringBoot使用MyBatis實現(xiàn)數(shù)據(jù)的CRUD

    SpringBoot使用MyBatis實現(xiàn)數(shù)據(jù)的CRUD

    MyBatis是一個輕量級的對象關(guān)系映射(Object-Relational Mapping,ORM)框架,它允許開發(fā)者通過編寫SQL動態(tài)查詢數(shù)據(jù)庫,而無需顯式地操作JDBC,對于增刪改查操作,MyBatis提供了一種基于XML或注解的方式來進行,本文介紹了SpringBoot使用MyBatis實現(xiàn)數(shù)據(jù)的CRUD
    2024-11-11
  • Java 8對LinkedHashSet元素進行排序的操作方法

    Java 8對LinkedHashSet元素進行排序的操作方法

    LinkedHashSet 是 Java 集合框架中的一個類,它繼承自 HashSet,并實現(xiàn)了 Set 接口,然而,LinkedHashSet 不支持元素的排序,它僅僅保持插入順序,所以本文給大家介紹了Java 8 如何對 LinkedHashSet 元素進行排序,需要的朋友可以參考下
    2024-11-11

最新評論

福建省| 临澧县| 米泉市| 紫阳县| 靖安县| 秦安县| 威远县| 盘山县| 苏州市| 平阳县| 秭归县| 桂林市| 宾川县| 达尔| 开鲁县| 栾城县| 巴彦淖尔市| 溧水县| 阿鲁科尔沁旗| 登封市| 灵山县| 安徽省| 吐鲁番市| 遵化市| 成都市| 兴化市| 仁化县| 鄂托克前旗| 长宁区| 乌恰县| 永修县| 曲麻莱县| 龙泉市| 冕宁县| 高密市| 保定市| 越西县| 阿克| 巨野县| 无极县| 宁安市|