繁体   English   中英

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

[英]Proper use of wait and notify methods in Java threading

我是 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");
            }
        }
    }
}

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

我尝试了两种选择来克服这个问题。 首先我把 while 条件放在同步块之外的第二个下面给出。

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();
            }
        }
    }
} 

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

我仍然无法弄清楚为什么我提出的代码不能正常工作

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

我仍然无法弄清楚为什么我提出的代码不能正常工作

我已设法修复您的代码,并附在固定代码片段下方。

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

同时,Consumer Thead 获得了 ProducerConsumerWorld 的锁,这允许它进入消费者方法,在那里它检查是否有尚未消费的产品。 如果是这样,它会消耗并将 isConsumed 变量更新为 true,并通知产品已被消耗。 然后消费者通过调用wait()继续释放其在ProducerConsumerWorld上的锁,并在Producer消费后等待重新获取ProducerConsumerWorld上的锁。

笔记:

调用notify() 不会释放锁,直到线程移出同步块,或者调用wait(),从而释放锁。

来源: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();
            }
        }
    }
}

这给了我一个输出,

在此处输入图片说明

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM