NotifyAll,IllegalMonitorStateException

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.");

    }
}

我想检查这两种方法之间的时间差异,但是 done.notifyAll() 一直抛出 IllegalMonitorStateException

问题在这里:

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

由于您正在为 done 分配新值,这意味着您正在 Boolean.TRUE 上执行 notifyAll,但您的同步块正在使用 Boolean.FALSE 的监视器。并且由于 notifyAll 要求线程拥有对其执行的对象的监视器,因此它抛出 IllegalMonitorStateException.

所以不要更改同步对象的值。还要避免同步可用于所有 classes(public 常量/文字)的对象,因为您冒着其他人会有相同想法并且也会在他们的同步中使用它们的风险,这可能会给您带来一些痛。

锁只能在 class 内访问。因此,以 Jon Skeet (What is the difference between synchronized on lockObject and using this as the lock?) 为例并自行同步

private final Object lock = new Object();

我想我知道发生了什么......如果你阅读 Java 的 Object.notifyAll()

文档

IllegalArgumentException - if the value of timeout is negative. IllegalMonitorStateException - if the current thread is not the owner of the object's monitor. InterruptedException - if any thread interrupted the current thread before or while the current thread was waiting for a notification. The interrupted status of the current thread is cleared when this exception is thrown.

因此,我认为您需要一个新的对象来充当访问您完成的对象的锁。 例如:aprivate final Object doneLock = new Object()。您现在可以在 doneLock 上同步,而不是在 Done 上同步。我应该是最终的,因为锁需要是私有的和最终的,所以它们不能被外部访问。

例如,

synchronize(doneLock) {
    done = true;
    doneLock.notifyAll();
}