import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;public class Producer {
private final Queue<String> productQueue = new LinkedBlockingQueue<String> ();

private final List<Consumer> consumers = new ArrayList<Consumer> ();

public void addConsumer(Consumer c) {
this.consumers.add(c);
}

public void notifyProductGenerated() {
for(Consumer c : this.consumers) {
c.notifyProductGenerated();
}
}

public static void main(String... args) {
Producer producer = new Producer();
final Consumer consumer = new Consumer(producer.productQueue);

producer.addConsumer(consumer);

new Thread(new Runnable() {
@Override
public void run() {
consumer.consume();
}
}).start();

for(int i = 0; i < 100; i++) {
try {
Thread.sleep(1000 * 1);
} catch(InterruptedException ex) {
ex.printStackTrace();
}

producer.productQueue.add("" + i);
System.out.println("" + i + " made.");

producer.notifyProductGenerated();
}
}
}class Consumer {
private Queue<String> productQueue;

public Consumer(Queue<String> productQueue) {
this.productQueue = productQueue;
}

public synchronized void notifyProductGenerated() {
notifyAll();
}

public synchronized void consume() {
String product = null;

while(true) {
product = productQueue.poll();

if(product == null) {
try {
wait();
continue;
} catch (InterruptedException ex) {
ex.printStackTrace();
return;
}
}

try {
Thread.sleep(1000 * 10);
} catch(InterruptedException ex) {
ex.printStackTrace();
return;
}

System.out.println("run out of product " + product);
}
}
}
以上代码是模拟生产者与消费者。当生产者生成出产品后,将通知消费者,消费都进而消费。
代码中设计成消费者每一秒生产一个产品,而消费者每10秒才能消费一个产品。
所以,我期待的输出应该像这样(输出一):
0 made.
1 made.
2 made.
3 made.
4 made.
5 made.
6 made.
7 made.
8 made.
9 made.
10 made.
run out of product 0
11 made.
12 made.
...然而输出的结果却是这样(输出二):
0 made.
1 made.
run out of product 0
run out of product 1
2 made.
3 made.
run out of product 2
run out of product 3
4 made.
...似乎是生产者在生产两个产品后,就在等待消费者消费,待消费者消费完成后再行生产。请各位大侠帮忙看看,如果要达到输出一的效果,代码中应该如何调整?谢谢!

解决方案 »

  1.   

    使用wait()与notify()/notifyAll()可以使得多个任务之间彼 此协作。调用sleep()和yield()的时候锁并没有被释放,而调用wait() 将释放锁。这样另一个任务(线程)可以获得当前对象的锁,从而 进入它的synchronized方法中。可以通过notify()/notifyAll(), 或者时间到期,从wait()中恢复执行。只能在同步控制方法或同步块中调用wait()、notify()和 notifyAll()。如果在非同步的方法里调用这些方法,在运行时会 抛出IllegalMonitorStateException异常。
      

  2.   

    粗看了下,消费者根本不需要再主动等十秒,本身是从动方
    再说已经有wait了,只要生产者生产够了10个产品,就通知消费者消费,同时等待
    消费完了消费者再通知生产者继续生产
      

  3.   

     我的做法:
    1 根据线程同步规则,concume()执行时时不释放其同步对象的锁旗标的,所以在其sleep(10000)时间里,main  线程因要执行notifyProductGenerated()这个方法,而在等待池里等待锁旗标,而什么也干不了。(无法生产)。
    2 根据上面的分析,关键是在consume等待时,不占有锁旗标,所以对consume()进行修改如下:
    public void consume()
    {
             String product = null;
    int number=0; //计数器,到100时线程正常结束。
    while(number<100)
    {
    try //把休眠等待放在同步块外。
    {
    Thread.sleep(100*10);
    }
    catch(InterruptedException ex)
    {
    ex.printStackTrace();
    } synchronized(this) //与notifyProductGenerated()共用同一同步对象。
    {
    product = productQueue.poll();
                
                 if(product == null)
            {
                     try 
    {
                         wait();
                         continue; //?
                     }
            catch (InterruptedException ex)
            {
                         ex.printStackTrace();
                         return;
                     }
    }//end if(product == null)
                 System.out.println("run out of product " + product);
    }//end synchronized block.
      

  4.   

    上面少贴了一部分:
    number++;
    }//end while
    }//end consume.
    休眠的时间为了调试的快,改小了。 楼主再改回即可。
      

  5.   

    看看我这个 刚写的
    class Info
    {
    private String value=null;
    private String key=null;
    private boolean flag=false;
    public synchronized void set(String value,String key)
    {
    if(flag)
    {
    try {
    super.wait();
    } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }
    this.setKey(key);
    this.setValue(value);
    flag=true;
    super.notify();
    }
    public void setValue(String value)
    {
    this.value=value;
    }
    public void setKey(String key)
    {
    this.key=key;
    }
    public String getKey()
    {
    return this.key;
    }
    public String getValue()
    {
    return this.value;
    }
    public synchronized void get()
    {
    if(!flag)
    {
    try {
    super.wait();
    } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }
    System.out.println(this.getKey()+"-----------"+this.getValue());
    flag=false;
    super.notify();


    }
    }
    class SetRun implements Runnable
    {
    private Info info=null;
    public SetRun(Info info)
    {
    this.info=info;
    }
    public void run()
    {
    boolean flag=false;
    for(int i=0;i<50;i++)
    {
    if(flag)
    {
    this.info.set("河南大学","henu.edu.cn");
    flag=false;
    }
    else
    {
    this.info.set("百度","www.baidu.com");
    flag=true;

    }
    }
    }
    }
    class GetRun implements Runnable
    {
    private Info info=null;
    public GetRun(Info info)
    {
    this.info=info;
    }
    public void run()
    {
    for(int i=0;i<50;i++)
    {
    this.info.get();
    }
    }
    }
    public class MyThread
    {
    public static void main(String[] args)
    {
    Info info=new Info();
    new Thread(new SetRun(info)).start();
    new Thread(new GetRun(info)).start();


    }}