@Override public synchronized void shutdown() { shuttingDown = true; locker.shutdown(); threadPool.shutdown(); stopped = true; }
/** * Method "clean". * * <p>Clean the map which contains the lock wrappers. * * <p>Removed lock wrappers are these where lock is not locked by a thread and no one thread is * waiting to obtain the lock. * * <p>The default clean will do an automatic clean all 1000 unlock operation, you can disable or * change this value from the constructor. */ @Override public void clean() { synchronized (lockAllOperations) { waitForRunningOperationsEnded(); locker.clean(); resumeAllOperations(); } }
/** * Method "tryLock". * * @param key * @return {@code true} if the lock was free and was acquired by the current thread, or the lock * was already held by the current thread; and {@code false} otherwise * @throws InterruptedException * @throws IllegalArgumentException if bean is null * @see java.util.concurrent.locks.ReentrantLock#tryLock() */ @Override public boolean tryLock(final KP key) { blockOperationIfRequired(); incrementRunningOperations(); try { return locker.tryLock(key); } finally { decrementRunningOperations(); } }
/** * Method "lockInterruptibly". * * @param key * @throws InterruptedException * @see java.util.concurrent.locks.ReentrantLock#lockInterruptibly() */ @Override public void lockInterruptibly(final KP key) throws InterruptedException { blockOperationIfRequired(); incrementRunningOperations(); try { locker.lockInterruptibly(key); } finally { decrementRunningOperations(); } }
/** * Method "tryLock". * * @param key * @param timeout the time to wait for the lock * @param unit the time unit of the timeout argument * @return true if the lock was free and was acquired by the current thread, or the lock was * already held by the current thread; and false if the waiting time elapsed before the lock * could be acquired * @throws InterruptedException * @throws IllegalArgumentException if bean is null * @see java.util.concurrent.locks.ReentrantLock#tryLock(long, java.util.concurrent.TimeUnit) */ @Override public boolean tryLock(final KP key, final long timeout, final TimeUnit unit) throws InterruptedException { blockOperationIfRequired(); incrementRunningOperations(); try { return locker.tryLock(key, timeout, unit); } finally { decrementRunningOperations(); } }
/** * Method "tryLockUnrestricted". * * @param key * @return {@code true} if the lock was free and was acquired by the current thread, or the lock * was already held by the current thread; and {@code false} otherwise * @throws InterruptedException * @throws IllegalArgumentException if bean is null * @see java.util.concurrent.locks.ReentrantLock#tryLock() */ public boolean tryLockUnrestricted(final KP key) { checkStopped(); blockOperationIfRequired(); incrementRunningOperations(); boolean tryLockResultBoolean; try { final AtomicBoolean tryLockResult = new AtomicBoolean(); final CyclicBarrier cyclicBarrier = new CyclicBarrier(2); Callable<Boolean> callable = new Callable<Boolean>() { /* * (non-Javadoc) * * @see java.util.concurrent.Callable#call() */ @Override public Boolean call() throws Exception { boolean locked; try { locked = locker.tryLock(key); tryLockResult.set(locked); } finally { // STEP 1 cyclicBarrier.await(); } if (locked) { // STEP 2 cyclicBarrier.await(); return locker.unlock(key); } else { return false; } } }; Future<Boolean> futureTask = threadPool.submit(callable); try { // STEP 1 cyclicBarrier.await(); } catch (Exception e) { throw new RuntimeException(e); } tryLockResultBoolean = tryLockResult.get(); if (tryLockResultBoolean) { LockerValue<KP> lockerValue = locker.getLockerValue(key); Thread callerThreadLocker = Thread.currentThread(); lockerValue.addHandler( new LockerValueHandler(futureTask, cyclicBarrier, callerThreadLocker)); } } finally { decrementRunningOperations(); } return tryLockResultBoolean; }
/** * Method "unlock". Unlock the operations with the provided key. * * <p>To detect incorrect unlocking, this method may return an <code>IllegalStateException</code> * when the lock has been already unlocked or it never been locked. * * @param key * @return true if the key has been found to release the lock; and false otherwise * @throws IllegalStateException * @see java.util.concurrent.locks.ReentrantLock#unlock() */ @Override public boolean unlock(final KP key) { boolean returnedValue = false; try { checkStopped(); blockOperationIfRequired(); incrementRunningOperations(); returnedValue = locker.unlock(key); } finally { decrementRunningOperations(); } cleanAccordingOperations(); return returnedValue; }
/** * Method "unlockUnrestricted". Unlock the operations with the provided key. * * <p>To detect incorrect unlocking, this method may return an <code>IllegalStateException</code> * when the lock has been already unlocked or it never been locked. * * @param key * @return true if the key has been found to release the lock; and false otherwise * @throws IllegalStateException * @see java.util.concurrent.locks.ReentrantLock#unlock() */ public boolean unlockUnrestricted(final KP key) { checkStopped(); blockOperationIfRequired(); Boolean resultFuture; incrementRunningOperations(); try { LockerValue<KP> lockerValue = locker.getLockerValue(key); if (lockerValue == null) { throw new IllegalStateException(NOT_ALREADY_LOCKED_MESSAGE + " key=" + key); } LockerValueHandler handler = lockerValue.getHandlerAndRemove(); if (handler == null) { throw new UnsupportedOperationException( "Either you have to use the restricted unlock() method to unlock, or you have to use '*Lock*Unrestricted()' methods to lock !"); } CyclicBarrier barrier = handler.getBarrier(); try { // STEP 2 barrier.await(); } catch (Exception e) { throw new RuntimeException(e); } Future<Boolean> future = handler.getFuture(); if (future.isCancelled()) { return false; } resultFuture = null; try { resultFuture = future.get(); } catch (Exception e) { throw new RuntimeException(e); } } finally { decrementRunningOperations(); } cleanAccordingOperations(); return resultFuture; }
private void waitForRunningOperationsEnded() { blockAllOperations(); boolean breakAtNext = false; while (true) { Collection<LockerValue<KP>> values = locker.getMapKeyLockToValueLock().values(); int waitingThreads = 0; for (LockerValue<KP> lockerValue : values) { waitingThreads += lockerValue.getLock().getQueueLength(); } if (runningOperations.get() - waitingThreads <= 0) { if (breakAtNext) { break; } breakAtNext = true; } else { breakAtNext = false; } try { Thread.sleep(10); } catch (InterruptedException e) { break; } } }
@Override public boolean isDetectSuspectLocks() { return locker.isDetectSuspectLocks(); }
@Override public void setDetectSuspectLocks(boolean detectSuspectLocks) { locker.setDetectSuspectLocks(detectSuspectLocks); }
@Override public List<LockerValue<KP>> getSuspectLocks(long timeDetectionLimitMs) { return locker.getSuspectLocks(timeDetectionLimitMs); }
@Override public boolean isLocked(KP key) { return locker.isLocked(key); }
@Override public LockerValue<KP> getLockerValue(KP key) { return locker.getLockerValue(key); }
/** * Method "tryLock". * * @param key * @param timeout the time to wait for the lock in milliseconds * @return true if the lock was free and was acquired by the current thread, or the lock was * already held by the current thread; and false if the waiting time elapsed before the lock * could be acquired * @throws InterruptedException * @throws IllegalArgumentException if bean is null * @see java.util.concurrent.locks.ReentrantLock#tryLock(long, java.util.concurrent.TimeUnit) */ @Override public boolean tryLock(final KP key, final long timeout) throws InterruptedException { return locker.tryLock(key, timeout, TimeUnit.MILLISECONDS); }
/** * Method "tryLockUnrestricted". * * @param key * @param timeout the time to wait for the lock * @param unit the time unit of the timeout argument * @return true if the lock was free and was acquired by the current thread, or the lock was * already held by the current thread; and false if the waiting time elapsed before the lock * could be acquired * @throws InterruptedException * @throws IllegalArgumentException if bean is null * @see java.util.concurrent.locks.ReentrantLock#tryLock(long, java.util.concurrent.TimeUnit) */ public boolean tryLockUnrestricted(final KP key, final long timeout, final TimeUnit unit) throws InterruptedException { checkStopped(); blockOperationIfRequired(); incrementRunningOperations(); boolean tryLockResultBoolean = false; try { final AtomicBoolean tryLockResult = new AtomicBoolean(); final AtomicReference<InterruptedException> interruptedExceptionFromTryRef = new AtomicReference<InterruptedException>(); final CyclicBarrier cyclicBarrier = new CyclicBarrier(2); Callable<Boolean> callable = new Callable<Boolean>() { /* * (non-Javadoc) * * @see java.util.concurrent.Callable#call() */ @Override public Boolean call() throws Exception { boolean locked = false; try { locked = locker.tryLock(key, timeout, unit); tryLockResult.set(locked); } catch (InterruptedException e) { interruptedExceptionFromTryRef.set(e); return false; } finally { // STEP 1 cyclicBarrier.await(); } if (locked) { // STEP 2 cyclicBarrier.await(); return locker.unlock(key); } else { return false; } } }; Future<Boolean> futureTask = threadPool.submit(callable); try { // STEP 1 cyclicBarrier.await(); } catch (Exception e) { throw new RuntimeException(e); } InterruptedException interruptedExceptionFromTry = interruptedExceptionFromTryRef.get(); if (interruptedExceptionFromTry != null) { throw interruptedExceptionFromTry; } tryLockResultBoolean = tryLockResult.get(); if (tryLockResultBoolean) { LockerValue<KP> lockerValue = locker.getLockerValue(key); Thread threadLocker = Thread.currentThread(); lockerValue.addHandler(new LockerValueHandler(futureTask, cyclicBarrier, threadLocker)); locker.traceStackForDebugging(lockerValue); } } finally { decrementRunningOperations(); } return tryLockResultBoolean; }
/** * Method "lockInterruptiblyUnrestricted". * * @param key * @throws InterruptedException * @see java.util.concurrent.locks.ReentrantLock#lockInterruptibly() */ public void lockInterruptiblyUnrestricted(final KP key) throws InterruptedException { checkStopped(); blockOperationIfRequired(); LockerValue<KP> lockerValue = null; LockerValueHandler handler = null; if (tryLockUnrestricted(key)) { return; } incrementRunningOperations(); /* Test if already locked by the same thread */ lockerValue = locker.getLockerValue(key); if (locker != null) { handler = lockerValue.getHandler(); if (handler != null && Thread.currentThread() == handler.getCallerThreadLocker()) { decrementRunningOperations(); return; } } try { final Thread threadLocker = Thread.currentThread(); final CyclicBarrier cyclicBarrier = new CyclicBarrier(2); final AtomicBoolean hasError = new AtomicBoolean(); Callable<Boolean> callable = new Callable<Boolean>() { /* * (non-Javadoc) * * @see java.util.concurrent.Callable#call() */ @Override public Boolean call() throws Exception { try { locker.lockInterruptibly(key); } catch (Exception e) { hasError.set(true); throw e; } finally { // STEP 1 cyclicBarrier.await(); } // STEP 2 cyclicBarrier.await(); boolean unlocked = locker.unlock(key); return unlocked; } }; Future<Boolean> futureTask = threadPool.submit(callable); try { // STEP 1 cyclicBarrier.await(); } catch (BrokenBarrierException e) { throw new RuntimeException(e); } if (hasError.get()) { try { futureTask.get(); } catch (ExecutionException e) { Throwable cause = e.getCause(); if (cause != null && cause instanceof InterruptedException) { throw (InterruptedException) cause; } else { throw new RuntimeException(e); } } } lockerValue = locker.getLockerValue(key); lockerValue.addHandler(new LockerValueHandler(futureTask, cyclicBarrier, threadLocker)); } finally { decrementRunningOperations(); } }