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

同步方法内新线程调用同步方法为何阻塞?如何异步执行?

问题原因

Java中实例级同步方法的锁是当前对象的实例(this),同一个对象的所有实例同步方法共用这把锁。

当主线程调用synchronized修饰的fooMethod时,会立即持有当前对象的锁,直到整个方法执行完毕才会释放。新线程启动后循环调用的dummyMethod同样是实例同步方法,需要获取同一把锁,但此时fooMethod还在执行(Thread.sleep(10000)不会释放同步锁),所以新线程会被阻塞,直到fooMethod执行完成、锁被释放后,才能继续执行剩余的dummyMethod调用。

你看到的“立即执行1次”是因为主线程启动新线程后,在进入sleep前的极短时间内,新线程刚好抢到了一次锁(或是日志输出的时序问题),但后续调用因为锁被主线程持有,只能等待。

解决方案

要让新线程能异步调用dummyMethod,核心是避免两个方法争抢同一把锁,以下是两种可行方案:

方案1:使用独立的锁对象

给fooMethod和dummyMethod分别指定不同的锁对象,替换默认的this锁:

// 定义两个独立的锁对象
private final Object fooLock = new Object();
private final Object dummyLock = new Object();

private void fooMethod() throws InterruptedException {
    // 使用fooLock作为当前方法的锁
    synchronized (fooLock) {
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                dummyMethod();
            }
        }).start();

        Thread.sleep(10000);
        Log.d("debug", "fooMethod() finished");
    }
}

private void dummyMethod() {
    // 使用dummyLock作为当前方法的锁
    synchronized (dummyLock) {
        Log.d("debug", "do nothing in dummyMethod()");
    }
}

方案2:调整同步范围(如果业务允许)

如果fooMethod的同步不需要覆盖整个方法,仅需要同步部分逻辑,可以缩小同步范围,让锁更早释放:

private void fooMethod() throws InterruptedException {
    // 仅同步需要保护的核心代码块,而非整个方法
    synchronized (this) {
        // 此处放置需要同步的业务逻辑
    }

    // 启动新线程时,锁已经释放
    new Thread(() -> {
        for (int i = 0; i < 10; i++) {
            dummyMethod();
        }
    }).start();

    Thread.sleep(10000);
    Log.d("debug", "fooMethod() finished");
}

private synchronized void dummyMethod() {
    Log.d("debug", "do nothing in dummyMethod()");
}

注意:Thread.sleep()不会释放同步锁,只有当同步块/方法执行完毕、或者调用wait()方法时,才会释放持有的锁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 03:17:08