在java中,執行緒間的通信可以使用wait、notify、notifyAll來進行控制,從名字就可以看出來這3個方法都是跟多執行緒相關的,但是可能讓你感到吃驚的是:這3個方法并不是Thread類或者是Runnable介面的方法,而是Object類的3個本地方法,
下圖是我總結的Java資料,想要資料的話請點795983544暗號CSDN,

其實要理解這一點也并不難,呼叫一個Object的wait與notify/notifyAll的時候,必須保證呼叫代碼對該Object是同步的,也就是說必須在作用等同于synchronized(obj){…}的內部才能夠去呼叫obj的wait與notify/notifyAll三個方法,否則就會報錯:
java.lang.IllegalMonitorStateException:current thread not owner
也就是說,在呼叫這3個方法的時候,當前執行緒必須獲得這個物件的鎖,那么這3個方法就是和物件鎖相關的,所以是屬于Object的方法而不是Thread,因為不是每個物件都是Thread,所以我們在理解wait、notify、notifyAll之前,先要了解以下物件鎖,
多個執行緒都持有同一個物件的時候,如果都要進入synchronized(obj){…}的內部,就必須拿到這個物件的鎖,synchronized的機制保證了同一時間最多只能有1個執行緒拿到了物件的鎖,如下圖:

下面我們來看一下這3個方法的作用:
- wait:執行緒自動釋放其占有的物件鎖,并等待notify
- notify:喚醒一個正在wait當前物件鎖的執行緒,并讓它拿到物件鎖
- notifyAll:喚醒所有正在wait前物件鎖的執行緒
notify和notifyAll的最主要的區別是:notify只是喚醒一個正在wait當前物件鎖的執行緒,而notifyAll喚醒所有,值得注意的是:notify是本地方法,具體喚醒哪一個執行緒由虛擬機控制;notifyAll后并不是所有的執行緒都能馬上往下執行,它們只是跳出了wait狀態,接下來它們還會是競爭物件鎖,
下面通過一個常用生產者、消費者的例子來說明,
訊息物體類:
package com.podongfeng;
/**
* Title: Message.class<br>
* Description: 訊息物體<br>
* Create DateTime: 2016年04月17日 下午1:27 <br>
*
* @author podongfeng
*/
public class Message {
}
生產者:
package com.podongfeng;
import java.util.ArrayList;
import java.util.List;
/**
* Title: Producer.class<br>
* Description: 訊息生產者<br>
* Create DateTime: 2016年04月17日 下午1:28 <br>
*
* @author podongfeng
*/
public class Producer extends Thread {
List<Message> msgList = new ArrayList<>();
@Override public void run() {
try {
while (true) {
Thread.sleep(3000);
Message msg = new Message();
synchronized(msgList) {
msgList.add(msg);
msgList.notify(); //這里只能是notify而不能是notifyAll,否則remove(0)會報java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public Message waitMsg() {
synchronized(msgList) {
if(msgList.size() == 0) {
try {
msgList.wait();
} catch(InterruptedException e) {
e.printStackTrace();
}
}
return msgList.remove(0);
}
}
}
消費者:
package com.podongfeng;
/**
* Title: Consumer.class<br>
* Description: 訊息消費者<br>
* Create DateTime: 2016年04月17日 下午1:28 <br>
*
* @author podongfeng
*/
public class Consumer extends Thread {
private Producer producer;
public Consumer(String name, Producer producer) {
super(name);
this.producer = producer;
}
@Override public void run() {
while (true) {
Message msg = producer.waitMsg();
System.out.println("Consumer " + getName() + " get a msg");
}
}
public static void main(String[] args) {
Producer p = new Producer();
p.start();
new Consumer("Consumer1", p).start();
new Consumer("Consumer2", p).start();
new Consumer("Consumer3", p).start();
}
}
消費者執行緒呼叫waitMsg去獲取一個訊息物體,如果msgList為空,則執行緒進入wait狀態;生產這執行緒每隔3秒鐘生產出體格msg物體并放入msgList串列,完成后,呼叫notify喚醒一個消費者執行緒去消費,
最后再次提醒注意:
wait、notify、notifyAll并不是Thread類或者是Runnable介面的方法,而是Object類的3個本地方法,
在呼叫這3個方法的時候,當前執行緒必須獲得這個物件的鎖
最后的慣例:點個小贊,好運不斷,來個關注,青春常駐,打個小賞,工資瘋漲,,,

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/230982.html
標籤:java

