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

如何实现:func1等待时自身不可重入,但允许func2进入同步块唤醒它

如何实现:func1等待时自身不可重入,但允许func2进入同步块唤醒它

嗨,咱们来一步步解决这个问题~你的核心需求很明确:当func1进入等待状态时,要挡住其他线程进入func1,但同时得让func2能正常进入同步逻辑,唤醒等待的func1。先聊聊你原来的思路问题,再给你推荐更优雅的实现方式。

首先分析你最初的代码:
第一个版本里,func1用synchronized(x1)包裹,当调用x1.wait()时,会释放x1的锁——这就导致其他线程可以获取x1锁,再次进入func1的同步块,直接打破了你要的“不可重入”要求,而且isWaiting这个标志位还可能被多个线程乱改,出现逻辑错误。

你后来想到的嵌套同步块思路,虽然用x2锁试图挡住其他线程进入func1,但嵌套同步块确实是个风险点,很容易因为锁的获取顺序不当触发死锁,而且代码可读性也差,确实不是最优解。

接下来给你推荐用java.util.concurrent.locks包里的工具类来实现,这比原生的synchronized+wait/notify灵活太多,完全不需要嵌套锁:

我们可以用**Semaphore来控制func1的入口(保证同一时间只有一个线程能进入func1,哪怕它处于等待状态),再用ReentrantLock+Condition**来实现安全的等待/唤醒逻辑,这样既能满足func1的不可重入要求,又能让func2正常执行唤醒操作。

具体代码如下:

import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Xyz {
    // 用Semaphore(1)保证func1同一时间只能有一个线程进入(其他线程不可重入)
    private final Semaphore func1EntryLock = new Semaphore(1);
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition waitCondition = lock.newCondition();
    private boolean isWaiting = false;

    public void func1() throws InterruptedException {
        // 先获取入口许可,其他线程进不来,直到当前线程释放许可
        func1EntryLock.acquire();
        try {
            lock.lock();
            try {
                // 这里执行你需要同步的逻辑
                doHereSomethingSynchronized();

                // 满足条件时进入等待
                if (/* condition1 == expectedValue */ 1 == 1) {
                    isWaiting = true;
                    // await会释放lock,让func2可以获取lock执行唤醒
                    waitCondition.await();
                }
            } finally {
                lock.unlock();
            }
        } finally {
            // 不管有没有等待,最终都释放入口许可,让下一个线程可以进入func1
            func1EntryLock.release();
        }
    }

    public void func2() {
        lock.lock();
        try {
            // 执行func2需要同步的逻辑
            doHereSomethingMoreSynchronized();

            if (isWaiting) {
                waitCondition.signalAll();
                isWaiting = false;
            }
        } finally {
            lock.unlock();
        }
    }

    private void doHereSomethingSynchronized() {
        // 你的同步逻辑实现
    }

    private void doHereSomethingMoreSynchronized() {
        // 你的另一段同步逻辑实现
    }
}

代码逻辑说明:

  • func1EntryLock(Semaphore(1)):它就像一个“入口门禁”,只有拿到许可的线程才能进入func1。哪怕这个线程后来调用waitCondition.await()释放了lock,它依然持有func1EntryLock的许可,其他线程无法acquire()到许可,自然就进不了func1,完美满足你要的“不可重入”要求。
  • ReentrantLock+Condition:用来替代原生的synchronized+wait/notify,waitCondition.await()会释放lock,这样func2就能获取lock执行同步逻辑和唤醒操作,唤醒后func1的线程会重新获取lock,继续执行后续逻辑。
  • 所有锁都用try-finally包裹,确保锁一定会被释放,避免死锁风险。

如果你想要的是严格的不可重入(包括同一个线程也不能重复进入func1),Semaphore也能满足需求——因为它不区分线程,同一个线程多次acquire()也会被挡住,完全符合你的要求。

这个方案既避免了嵌套同步块的风险,又清晰地实现了你的需求,代码可读性和可维护性都比原来的思路好很多。

备注:内容来源于stack exchange,提问作者sam sus

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 11:24:34