Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NotifyAll, IllegalMonitorStateException

import java.math.BigInteger;

class Numbers {

    final static int NUMBER = 2;
    final static int POWER = 4;

    static long msecs;
    static BigInteger result;
    static Boolean done = false;

    public static void main(String[] args) {

        BigInteger number = BigInteger.valueOf(NUMBER);
        result = number;

        //Boolean done = false;

        Runnable pow = () -> {
            System.out.println(number + " pow " + POWER + " = " + number.pow(POWER));

            synchronized (done) {
                done = true;
                done.notifyAll();
            }
        };

        Runnable sum = () -> {
            for(int i = 2; i<POWER; i=i*i) {
                result = result.multiply(result);
            }

            System.out.println(number + " sum " + POWER + " = " + result);

            synchronized (done) {
                done = true;
                done.notifyAll();
            }
        };

        Runnable time = () -> {
            for(msecs = 0; true; msecs++) {
                try {
                    Thread.sleep(1);
                } catch(InterruptedException e) {
                    //nic
                }
            }
        };

        Thread timet = new Thread(time);
        Thread sumt = new Thread(sum);
        Thread powt = new Thread(pow);

        timet.start();
        powt.start();

        synchronized (done) {
            while(!done) {
                try {
                    done.wait();
                } catch (InterruptedException e) {
                    //nic
                }
            }
        }

        timet.interrupt();
        powt.interrupt();

        System.out.println("Pow time " + msecs + " msecs.");
        done = false;

        timet.start();
        sumt.start();

        try {
            synchronized (done) {
                while (!done) {
                    done.wait();
                }
            }
        } catch (InterruptedException e) {
            //nic
        }


        timet.interrupt();
        sumt.interrupt();

        System.out.println("Sum time " + msecs + " msecs.");

    }
}

I want to check time differences between those two methods, but done.notifyAll() keeps throwing IllegalMonitorStateException.

like image 527
SecurityBreach Avatar asked Dec 18 '22 20:12

SecurityBreach


1 Answers

Problem is here:

synchronized (done) {
    done = true;//<---problem
    done.notifyAll();
}

Since you are assigning new value to done it means you are executing notifyAll on Boolean.TRUE but your synchronization block is using monitor of Boolean.FALSE. And since notifyAll requires thread to posses monitor of object on which it is executed it throws IllegalMonitorStateException.

So don't change value of object on which you synchronize. Also avoid synchronizing on objects which are available for all classes (public constants /literals) since you are risking that other people will have same idea and will also use them in their synchronization which could cause you some pain.

Locks should be accessible only from within class to they belong. So take example from Jon Skeet (What is the difference between synchronized on lockObject and using this as the lock?) and synchronize on your own

private final Object lock = new Object();
like image 55
Pshemo Avatar answered Dec 21 '22 09:12

Pshemo