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

JUC中的wait與notify方法實現(xiàn)原理詳解

 更新時間:2023年03月10日 10:18:53   作者:Young丶  
這篇文章主要介紹了JUC中的wait與notify方法實現(xiàn)原理,在進(jìn)行wait()之前,就代表著需要爭奪Synchorized,而Synchronized代碼塊通過javap生成的字節(jié)碼中包含monitor?enter和monitor?exit兩個指令

1.Object中的wait()實現(xiàn)原理

在進(jìn)行wait()之前,就代表著需要爭奪Synchorized,而Synchronized代碼塊通過javap生成的字節(jié)碼中包含monitor entermonitor exit兩個指令。

當(dāng)在進(jìn)加鎖的時候會執(zhí)行monitor enter指令,執(zhí)行該指令可以獲取對象的monitor。同時在執(zhí)行Lock.wait()的時候也必須持有monitor對象。

在多核環(huán)境下,多個線程有可能同時執(zhí)行monitor enter指令,并獲取lock對象關(guān)聯(lián)的monitor,但只有一個線程可以和monitor建立關(guān)聯(lián),這個線程執(zhí)行到wait方法時,wait方法會將當(dāng)前線程放入wait set,使其進(jìn)行等待直到被喚醒,并放棄lock對象上的所有同步聲明,意味著該線程釋放了鎖,其他線程可以重新執(zhí)行加鎖操作,notify方法會選擇wait set中任意一個線程進(jìn)行喚醒,notifyAll方法會喚醒monitor的wait set中所有線程。執(zhí)行完notify方法并不會立馬喚醒等待線程。那么wait具體是怎么實現(xiàn)的呢?

首先在HotSpot虛擬機(jī)中,monitor采用ObjectMonitor實現(xiàn),每個線程都具有兩個隊列,分別為free和used,用來存放ObjectMonitor。如果當(dāng)前free列表為空,線程將向全局global list請求分配ObjectMonitor。

ObjectMonitor對象中有兩個隊列,都用來保存ObjectWaiter對象,分別是_WaitSet 和 _EntrySet。_owner用來指向獲得ObjectMonitor對象的線程

ObjectWaiter對象是雙向鏈表結(jié)構(gòu),保存了_thread(當(dāng)前線程)以及當(dāng)前的狀態(tài)TState等數(shù)據(jù), 每個等待鎖的線程都會被封裝成ObjectWaiter對象。

_WaitSet:處于wait狀態(tài)的線程,會被加入到wait set;

_EntrySett:處于等待鎖block狀態(tài)的線程,會被加入到entry set;

wait方法實現(xiàn)

lock.wait()方法最終通過ObjectMonitor的 wait(jlong millis, bool interruptable, TRAPS)實現(xiàn)

1、將當(dāng)前線程封裝成ObjectWaiter對象node

2、通過ObjectMonitor::AddWaiter方法將node添加到_WaitSet列表中

3、通過ObjectMonitor::exit方法釋放當(dāng)前的ObjectMonitor對象,這樣其它競爭線程就可以獲取該ObjectMonitor對象

4、最終底層的park方法會掛起線程

ObjectSynchorizer::wait方法通過Object對象找到ObjectMonitor對象來調(diào)用方法 ObjectMonitor::wait(),通過調(diào)用ObjectMonitor::AddWaiter()可以把新建的ObjectWaiter對象,放入到_WaitSet隊列的末尾,然后在ObjectMonitor::exit釋放鎖,接著通過執(zhí)行thread_ParkEvent->park來掛起線程,也就是進(jìn)行wait。

2.Object對象中的wait,notify,notifyAll的理解

wait,notify,notifyAll 是定義在Object類的實例方法,用于控制線程狀態(tài),在線程協(xié)作時,大家都會用到notify()或者notifyAll()方法,其中wait與notify是java同步機(jī)制中重要的組成部分,需要結(jié)合與synchronized關(guān)鍵字才能使用,在調(diào)用一個Object的wait與notify/notifyAll的時候,必須保證調(diào)用代碼對該Object是同步的,也就是說必須在作用等同于synchronized(object){…}的內(nèi)部才能夠去調(diào)用obj的wait與notify/notifyAll三個方法,否則就會報錯:java.lang.IllegalMonitorStateException:current thread not owner(意思是因為沒有同步,所以線程對對象鎖的狀態(tài)是不確定的,不能調(diào)用這些方法)。

wait的目的就在于暴露出對象鎖,所以需要保證在lock的同步代碼中調(diào)用lock.wait()方法,讓其他線程可以通過對象的notify叫醒等待在該對象的等該池里的線程。同樣notify也會釋放對象鎖,在調(diào)用之前必須獲得對象的鎖,不然也會報異常。所以,在線程自動釋放其占有的對象鎖后,不會去申請對象鎖,只有當(dāng)線程被喚醒的時候或者達(dá)到最大的睡眠時間,它才再次爭取對象鎖的權(quán)利

主要方法:

wait()

等待對象的同步鎖,需要獲得該對象的同步鎖才可以調(diào)用這個方法,否則編譯可以通過,但運行時會收到一個異常:IllegalMonitorStateException。調(diào)用任意對象的 wait() 方法導(dǎo)致該線程阻塞,該線程不可繼續(xù)執(zhí)行,并且該對象上的鎖被釋放。

notify()

喚醒在等待該對象同步鎖的線程(只喚醒一個,如果有多個在等待),注意的是在調(diào)用此方法的時候,并不能確切的喚醒某一個等待狀態(tài)的線程,而是由JVM確定喚醒哪個線程,而且不是按優(yōu)先級。調(diào)用任意對象的notify()方法則導(dǎo)致因調(diào)用該對象的 wait()方法而阻塞的線程中隨機(jī)選擇的一個解除阻塞(但要等到獲得鎖后才真正可執(zhí)行)。

notifyAll()

喚醒所有等待的線程,注意喚醒的是notify之前wait的線程,對于notify之后的wait線程是沒有效果的。

3.wait 實戰(zhàn)

通過一個實例來看一下實際的效果,開啟兩個線和,一個線程 打印1到52的數(shù)字,一個打印A到Z的字母,要求,打印兩個數(shù),打印一個字母,這樣交替順序打印,代碼如下:

public class ShuZiZiMuThread {
    public static void main(String[] args) {
        Object object = new Object();
        shuzi shuzi = new shuzi(object);
        zimu zimu = new zimu(object);
        Thread t = new Thread(shuzi);
        t.setName("shuzi");
        Thread t1 = new Thread(zimu);
        t1.setName("zimu");
        t.start();//數(shù)字線程先運行
        t1.start();
    }
}
class shuzi implements Runnable{
    private Object object;
    //聲明類的引用
    public shuzi(Object object) {
        this.object = object;
    }
    public void run() {
        synchronized (object) {//上鎖
            for(int i=1;i<53;i++){
                System.out.print(i+",");
                if(i%2==0){
                    object.notifyAll();//喚醒其它爭奪權(quán)限的線程
                    try {
                        object.wait();//釋放鎖,進(jìn)入等待
                        System.out.println("數(shù)字打印類打全打印當(dāng)前對象擁有對象鎖的線程"+Thread.currentThread().getName());//輸出當(dāng)前擁有鎖的線程名稱
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
class zimu implements Runnable{
    private Object object;
    public zimu(Object object) {
        this.object = object;
    }
    public void run() {
        synchronized (object) {
            for(int j=65;j<91;j++){
                char c = (char)j;
                System.out.print(c);
                object.notifyAll();//喚醒其它爭奪權(quán)限的線程
                try {
                    object.wait();//釋放鎖,進(jìn)入等待
                    System.out.println("字母打印類打全打印當(dāng)前對象擁有對象鎖的線程"+Thread.currentThread().getName());//輸出當(dāng)前擁有鎖的線程名稱
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

實際運行的結(jié)果 :

1,2,A數(shù)字打印類打印當(dāng)前對象擁有對象鎖的線程shuzi
3,4,字母打印類打印當(dāng)前對象擁有對象鎖的線程zimu
B數(shù)字打印類打印當(dāng)前對象擁有對象鎖的線程shuzi
5,6,字母打印類打印當(dāng)前對象擁有對象鎖的線程zimu
C數(shù)字打印類打印當(dāng)前對象擁有對象鎖的線程shuzi
7,8,字母打印類打印當(dāng)前對象擁有對象鎖的線程zimu
D數(shù)字打印類打印當(dāng)前對象擁有對象鎖的線程shuzi
9,10,字母打印類打印當(dāng)前對象擁有對象鎖的線程zimu
E數(shù)字打印類打印當(dāng)前對象擁有對象鎖的線程shuzi
11,12,字母打印類打印當(dāng)前對象擁有對象鎖的線程zimu
F數(shù)字打印類打印當(dāng)前對象擁有對象鎖的線程shuzi
13,14,字母打印類打印當(dāng)前對象擁有對象鎖的線程zimu
G數(shù)字打印類打印當(dāng)前對象擁有對象鎖的線程shuzi
15,16,字母打印類打印當(dāng)前對象擁有對象鎖的線程zimu
H數(shù)字打印類打印當(dāng)前對象擁有對象鎖的線程shuzi
17,18,字母打印類打印當(dāng)前對象擁有對象鎖的線程zimu
I數(shù)字打印類打印當(dāng)前對象擁有對象鎖的線程shuzi
19,20,字母打印類打印當(dāng)前對象擁有對象鎖的線程zimu
J數(shù)字打印類打印當(dāng)前對象擁有對象鎖的線程shuzi
21,22,字母打印類打印當(dāng)前對象擁有對象鎖的線程zimu
K數(shù)字打印類打印當(dāng)前對象擁有對象鎖的線程shuzi
23,24,字母打印類打印當(dāng)前對象擁有對象鎖的線程zimu
L數(shù)字打印類打印當(dāng)前對象擁有對象鎖的線程shuzi
25,26,字母打印類打印當(dāng)前對象擁有對象鎖的線程zimu
M數(shù)字打印類打印當(dāng)前對象擁有對象鎖的線程shuzi
27,28,字母打印類打印當(dāng)前對象擁有對象鎖的線程zimu
N數(shù)字打印類打印當(dāng)前對象擁有對象鎖的線程shuzi
29,30,字母打印類打印當(dāng)前對象擁有對象鎖的線程zimu
O數(shù)字打印類打印當(dāng)前對象擁有對象鎖的線程shuzi
31,32,字母打印類打印當(dāng)前對象擁有對象鎖的線程zimu
P數(shù)字打印類打印當(dāng)前對象擁有對象鎖的線程shuzi
33,34,字母打印類打印當(dāng)前對象擁有對象鎖的線程zimu
Q數(shù)字打印類打印當(dāng)前對象擁有對象鎖的線程shuzi
35,36,字母打印類打印當(dāng)前對象擁有對象鎖的線程zimu
R數(shù)字打印類打印當(dāng)前對象擁有對象鎖的線程shuzi
37,38,字母打印類打印當(dāng)前對象擁有對象鎖的線程zimu
S數(shù)字打印類打印當(dāng)前對象擁有對象鎖的線程shuzi
39,40,字母打印類打印當(dāng)前對象擁有對象鎖的線程zimu
T數(shù)字打印類打印當(dāng)前對象擁有對象鎖的線程shuzi
41,42,字母打印類打印當(dāng)前對象擁有對象鎖的線程zimu
U數(shù)字打印類打印當(dāng)前對象擁有對象鎖的線程shuzi
43,44,字母打印類打印當(dāng)前對象擁有對象鎖的線程zimu
V數(shù)字打印類打印當(dāng)前對象擁有對象鎖的線程shuzi
45,46,字母打印類打印當(dāng)前對象擁有對象鎖的線程zimu
W數(shù)字打印類打印當(dāng)前對象擁有對象鎖的線程shuzi
47,48,字母打印類打印當(dāng)前對象擁有對象鎖的線程zimu
X數(shù)字打印類打印當(dāng)前對象擁有對象鎖的線程shuzi
49,50,字母打印類打印當(dāng)前對象擁有對象鎖的線程zimu
Y數(shù)字打印類打印當(dāng)前對象擁有對象鎖的線程shuzi
51,52,字母打印類打印當(dāng)前對象擁有對象鎖的線程zimu
Z數(shù)字打印類打印當(dāng)前對象擁有對象鎖的線程shuzi

結(jié)果分析:

通過結(jié)果可以看出:

在字母打一打印類里 調(diào)用完

通過結(jié)果可以看出:

在字母打一打印類里 調(diào)用完

到此這篇關(guān)于JUC中的wait()與notify()方法實現(xiàn)原理詳解的文章就介紹到這了,更多相關(guān)JUC wait()與notify()內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 解決springboot項目啟動報錯Field xxxMapper in com...xxxController required

    解決springboot項目啟動報錯Field xxxMapper in com...xx

    這篇文章主要介紹了解決springboot項目啟動報錯Field xxxMapper in com...xxxContr問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • Spring Boot 定制與優(yōu)化內(nèi)置的Tomcat容器實例詳解

    Spring Boot 定制與優(yōu)化內(nèi)置的Tomcat容器實例詳解

    本文主要記錄對內(nèi)置容器優(yōu)化和定制的方式,用于自己加深對SpringBoot理解。本文給大家介紹的非常詳細(xì),具有參考借鑒價值,需要的朋友參考下吧
    2017-12-12
  • 淺談redis key值內(nèi)存消耗以及性能影響

    淺談redis key值內(nèi)存消耗以及性能影響

    這篇文章主要介紹了淺談redis key值內(nèi)存消耗以及性能影響,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • java的poi技術(shù)讀取和導(dǎo)入Excel實例

    java的poi技術(shù)讀取和導(dǎo)入Excel實例

    本篇文章主要介紹了java的poi技術(shù)讀取和導(dǎo)入Excel實例,報表輸出是Java應(yīng)用開發(fā)中經(jīng)常涉及的內(nèi)容,有需要的可以了解一下。
    2016-11-11
  • 關(guān)于HashMap源碼解讀

    關(guān)于HashMap源碼解讀

    HashMap是基于哈希表的Map接口實現(xiàn),主要用于存儲鍵值對,它通過數(shù)組、鏈表和紅黑樹來實現(xiàn),解決了哈希沖突問題,Java?8中,HashMap對數(shù)據(jù)結(jié)構(gòu)進(jìn)行了優(yōu)化,引入紅黑樹來提高查找效率,此外,HashMap是非線程安全的,適用于單線程環(huán)境
    2024-09-09
  • 使用spring整合Quartz實現(xiàn)—定時器功能

    使用spring整合Quartz實現(xiàn)—定時器功能

    這篇文章主要介紹了使用spring整合Quartz實現(xiàn)—定時器功能,不基于特定的基類的方法,需要的朋友可以參考下
    2018-04-04
  • Springboot使用thymeleaf動態(tài)模板實現(xiàn)刷新

    Springboot使用thymeleaf動態(tài)模板實現(xiàn)刷新

    這篇文章主要介紹了Springboot使用thymeleaf動態(tài)模板實現(xiàn)刷新,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-08-08
  • Java中解密微信加密數(shù)據(jù)工具類

    Java中解密微信加密數(shù)據(jù)工具類

    最近小編一直在開發(fā)微信公眾號、小程序項目,微信返回給我們的數(shù)據(jù)都是加密的,我們需要使用sessionkey配合解密,才能看到我們想要的數(shù)據(jù),基于代碼怎么實現(xiàn)呢,下面小編給大家?guī)砹薐ava中解密微信加密數(shù)據(jù)工具類的完整代碼,一起看看吧
    2021-06-06
  • 一篇文章帶你入門java泛型

    一篇文章帶你入門java泛型

    這篇文章主要介紹了java泛型基礎(chǔ)知識及通用方法,從以下幾個方面介紹一下java的泛型: 基礎(chǔ), 泛型關(guān)鍵字, 泛型方法, 泛型類和接口,感興趣的可以了解一下
    2021-08-08
  • 為什么阿里要慎重使用ArrayList中的subList方法

    為什么阿里要慎重使用ArrayList中的subList方法

    這篇文章主要介紹了為什么要慎重使用ArrayList中的subList方法,subList是List接口中定義的一個方法,該方法主要用于返回一個集合中的一段、可以理解為截取一個集合中的部分元素,他的返回值也是一個List。,需要的朋友可以參考下
    2019-06-06

最新評論