通知方法不会在循环中唤醒wait方法

时间:2017-07-20 14:46:59

标签: java

我有两个班级ThreadsProducerConsumer。在Thread中我运行了两个线程:一个用于添加元素,第二个用于删除添加的元素。

问题是在删除第一个元素后consume()中,notify不会唤醒wait方法。在第二次迭代中,它正在通知。

我的要求是我希望每次迭代都通知生产者。我需要做什么?

public class Threads {
    public static void main(String args[]){ 
        ProducerConsumer pc = new ProducerConsumer(); 
        new Thread(){  
        public void run(){pc.produce();}  
        }.start();

        new Thread(){  
        public void run(){pc.consume();}  
        }.start();  
    }
}


    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.LinkedList;
    import java.util.List;

    public class ProducerConsumer {
        LinkedList<Integer> list = new LinkedList<>();
        public synchronized void produce() {
            for(int j = 0; j < 5; j++) {
                list.add(j);
                System.out.println(list+"producer");
                System.out.println("producing and adding values"+j);
                   try {
                        wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
            }

        }
        public synchronized void consume() {
                for(int j = 0; j < 5; j++) {
                    System.out.println(list+"list"+"consumer");
                    list.removeFirst();
                    System.out.println("consuming values"+j);
                    notify();
                }
        }
    }

1 个答案:

答案 0 :(得分:0)

当我运行此代码时,它会产生NoSuchElementException。问题是,在通知消费线程后不会释放监视器,因此生产将永远不会恢复。对代码的一个简单修复就是以更加亲切的方式编写消费,比如说:

public void consume() {
    int remaining = 5;
    while (remaining > 0) {
        synchronized (this) {
            if (!list.isEmpty()) {
                System.out.println(list + "list" + "consumer");
                final int value = list.removeFirst();
                System.out.println("consuming value " + value);
                remaining--;
                notify();
            }
        }
    }
}

注意循环内的同步是如何发生的,这意味着每次迭代都会释放它。这使产品线程有机会抓住它。生成线程放弃它的原因 - 允许消费线程获取它并保持它,即使它们都声明方法同步 - 是因为wait方法释放了监视器锁。