日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

七 内置锁 wait notify notifyall; 显示锁 ReentrantLock

發(fā)布時間:2023/11/29 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 七 内置锁 wait notify notifyall; 显示锁 ReentrantLock 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Object中對內置鎖進行操作的一些方法:

Java內置鎖通過synchronized關鍵字使用,使用其修飾方法或者代碼塊,就能保證方法或者代碼塊以同步方式執(zhí)行.

內置鎖使用起來非常方便,不需要顯式的獲取和釋放,任何一個對象都能作為一把內置鎖。使用內置鎖能夠解決大部分的同步場景。“任何一個對象都能作為一把內置鎖”也意味著出現(xiàn)synchronized關鍵字的地方,都有一個對象與之關聯(lián),具體說來:

  • 當synchronized作用于普通方法是,鎖對象是this;
  • 當synchronized作用于靜態(tài)方法是,鎖對象是當前類的Class對象;
  • 當synchronized作用于代碼塊時,鎖對象是synchronized(obj)中的這個obj。

wait()系列:

wait()系列方法的作用是:使當前已經(jīng)獲得該對象鎖的線程進入等待狀態(tài),并且釋放該對象的鎖。

notify()系列:

notify()系列方法的作用是:喚醒那些正在等待該對象鎖的線程,使其繼續(xù)運行。

基于wait() notify()機制,我們可以實現(xiàn)一個簡易的生產者-消費者模型。

大體思路如下,一個生產者線程負責向一個倉庫中存放(put)物品,一個消費者線程負責從倉庫中取出(get)物品。

public class Warehouse {private Queue<Integer> queue;private int capacity;public Warehouse(int capacity) {this.capacity = capacity;queue = new LinkedList();}public synchronized void put(int num) {if (queue.size() >= capacity) {try {System.out.println(Thread.currentThread().getName() + " , put full wait");wait();} catch (InterruptedException e) {e.printStackTrace();}}queue.add(num);System.out.println(Thread.currentThread().getName() + " , put : " + num + " , queue -> " + queue);notifyAll();}public synchronized int get() {if (queue.isEmpty()) {try {System.out.println(Thread.currentThread().getName() + " , get empty wait");wait();} catch (InterruptedException e) {e.printStackTrace();}}int num = queue.poll();System.out.println(Thread.currentThread().getName() + " , get : " + num + " , queue -> " + queue);notifyAll();return num;} } public static void main(String[] args) {Warehouse warehouse = new Warehouse(4);Random random = new Random();new Thread(new Runnable() {@Overridepublic void run() {while (true) {warehouse.put(random.nextInt(10));try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}}, "生產者-01").start();new Thread(new Runnable() {@Overridepublic void run() {while (true) {warehouse.get();try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}}}}, "消費者-01").start();}

?

顯式鎖

內置鎖這么好用,為什么還需多出一個顯式鎖呢?因為有些事情內置鎖是做不了的,比如:

  • 我們想給鎖加個等待時間超時時間,超時還未獲得鎖就放棄,不至于無限等下去;
  • 我們想以可中斷的方式獲取鎖(線程可以被打斷),這樣外部線程給我們發(fā)一個中斷信號就能喚起等待鎖的線程;
  • 我們想為鎖維持多個等待隊列,比如一個生產者隊列,一個消費者隊列,一邊提高鎖的效率。
  • 顯式鎖(ReentrantLock)正式為了解決這些靈活需求而生。ReentrantLock的字面意思是可重入鎖,可重入的意思是線程可以同時多次請求同一把鎖而不會自己導致自己死鎖。下面是內置鎖和顯式鎖的區(qū)別:

    • 可定時:RenentrantLock.tryLock(long timeout, TimeUnit unit)提供了一種以定時結束等待的方式,如果線程在指定的時間內沒有獲得鎖,該方法就會返回false并結束線程等待。

    • 可中斷:你一定見過InterruptedException,很多跟多線程相關的方法會拋出該異常,這個異常并不是一個缺陷導致的負擔,而是一種必須,或者說是一件好事。可中斷性給我們提供了一種讓線程提前結束的方式(而不是非得等到線程執(zhí)行結束),這對于要取消耗時的任務非常有用對于內置鎖,線程拿不到內置鎖就會一直等待,除了獲取鎖沒有其他辦法能夠讓其結束等待。RenentrantLock.lockInterruptibly()給我們提供了一種以中斷結束等待的方式。

    • 條件隊列(condition queue):線程在獲取鎖之后,可能會由于等待某個條件發(fā)生而進入等待狀態(tài)(內置鎖通過Object.wait()方法,顯式鎖通過Condition.await()方法),進入等待狀態(tài)的線程會掛起并自動釋放鎖,這些線程會被放入到條件隊列當中。synchronized對應的只有一個條件隊列,而ReentrantLock可以有多個條件隊列,多個隊列有什么好處呢?請往下看

    • 條件謂詞:線程在獲取鎖之后,有時候還需要等待某個條件滿足才能做事情,比如生產者需要等到“緩存不滿”才能往隊列里放入消息,而消費者需要等到“緩存非空”才能從隊列里取出消息。這些條件被稱作條件謂詞,線程需要先獲取鎖,然后判斷條件謂詞是否滿足,如果不滿足就不往下執(zhí)行,相應的線程就會放棄執(zhí)行權并自動釋放鎖。使用同一把鎖的不同的線程可能有不同的條件謂詞,如果只有一個條件隊列,當某個條件謂詞滿足時就無法判斷該喚醒條件隊列里的哪一個線程;但是如果每個條件謂詞都有一個單獨的條件隊列,當某個條件滿足時我們就知道應該喚醒對應隊列上的線程(內置鎖通過Object.notify()或者Object.notifyAll()方法喚醒,顯式鎖通過Condition.signal()或者Condition.signalAll()方法喚醒)。這就是多個條件隊列的好處。

    使用內置鎖時,對象本身既是一把鎖又是一個條件隊列;使用顯式鎖時,RenentrantLock的對象是鎖,條件隊列通過RenentrantLock.newCondition()方法獲取,多次調用該方法可以得到多個條件隊列

    一個使用顯式鎖的典型示例如下:

    // 顯式鎖的使用示例 ReentrantLock lock = new ReentrantLock();// 獲取鎖,這是跟synchronized關鍵字對應的用法。 lock.lock(); try{// your code }finally{lock.unlock(); }// 可定時,超過指定時間為得到鎖就放棄 try {lock.tryLock(10, TimeUnit.SECONDS);try {// your code}finally {lock.unlock();} } catch (InterruptedException e1) {// exception handling }// 可中斷,等待獲取鎖的過程中線程線程可被中斷 try {lock.lockInterruptibly();try {// your code}finally {lock.unlock();} } catch (InterruptedException e) {// exception handling }// 多個等待隊列,具體參考[ArrayBlockingQueue](https://github.com/CarpenterLee/JCRecipes/blob/master/markdown/ArrayBlockingQueue.md) /** Condition for waiting takes */ private final Condition notEmpty = lock.newCondition(); /** Condition for waiting puts */ private final Condition notFull = lock.newCondition();

    ?注意,上述代碼將unlock()放在finally塊里,這么做是必需的。顯式鎖不像內置鎖那樣會自動釋放,使用顯式鎖一定要在finally塊中手動釋放,如果獲取鎖后由于異常的原因沒有釋放鎖,那么這把鎖將永遠得不到釋放!將unlock()放在finally塊中,保證無論發(fā)生什么都能夠正常釋放。

    ?

    內置鎖能夠解決大部分需要同步的場景,只有在需要額外靈活性是才需要考慮顯式鎖,比如可定時、可中斷、多等待隊列等特性。

    顯式鎖雖然靈活,但是需要顯式的申請和釋放,并且釋放一定要放到finally塊中,否則可能會因為異常導致鎖永遠無法釋放!這是顯式鎖最明顯的缺點。

    綜上,當需要同步時請優(yōu)先考慮更安全的更易用的隱式鎖。

    package com.imooc.locks;import java.util.LinkedList; import java.util.List; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock;public class Task {private final Lock lock = new ReentrantLock();private final Condition addCondition = lock.newCondition();private final Condition subCondition = lock.newCondition();private static int num = 0;private List<String> lists = new LinkedList<String>();public void add() {lock.lock();try {while(lists.size() == 10) {//當集合已滿,則"添加"線程等待addCondition.await();}num++;lists.add("add Banana" + num);System.out.println("The Lists Size is " + lists.size());System.out.println("The Current Thread is " + Thread.currentThread().getName());System.out.println("==============================");this.subCondition.signal();} catch (InterruptedException e) {e.printStackTrace();} finally {//釋放鎖lock.unlock();}}public void sub() {lock.lock();try {while(lists.size() == 0) {//當集合為空時,"減少"線程等待subCondition.await();}String str = lists.get(0);lists.remove(0);System.out.println("The Token Banana is [" + str + "]");System.out.println("The Current Thread is " + Thread.currentThread().getName());System.out.println("==============================");num--;addCondition.signal();} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}}

    ?

    轉載于:https://www.cnblogs.com/liufei1983/p/8120395.html

    總結

    以上是生活随笔為你收集整理的七 内置锁 wait notify notifyall; 显示锁 ReentrantLock的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。