線程間的通信(生產(chǎn)者-消費者模式)
有如下情形,線程A向盤子里放桔子(盤子很小,只能容得下一個桔子),放完桔子后,如果其它線程沒有來拿桔子,則A下次再放桔子時,留在盤子里的上次那個桔子就被覆蓋掉了(現(xiàn)實并非這樣),但我們并不希望這個可口的桔子就這樣被第二個桔子覆蓋掉。我們的理想情況是:線程A每次在盤子里放完一個桔子后,馬上通知其它線程來取這個桔子,這時,線程A就暫停放桔子在盤子里,其它線程取走桔子之后,馬上通知A桔子已經(jīng)被取走,這時,A繼續(xù)放下一個桔子,并通知其它線程來取,這樣反復下去(為了不讓產(chǎn)生者永久的放,消費者永久地取,可限定生產(chǎn)者一共要放100次桔子)……于是,放一個就取走一個,所有桔子都被成功取走。
在上述案例子中,線程A與線程B之間是生產(chǎn)者與消費者的關系,線程A生產(chǎn)桔子,把桔子在盤子里,線程B從盤子里拿走桔子,享受美味。而且,為了達到生產(chǎn)一個,拿走一個,這樣的一對一的過程,線程A必須告訴線程B:桔子已經(jīng)放好了,來拿吧,你拿走了,我再放下一個。當線程B拿走后,必須告訴線程A:我把桔子拿走了,你快放下一個吧。線程A和B互相告訴對方的動作,就是線程間的通信。
取放桔子的整個過程,涉及到了四個對象,分別是生產(chǎn)者(線程A),消費者(線程B),消費的商品(桔子),商店(盤子)。因此,可以把上述過程看作是生產(chǎn)者和消費者在商店里交易桔子。下圖描繪了上述整個過程:

下面的代碼實現(xiàn)了本案例:
class MyTest1{
public static void main(String[] args){
Panel pan = new Panel();
Consumer c = new Consumer(pan);
Producer p = new Producer(pan, c);
c.setDaemon(true);/*將消費者設為守護線程,也就是說,當生產(chǎn)者不再生產(chǎn)時,消費者立即主動不再消費*/
p.start();
c.start();
}
}
class Producer extends Thread{
Panel pan = null;
Consumer c = null;
public Producer(Panel pan, Consumer c){
this.pan = pan;
this.c = c;
}
public void run(){
synchronized(c){
int count = 0;
//Examda提示: 生產(chǎn)者一共要生產(chǎn)100個桔子
while(count++ < 100){
if(!pan.isBlank){
try{c.wait();}catch(Exception ex){ex.printStackTrace();}
}
int orgWeight = (int)(Math.random() * 100);
Orange org = new Orange(orgWeight, "red");
pan.putOrange(org);
c.notify();
}
}
}
}
class Consumer extends Thread{
Panel pan;
public Consumer(Panel pan){
this.pan = pan;
}
public void run(){
synchronized(this){
while(true){
if(pan.isBlank){
try{wait();}catch(Exception ex){ex.printStackTrace();}
}
pan.getOrange();
notify();
}
}
}
}
class Orange{
int weight;
String color;
public Orange(int weight, String color){
this.weight = weight;
this.color = color;
}
public String toString(){
return "Orange, weight = " + weight + ", color = " + color;
}
}
class Panel{
public boolean isBlank = true;
private Orange org;
public void putOrange(Orange org){
this.org = org;
isBlank = false;
System.out.println("I put: " + org.toString());
}
public Orange getOrange(){
System.out.println("I get: " + org.toString());
isBlank = true;
return org;
}
}
有如下情形,線程A向盤子里放桔子(盤子很小,只能容得下一個桔子),放完桔子后,如果其它線程沒有來拿桔子,則A下次再放桔子時,留在盤子里的上次那個桔子就被覆蓋掉了(現(xiàn)實并非這樣),但我們并不希望這個可口的桔子就這樣被第二個桔子覆蓋掉。我們的理想情況是:線程A每次在盤子里放完一個桔子后,馬上通知其它線程來取這個桔子,這時,線程A就暫停放桔子在盤子里,其它線程取走桔子之后,馬上通知A桔子已經(jīng)被取走,這時,A繼續(xù)放下一個桔子,并通知其它線程來取,這樣反復下去(為了不讓產(chǎn)生者永久的放,消費者永久地取,可限定生產(chǎn)者一共要放100次桔子)……于是,放一個就取走一個,所有桔子都被成功取走。
在上述案例子中,線程A與線程B之間是生產(chǎn)者與消費者的關系,線程A生產(chǎn)桔子,把桔子在盤子里,線程B從盤子里拿走桔子,享受美味。而且,為了達到生產(chǎn)一個,拿走一個,這樣的一對一的過程,線程A必須告訴線程B:桔子已經(jīng)放好了,來拿吧,你拿走了,我再放下一個。當線程B拿走后,必須告訴線程A:我把桔子拿走了,你快放下一個吧。線程A和B互相告訴對方的動作,就是線程間的通信。
取放桔子的整個過程,涉及到了四個對象,分別是生產(chǎn)者(線程A),消費者(線程B),消費的商品(桔子),商店(盤子)。因此,可以把上述過程看作是生產(chǎn)者和消費者在商店里交易桔子。下圖描繪了上述整個過程:

下面的代碼實現(xiàn)了本案例:
class MyTest1{
public static void main(String[] args){
Panel pan = new Panel();
Consumer c = new Consumer(pan);
Producer p = new Producer(pan, c);
c.setDaemon(true);/*將消費者設為守護線程,也就是說,當生產(chǎn)者不再生產(chǎn)時,消費者立即主動不再消費*/
p.start();
c.start();
}
}
class Producer extends Thread{
Panel pan = null;
Consumer c = null;
public Producer(Panel pan, Consumer c){
this.pan = pan;
this.c = c;
}
public void run(){
synchronized(c){
int count = 0;
//Examda提示: 生產(chǎn)者一共要生產(chǎn)100個桔子
while(count++ < 100){
if(!pan.isBlank){
try{c.wait();}catch(Exception ex){ex.printStackTrace();}
}
int orgWeight = (int)(Math.random() * 100);
Orange org = new Orange(orgWeight, "red");
pan.putOrange(org);
c.notify();
}
}
}
}
class Consumer extends Thread{
Panel pan;
public Consumer(Panel pan){
this.pan = pan;
}
public void run(){
synchronized(this){
while(true){
if(pan.isBlank){
try{wait();}catch(Exception ex){ex.printStackTrace();}
}
pan.getOrange();
notify();
}
}
}
}
class Orange{
int weight;
String color;
public Orange(int weight, String color){
this.weight = weight;
this.color = color;
}
public String toString(){
return "Orange, weight = " + weight + ", color = " + color;
}
}
class Panel{
public boolean isBlank = true;
private Orange org;
public void putOrange(Orange org){
this.org = org;
isBlank = false;
System.out.println("I put: " + org.toString());
}
public Orange getOrange(){
System.out.println("I get: " + org.toString());
isBlank = true;
return org;
}
}