2010-02-28 84 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-一样,但它也会阻止生产者,直到消费者完成上一轮工作。

就你而言,消费者可能没有任何有用的东西可以回到生产者身上。无论如何,你可以在参与者之间形成一个协议。当生产者希望消费者线程关闭时,它可以提供一个空值。一旦消费者接受空值,生产者可能会进行一轮交换来完成关闭请求并收集消费者的任何最终结果。