我们已经了解了AQS的的基本原理了,不如自己仿照其它锁实现一个排他锁吧。
要求如下:同一时间只允许一个线程持有锁,不要求可重入(反复加锁直接忽视即可)。
(1)实现Lock接口
public class Demo23 { public static void main(String[] args) { } private static class myLock implements Lock{ @Override public void lock() { } @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() { } @Override public Condition newCondition() { return null; } } }
(2) 创建内部类sync继承AQS,内部调用sync完成逻辑
上面代码的运行结果如下。
/home/wangzhou/IdeaProjects/jucdemo/src/com/wangzhou/Demo21.java:11:24 java: 未报告的异常错误java.lang.InterruptedException; 必须对其进行捕获或声明以便抛出 1 2
这是因为其父类的tryAcquire方法实现如下。
protected boolean tryAcquire(int arg) { throw new UnsupportedOperationException(); } 1 2 3
(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操作了。
@Override 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; }
我们要实现的逻辑也很简单,没加锁的情况下不允许解锁。加锁的情况下解锁。
@Override 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");