完全 模仿ReentrantLock, 通过继承 java.util.concurrent.locks.Lock , 内置 AbstractQueuedSynchronizer 实现类,限制可以重入次数的锁。
这个其实不难, 只要稍微注意一点就好了
ReenterLimitedLock 关键实现:
/** * l.k * * 限制可以重入次数的锁,默认是2次 * */ public class ReenterLimitedLock implements Lock, java.io.Serializable { private static final long serialVersionUID = 7373984872572414699L; private final Sync sync; /** * Creates an instance of {@code ReenterLimitedLock}. * This is equivalent to using {@code ReenterLimitedLock(false)}. */ public ReenterLimitedLock() { sync = new NonfairSync(2); } public ReenterLimitedLock(int reenterLimit) { sync = new NonfairSync(reenterLimit); } public ReenterLimitedLock(boolean fair, int reenterLimit) { sync = fair ? new FairSync(reenterLimit) : new NonfairSync(reenterLimit); } public ReenterLimitedLock(boolean fair) { sync = fair ? new FairSync(2) : new NonfairSync(2); } abstract static class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = -5179523762034025860L; private boolean exceeded; private int reenterLimit; public Sync(int reenterLimit) { this.reenterLimit = reenterLimit; } abstract void lock(); final boolean nonfairTryAcquire(int acquires) throws MaximumLockCountExceededException { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; // if (nextc < 0) // overflow if (nextc > reenterLimit) { // 关键 exceeded = true; // return false; // throw new IllegalStateException("Maximum lock count exceeded" + 2); throw new MaximumLockCountExceededException(reenterLimit); } setState(nextc); return true; } return false; } protected final boolean tryRelease(int releases) { if (isExceeded()) { return false; } 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 final boolean isHeldExclusively() { // While we must in general read state before owner, // we don't need to do so to check if current thread is owner return getExclusiveOwnerThread() == Thread.currentThread(); } final ConditionObject newCondition() { return new ConditionObject(); } // Methods relayed from outer class final Thread getOwner() { return getState() == 0 ? null : getExclusiveOwnerThread(); } final int getHoldCount() { return isHeldExclusively() ? getState() : 0; } final boolean isLocked() { return getState() != 0; } /** * Reconstitutes the instance from a stream (that is, deserializes it). */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); setState(0); // reset to unlocked state } public boolean isExceeded() { return exceeded; } public void setExceeded(boolean exceeded) { this.exceeded = exceeded; } public int getReenterLimit() { return reenterLimit; } public void setReenterLimit(int reenterLimit) { this.reenterLimit = reenterLimit; } } /** * Sync object for non-fair locks */ static final class NonfairSync extends Sync { private static final long serialVersionUID = 7316153563782823691L; public NonfairSync(int reenterLimit) { super(reenterLimit); } /** * Performs lock. Try immediate barge, backing up to normal * acquire on failure. */ final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); } protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); } } /** * Sync object for fair locks */ static final class FairSync extends Sync { private static final long serialVersionUID = -3000897897090466540L; public FairSync(int reenterLimit) { super(reenterLimit); } final void lock() { acquire(1); } /** * Fair version of tryAcquire. Don't grant access unless * recursive call or no waiters or is first. */ 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) if (nextc > getReenterLimit()) // 这里是关键 throw new MaximumLockCountExceededException(getReenterLimit()); // throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } } public void lock() { sync.lock(); } public void lockInterruptibly() throws InterruptedException { sync.acquireInterruptibly(1); } public boolean tryLock() { return sync.nonfairTryAcquire(1); } public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); } public void unlock() { sync.release(1); } public Condition newCondition() { return sync.newCondition(); } public int getHoldCount() { return sync.getHoldCount(); } public boolean isHeldByCurrentThread() { return sync.isHeldExclusively(); } public boolean isLocked() { return sync.isLocked(); } public final boolean isFair() { return sync instanceof FairSync; } protected Thread getOwner() { return sync.getOwner(); } public final boolean hasQueuedThreads() { return sync.hasQueuedThreads(); } public final boolean hasQueuedThread(Thread thread) { return sync.isQueued(thread); } public final int getQueueLength() { return sync.getQueueLength(); } protected Collection<Thread> getQueuedThreads() { return sync.getQueuedThreads(); } public boolean hasWaiters(Condition condition) { if (condition == null) throw new NullPointerException(); if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) throw new IllegalArgumentException("not owner"); return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition); } public int getWaitQueueLength(Condition condition) { if (condition == null) throw new NullPointerException(); if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) throw new IllegalArgumentException("not owner"); return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition); } protected Collection<Thread> getWaitingThreads(Condition condition) { if (condition == null) throw new NullPointerException(); if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) throw new IllegalArgumentException("not owner"); return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition); } public String toString() { Thread o = sync.getOwner(); return super.toString() + ((o == null) ? "[Unlocked]" : "[Locked by thread " + o.getName() + "]"); } }
MaximumLockCountExceededException 异常:
public class MaximumLockCountExceededException extends IllegalStateException { //public class MaximumLockCountExceededException extends Exception { public MaximumLockCountExceededException(String s) { super(s); } public MaximumLockCountExceededException(int n) { super("Maximum lock count exceeded: " + n); } }
测试:
/** * Created by L.k on 2018/11/29. */ public class Testaa { ReenterLimitedLock twiceLock = new ReenterLimitedLock(); public static void main(String[] args) { ReenterLimitedLock twiceLock = new ReenterLimitedLock(); Testaa testaa = new Testaa(twiceLock); testaa.aa("asf"); } public Testaa(ReenterLimitedLock twiceLock) { this.twiceLock = twiceLock; } public void aa(String aa) { try { twiceLock.lock(); Thread.sleep(1000); System.out.println("aa = [" + aa + "]"); bb(aa); } catch (InterruptedException e) { e.printStackTrace(); } finally { twiceLock.unlock(); } } public void bb(String bb) { try { twiceLock.lock(); Thread.sleep(1000); System.out.println("bb = [" + bb + "]"); cc(bb); System.out.println("Testaa.bb"); } catch (InterruptedException e) { e.printStackTrace(); } finally { twiceLock.unlock(); } } public void cc(String cc) { try { twiceLock.lock(); Thread.sleep(1000); System.out.println("cc = [" + cc + "]"); } catch (InterruptedException e) { e.printStackTrace(); // } catch (InterruptedException | IllegalStateException e) { } catch (MaximumLockCountExceededException e) { // 这里必须要 捕获 MaximumLockCountExceededException, 否则 bb 方法也会异常退出 // e.printStackTrace(); System.out.println("xxxx IllegalStateException = " + e); } finally { twiceLock.unlock(); } } }