谁能解释为什么这个程序显示 IllegalMonitorStateException?

Can anybody explain why this program is showing an IllegalMonitorStateException?

class Lock 
{
    public int l=0;
}

class Numbers extends Thread
{
    final Lock lock;
    Numbers(Lock l,String name)
    {
        super(name);
        lock=l;
    }
    
    public void run()
    {
        synchronized(lock)
        {
            for(int i=0;i<100;i++)
            {
                if(i==50)
                {
                    try
                    {
                        while(lock.l==0)
                        {
                            System.out.println("Waiting for letters to complete");
                            wait();
                            System.out.println("Wait complete");
                        }
                    }
                    catch(InterruptedException e)
                    {
                        System.err.println("ERROR");
                    }
                }
                System.out.println(i);
            }
        }
    }
}

class Letters extends Thread
{
    final Lock lock;
    Letters(Lock l,String name)
    {
        super(name);
        lock=l;
    }
    
    public void run()
    {
        synchronized(lock)
        {
            for(int i=65;i<=90;i++)
                System.out.println((char)i);
            lock.l=1;
            notify();
        }
    }
}

public class MyClass
{
    public static void main(String args[])
    {
        Lock l=new Lock();
        Numbers n=new Numbers(l,"Numbers");
        Letters let=new Letters(l,"Letters");
        n.start();
        let.start();
    }
}

我打算通过这个程序打印最多 49 的数字,然后等待 Letters 线程完成打印字母,然后控件返回 Numbers 线程并完成执行。

但是此代码在打印最多 49 个数字然后打印 A-Z 之后抛出异常,然后执行失败显示 IllegalMonitorStateException

fails to execute showing IllegalMonitorStateException.

这是因为对 notify(); 方法的调用不遵守其 contract:

Wakes up a single thread that is waiting on this object's monitor. (...) This method should only be called by a thread that is the owner of this object's monitor.

同样适用于wait方法:

This method should only be called by a thread that is the owner of this object's monitor.

TL:DR

您在错误的 lock 上调用 waitnotify() 实例 return 的隐式 this).

分别将这些调用更改为:

lock.notify();lock.wait();

运行 基于您的代码的示例:

class Lock{
    public int l=0;
}

class Numbers extends Thread
{
    final Lock lock;
    Numbers(Lock l,String name){
        super(name);
        lock=l;
    }

    public void run() {
        synchronized(lock) {
            for(int i=0;i<100;i++){
                if(i==50){
                    try {
                        while(lock.l==0){
                            System.out.println("Waiting for letters to complete");
                            lock.wait();
                            System.out.println("Wait complete");
                        }
                    }
                    catch(InterruptedException e){
                        System.err.println("ERROR");
                    }
                }
                System.out.println(i);
            }
        }
    }
}

class Letters extends Thread {
    final Lock lock;
    Letters(Lock l,String name)
    {
        super(name);
        lock=l;
    }

    public void run()
    {
        synchronized(lock){
            for(int i=65;i<=90;i++)
                System.out.println((char)i);
            lock.l=1;
            lock.notify();
        }
    }
}

class MyClass {
    public static void main(String args[]) {
        Lock l=new Lock();
        Numbers n=new Numbers(l,"Numbers");
        Letters let=new Letters(l,"Letters");
        n.start();
        let.start();
    }
}