等待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 qq = new LinkedBlockingQueue(); 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(); } }
wait()将永远继续,因为您从不调用notify()。
您可以等待队列并在您希望等待线程唤醒时调用notify。 要执行此操作,您需要将Producer更改为:
synchronized(qq){ while(qq.size()> 0) qq.wait(); System.out.println(“添加新”); qq.put(“价值1”); qq.put(“价值2”); qq.put(“价值3”); qq.put(“价值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; 公共课SO { public String test; public String [] list = new String [] {test}; public static void main(String [] args){ 新的SO(); } public SO(){ 走(); } BlockingQueue qq = new LinkedBlockingQueue(); class Producer实现Runnable { public void run(){ 尝试{ while(true){ synchronized(qq){ if(!qq.isEmpty()){ qq.wait(); } System.out.println(“添加新”); qq.put(“价值1”); qq.put(“价值2”); qq.put(“价值3”); qq.put(“价值4”); qq.notify(); } } } catch(InterruptedException ex){ } } } class Consumer实现Runnable { public void run(){ 尝试{ 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(); 消费者c =新消费者(); new Thread(p).start(); new Thread(c).start(); } }
从不通知wait()
。
您正在使用BlockingQueue
,您不必使用synchronized
,因为默认情况下BlockingQueue
是同步的。 如果要使用同步,则应通过同一对象进行同步:
synchronized(theSameObjectInstance) { while (true) { while (qq.size() > 0) theSameObjectInstance.wait(); System.out.println("Adding new"); qq.put("Value 1"); ... theSameObjectInstance.notifyAll(); } }
并且消费者的方法应该包含在synchronized(theSameObjectInstance)
中以便接收通知,消费者也应该“等待”某处,例如当qq为空时。
您的要求声明您打算在值为空时将值放入队列中 – 我接受的是几个值,而不仅仅是一个值。 如果你的要求略有改变,说你把一个项目放入队列并等到它被消耗掉然后放入另一个项目,那么你就可以使用java.util.concurrent.Exchanger
。
它的行为类似于深度为1的BlockingQueue
,但它做的更多:它以两种方式传递一个对象,其中每个参与者都是“生产者”和“消费者”。 因此,在“消费者”也准备好提供物品之前, Exchanger
者不会接受“生产者”提供的物品。 对于“制片人”来说,这不是“火与忘”; 生产和消费时间是互锁的。 这可以防止实际的生产者淹没消费者的工作队列 – 再次像BlockingQueue
一样 – 但它也会BlockingQueue
生产者,直到消费者完成最后一轮工作。
在您的情况下,消费者可能没有任何有用的东西可以返回生产者。 无论如何,您可以在参与者之间形成协议。 当生产者希望消费者线程关闭时,它可以提供空值。 一旦消费者接受空值,生产者可以再进行一轮交换以完成关闭请求并从消费者处收集任何最终结果。