读书人

java 中使用wait与notifyAll的奇怪的有

发布时间: 2012-02-22 19:36:56 作者: rapoo

java 中使用wait与notifyAll的奇怪的问题

Java code
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.
...

似乎是生产者在生产两个产品后,就在等待消费者消费,待消费者消费完成后再行生产。

请各位大侠帮忙看看,如果要达到输出一的效果,代码中应该如何调整?

谢谢!

[解决办法]
使用wait()与notify()/notifyAll()可以使得多个任务之间彼 此协作。

调用sleep()和yield()的时候锁并没有被释放,而调用wait() 将释放锁。这样另一个任务(线程)可以获得当前对象的锁,从而 进入它的synchronized方法中。可以通过notify()/notifyAll(), 或者时间到期,从wait()中恢复执行。

只能在同步控制方法或同步块中调用wait()、notify()和 notifyAll()。如果在非同步的方法里调用这些方法,在运行时会 抛出IllegalMonitorStateException异常。
[解决办法]
粗看了下,消费者根本不需要再主动等十秒,本身是从动方
再说已经有wait了,只要生产者生产够了10个产品,就通知消费者消费,同时等待
消费完了消费者再通知生产者继续生产
[解决办法]
我的做法:
1 根据线程同步规则,concume()执行时时不释放其同步对象的锁旗标的,所以在其sleep(10000)时间里,main 线程因要执行notifyProductGenerated()这个方法,而在等待池里等待锁旗标,而什么也干不了。(无法生产)。
2 根据上面的分析,关键是在consume等待时,不占有锁旗标,所以对consume()进行修改如下:


Java code
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.
[解决办法]
看看我这个 刚写的
Java code
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();                    }} 

读书人网 >J2SE开发

热点推荐