情境
要怎麼解釋wait的作用, 蠻難的. 這主題讓我想破了頭, 該用什麼例子讓大家輕易的明白呢.
好啦, 還是用我們的經典例子~~神奇寶貝來說明吧.
我的公司專門生產皮卡丘的玩偶. 公司每秒鐘只能生產一隻皮卡丘. 但因為賣的太好了, 很多的Vendor(販賣商, A店, B店, C店)都要來搶貨.
Vendor當然是到我公司的倉庫搶, 倉庫只有一個出貨窗口. 大家一個一個來, 有貨就通知ABC店來搶. 搶得到就拿去賣. 搶不到就只能跟買主說缺貨啦.
主程式
class Factory是我的公司, 專門製造皮卡丘玩偶.
Thread t1, t2, t3, 是我的販賣商, 三不五時都有客人要來買皮卡丘.
而我的公司有inventory(倉庫), getGoods(取貨)
class Pikachu則是我公司的產品.
public class JavaApp{
public static void main(String[] args) {
Factory factory=new Factory();
factory.start();
Vendor vendor=new Vendor(factory);
Thread t1=new Thread(vendor, "A店");
Thread t2=new Thread(vendor, "B店");
Thread t3=new Thread(vendor, "C店");
t1.start();
t2.start();
t3.start();
}
}
class Vendor implements Runnable{
Factory factory;
public Vendor(Factory factory){
this.factory=factory;
}
@Override
public void run() {
while(true){
synchronized(factory){
if(factory.warehouse.size()==0){
try {
//請注意, 此處是擁有factory物件鎖的執行緒到blocked區, 並不是warehouse去等待區
factory.wait();
} catch (InterruptedException ex) {}
}
if(factory.warehouse.size()!=0){
System.out.printf("%s:%s\n", Thread.currentThread().getName(), factory.warehouse.remove(0).product);
}
}
}
}
}
class Factory extends Thread{
//倉庫
Listwarehouse=new ArrayList<>();
//生產線, 每一秒生產一隻皮卡丘
public void run(){
while(true){
synchronized(this){
warehouse.add(new Pikachu());
this.notify();
}
try {
Thread.sleep(500);
} catch (InterruptedException ex) {}
}
}
}
//商品名稱 -- 皮卡丘
class Pikachu{
public static int sn=1;
public String product="";
public Pikachu(){
String tmp="";
for (int i=0;i<10;i++){
tmp+=(char)(Math.random()*26+65);
}
product=String.format("序號:%05d, 名稱 : %s", sn++, tmp);
}
}
結果如下
C店:序號:00001, 名稱 : ONFNSMTVIB C店:序號:00002, 名稱 : PVHOJRJETR B店:序號:00003, 名稱 : AQJXNUECMQ A店:序號:00004, 名稱 : OVSMKAWBDI C店:序號:00005, 名稱 : COYFIWGHYM B店:序號:00006, 名稱 : AAKIOGSNOE A店:序號:00007, 名稱 : YSDWJIQMFT C店:序號:00008, 名稱 : BGONCGANWW B店:序號:00009, 名稱 : MUPZVJINAY A店:序號:00010, 名稱 : CZMVMVBYYM C店:序號:00011, 名稱 : DCKIVZHKSU
重點
wait, 是讓目前執行緒, 在擁有某物件鎖且進入synchronized區塊後, 調用此物件的wait方法, 然後將目前執行緒推入等待區暫緩執行.
所以要使用wait方法, 一定要在synchronized的區塊會方法中. 執行緒經由wait推入blocked區後, 會交出物件鎖, 供其他執行緒使用.
其他執行緒取得物件鎖(進入synchronized)後, 可以使用notify通知等待區的一個執行緒復活. 或使用notifyAll讓所有執行緒復活.
請注意, factory.wait(); 是擁有factory物件鎖的執行緒到blocked區, 並不是factory去等待區.