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

У меня вопрос: почему вызов notifiall() в printZero() не приводит к освобождению ожидания в других потоках?

Вывод: Waiting evenWaiting oddZero0notified

Программа :

package com.leetcode.problems;

import java.util.ArrayList;
import java.util.List;

public class PrintZeroEvenOdd {

    private class Printer {
        int temp= 0;
        int i = 0;
        List list = new ArrayList();

        public synchronized void printZero(){

                    if((temp) > 0 || temp < 0){
                        try{
                            wait();
                        } catch(InterruptedException e){

                        }
                    }
                    System.out.print("Zero" + 0);

                    if(temp%2 == 0){
                        temp = temp -1;
                    } else if(temp%2 == 1){
                        temp = 1 - temp;
                    }
                    i++;
                    notifyAll();
                    System.out.print("notified");

        }

        public synchronized  void printOdd(){
            if(( temp == 0 || (temp % 2) == 0)){
                try{
                    System.out.print("Waiting odd");
                    wait();
                } catch(InterruptedException e){

                }
            }

            System.out.println("Odd"+i);

            temp = 1- temp;

            i++;
            notifyAll();

        }

        public synchronized  void printEven(){

            if(( temp == 0 || (temp % 2) == 1)){
                try{
                    System.out.print("Waiting even");
                    wait();
                } catch(InterruptedException e){

                }
            }

            System.out.println("Even"+i);

            temp = temp -1;
            i++;

            notifyAll();


        }
    }
     transient int i = 0;
    private class ZeroPrinter implements Runnable{

        Printer printer ;

        ZeroPrinter( ){
            printer = new Printer();
        }

        @Override 
        public void run(){
            while(i<20)
            printer.printZero();
        }
    }


    private class OddPrinter implements Runnable{

        Printer printer ;

        OddPrinter( ){
            printer = new Printer();
        }

        @Override 

        public void run(){
            while(i<20)
            printer.printOdd();
        }
    }


    private class EvenPrinter implements Runnable{

        Printer printer ;

        EvenPrinter(){
            printer = new Printer();
        }

        @Override 
        public void run(){
            while(i<20)
            printer.printEven();
        }
    }

    public static void main(String[] argw) throws InterruptedException{
        PrintZeroEvenOdd printZeroEvenOdd = new PrintZeroEvenOdd();
        Thread printEvenThread = new Thread(printZeroEvenOdd.new EvenPrinter());    
        Thread printZeroThread = new Thread(printZeroEvenOdd.new ZeroPrinter());
        Thread printOddThread = new Thread(printZeroEvenOdd.new OddPrinter());  

        printEvenThread.start();
        Thread.sleep(1000);
        printOddThread.start();
        Thread.sleep(100);
        printZeroThread.start();
        }
  }
-1
Prashant 4 Окт 2019 в 13:41

2 ответа

Каждый поток синхронизируется (удерживает блокировку) на своем собственном экземпляре Printer (поскольку вы создаете новый экземпляр Printer в каждом из 3 конструкторов), поэтому notifyAll() не приводит к в других потоках пробуждаются, поскольку они ожидают на разных мониторах (экземпляры разностных объектов Printer).

PrintZeroThread печатает результат, который вы видите, потому что он никогда не входит в условие if((temp) > 0 || temp < 0).

Я не совсем уверен, чего именно пытается достичь ваша программа, но мне кажется, что она должна работать с единственным экземпляром Printer.

Похоже, что в ваших частных классах вам следует удалить new Printer() и вместо этого использовать включающий класс, например, в Zero printer я выделил части, которые необходимо удалить:

private class ZeroPrinter implements Runnable{

    // Printer printer ;

    // ZeroPrinter( ){
    //    printer = new Printer();
    // }

    @Override 
    public void run(){
        while(i<20)
        // printer.
        printZero();
    }
}

То же самое следует сделать для EvenPrinter и OddPrinter, тогда эти частные классы будут использовать окружающий instace Printer, так что будет один монитор, общий для этих экземпляров.

0
Krzysztof Cichocki 4 Окт 2019 в 14:46

Конечно, вот программа с исправлениями: -

Пакет com.leetcode.problems;

Import java.util.ArrayList; import java.util.List;

Public class PrintZeroEvenOdd {

private class Printer {
    int temp = 2;
    int i = 0;
    List list = new ArrayList();

    public Printer() {
    };

    public synchronized void printZero() {

        while (i < 19) {
            if ((temp) == 0) {
                try {
                    wait();
                } catch (InterruptedException e) {

                }
            }
            System.out.print(0);// System class is a final class , and thus
                                // only one threead will take control
            temp = 0;

            i++;
            notifyAll();
            // System.out.print("notified");
        }
    }

    public synchronized void printOdd() {
        while (i < 19) {
            if (((temp) != 0)) {
                try {
                    wait();
                } catch (InterruptedException e) {

                }
            }

            if ((i % 2) == 1) {
                System.out.println(i);

                notifyAll();
            }
            temp = 1;

        }
    }

    public synchronized void printEven() {

        while (i < 19) {
            if (temp != 0) {
                try {
                    // System.out.print("Waiting even");
                    wait();
                } catch (InterruptedException e) {

                }
            }

            if ((i % 2) == 0) {

                System.out.println(i);

                notifyAll();
            }
            temp = 1;
        }

    }
}

transient int i = 0;

private class ZeroPrinter implements Runnable {

    Printer printer;

    ZeroPrinter(Printer printer) {
        this.printer = printer;
    }

    @Override
    public void run() {
        printer.printZero();
    }
}

private class OddPrinter implements Runnable {

    Printer printer;

    OddPrinter(Printer printer) {
        this.printer = printer;
    }

    @Override
    public void run() {
        printer.printOdd();
    }
}

private class EvenPrinter implements Runnable {

    Printer printer;

    EvenPrinter(Printer printer) {
        this.printer = printer;
    }

    @Override
    public void run() {
        printer.printEven();
    }
}

public static void main(String[] argw) throws InterruptedException {
    PrintZeroEvenOdd printZeroEvenOdd = new PrintZeroEvenOdd();
    Printer printer = printZeroEvenOdd.new Printer();
    Thread printEvenThread = new Thread(printZeroEvenOdd.new EvenPrinter(
            printer));
    Thread printZeroThread = new Thread(printZeroEvenOdd.new ZeroPrinter(
            printer));
    Thread printOddThread = new Thread(printZeroEvenOdd.new OddPrinter(
            printer));

    // Above order does not matter
    // In short , in MT Order to start the threads does not matter at all

    printEvenThread.start();
    Thread.sleep(1000);
    printOddThread.start();
    Thread.sleep(100);
    printZeroThread.start();

}

}

-1
Prashant 8 Окт 2019 в 12:11