最近找工作,被問了很多多線程和鎖的知識,這裏總結一下多線程中wait()與notify()的用法。
直接上代碼(生產者/消費者模式:代碼來自馬士兵老師):
public class ProducerConsumer {
public static void main(String[] args) {
SyncStack ss = new SyncStack();
Producer p1 = new Producer(ss, "p1");
Producer p2 = new Producer(ss, "p2");
Consumer c1 = new Consumer(ss, "c1");
Consumer c2 = new Consumer(ss, "c2");
new Thread(p1).start();
new Thread(p2).start();
new Thread(c1).start();
new Thread(c2).start();
}
}
class WoTou {
int id;
public WoTou(int id) {
this.id = id;
}
public String toString() {
return "WoTou:" + id;
}
}
//放窩頭的籃子
class SyncStack {
int index = 0;
WoTou[] arrWoTou = new WoTou[6];
public synchronized void push(WoTou wt) {
while (index == arrWoTou.length) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notify();
arrWoTou[index] = wt;
index++;
}
public synchronized WoTou pop() {
while (index == 0) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notify();
index--;
return arrWoTou[index];
}
}
class Producer implements Runnable {
SyncStack ss = null;
String name;
Producer(SyncStack ss, String name) {
this.ss = ss;
this.name = name;
}
public void run() {
for (int i = 0; i < 20; i++) {
WoTou wt = new WoTou(i);
ss.push(wt);
System.out.println("procude_" + name + " : "+ wt);
try {
Thread.sleep((int) (Math.random() * 200));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable {
SyncStack ss = null;
String name;
Consumer(SyncStack ss, String name) {
this.ss = ss;
this.name = name;
}
public void run() {
for (int i = 0; i < 20; i++) {
WoTou wt;
wt = ss.pop();
System.out.println("consume_" + name + " : "+ wt);
try {
Thread.sleep((int) (Math.random() * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
1、wait() 和 notify()必須在有加鎖的時候才能使用;
2、this.wait()不是指當前對象等待,而是指持有當前對象的線程等待!!!
3、notify()是指:調用notify方法的當前線程1,叫醒等待在線程1持有的對象上(上面例子中的ss對象)的另外一個線程;
4、notifyAll()就是叫醒等待ss對象上的其他所有線程,一起去搶對象ss的鎖!