package org.warp.commonutils.locks; import java.util.concurrent.Semaphore; import java.util.concurrent.atomic.AtomicInteger; public class TransitLock { private final FlexibleCountDownLatch unfinishedTransits = new FlexibleCountDownLatch(0); private final Semaphore permits = new Semaphore(Integer.MAX_VALUE); private final AtomicInteger allowedTransits = new AtomicInteger(1); private final Object synchronization = new Object(); public TransitLock() { } public void allowTransit() { var allowedTransits = this.allowedTransits.incrementAndGet(); if (allowedTransits == 1) { var permitsToRelease = Math.max(0, Integer.MAX_VALUE - (permits.availablePermits() + 10000)); permits.release(permitsToRelease); } else if (allowedTransits > 1) { throw new IllegalStateException("Already allowed transit!"); } } public void disallowTransit() { synchronized (synchronization) { var allowedTransits = this.allowedTransits.decrementAndGet(); if (allowedTransits == 0) { unfinishedTransits.await(); permits.drainPermits(); } else if (allowedTransits > 0) { throw new IllegalStateException("Transits are still allowed for an unknown reason!"); } } } public void transit() { startTransit(); endTransit(); } public void startTransit() { synchronized (synchronization) { unfinishedTransits.grow(); permits.acquireUninterruptibly(); } } public void endTransit() { unfinishedTransits.countDown(); } }