在Java线程中正确使用wait和notify方法

时间:2018-12-23 14:09:52

标签: java multithreading concurrency

我是Java多线程的新手。我使用wait和notify创建了简单的生产者-消费者模式,但是生产者在启动时只被调用一次。

public class ThreadApp {
    public static void main(String[] args) throws InterruptedException {
        ProducerConsumerWorldp = new ProducerConsumerWorld();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    p.producer();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    p.consumer();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
    }
}
class ProducerConsumerWorld{
    public void producer() throws InterruptedException{
        synchronized (this) {
            while(true){
                System.out.println("Producer thread started running");
                wait();
                System.out.println("Resumed Producing");
            }
        }
    }
    public void consumer() throws InterruptedException{
        synchronized (this) {
            while(true){
                Thread.sleep(2000);
                System.out.println("Consumer thread started running");
                System.out.println("Press enter to consume all and start producing");
                Scanner s = new Scanner(System.in);
                s.nextLine();
                notify();
                Thread.sleep(2000);
                System.out.println("consumed all");
            }
        }
    }
}

我正在为生产者和消费者创建单独的线程。生产者线程仅在开始时被调用,之后再也不会执行。

我尝试了两种选择来解决此问题。首先,我将同步块之外的条件放在下面,

class ProducerConsumerWorld{
    public void producer() throws InterruptedException{
        synchronized (this) {
            while(true){
                System.out.println("Producer thread started running");
                notify();
                wait();
                System.out.println("Resumed Producing");
            }
        }
    }
    public void consumer() throws InterruptedException{
        synchronized (this) {
            while(true){
                Thread.sleep(2000);
                System.out.println("Consumer thread started running");
                System.out.println("Press enter to consume all and start producing");
                Scanner s = new Scanner(System.in);
                s.nextLine();
                notify();
                Thread.sleep(2000);
                System.out.println("consumed all");
                wait();
            }
        }
    }
} 

两者都很好。使用哪种合适的解决方案?我仍然无法弄清楚为什么我所讨论的代码无法正常工作。

2 个答案:

答案 0 :(得分:3)

  

我仍然无法弄清楚为什么我所讨论的代码无法正常工作

wait()中的producer()释放监视器,允许consumer()进入其synchronized块。然后wait()中的producer()开始等待,直到consumer()调用notify() 释放监视器(即退出其synchronized块)。您永远不会退出synchronized中的consumer(),因此wait()中的producer()会永远被阻止

答案 1 :(得分:1)

  

我仍然无法弄清楚为什么我所讨论的代码不是   工作正常

我们已设法解决了您的代码,并附在固定的代码段下方。

我为ProducerConsumerWorld引入了一个名为isConsumed的布尔实例变量。这样做的本质是,在Producer Thread产生之后,他将isConsumed的状态更新为false,因为他产生了尚未消费的东西。此后,生产者通知消费者线程,生产者已经完成生产。接下来,它在ProducerConsumerWorld上调用wait(),从而释放Producer对ProducerConsumerWorld的锁定。然后,它等待ProducerConsumerWorld上的锁定。

与此同时,Consumer Thead获得了ProducerConsumerWorld上的锁,这使它可以进入Consumer方法,在此方法中检查是否还有待消费的农产品。如果是这样,它将使用isConsumed变量并将其更新为true,并通知生产已被消耗。然后,消费者通过调用wait()释放对ProducerConsumerWorld的锁定,并在Producer消费后等待重新获取对ProducerConsumerWorld的锁定。

注意:

  

在线程从同步块中移出或调用wait()从而释放锁之前,调用notify()不会释放锁。

     

来源:Oracle的OCA / OCP Java SE 7学习指南760

代码:

import java.util.Scanner;

public class ThreadApp {
    public static void main(String[] args) throws InterruptedException {
        ProducerConsumerWorld p = new ProducerConsumerWorld();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    p.producer();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    p.consumer();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t1.start();
        t2.start();
    }
}
class ProducerConsumerWorld{

    boolean consumed = false;

    public void producer() throws InterruptedException{
        System.out.println("Producer thread started running");
        synchronized (this) {
            while(this.consumed == true){ // Consumer has consumed and is waiting for produce
                System.out.println("Resumed Producing");
                this.consumed = false;
                notify();
                wait();
            }
        }
    }
    public void consumer() throws InterruptedException{
        synchronized (this) {
            while(this.consumed == false){
                Thread.sleep(2000);
                System.out.println("Consumer thread started running");
                System.out.println("Press enter to consume all and start producing");
                Scanner s = new Scanner(System.in);
                s.nextLine();
                this.consumed = true;
                System.out.println("consumed all");
                notify(); 
                wait();
            }
        }
    }
}

这给了我类似

的输出

enter image description here