Правильное использование методов ожидания и уведомления в потоках Java - PullRequest
0 голосов
/ 23 декабря 2018

Я новичок в многопоточности Java.Я создал простой шаблон «производитель-потребитель», используя ожидание и уведомление, но мой производитель вызывается только один раз при запуске.

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 голосов
/ 23 декабря 2018

Я все еще не могу понять, почему код, который я ставлю, не работает должным образом

Мне удалось исправить ваш код, и я прикрепил ниже исправленногофрагмент кода.

Я ввел логическую переменную экземпляра с именем isConsumed для ProducerConsumerWorld.При этом, по сути, происходит то, что после того, как Producer Thread производит, он обновляет состояние isConsumed на false, так как он произвел что-то, что еще должно быть использовано.После этого производитель уведомляет Поток потребителя о том, что Производитель завершил производство.Затем он вызывает wait () для ProducerConsumerWorld, который снимает блокировку с ProducerConsumerWorld.Затем он ожидает блокировки на ProducerConsumerWorld.

Тем временем, Consumer Thead получает блокировку на ProducerConsumerWorld, что позволяет ему войти в потребительский метод, где он проверяет, есть ли еще продукт, который еще не будет потреблен.Если это так, он потребляет и обновляет переменную isConsumed до true и уведомляет, что продукт был потреблен.Затем потребитель переходит к снятию своей блокировки на ProducerConsumerWorld, вызывая wait (), и ожидает повторного получения блокировки на ProducerConsumerWorld после того, как Producer использует.

Примечание:

Вызов notify ()не снимает блокировку до тех пор, пока поток не выйдет из синхронизированного блока или не будет вызван wait (), освобождая блокировку.

Источник: Oracle OCA / OCP Java SE 7 Study Guide Page 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

0 голосов
/ 23 декабря 2018

Я все еще не могу понять, почему код, который я ставлю, не работает должным образом

wait() в producer() освобождает монитор, который позволяет consumer()введите его synchronized блок.Затем wait() в producer() начинает ждать, пока consumer() вызовет notify() и освободит монитор (т.е. выйдет из его блока synchronized).Вы никогда не выйдете из synchronized в consumer(), поэтому wait() в producer() заблокирован навсегда

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...