Java线程wait()方法行为解析及相关疑难问题咨询
第一段代码:未加synchronized导致IllegalMonitorStateException
直接调用thread.wait()时抛出IllegalMonitorStateException,核心原因是**wait()方法的强制规则**:调用任意对象的wait()前,当前线程必须持有该对象的监视器锁(即必须在synchronized块或synchronized方法中操作这个对象)。
这段代码里,主线程没有通过synchronized获取thread对象的锁就调用了wait(),违反规则,因此JVM直接抛出异常。
代码示例:
class Scratch { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(() -> { System.out.println("Inside thread"); }); thread.wait(); } }
异常信息:
Exception in thread "main" java.lang.IllegalMonitorStateException: current thread is not owner at java.base/java.lang.Object.wait0(Native Method) at java.base/java.lang.Object.wait(Object.java:366) at java.base/java.lang.Object.wait(Object.java:339) at Scratch.main(scratch_125.java:8)
第二段代码:持有锁但无人唤醒导致永久阻塞
添加synchronized (thread)块后,主线程获取了thread对象的锁,满足wait()的调用条件,因此不再抛出异常。但主线程会一直阻塞在thread.wait()处,原因是:
wait()执行时会释放当前持有的锁,让线程进入等待状态,直到有其他线程调用该对象的notify()或notifyAll()唤醒它。- 这段代码里
thread未调用start(),线程永远不会启动,更不会终止。而只有当Thread对象关联的线程终止时,JVM才会自动调用该对象的notifyAll()。没有任何线程来唤醒主线程,所以它会一直等待下去。
你误以为未启动线程调用wait()会抛异常,其实wait()是Object类的方法,和线程是否启动无关——只要当前线程持有对象锁,就能调用,不会因线程未启动抛出异常。
代码示例:
class Scratch { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(() -> { System.out.println("Inside thread"); }); synchronized (thread) { thread.wait(); // keeps waiting here } System.out.println("Main thread working fine?"); // never reached here } }
第三段代码:线程终止触发自动唤醒,wait()结束阻塞
添加thread.start()后,子线程启动并执行,当它运行完毕(包括sleep 5秒后),线程进入终止状态。此时JVM会自动调用该Thread对象的notifyAll()方法,唤醒所有在该对象上等待的线程——也就是主线程。因此主线程的wait()被唤醒,继续执行后续的打印语句。
注意:虽然这里wait()起到了等待线程结束的效果,但这不是wait()的正确用法,等待线程终止应该用thread.join()。这里的行为是JVM对Thread对象的特殊处理,不要依赖这个特性实现线程同步。
代码示例:
class Scratch { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(() -> { System.out.println("Inside thread"); try { Thread.sleep(5000); } catch (InterruptedException e) { throw new RuntimeException(e); } }); thread.start(); synchronized (thread) { thread.wait(); } System.out.println("Main thread working fine?"); } }
内容的提问来源于stack exchange,提问作者Mohit Kumar

