2010-02-28 82 views
1

我想創建一個線程,當值變爲空時將值放入隊列中,等待這種情況,而不是。這裏是我試過使用的代碼,但它打印在Java中等待條件

Adding new 
Taking Value 1 
Taking Value 2 
Taking Value 3 
Taking Value 4 

所以它只工作一次。問題是什麼?

import java.util.concurrent.BlockingQueue; 
import java.util.concurrent.LinkedBlockingQueue; 


public class SO { 
    public String test; 
    public String[] list = new String[] {test}; 

    public static void main(String[] args) { 
     new SO(); 
    } 

    public SO() { 
     go(); 
    } 

    BlockingQueue<String> qq = new LinkedBlockingQueue<String>(); 

    class Producer implements Runnable { 
     public void run() { 
      try { 
       while (true) { 
        synchronized (this) { 
         while (qq.size() > 0) 
          wait(); 

         System.out.println("Adding new"); 
         qq.put("Value 1"); 
         qq.put("Value 2"); 
         qq.put("Value 3"); 
         qq.put("Value 4"); 
        } 
       } 
      } catch (InterruptedException ex) {} 
     } 
    } 

    class Consumer implements Runnable { 
     public void run() { 
      try { 
       while(true) { 
        System.out.println("Taking " + qq.take()+". "+String.valueOf(qq.size())+" left"); 
        Thread.sleep(1000); 
       } 
      } catch (InterruptedException ex) {} 
     } 
    } 

    public void go() { 
     Producer p = new Producer(); 
     Consumer c = new Consumer(); 

     new Thread(p).start(); 
     new Thread(c).start(); 
    } 
} 
+0

而不是使用等待/通知和相關大小檢查邏輯,您可以使用隊列上的LinkedBlockingQueue.put來做到這一點(取決於您是否希望多個對象在隊列中等待消耗)的容量1。'put'方法javadocs說:「將指定的元素插入此隊列的尾部,如果有必要,等待空間變爲可用。」 – Ash 2010-02-28 10:49:53

回答

1

wait()會永遠持續下去,因爲你永遠不會調用notify()。

您可以在隊列上等待,並在您希望等待線程喚醒時調用通知。要做到這一點,你會改變生產者閱讀:

 
    synchronized (qq) { 
     while (qq.size() > 0) 
      qq.wait(); 

      System.out.println("Adding new"); 
      qq.put("Value 1"); 
      qq.put("Value 2"); 
      qq.put("Value 3"); 
      qq.put("Value 4"); 
    } 

並改變消費者閱讀:

 
    while(true) { 
     synchronized (qq) { 
      System.out.println("Taking " + qq.take() + ". " + String.valueOf(qq.size()) + " left"); 
      qq.notify(); 
     } 
     Thread.sleep(1000); 
    } 

正如史蒂夫說,在他的回答,你也可以使用的wait()在消費線程,以便它可以等到列表中有東西而不是睡覺。所以,你的代碼將變成:

 
import java.util.concurrent.BlockingQueue; 
import java.util.concurrent.LinkedBlockingQueue; 

public class SO { 
    public String test; 
    public String[] list = new String[] { test }; 

    public static void main(String[] args) { 
     new SO(); 
    } 

    public SO() { 
     go(); 
    } 

    BlockingQueue qq = new LinkedBlockingQueue(); 

    class Producer implements Runnable { 
     public void run() { 
      try { 
       while (true) { 
        synchronized (qq) { 
         if (!qq.isEmpty()) { 
          qq.wait(); 
         } 

         System.out.println("Adding new"); 
         qq.put("Value 1"); 
         qq.put("Value 2"); 
         qq.put("Value 3"); 
         qq.put("Value 4"); 
         qq.notify(); 
        } 
       } 
      } catch (InterruptedException ex) { 
      } 
     } 
    } 

    class Consumer implements Runnable { 
     public void run() { 
      try { 
       while (true) { 
        synchronized (qq) { 
         System.out.println("Taking " + qq.take() + ". " 
           + String.valueOf(qq.size()) + " left"); 
         if (qq.isEmpty()) { 
          qq.notify(); 
          qq.wait(); 
         } 
        } 
       } 
      } catch (InterruptedException ex) { 
      } 
     } 
    } 

    public void go() { 
     Producer p = new Producer(); 
     Consumer c = new Consumer(); 

     new Thread(p).start(); 
     new Thread(c).start(); 
    } 
} 
3

wait()永遠不會被通知。

0

SICE您使用BlockingQueue,你不必使用​​,因爲BlockingQueue默認情況下sychronized。如果你想使用同步,比你應該同步槽相同的對象:

synchronized(theSameObjectInstance) { 
    while (true) {       
     while (qq.size() > 0) 
      theSameObjectInstance.wait();        

     System.out.println("Adding new"); 
     qq.put("Value 1"); 
     ... 

     theSameObjectInstance.notifyAll(); 
    } 
} 

和消費者的方法應以收到通知,被包裹在synchronized(theSameObjectInstance),消費者也應「等待」如某處當qq爲空時。

0

您的要求聲明,如果您打算在值爲空時將放入隊列中,則我需要這些值,而不僅僅是一個值。如果您的要求略有變化,說您將一個物品放入隊列中,並等待其在放入另一個物品之前消耗,那麼您將使用java.util.concurrent.Exchanger已經成熟。

它的行爲類似於深度爲BlockingQueue的行爲,但它做得更多一些:它傳遞一個對象的兩種方式,其中每個參與者既是「生產者」又是「消費者」。因此,Exchanger將不會接受「製作人」提供的物品,直到「消費者」也準備提供物品。對於「製片人」來說,這不是「火和遺忘」;生產和消費時機是相互聯繫的。這可以防止實際生產者淹沒消費者的工作隊列 - 再次像BlockingQueue-一樣,但它也會阻止生產者,直到消費者完成上一輪工作。

就你而言,消費者可能沒有任何有用的東西可以回到生產者身上。無論如何,你可以在參與者之間形成一個協議。當生產者希望消費者線程關閉時,它可以提供一個空值。一旦消費者接受空值,生產者可能會進行一輪交換來完成關閉請求並收集消費者的任何最終結果。