Java threading program does not work with wait () and notifyAll ()

Below is my program. Always stream 0 receives the printer, other threads do not receive it. There is one printer object, and I want several job streams to use the printer. How to make this program work so that all jobs receive a printer. For me, the code stream seems wonderful. Synchronization on one object of the printer. Please, help.

    package classesTesting;

    public class PrinterQueue {

        final static Printer printer = new Printer();;

        public static void main(String[] args) {
            // TODO Auto-generated method stub
            System.out.println("In Main");

            for (int i = 0; i < 5; i++) {
                new Thread(new Jobs(), "Thread - " + i).start();
                System.out.println("started " + i + " thread");
            }

        }

    }

    class Printer {
        private boolean isUsed;

        Printer() {
            this.isUsed = false;
        }

        public void setUsed(boolean used) {
            this.isUsed = used;
        }

        public boolean isUsed() {

            return this.isUsed;
        }
    }

    class Jobs implements Runnable {

        String name;
        boolean isDataAvailble;

        Jobs() {        
            this.isDataAvailble = true;
        }

        public void setNoData(boolean noData) {
            this.isDataAvailble = false;
        }

        @Override
        public void run() {

            while (isDataAvailble) {

                if (PrinterQueue.printer.isUsed()) {
                    try {
                        System.out.println(Thread.currentThread()
                                + "WAITING FOR PRINTER");
                        synchronized (PrinterQueue.printer) {
                            PrinterQueue.printer.wait();
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                } else {
                    synchronized (PrinterQueue.printer) {
                        System.out.println(Thread.currentThread() + "GOT PRINTER");
                        PrinterQueue.printer.setUsed(true);
                        try {
                            Thread.sleep(3000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        PrinterQueue.printer.setUsed(false);
                        PrinterQueue.printer.notify();
                    }
                }
            }

            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

Hi, I reworked my program to first lock and then check the conditions. Even then, thread 0 always receives the printer. Other topics are starving.

Revised Program:

    package classesTesting;

    public class PrinterQueue {

        static Printer printer;

        public static void main(String[] args) {
            // TODO Auto-generated method stub
            System.out.println("In Main");

            printer = new Printer();

            for (int i = 0; i < 5; i++) {
                Jobs j1 = new Jobs();
                j1.setPrinter(printer);

                Thread t1 = new Thread(j1, "Thread - " + i);
                t1.start();

                System.out.println("started " + i + " thread");
            }

        }

    }

    class Printer {
        private boolean isUsed;

        Printer() {
            this.isUsed = false;
        }

        public void setUsed(boolean used) {
            this.isUsed = used;
        }

        public boolean isUsed() {

            return this.isUsed;
        }
    }

    class Jobs implements Runnable {

        String name;
        Printer printer;

        public Printer getPrinter() {
            return printer;
        }

        public void setPrinter(Printer printer) {
            this.printer = printer;
        }

        boolean isDataAvailble;

        Jobs() {
            this.isDataAvailble = true;
        }

        public void setNoData(boolean noData) {
            this.isDataAvailble = false;
        }

        @Override
        public void run() {

            while (isDataAvailble) {
                synchronized (PrinterQueue.printer) {
                    if (this.printer.isUsed()) {
                        try {
                            System.out.println(Thread.currentThread()
                                    + "WAITING FOR PRINTER");

                            PrinterQueue.printer.wait();

                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }

                    else {

                        System.out.println(Thread.currentThread() + "GOT PRINTER");

                        PrinterQueue.printer.setUsed(true);

                        try {
                            Thread.sleep(3000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }

                        PrinterQueue.printer.setUsed(false);
                        PrinterQueue.printer.notify();
                    }
                }
            }

        }

    }
+4
source share
3 answers

, , ReentrantLock fair = true. , . :

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class PrinterQueue {
    static Printer printer;

    public static void main(String[] args) {
        System.out.println("In Main");
        printer = new Printer();
        for (int i = 0; i < 5; i++) {
            // I added printer constructor parameter to pass the same printer
            // to all the Jobs
            new Thread(new Jobs(printer), "Thread - " + i).start();
            System.out.println("started " + i + " thread");
        }
    }
}

class Printer {
    // internally printer holds a fair ReentrantLock
    Lock lock = new ReentrantLock(true);

    // call this to get the printer
    public void acquire() {
        lock.lock();
    }

    // call this to release the printer, so it available for other threads
    public void release() {
        lock.unlock();
    }
}

class Jobs implements Runnable {
    // Declare isDataAvailble as volatile as you're going to change it from another thread
    volatile boolean isDataAvailble;
    private final Printer printer;

    // constructor now takes the printer argument
    Jobs(Printer printer) {
        this.isDataAvailble = true;
        this.printer = printer;
    }

    @Override
    public void run() {
        try {
            while (isDataAvailble) {
                System.out.println(Thread.currentThread()
                        + "Trying to get the printer");
                // get the printer
                this.printer.acquire();
                try {
                    System.out.println(Thread.currentThread()
                            + "Printer acquired!");
                    // use it
                    Thread.sleep(3000);
                } finally {
                    // Release the printer. Better to do it in finally block
                    // so you will release it even if some unexpected exception occurs
                    this.printer.release();
                }
            }

            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
+1

:

  • :

    synchronized (PrinterQueue.printer) {
        while (PrinterQueue.printer.isUsed()) {
            try {
                System.out.println(Thread.currentThread()
                                + "WAITING FOR PRINTER");
                PrinterQueue.printer.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(Thread.currentThread() + "GOT PRINTER");
        PrinterQueue.printer.setUsed(true);
    }
    
  • , , Thread.sleep():

    try {
        Thread.sleep(3000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    
  • :

    synchronized (PrinterQueue.printer) {
        PrinterQueue.printer.setUsed(false);
        PrinterQueue.printer.notifyAll();
    }
    

You need to use while, not if, and you need to check the same object on which you are synchronized. And use notifyAll(), notnotify().

But it is not clear to me that you need any of this, just a block synchronized.

0
source

All Articles