You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中如何暂停Runnable或线程?wait()抛异常解析与解决

线程wait()抛出IllegalMonitorStateException问题解析

问题重现

你定义的Runnable类:

package com.example.testtest;

public class FootballRunner implements Runnable {
    @Override
    public void run() {
        while (true) {
            System.out.println("Running " + Thread.currentThread().getId() + " " + Math.random());
            try {
                Thread.sleep(1_000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

主类代码:

package com.example.testtest;

public class TestScheduling {
    public static void main(String[] args) throws InterruptedException {
        FootballRunner footballRunner = new FootballRunner();
        Thread t1 = new Thread(footballRunner, "one");
        t1.start();
        t1.wait();
    }
}

运行后抛出异常:

Exception in thread "main" java.lang.IllegalMonitorStateException: current thread is not owner
    at java.base/java.lang.Object.wait(Native Method)
    at java.base/java.lang.Object.wait(Object.java:338)
    at com.example.testtest.TestScheduling.main(TestScheduling.java:8)

1. "current thread is not owner" 是什么意思?

wait()是Object类的核心方法,它的调用有严格前提:当前线程必须持有该对象的监视器锁(即通过synchronized关键字获取的锁)。

你在main线程中直接调用t1.wait(),但main线程从未通过synchronized(t1)代码块获取t1对象的锁,所以JVM会抛出IllegalMonitorStateException,提示的"current thread is not owner"直白来说就是:你当前的线程(main)不是t1这个对象监视器锁的持有者,没有资格调用它的wait()方法。

另外要明确:wait()的作用是让持有锁的线程自己进入等待状态,并释放锁,它不是用来暂停其他线程的工具,你的用法完全误解了这个方法的用途。


2. 如何正确实现线程t1的暂停?

Thread类的suspend()方法已被废弃(容易导致死锁,锁无法释放),推荐用以下两种标准方式:

方法一:利用线程中断机制

通过中断标志位控制线程循环,同时正确响应中断异常:

package com.example.testtest;

public class FootballRunner implements Runnable {
    @Override
    public void run() {
        // 循环前检查线程中断状态
        while (!Thread.currentThread().isInterrupted()) {
            System.out.println("Running " + Thread.currentThread().getId() + " " + Math.random());
            try {
                Thread.sleep(1_000);
            } catch (InterruptedException e) {
                // 捕获中断后,重置中断状态(因为sleep会清除中断标志)
                Thread.currentThread().interrupt();
                break; // 退出循环,终止线程
            }
        }
        System.out.println("线程t1已停止");
    }
}

主类中调用interrupt()触发中断:

package com.example.testtest;

public class TestScheduling {
    public static void main(String[] args) throws InterruptedException {
        FootballRunner footballRunner = new FootballRunner();
        Thread t1 = new Thread(footballRunner, "one");
        t1.start();
        
        // 让main线程等待3秒后,中断t1
        Thread.sleep(3000);
        t1.interrupt();
    }
}

方法二:使用volatile标志位控制

定义一个volatile修饰的布尔变量(保证多线程下的可见性),通过修改该变量来终止线程循环:

package com.example.testtest;

public class FootballRunner implements Runnable {
    // volatile保证变量修改对其他线程立即可见
    private volatile boolean isRunning = true;

    // 提供外部调用的停止方法
    public void stopThread() {
        isRunning = false;
    }

    @Override
    public void run() {
        while (isRunning) {
            System.out.println("Running " + Thread.currentThread().getId() + " " + Math.random());
            try {
                Thread.sleep(1_000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        System.out.println("线程t1已停止");
    }
}

主类中调用stopThread()方法:

package com.example.testtest;

public class TestScheduling {
    public static void main(String[] args) throws InterruptedException {
        FootballRunner footballRunner = new FootballRunner();
        Thread t1 = new Thread(footballRunner, "one");
        t1.start();
        
        Thread.sleep(3000);
        footballRunner.stopThread(); // 触发线程停止
    }
}

内容的提问来源于stack exchange,提问作者ilhan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 23:33:16