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

Java并發(fā)編程之ReentrantLock可重入鎖的實例代碼

 更新時間:2021年02月06日 14:21:04   作者:Java硬件工程師  
這篇文章主要介紹了Java并發(fā)編程之ReentrantLock可重入鎖的實例代碼,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

目錄 1.ReentrantLock可重入鎖概述2.可重入3.可打斷4.鎖超時5.公平鎖6.條件變量 Condition

1.ReentrantLock可重入鎖概述

相對于 synchronized 它具備如下特點
可中斷
synchronized鎖加上去不能中斷,a線程應用鎖,b線程不能取消掉它
可以設置超時時間
synchronized它去獲取鎖時,如果對方持有鎖,那么它就會進入entryList一直等待下去。而可重入鎖可以設置超時時間,規(guī)定時間內如果獲取不到鎖,就放棄鎖
可以設置為公平鎖
防止線程饑餓的情況,即先到先得。如果爭搶的人比較多,則可能會發(fā)生永遠都得不到鎖

支持多個條件變量多個waitset(不支持條件一的去a不支持條件二的去b)
synchronized只支持同一個waitset.
與 synchronized 一樣,都支持可重入

基本語法

// 獲取鎖
reentrantLock.lock();
try {
 // 臨界區(qū)
} finally {
 // 釋放鎖
 reentrantLock.unlock();
}

synchronized是在關鍵字的級別來保護臨界區(qū),而reentrantLock是在對象的級別保護臨界區(qū)。臨界區(qū)即訪問共享資源的那段代碼。finally中表明不管將來是否出現(xiàn)異常,都會釋放鎖,釋放鎖即調用unlock方法。否則無法釋放鎖,其它線程就永遠也獲取不了鎖。

2.可重入

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

public class TestReentranLock1 {
 static ReentrantLock lock = new ReentrantLock();
 public static void main(String[] args) {
  method1();
 }
 public static void method1() {
  lock.lock();
  try {
   System.out.println("execute method1");
   method2();
  } finally {
   lock.unlock();
  }
 }
 public static void method2() {
  lock.lock();
  try {
   System.out.println("execute method2");
   method3();
  } finally {
   lock.unlock();
  }
 }
 public static void method3() {
  lock.lock();
  try {
   System.out.println("execute method3");
  } finally {
   lock.unlock();
  }
 }
}
execute method1
execute method2
execute method3

3.可打斷

可打斷是指在等待鎖的過程中,其它線程可以用interrupt方法終止我的等待。synchronized鎖是不可打斷的。
我們要想在等鎖的過程中被打斷,就要使用lockInterruptibly()方法對lock對象加鎖,而不是lock()方法

public class TestReentranLock2 {
 public static void main(String[] args) {
  ReentrantLock lock = new ReentrantLock();
  Thread t1 = new Thread(() -> {
   try {
    //如果沒有競爭,此方法就會獲取lock對象的鎖
    //如果有競爭,就進入阻塞隊列等待,可以被其它線程用interrupt打斷
    System.out.println("嘗試獲得鎖");
    lock.lockInterruptibly();
   } catch (InterruptedException e) {
    e.printStackTrace();
    System.out.println("等鎖的過程中被打斷");
    return;
   }
   try {
    System.out.println("t1獲得了鎖");
   } finally {
    lock.unlock();
   }
  }, "t1");
  lock.lock();
  System.out.println("主線程獲得了鎖");
  t1.start();
  try {
   try {
    sleep(1);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
   t1.interrupt();
   System.out.println("執(zhí)行打斷t1");
  } finally {
   lock.unlock();
  }
 }
}
主線程獲得了鎖
嘗試獲得鎖
執(zhí)行打斷t1
等鎖的過程中被打斷
java.lang.InterruptedException
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:898)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222)
	at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
	at cn.yj.jvm.TestReentranLock2.lambda$main$0(TestReentranLock2.java:15)
	at java.lang.Thread.run(Thread.java:748)

注意如果是不可中斷模式,那么即使使用了 interrupt 也不會讓等待中斷,即不是。即使用lock()方法。
這種方式可以避免死鎖情況的發(fā)生,避免無休止的等待。

ReentrantLock lock = new ReentrantLock();
Thread t1 = new Thread(() -> {
 System.out.println("啟動...");
 lock.lock();
 try {
  System.out.println("獲得了鎖");
 } finally {
  lock.unlock();
 }
}, "t1");
lock.lock();
System.out.println("獲得了鎖");
t1.start();
try {
 sleep(1);
 t1.interrupt();
 System.out.println("執(zhí)行打斷");
 sleep(1);
} finally {
 System.out.println("釋放了鎖");
 lock.unlock();
}

4.鎖超時

ReentranLock支持可打斷,其實就是為了避免死等,這樣就可以減少死鎖的發(fā)生。實際上可打斷這種方式屬于一種被動的避免死等,是由其它線程interrupt來打斷。
而鎖超時是主動的方式避免死等的手段。
獲取鎖用tryLock()方法,即嘗試獲得鎖,如果成功了,它就獲得鎖,如果失敗了,它就可以不去進入阻塞隊列等待,它就會返回false,表示沒有獲得鎖。

立刻失敗

public static void main(String[] args) {
  ReentrantLock lock = new ReentrantLock();
  Thread t1 = new Thread(() -> {
   System.out.println("啟動...");
   if (!lock.tryLock()) {
    System.out.println("獲取不到鎖,立刻失敗,返回");
    return;
   }
   try {
    System.out.println("獲得了鎖");
   } finally {
    lock.unlock();
   }
  }, "t1");
  lock.lock();
  System.out.println("獲得了鎖");
  t1.start();
  try {
   try {
    sleep(500);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  } finally {
   lock.unlock();
  }
}

獲得了鎖
啟動...
獲取不到鎖,立刻失敗,返回

超時失敗
lock.tryLock(1,TimeUnit.SECONDS)表示嘗試等待1s,如果主線程不釋放鎖,那么它就會返回false,如果釋放了鎖,那么它就會返回true.tryLock也支持被打斷,被打斷時報異常。

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();
}

輸出

18:19:40.537 [main] c.TestTimeout - 獲得了鎖
18:19:40.544 [t1] c.TestTimeout - 啟動...
18:19:41.547 [t1] c.TestTimeout - 獲取等待 1s 后失敗,返回

5.公平鎖

對于synchronized來說,它是不公平的鎖。當一個線程持有鎖,其他線程就會進入阻塞隊列等待,當鎖的持有者釋放鎖的時候,這些線程就會一擁而上,誰先搶到,誰就成為monitor的主人,而不會按照先來先得的規(guī)則。

ReentrantLock 默認是不公平的
ReentrantLock有一個帶參構造方法。默認是非公平的。

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

 

我們可以通過布爾值改成真,來保證它的公平性。即將來阻塞隊列里的線程,爭搶鎖的時候會按照進入阻塞隊列的順序執(zhí)行,先到先得。

6.條件變量 Condition

synchronized 中也有條件變量,就是我們講原理時那個 waitSet 休息室,當條件不滿足時進入 waitSet 等待

ReentrantLock 的條件變量比 synchronized 強大之處在于,它是支持多個條件變量的,這就好比

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

使用要點:

  • await 前需要獲得鎖
  • await 執(zhí)行后,會釋放鎖,進入 conditionObject 等待
  • await 的線程被喚醒(或打斷、或超時)取重新競爭 lock 鎖
  • 競爭 lock 鎖成功后,從 await 后繼續(xù)執(zhí)行
  • signal 相當于 notify,signalAll 相當于 notifyAll
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();
   while (!hasCigrette) {
    try {
     waitCigaretteQueue.await();
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
   }
   log.debug("等到了它的煙");
  } finally {
   lock.unlock();
  }
 }).start();
 new Thread(() -> {
  try {
   lock.lock();
   while (!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();
 }
}

輸出

18:52:27.680 [main] c.TestCondition - 送早餐來了
18:52:27.682 [Thread-1] c.TestCondition - 等到了它的早餐
18:52:28.683 [main] c.TestCondition - 送煙來了
18:52:28.683 [Thread-0] c.TestCondition - 等到了它的煙

到此這篇關于Java并發(fā)編程之ReentrantLock可重入鎖的實例代碼的文章就介紹到這了,更多相關Java ReentrantLock可重入鎖內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • jdk7 中HashMap的知識點總結

    jdk7 中HashMap的知識點總結

    HashMap的原理是老生常談了,不作仔細解說。一句話概括為HashMap是一個散列表,它存儲的內容是鍵值對(key-value)映射。這篇文章主要總結了關于jdk7 中HashMap的知識點,需要的朋友可以參考借鑒,一起來看看吧。
    2017-01-01
  • Protobuf詳解及入門指南附完整代碼

    Protobuf詳解及入門指南附完整代碼

    Protobuf是一種由Google開發(fā)的二進制序列化格式,用于高效地序列化和反序列化結構化數(shù)據(jù),它廣泛應用于分布式系統(tǒng)、RPC框架和數(shù)據(jù)存儲中,提供了高效性、簡潔性、版本兼容性和語言無關性,本文介紹Protobuf詳解及入門指南,感興趣的朋友一起看看吧
    2025-03-03
  • 詳解SpringMVC實現(xiàn)圖片上傳以及該注意的小細節(jié)

    詳解SpringMVC實現(xiàn)圖片上傳以及該注意的小細節(jié)

    本篇文章主要介紹了詳解SpringMVC實現(xiàn)圖片上傳以及該注意的小細節(jié),具有一定的參考價值,感興趣的小伙伴們可以參考一下。
    2017-02-02
  • Spring AOP實現(xiàn)原理解析

    Spring AOP實現(xiàn)原理解析

    這篇文章主要為大家詳細介紹了Spring AOP的實現(xiàn)原理,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • SpringCloud啟動eureka server后,沒報錯卻不能訪問管理頁面(404問題)

    SpringCloud啟動eureka server后,沒報錯卻不能訪問管理頁面(404問題)

    這篇文章主要介紹了SpringCloud啟動eureka server后,沒報錯卻不能訪問管理頁面(404問題),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • 一篇文章帶你了解Java SpringBoot Nacos

    一篇文章帶你了解Java SpringBoot Nacos

    這篇文章主要介紹了SpringBoot使用Nacos配置中心的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-09-09
  • Java中遍歷數(shù)組使用foreach循環(huán)還是for循環(huán)?

    Java中遍歷數(shù)組使用foreach循環(huán)還是for循環(huán)?

    這篇文章主要介紹了Java中遍歷數(shù)組使用foreach循環(huán)還是for循環(huán)?本文著重講解for語句的語法并給出使用實例,同時總結出盡量使用foreach語句遍歷數(shù)組,需要的朋友可以參考下
    2015-06-06
  • SpringBoot中@PostConstruct 注解的實現(xiàn)

    SpringBoot中@PostConstruct 注解的實現(xiàn)

    在Spring Boot框架中,?@PostConstruct是一個非常有用的注解,它用于在依賴注入完成后執(zhí)行初始化方法,本文將介紹?@PostConstruct的基本概念、使用場景以及提供詳細的代碼示例,感興趣的可以了解一下
    2024-09-09
  • Spring Cloud Ribbon客戶端詳細介紹

    Spring Cloud Ribbon客戶端詳細介紹

    Spring Cloud Ribbon 是一套基于 Netflix Ribbon 實現(xiàn)的客戶端負載均衡和服務調用工具。通過Spring Cloud的封裝,可以讓我們輕松地將面向服務的REST模版請求自動轉換成客戶端負載均衡的服務調用
    2022-09-09
  • Java編碼算法與哈希算法深入分析使用方法

    Java編碼算法與哈希算法深入分析使用方法

    首先,我們一起來學習一下編碼算法,舉例說明,ASCII碼就是我們常見的一種編碼,字母a的編碼是十六進制的0x61,字母b是0x62,以此類推。哈希算法,可被稱為摘要算法。因此,哈希算法的加密是單向的,不可用密文解密得到明文
    2022-11-11

最新評論

诸城市| 凌源市| 南京市| 甘洛县| 莫力| 获嘉县| 泸溪县| 望城县| 长葛市| 济阳县| 福安市| 鄂托克前旗| 柏乡县| 延边| 北碚区| 长葛市| 福鼎市| 无为县| 阳新县| 邵武市| 绥滨县| 云霄县| 阿荣旗| 手游| 马龙县| 武定县| 原阳县| 灵丘县| 饶平县| 赤峰市| 雷波县| 庐江县| 凤冈县| 清河县| 夏津县| 易门县| 宁城县| 开封市| 永平县| 灌南县| 普宁市|