JAVA技巧(Java線程間的通信)

字號:

線程間的通信(生產(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;
    }
    }