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

如何在Java中原子性获取多个锁?是否有类似C++ scoped_lock的机制?

Java中类似C++ scoped_lock的机制

Java标准库没有提供和C++ scoped_lock完全一致的内置构造,但可以通过两种方式实现原子性获取多锁+作用域自动释放的效果,同时避免死锁:

1. 封装AutoCloseable类实现类似scoped_lock的功能

利用Java的try-with-resources语法(要求类实现AutoCloseable),封装一个自定义的多锁管理类,内部通过排序锁的顺序来避免死锁,同时在作用域结束时自动释放所有锁:

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.locks.Lock;

public class ScopedLock implements AutoCloseable {
    private final List<Lock> locks;

    public ScopedLock(Lock... locks) throws InterruptedException {
        // 按锁的标识排序,确保所有线程获取锁的顺序一致,避免死锁
        Lock[] sortedLocks = Arrays.stream(locks)
                .sorted(Comparator.comparingInt(System::identityHashCode))
                .toArray(Lock[]::new);
        this.locks = Arrays.asList(sortedLocks);
        
        // 可中断地获取所有锁
        for (Lock lock : sortedLocks) {
            lock.lockInterruptibly();
        }
    }

    @Override
    public void close() {
        // 反向释放锁(和获取顺序相反)
        locks.stream().reverse().forEach(Lock::unlock);
    }
}

使用示例:

import java.util.concurrent.locks.ReentrantLock;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        ReentrantLock lock1 = new ReentrantLock();
        ReentrantLock lock2 = new ReentrantLock();

        // 自动管理锁的获取与释放
        try (ScopedLock scopedLock = new ScopedLock(lock1, lock2)) {
            // 执行临界区逻辑
            System.out.println("进入临界区");
        }
    }
}

2. 手动固定锁的获取顺序(基于Lock接口)

如果不想自定义类,可以直接使用Lock接口的实现类(如ReentrantLock),手动按照固定顺序获取锁,并通过try-finally确保锁的释放,从根源上避免死锁:

import java.util.concurrent.locks.ReentrantLock;

public class Main {
    public static void main(String[] args) {
        ReentrantLock lock1 = new ReentrantLock();
        ReentrantLock lock2 = new ReentrantLock();

        // 所有线程统一按lock1 -> lock2的顺序获取锁
        lock1.lock();
        try {
            lock2.lock();
            try {
                // 临界区逻辑
                System.out.println("进入临界区");
            } finally {
                lock2.unlock();
            }
        } finally {
            lock1.unlock();
        }
    }
}

注意事项

  • 对于Java原生的synchronized关键字,无法直接实现原子性多锁获取,必须严格保证所有线程按相同顺序获取锁才能避免死锁,且依赖代码块作用域完成释放,无法实现自动的多锁原子性获取。
  • 自定义ScopedLock类时,使用lockInterruptibly()而非lock(),可以让线程在等待锁时响应中断,避免无限阻塞。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 19:43:37