wait(),notify()和notifyAll()都是Java基類java.lang.Object的方法。
通俗解釋
wait():在當前線程等待其它線程喚醒。
notify(): 喚醒一個線程正在等待這個對象的監視器。
notifyAll(): 喚醒在這個對象監視器上等待的所有線程。
這三個方法,都是Java語言提供的實現線程間阻塞(Blocking)和控制進程內調度(inter-process communication)的底層機制。
下面通過一個生產者/消費者的例子來講解這三個方法的使用
/**
* 消費者
* Created by Wiki on 16/1/28.
*/
public class Customer implements Runnable {
private String name;
private Channel channel;
public Customer(String name, Channel channel) {
this.name = name;
this.channel = channel;
}
@Override
public void run() {
while (true) {
Good good = channel.get();
if (good != null) {
System.out.println(name + " 獲得商品:" + good.getName());
} else {
synchronized (channel) {
try {
System.out.println(name + " 進入等待");
channel.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
/**
* 生產者
* Created by Wiki on 16/1/28.
*/
public class Producer implements Runnable {
private static volatile int goodNumber = 0;
private String name;
private Channel channel;
public Producer(String name, Channel channel) {
this.name = name;
this.channel = channel;
}
@Override
public void run() {
while (true) {
int sleep = new Random().nextInt(2000);
try {
Thread.sleep(sleep);
} catch (InterruptedException e) {
e.printStackTrace();
}
Good good = new Good("商品-編號" + (++goodNumber));
System.out.println(name + " 生產商品:" + good.getName());
channel.put(good);
}
}
}
/**
* 商品
* Created by Wiki on 16/1/28.
*/
public class Good {
private String name;
public Good(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
/**
* 消費通道
* Created by Wiki on 16/1/28.
*/
public class Channel {
private Queue<Good> goodList = new LinkedList<>();
public synchronized Good get() {
if (goodList.size() == 0) {
return null;
}
Good good = goodList.remove();
return good;
}
public synchronized void put(Good good) {
goodList.add(good);
// notifyAll();
notify();
}
}
public class Main {
public static void main(String[] args) {
Channel channel = new Channel();
new Thread(new Producer("生產者1", channel)).start();
new Thread(new Producer("生產者2", channel)).start();
new Thread(new Producer("生產者2", channel)).start();
new Thread(new Customer("消費者1", channel)).start();
new Thread(new Customer("消費者2", channel)).start();
new Thread(new Customer("消費者3", channel)).start();
}
}
運行結果分析一(notify):
每次生產一個商品調用notify時,都只喚醒一個消費者進行消費,喚醒原則是從等待時間最長的開始。
消費者1 進入等待
消費者2 進入等待
消費者3 進入等待
生產者1 生產商品:商品-編號1
消費者1 獲得商品:商品-編號1
消費者1 進入等待
生產者2 生產商品:商品-編號2
消費者2 獲得商品:商品-編號2
消費者2 進入等待
生產者2 生產商品:商品-編號3
消費者3 獲得商品:商品-編號3
消費者3 進入等待
生產者1 生產商品:商品-編號4
消費者1 獲得商品:商品-編號4
消費者1 進入等待
生產者1 生產商品:商品-編號5
消費者2 獲得商品:商品-編號5
消費者2 進入等待
...
運行結果分析二(把notify改成notifyAll):
每生產一件商品時調用notifyAll,都會把所有的消費者喚醒。
消費者1 進入等待
消費者3 進入等待
消費者2 進入等待
生產者2 生產商品:商品-編號1
消費者3 進入等待
消費者2 獲得商品:商品-編號1
消費者1 進入等待
消費者2 進入等待
生產者2 生產商品:商品-編號2
消費者2 獲得商品:商品-編號2
消費者1 進入等待
消費者3 進入等待
消費者2 進入等待
生產者2 生產商品:商品-編號3
消費者2 獲得商品:商品-編號3
...
