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

多线程共享AtomicLong:能否将递减while循环移出锁范围?

关于ReentrantLock同步下AtomicLong递减循环位置的疑问

现有两个线程共享一个AtomicLong实例,线程1仅执行递增操作,线程2仅执行递减操作,使用ReentrantLock和Condition实现线程同步。相关共享变量及线程代码如下:

final var lock = new ReentrantLock();
final var condition = lock.newCondition();
final var accumulated = new AtomicLong(); // accumulated <n> from <request(n)>

线程1代码:

// Thread 1
void doSome(final long n) {
    try {
        lock.lock();
        if (accumulated.addAndGet(n) < 0L) { // overflowed
            accumulated.set(Long.MAX_VALUE); // > effectively unbounded
        }
        condition.signal();
    } finally {
        lock.unlock();
    }
}

线程2代码:

// Thread 2
while (!Thread.currentThread().isInterrupted()) {

    lock.lock();
    try {
        while (accumulated.get() == 0L) {
            try {
                condition.await();
            } catch (final InterruptedException ie) {
                log.info("interrupted while awaiting the condition", ie);
                Thread.currentThread().interrupt();
                break;
            }
        }

        while (accumulated.getAndDecrement() > 0L) { // -
             // do some                              //  |
        }                                            //  |
                                                     //  |
    } finally {                                      //  |
        lock.unlock();                               //  |
    }                                                //  |
                                                     //  |
                                                     //  |
    //while (accumulated.getAndDecrement() > 0L) { // <-- Can(Should) I move the while loop to here?
    //     // do some
    // }

}

咨询问题:是否可以将线程2中用于递减AtomicLong的while循环移到锁代码块之外?


回答

不能将该while循环移到锁代码块之外,原因如下:

  • 破坏原同步逻辑的原子性
    线程1的递增操作是在lock的保护下执行的,原逻辑中线程2持有锁时,线程1无法修改accumulated,因此线程2可以安全地将当前累积值一次性递减到0。如果把循环移到锁外,线程2释放锁后,线程1会立即执行递增操作,导致线程2的递减循环会同时处理后续新增的值,违背了“被唤醒后处理当前累积值”的设计意图。

  • 多线程场景下引发竞态问题
    如果存在多个线程2实例,移到锁外后,多个线程会同时执行getAndDecrement操作。虽然该方法本身是原子的,但会导致多个线程同时进入// do some逻辑,可能引发业务逻辑混乱或数据不一致——原代码通过独占锁保证了同一时间只有一个线程在处理递减逻辑。

  • 锁持有时间优化的替代方案
    如果想减少锁的持有时间以提升性能,可以修改逻辑:在锁内获取当前累积值并重置为0,再释放锁,之后在锁外循环处理对应次数的业务逻辑。示例代码如下:

    // Thread 2 修改后的代码
    while (!Thread.currentThread().isInterrupted()) {
        long count = 0;
        lock.lock();
        try {
            while (accumulated.get() == 0L) {
                try {
                    condition.await();
                } catch (final InterruptedException ie) {
                    log.info("interrupted while awaiting the condition", ie);
                    Thread.currentThread().interrupt();
                    break;
                }
            }
            // 获取当前累积值并重置为0
            count = accumulated.getAndSet(0L);
        } finally {
            lock.unlock();
        }
        // 在锁外处理业务逻辑
        while (count-- > 0) {
            // do some
        }
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 15:55:01