Java中不使用wait()和sleep()实现线程等待(自定义重入锁场景)
可重入锁acquire方法实现方案
首先需要明确,你要实现的是可重入锁,所以必须处理同一个线程重复获取锁的场景,同时在锁被其他线程占用时,通过自旋(忙等)持续尝试获取锁(符合不能用wait()/sleep()的要求)。先修正原代码中的逻辑错误,再给出完整实现:
public class MyReentrantLock implements Lock { private AtomicBoolean locked = new AtomicBoolean(false); private long idOfThreadCurrentlyHoldingLock; private int reentrantCount = 0; // 记录锁的重入次数 @Override public void acquire() { long currentThreadId = Thread.currentThread().getId(); // 1. 可重入判断:当前线程已持有锁,直接增加重入次数 if (idOfThreadCurrentlyHoldingLock == currentThreadId) { reentrantCount++; return; } // 2. 其他线程自旋尝试CAS获取锁(原标记位置的核心逻辑) while (!locked.compareAndSet(false, true)) { // 空循环持续尝试CAS,属于忙等,满足禁用wait/sleep的要求 } // 3. 获取锁成功后,记录持有线程ID并初始化重入次数 idOfThreadCurrentlyHoldingLock = currentThreadId; reentrantCount = 1; } @Override public boolean tryAcquire() { long currentThreadId = Thread.currentThread().getId(); // 可重入判断 if (idOfThreadCurrentlyHoldingLock == currentThreadId) { reentrantCount++; return true; } // 尝试一次CAS获取锁 boolean acquired = locked.compareAndSet(false, true); if (acquired) { idOfThreadCurrentlyHoldingLock = currentThreadId; reentrantCount = 1; } return acquired; } @Override public void release() { long currentThreadId = Thread.currentThread().getId(); // 先校验当前线程是否持有锁,非法释放直接抛异常 if (idOfThreadCurrentlyHoldingLock != currentThreadId) { throw new IllegalReleaseAttempt(); } // 重入次数递减,只有次数归0时才真正释放锁 reentrantCount--; if (reentrantCount == 0) { locked.set(false); idOfThreadCurrentlyHoldingLock = -1; // 重置持有线程ID } } // Lock接口其他方法(如lockInterruptibly、newCondition等)需按需补充实现 }
核心逻辑说明:
- 可重入处理:通过
idOfThreadCurrentlyHoldingLock判断当前线程是否已持有锁,避免同一线程重复获取锁时自我阻塞 - 自旋等待:当锁被其他线程占用时,进入
while循环持续调用compareAndSet尝试抢占锁,完全符合你只能使用AtomicBoolean和Thread类的要求 - 修正release逻辑:先校验线程合法性,再根据重入次数决定是否真正释放锁,避免错误释放其他线程持有的锁
内容的提问来源于stack exchange,提问作者rachel
相关产品推荐
相关产品推荐

