如何在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
相关产品推荐
相关产品推荐

