中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

java線程等待喚醒機制

發布時間:2021-09-09 10:07:45 來源:億速云 閱讀:143 作者:chen 欄目:編程語言

這篇文章主要講解了“java線程等待喚醒機制”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“java線程等待喚醒機制”吧!

1)3種讓線程等待和喚醒的方法

方式1:使用Object中的wait()方法讓線程等待,使用Object中的notify()方法喚醒線程

1、wait()、notify/notifyAll() 方法是Object的本地final方法,無法被重寫。

2、wait()使當前線程阻塞,前提是 必須先獲得鎖,一般配合synchronized 關鍵字使用,即,一般在synchronized 同步代碼塊里使用 wait()、notify/notifyAll() 方法。

3、 由于 wait()、notify/notifyAll() 在synchronized 代碼塊執行,說明當前線程一定是獲取了鎖的。

當線程執行wait()方法時候,會釋放當前的鎖,然后讓出CPU,進入等待狀態。

只有當 notify/notifyAll() 被執行時候,才會喚醒一個或多個正處于等待狀態的線程,然后繼續往下執行,直到執行完synchronized 代碼塊的代碼或是中途遇到wait() ,再次釋放鎖。

也就是說,notify/notifyAll() 的執行只是喚醒沉睡的線程,而不會立即釋放鎖,鎖的釋放要看代碼塊的具體執行情況。所以在編程中,盡量在使用了notify/notifyAll() 后立即退出臨界區,以喚醒其他線程讓其獲得鎖

4、wait() 需要被try catch包圍,以便發生異常中斷也可以使wait等待的線程喚醒。

5、notify 和wait 的順序不能錯,如果A線程先執行notify方法,B線程在執行wait方法,那么B線程是無法被喚醒的。

6、notify 和 notifyAll的區別

notify方法只喚醒一個等待(對象的)線程并使該線程開始執行。所以如果有多個線程等待一個對象,這個方法只會喚醒其中一個線程,選擇哪個線程取決于操作系統對多線程管理的實現。notifyAll 會喚醒所有等待(對象的)線程,盡管哪一個線程將會第一個處理取決于操作系統的實現。如果當前情況下有多個線程需要被喚醒,推薦使用notifyAll 方法。比如在生產者-消費者里面的使用,每次都需要喚醒所有的消費者或是生產者,以判斷程序是否可以繼續往下執行。

7、在多線程中要測試某個條件的變化,使用if 還是while?

  要注意,notify喚醒沉睡的線程后,線程會接著上次的執行繼續往下執行。所以在進行條件判斷時候,可以先把 wait 語句忽略不計來進行考慮;顯然,要確保程序一定要執行,并且要保證程序直到滿足一定的條件再執行,要使用while進行等待,直到滿足條件才繼續往下執行

package com.lyy.juc;import java.util.concurrent.TimeUnit;public class LockSupportDemo {public static void main(String[] args)//main方法,主線程一切程序入口    {Object objectLock = new Object(); //同一把鎖,類似資源類        new Thread(() -> {synchronized (objectLock) {try {objectLock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }System.out.println(Thread.currentThread().getName() + "\t" + "被喚醒了");
        }, "t1").start();//暫停幾秒鐘線程        try {TimeUnit.SECONDS.sleep(3L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }new Thread(() -> {synchronized (objectLock) {objectLock.notify();
            }//objectLock.notify();            /*synchronized (objectLock) {                try {                    objectLock.wait();                } catch (InterruptedException e) {                    e.printStackTrace();                }            }*/        }, "t2").start();


    }
}

三秒后打印

t1    被喚醒了

java線程等待喚醒機制

方式2:使用JUC包中Condition的await()方法讓線程等待,使用signal()方法喚醒線程

package com.lyy.juc;import java.util.concurrent.TimeUnit;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class LockSupportDemo2 {public static void main(String[] args) {Lock lock = new ReentrantLock();Condition condition = lock.newCondition();new Thread(() -> {lock.lock();try {System.out.println(Thread.currentThread().getName() + "\t" + "start");condition.await();System.out.println(Thread.currentThread().getName() + "\t" + "被喚醒");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {lock.unlock();
            }
        }, "t1").start();//暫停幾秒鐘線程        try {TimeUnit.SECONDS.sleep(3L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }new Thread(() -> {lock.lock();try {condition.signal();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {lock.unlock();
            }System.out.println(Thread.currentThread().getName() + "\t" + "通知了");
        }, "t2").start();

    }
}

java線程等待喚醒機制

t1 線程在前,先執行start 然后,main執行睡三秒,t2執行start ,先執行await方法,后執行signal ,所以先打印t1 被喚醒,t2 被通知在后

但我把順序換一下,打印結果順序就不一樣了

package com.lyy.juc;import java.util.concurrent.TimeUnit;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class LockSupportDemo2 {public static void main(String[] args) {Lock lock = new ReentrantLock();Condition condition = lock.newCondition();//暫停幾秒鐘線程        try {TimeUnit.SECONDS.sleep(3L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }new Thread(() -> {lock.lock();try {System.out.println(Thread.currentThread().getName() + "\t" + "start");condition.await();System.out.println(Thread.currentThread().getName() + "\t" + "被喚醒");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {lock.unlock();
            }
        }, "t1").start();new Thread(() -> {lock.lock();try {System.out.println(Thread.currentThread().getName() + "\t" + "start");condition.signal();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {lock.unlock();
            }System.out.println(Thread.currentThread().getName() + "\t" + "通知了");
        }, "t2").start();

    }
}

java線程等待喚醒機制

Object和Condition使用的限制條件

線程先要獲得并持有鎖,必須在鎖塊(synchronized或lock)中

方式3:LockSupport類可以阻塞park當前線程以及喚醒unpark指定被阻塞的線程

通過park()和unpark(thread)方法來實現阻塞和喚醒線程的操作

LockSupport是用來創建鎖和其他同步類的基本線程阻塞原語。
 
LockSupport類使用了一種名為Permit(許可)的概念來做到阻塞和喚醒線程的功能, 每個線程都有一個許可(permit),
permit只有兩個值1和零,默認是零。
可以把許可看成是一種(0,1)信號量(Semaphore),但與 Semaphore 不同的是,許可的累加上限是1。

park() /park(Object blocker)

不傳阻塞當前線程/傳阻塞傳入的具體線程

unpark(Thread thread) 必須指定要喚醒的線程 

package com.lyy.juc;import java.util.concurrent.TimeUnit;import java.util.concurrent.locks.LockSupport;public class LockSupportDemo3 {public static void main(String[] args) {//正常使用+不需要鎖塊        Thread t1 = new Thread(() -> {System.out.println(Thread.currentThread().getName() + " " + "1111111111111");LockSupport.park();System.out.println(Thread.currentThread().getName() + " " + "2222222222222------end被喚醒");
        }, "t1");t1.start();//暫停幾秒鐘線程        try {TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }LockSupport.unpark(t1);System.out.println(Thread.currentThread().getName() + "   -----LockSupport.unparrk() invoked over");

    }
}

java線程等待喚醒機制

permit默認是零,所以一開始調用park()方法,當前線程就會阻塞,直到別的線程將當前線程的permit設置為1時,park方法會被喚醒,
然后會將permit再次設置為零并返回。
 

java線程等待喚醒機制
調用unpark(thread)方法后,就會將thread線程的許可permit設置成1(注意多次調用unpark方法,不會累加,permit值還是1)會自動喚醒thread線程,即之前阻塞中的LockSupport.park()方法會立即返回。

java線程等待喚醒機制

感謝各位的閱讀,以上就是“java線程等待喚醒機制”的內容了,經過本文的學習后,相信大家對java線程等待喚醒機制這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

兴业县| 长乐市| 望都县| 阳曲县| 冷水江市| 建德市| 洪雅县| 松溪县| 临西县| 财经| 内黄县| 肃北| 揭西县| 丰台区| 保康县| 高陵县| 运城市| 怀化市| 清镇市| 博乐市| 伊金霍洛旗| 台州市| 巴东县| 大悟县| 茌平县| 广饶县| 南通市| 松溪县| 兴和县| 宁晋县| 三原县| 张掖市| 武威市| 大埔区| 冕宁县| 寿宁县| 赤水市| 龙口市| 江门市| 翼城县| 潮安县|