2014-07-12 79 views
0

我正在練習這個着名的應用程序,並有一個問題。我發現這個網站有4000個關於這個主題的Q/A,但是沒有一個與這個問題有關,因此提出這個問題。JAVA消費者生產者多線程應用程序 - 代碼流程

下面是簡單的代碼 -

class Resource { 
    int contents; 
    boolean available = false; 
} 

class Producer implements Runnable { 
    Thread t; 
    private Resource resource; 

    public Producer(Resource c) { 
     resource = c; 
     t=new Thread(this); 
     t.start(); 
    } 

    public void run() { 
     for (int i = 0; i < 3; i++) { 
      synchronized (resource) { 
       while (resource.available == true) { 
        //System.out.println("Producer -> calling wait"); 
        try { 
LINE 1     resource.wait(); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
       } 
LINE 2   resource.contents = i; 
       resource.available = true; 
       //System.out.println("Producer -> calling notify"); 
       resource.notify(); 
       System.out.println("Producer " + " put: " + resource.contents); 
       try { 
        Thread.sleep((int)(Math.random() * 100)); 
       } catch (InterruptedException e) { } 
      } 
     } 
    } 
} 

class Consumer implements Runnable { 
    Thread t; 
    private Resource resource; 

    public Consumer(Resource c) { 
     resource= c; 
     t=new Thread(this); 
     t.start(); 
    } 

    public void run() { 
     for (int i = 0; i < 3; i++) { 
      synchronized (resource) { 
       while (resource.available == false) { 
        System.out.println("Consumer -> calling wait"); 
        try { 
LINE 3     resource.wait(); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
       } 
LINE 4   resource.available = false; 
       //System.out.println("Consumer -> calling notify"); 
       resource.notify(); 
       System.out.println("Consumer " + " got: " + resource.contents); 
      } 
     } 
    } 
} 

public class ProducerConsumerTest { 
    public static void main(String[] args) { 
     Resource c = new Resource(); 
     Producer p1 = new Producer(c); 
     Consumer c1 = new Consumer(c); 
    } 
} 

這裏是輸出 -

#1 Producer put: 0 
#2 Consumer got: 0 
#3 Consumer -> calling wait 
#4 Producer put: 1 
#5 Consumer got: 1 
#6 Consumer -> calling wait 
#7 Producer put: 2 
#8 Consumer got: 2 

所以這裏的代碼流 -

#1 Since available=false, Producer will go to LINE 2, make available=true and notify the other thread. 
#2 Since available=true, Consumer will go to LINE 4, make available=false and notify the other thread. 
#3 So now code should go back to the Producer thread. But why Consumer is entering it's own wait() block at LINE 3? 

我失去了一些東西簡單?你能解釋一下嗎?

很多人提前感謝。

回答

1

你問

3所以,現在的代碼應該回到生產者線程。但爲什麼消費者 在LINE 3上輸入自己的wait()塊?

好消費者線程將繼續運行後,它使available=false並通知其他線程。直到生產者線程不可用=真,它會調用wait和blocking。實行生產者/消費者模式

最好的辦法是通過BlockingQueue

這裏是example

+0

嗨薩克 - 非常感謝答覆。所以重點是消費者線程將繼續運行 - 它將在它的塊內來回遍歷,直到它調用wait(),然後控件將轉到另一個線程。我錯過了這一點。歡呼,從我的盡頭! –

+0

是的,你是對的。 –

0

我怎麼沒看到你的線程正在協調他們的活動。生產者睡覺時不等待資源。當消費者調用resource.notify()時,可能沒有Producer正在等待資源。

由於@M Sach已經指出,消費者線程可以自由地繼續處理。

在這一點上,兩個線程並不通過資源相互協調,所以觀察到的行爲似乎與正在運行的消費者和睡眠生產者預期的一樣。

+0

嗨Rich,非常感謝您的回答。是的,代碼並不完美,我只是從一些互聯網站點拿起,以便於理解。我同意在一個線程調用notify()之後,這些線程之間沒有這種通信。正如我所評論的,我瞭解線程將繼續運行的真正意義。我試圖讓兩個答案都被接受,但不幸的是我只能做到一個!感謝我的結束! –

+0

嗨,我再次困惑!請原諒我。在這種情況下,當代碼到達LINE 4時,爲什麼代碼會再次回到LINE 3?消費者線程爲什麼會繼續運行?如果我刪除'for(int i = 0; i <3; i ++)'行,那麼即使LINE 3正在執行。我沒有真正明白這一點 - 如果你能解釋,我會很感激。 –

+0

LINE 4設置resource.available = false,所以下一次消費者通過for循環運行時,它將轉到LINE 3,除非生產者在此期間設置了resource.available = true。由於Producer線程處於睡眠狀態,因此可能是資源。可用仍然是錯誤的。 – richj