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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

JAVA多线程之wait/notify

發(fā)布時(shí)間:2025/3/20 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JAVA多线程之wait/notify 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

本文主要學(xué)習(xí)JAVA多線程中的 wait()方法 與 notify()/notifyAll()方法的用法。

①wait() 與 notify/notifyAll 方法必須在同步代碼塊中使用

②wait() 與? notify/notifyAll() 的執(zhí)行過程

③中斷 調(diào)用wait()方法進(jìn)入等待隊(duì)列的 線程

④notify 通知的順序不能錯(cuò)

⑤多線程中測(cè)試某個(gè)條件的變化用 if 還是用 while?

?

?

①wait() 與 notify/notifyAll 方法必須在同步代碼塊中使用

wait() 與 notify/notifyAll() 是Object類的方法,在執(zhí)行兩個(gè)方法時(shí),要先獲得鎖。那么怎么獲得鎖呢?

在這篇:JAVA多線程之Synchronized關(guān)鍵字--對(duì)象鎖的特點(diǎn)文章中介紹了使用synchronized關(guān)鍵字獲得鎖。因此,wait() 與? notify/notifyAll() 經(jīng)常與synchronized搭配使用,即在synchronized修飾的同步代碼塊或方法里面調(diào)用wait() 與? notify/notifyAll()方法。

?

②wait() 與? notify/notifyAll() 的執(zhí)行過程

由于 wait() 與? notify/notifyAll() 是放在同步代碼塊中的,因此線程在執(zhí)行它們時(shí),肯定是進(jìn)入了臨界區(qū)中的,即該線程肯定是獲得了鎖的。

當(dāng)線程執(zhí)行wait()時(shí),會(huì)把當(dāng)前的鎖釋放,然后讓出CPU,進(jìn)入等待狀態(tài)。

?當(dāng)執(zhí)行notify/notifyAll方法時(shí),會(huì)喚醒一個(gè)處于等待該 對(duì)象鎖 的線程,然后繼續(xù)往下執(zhí)行,直到執(zhí)行完退出對(duì)象鎖鎖住的區(qū)域(synchronized修飾的代碼塊)后再釋放鎖。

從這里可以看出,notify/notifyAll()執(zhí)行后,并不立即釋放鎖,而是要等到執(zhí)行完臨界區(qū)中代碼后,再釋放。故,在實(shí)際編程中,我們應(yīng)該盡量在線程調(diào)用notify/notifyAll()后,立即退出臨界區(qū)。即不要在notify/notifyAll()后面再寫一些耗時(shí)的代碼。

示例如下:(摘自《JAVA多線程核心技術(shù)》)

1 public class Service {2 3 public void testMethod(Object lock) {4 try {5 synchronized (lock) {6 System.out.println("begin wait() ThreadName="7 + Thread.currentThread().getName());8 lock.wait();9 System.out.println(" end wait() ThreadName=" 10 + Thread.currentThread().getName()); 11 } 12 } catch (InterruptedException e) { 13 e.printStackTrace(); 14 } 15 } 16 17 public void synNotifyMethod(Object lock) { 18 try { 19 synchronized (lock) { 20 System.out.println("begin notify() ThreadName=" 21 + Thread.currentThread().getName() + " time=" 22 + System.currentTimeMillis()); 23 lock.notify(); 24 Thread.sleep(5000); 25 System.out.println(" end notify() ThreadName=" 26 + Thread.currentThread().getName() + " time=" 27 + System.currentTimeMillis()); 28 } 29 } catch (InterruptedException e) { 30 e.printStackTrace(); 31 } 32 } 33 }

在第3行的testMethod()中調(diào)用 wait(),在第17行的synNotifyMethod()中調(diào)用notify()

從上面的代碼可以看出,wait() 與? notify/notifyAll()都是放在同步代碼塊中才能夠執(zhí)行的。如果在執(zhí)行wait() 與? notify/notifyAll() 之前沒有獲得相應(yīng)的對(duì)象鎖,就會(huì)拋出:java.lang.IllegalMonitorStateException異常。

在第8行,當(dāng)ThreadA線程執(zhí)行l(wèi)ock.wait();這條語句時(shí),釋放獲得的對(duì)象鎖lock,并放棄CPU,進(jìn)入等待隊(duì)列。

當(dāng)另一個(gè)線程執(zhí)行第23行l(wèi)ock.notify();,會(huì)喚醒ThreadA,但是此時(shí)它并不立即釋放鎖,接下來它睡眠了5秒鐘(sleep()是不釋放鎖的,事實(shí)上sleep()也可以不在同步代碼塊中調(diào)用),直到第28行,退出synchronized修飾的臨界區(qū)時(shí),才會(huì)把鎖釋放。這時(shí),ThreadA就有機(jī)會(huì)獲得另一個(gè)線程釋放的鎖,并從等待的地方起(第24行)起開始執(zhí)行。

?

接下來是兩個(gè)線程類,線程類ThreadA調(diào)用testMethod()方法執(zhí)行l(wèi)ock.wait();時(shí)被掛起,另一個(gè)線程類synNotifyMethodThread調(diào)用synNotifyMethod()負(fù)責(zé)喚醒掛起的線程。代碼如下:

?

1 public class ThreadA extends Thread {2 private Object lock;3 4 public ThreadA(Object lock) {5 super();6 this.lock = lock;7 }8 9 @Override 10 public void run() { 11 Service service = new Service(); 12 service.testMethod(lock); 13 } 14 } 15 16 public class synNotifyMethodThread extends Thread { 17 private Object lock; 18 19 public synNotifyMethodThread(Object lock) { 20 super(); 21 this.lock = lock; 22 } 23 24 @Override 25 public void run() { 26 Service service = new Service(); 27 service.synNotifyMethod(lock); 28 } 29 }

?

?

再接下來是測(cè)試類:

1 public class Test {2 3 public static void main(String[] args) throws InterruptedException {4 5 Object lock = new Object();6 7 ThreadA a = new ThreadA(lock);8 a.start();9 10 NotifyThread notifyThread = new NotifyThread(lock); 11 notifyThread.start(); 12 13 synNotifyMethodThread c = new synNotifyMethodThread(lock); 14 c.start(); 15 } 16 }

?

③中斷 調(diào)用wait()方法進(jìn)入等待隊(duì)列的 線程

示例代碼如下:

1 public class Service {2 3 public void testMethod(Object lock) {4 try {5 synchronized (lock) {6 System.out.println("begin wait()");7 lock.wait();8 System.out.println(" end wait()");9 } 10 } catch (InterruptedException e) { 11 e.printStackTrace(); 12 System.out.println("出現(xiàn)異常"); 13 } 14 } 15 } 16 17 public class ThreadA extends Thread { 18 19 private Object lock; 20 21 public ThreadA(Object lock) { 22 super(); 23 this.lock = lock; 24 } 25 26 @Override 27 public void run() { 28 Service service = new Service(); 29 service.testMethod(lock); 30 } 31 }

注意,在第23行wait()方法是Object類的對(duì)象lock調(diào)用的。而下面的interrupt()方法是ThreadA類的對(duì)象調(diào)用的。在ThreadA里面,將Object的對(duì)象作為參數(shù)傳給了testMethod()方法,ThreadA的run()方法去調(diào)用testMethod(),從而wait()使ThreadA的線程暫停了(暫停當(dāng)前執(zhí)行wait()的線程)。從這里可以看出一個(gè)區(qū)別:

Object類中與線程有關(guān)的方法:

1)notify/notifyAll

2)wait()/wait(long)

java.lang.Thread中與之相關(guān)的方法:

1)interrupt()

2)sleep()/sleep(long)

3)join()/suspend()/resume()....

測(cè)試類代碼如下:

1 public class Test {2 3 public static void main(String[] args) {4 5 try {6 Object lock = new Object();7 8 ThreadA a = new ThreadA(lock);9 a.start(); 10 11 Thread.sleep(5000); 12 13 a.interrupt(); 14 } catch (InterruptedException e) { 15 e.printStackTrace(); 16 } 17 } 18 }

當(dāng)執(zhí)行第13行的interrupt()時(shí),處于wait中的線程“立即”被喚醒(一般是立即響應(yīng)中斷請(qǐng)求),并拋出異常。此時(shí),線程也就結(jié)束了。

?

④notify 通知的順序不能錯(cuò)

假設(shè)在線程A中執(zhí)行wait(),在線程B中執(zhí)行notify()。但如果線程B先執(zhí)行了notify()然后結(jié)束了,線程A才去執(zhí)行wait(),那此時(shí),線程A將無法被正常喚醒了(還可以通過③中提到的interrupt()方法以拋出異常的方式喚醒^~^)。

這篇文章: JAVA多線程之線程間的通信方式中的第③點(diǎn)提到了notify通知順序出錯(cuò)會(huì)導(dǎo)致 調(diào)用wait()進(jìn)入等待隊(duì)列的線程再也無法被喚醒了。

?

⑤多線程中測(cè)試某個(gè)條件的變化用 if 還是用 while?

以前一直不明白 當(dāng)在線程的run()方法中需要測(cè)試某個(gè)條件時(shí),為什么用while,而不用if???直到看到了這個(gè)簡單的例子,終于明白了。。。。

這個(gè)例子是這樣的:

有兩個(gè)線程從List中刪除數(shù)據(jù),而只有一個(gè)線程向List中添加數(shù)據(jù)。初始時(shí),List為空,只有往List中添加了數(shù)據(jù)之后,才能刪除List中的數(shù)據(jù)。添加數(shù)據(jù)的線程向List添加完數(shù)據(jù)后,調(diào)用notifyAll(),喚醒了兩個(gè)刪除線程,但是它只添加了一個(gè)數(shù)據(jù),而現(xiàn)在有兩個(gè)喚醒的刪除線程,這時(shí)怎么辦??

如果用 if 測(cè)試List中的數(shù)據(jù)的個(gè)數(shù),則會(huì)出現(xiàn)IndexOutofBoundException,越界異常。原因是,List中只有一個(gè)數(shù)據(jù),第一個(gè)刪除線程把數(shù)據(jù)刪除后,第二個(gè)線程再去執(zhí)行刪除操作時(shí),刪除失敗,從而拋出 IndexOutofBoundException。

但是如果用while 測(cè)試List中數(shù)據(jù)的個(gè)數(shù),則不會(huì)出現(xiàn)越界異常!!!神奇。

當(dāng)wait等待的條件發(fā)生變化時(shí),會(huì)造成程序的邏輯混亂---即,List中沒有數(shù)據(jù)了,再還是有線程去執(zhí)行刪除數(shù)據(jù)的操作。因此,需要用while循環(huán)來判斷條件的變化,而不是用if。

示例如下:摘自《JAVA多線程編程核心技術(shù)》

Add類,負(fù)責(zé)添加數(shù)據(jù):

public class Add {private String lock;public Add(String lock) {super();this.lock = lock;}public void add() {synchronized (lock) {ValueObject.list.add("anyString");lock.notifyAll();}} }

public class ThreadAdd extends Thread {

?? ?private Add p;

?? ?public ThreadAdd(Add p) {
?? ??? ?super();
?? ??? ?this.p = p;
?? ?}

?? ?@Override
?? ?public void run() {
?? ??? ?p.add();
?? ?}
}

?

Subtract類,負(fù)責(zé)刪除數(shù)據(jù)----先要進(jìn)行條件判斷,然后執(zhí)行wait(),這意味著:wait等待的條件可能發(fā)生變化!!!

public class Subtract {private String lock;public Subtract(String lock) {super();this.lock = lock;}public void subtract() {try {synchronized (lock) {if(ValueObject.list.size() == 0) {//將這里的if改成while即可保證不出現(xiàn)越界異常!!!!System.out.println("wait begin ThreadName="+ Thread.currentThread().getName());lock.wait();System.out.println("wait end ThreadName="+ Thread.currentThread().getName());}ValueObject.list.remove(0);System.out.println("list size=" + ValueObject.list.size());}} catch (InterruptedException e) {e.printStackTrace();}} }

public class ThreadSubtract extends Thread {

?? ?private Subtract r;

?? ?public ThreadSubtract(Subtract r) {
?? ??? ?super();
?? ??? ?this.r = r;
?? ?}

?? ?@Override
?? ?public void run() {
?? ??? ?r.subtract();
?? ?}
}

?

封裝的List隊(duì)列:

public class ValueObject {public static List list = new ArrayList();}

?

測(cè)試類:

public class Run {public static void main(String[] args) throws InterruptedException {String lock = new String("");Add add = new Add(lock);Subtract subtract = new Subtract(lock);ThreadSubtract subtract1Thread = new ThreadSubtract(subtract);subtract1Thread.setName("subtract1Thread");subtract1Thread.start();ThreadSubtract subtract2Thread = new ThreadSubtract(subtract);subtract2Thread.setName("subtract2Thread");subtract2Thread.start();Thread.sleep(1000);ThreadAdd addThread = new ThreadAdd(add);addThread.setName("addThread");addThread.start();} }

轉(zhuǎn)載于:https://www.cnblogs.com/bangchen/p/6593955.html

總結(jié)

以上是生活随笔為你收集整理的JAVA多线程之wait/notify的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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