设计一个同步工具:该工具在同一时刻,只允许至多两个线程同时访问,超过两个线程的
访问将被阻塞,我们将这个同步工具命名为TwinsLock。
要求同步工具支持两个线程同时获得锁,所以需要acquireShared这个共享的方法。
看一下AQS中acquireShared的实现
public final void acquireShared(int arg) {
// 调用tryAcquireShared方法
if (tryAcquireShared(arg) < 0)
// 当返回结果小于0的时候,进行阻塞
doAcquireShared(arg);
}
// 没有实现,是留给子类实现的
protected int tryAcquireShared(int arg) {
throw new UnsupportedOperationException();
}
因此需要一个类实现tryAcquireShared方法。
同理,releaseShared也是需要实现tryReleaseShared方法。
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
protected boolean tryReleaseShared(int arg) {
throw new UnsupportedOperationException();
}
实现:
public class TwinsLock implements Lock {
// 在Lock中需要一个同步器,有2个计数
Sync sync = new Sync(2);
// 同步器继承AQS
private static final class Sync extends AbstractQueuedSynchronizer{
Sync(int count) {
if (count <= 0) {
throw new IllegalArgumentException();
}
setState(count);
}
@Override
protected int tryAcquireShared(int reduceCount) {
for (;;){
int cur = getState();
// 获取加锁后state的值
int newCount = cur - reduceCount;
// 如果小于0,说明无法加锁,自旋
// 如果cas失败,说明加锁失败,自旋
if (newCount < 0 || compareAndSetState(cur, newCount)){
return newCount;
}
}
}
@Override
protected boolean tryReleaseShared(int returnCount) {
for (;;) {
int cur = getState();
int newCount = cur + returnCount;
if (compareAndSetState(cur, newCount)) {
return true;
}
}
}
}
@Override
public void lock() {
sync.acquireShared(1);
}
@Override
public void lockInterruptibly() throws InterruptedException { }
@Override
public boolean tryLock() { return false; }
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { return false; }
@Override
public void unlock() {
sync.releaseShared(1);
}
@Override
public Condition newCondition() { return null; }
}
当前以上代码实际上是有点小问题的,因为释放锁的时候没有进行判断是否该线程已经上锁。
这部分的释放锁可以去看ReentrantReadWriteLock中的实现。