我们已经了解了AQS的的基本原理了,不如自己仿照其它锁实现一个排他锁吧。
要求如下:同一时间只允许一个线程持有锁,不要求可重入(反复加锁直接忽视即可)。
(1)实现Lock接口
public class Demo23 { | |
public static void main(String[] args) { | |
} | |
private static class myLock implements Lock{ | |
public void lock() { | |
} | |
public void lockInterruptibly() throws InterruptedException { | |
} | |
public boolean tryLock() { | |
return false; | |
} | |
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { | |
return false; | |
} | |
public void unlock() { | |
} | |
public Condition newCondition() { | |
return null; | |
} | |
} | |
} |
(2) 创建内部类sync继承AQS,内部调用sync完成逻辑
public class Demo23 { | |
public static void main(String[] args) { | |
myLock lock = new myLock(); | |
lock.lock(); | |
} | |
private static class myLock implements Lock{ | |
private class sync extends AbstractQueuedSynchronizer { | |
protected boolean tryAcquire(int arg) { | |
return super.tryAcquire(arg); | |
} | |
protected boolean isHeldExclusively() { | |
return getExclusiveOwnerThread() == Thread.currentThread(); | |
} | |
protected Condition newCondition() { | |
return new ConditionObject(); | |
} | |
} | |
sync sync = new sync(); | |
public void lock() { | |
sync.acquire(1); | |
} | |
public void lockInterruptibly() throws InterruptedException { | |
sync.acquireInterruptibly(1); | |
} | |
public boolean tryLock() { | |
return sync.tryAcquire(1); | |
} | |
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { | |
return sync.tryAcquireNanos(1, unit.toNanos(time)); | |
} | |
public void unlock() { | |
sync.release(1); | |
} | |
public Condition newCondition() { | |
return sync.newCondition(); | |
} | |
} | |
} |
上面代码的运行结果如下。
/home/wangzhou/IdeaProjects/jucdemo/src/com/wangzhou/Demo21.java:11:24 | |
java: 未报告的异常错误java.lang.InterruptedException; 必须对其进行捕获或声明以便抛出 |
这是因为其父类的tryAcquire方法实现如下。
protected boolean tryAcquire(int arg) { | |
throw new UnsupportedOperationException(); | |
} |
(3)实现tryAcquire 先看看其它锁怎么做的。比如公平锁。
protected final boolean tryAcquire(int acquires) { | |
final Thread current = Thread.currentThread(); | |
int c = getState(); | |
if (c == 0) { | |
if (!hasQueuedPredecessors() && | |
compareAndSetState(0, acquires)) { | |
setExclusiveOwnerThread(current); | |
return true; | |
} | |
} | |
else if (current == getExclusiveOwnerThread()) { | |
int nextc = c + acquires; | |
if (nextc < 0) | |
throw new Error("Maximum lock count exceeded"); | |
setState(nextc); | |
return true; | |
} | |
return false; | |
} |
上面代码包含可重入逻辑,我们这里如果重入直接忽略,返回false,因此核心逻辑就只需要进行一个CAS
操作了。
protected boolean tryAcquire(int acquires) { | |
if(isHeldExclusively()) { | |
return true; | |
} | |
if (compareAndSetState(0, acquires)) { | |
setExclusiveOwnerThread(Thread.currentThread()); | |
return true; | |
} | |
return false; | |
} |
加锁过程已经完成,您可以自行测试,接下来我们来实现解锁功能。
同样先看看其它锁怎么实现。
protected final boolean tryRelease(int releases) { | |
int c = getState() - releases; | |
if (Thread.currentThread() != getExclusiveOwnerThread()) | |
throw new IllegalMonitorStateException(); | |
boolean free = false; | |
if (c == 0) { | |
free = true; | |
setExclusiveOwnerThread(null); | |
} | |
setState(c); | |
return free; | |
} |
我们要实现的逻辑也很简单,没加锁的情况下不允许解锁。加锁的情况下解锁。
protected boolean tryRelease(int args) { | |
if(getState() == 0) { | |
throw new UnsupportedOperationException(); | |
} | |
if(isHeldExclusively()) { | |
setExclusiveOwnerThread(null); | |
setState(0); | |
return true; | |
} | |
return false; | |
} |
测试.
public static void main(String[] args) throws InterruptedException { | |
myLock lock = new myLock(); | |
lock.lock(); | |
new Thread(() ->{ | |
lock.lock(); | |
System.out.println("thread2 get lock"); | |
lock.unlock(); | |
}).start(); | |
TimeUnit.SECONDS.sleep(1); | |
lock.unlock(); | |
System.out.println("thread 1 unlock"); | |
} |
condition请读者自测。