/** * Returns a new {@link KeyLockManager} with default settings. The best available multi purpose implementation is * used. * * @return the newly created lock */ public static KeyLockManager newLock() { return new StripedKeyLockManager(DEFAULT_LOCK_TIMEOUT, TimeUnit.HOURS); }
private void freeKeyLock(final Object key, final CountingLock lock) { assert key != null : "contract broken: key != null"; assert lock != null : "contract broken: lock != null"; getStripedLock(key).tryLock(); try { lock.decrementUses(); if (!lock.isUsed()) { key2lock.remove(key); } } finally { getStripedLock(key).unlock(); } }
private <R> R executeLockedInternal(final Object key, final ReturnValueLockCallback<R> callback) { assert key != null : "contract broken: key != null"; assert callback != null : "contract broken: callback != null"; final CountingLock lock = getKeyLock(key); try { lock.tryLock(); try { return callback.doInLock(); } finally { lock.unlock(); } } finally { freeKeyLock(key, lock); } }
private CountingLock getKeyLock(final Object key) { assert key != null : "contract broken: key != null"; getStripedLock(key).tryLock(); try { final CountingLock result; final CountingLock previousLock = key2lock.get(key); if (previousLock == null) { result = new CountingLock(lockTimeout, lockTimeoutUnit); key2lock.put(key, result); } else { result = previousLock; } result.incrementUses(); return result; } finally { getStripedLock(key).unlock(); } }
@Override public final <R> R executeLocked(final Object key, final ReturnValueLockCallback<R> callback) { Contract.isNotNull(key, "key != null"); Contract.isNotNull(callback, "callback != null"); return executeLockedInternal(key, callback); }
/** * for testing only * * @return the number of threads currently waiting in the queues of the key locks */ int waitingThreadsCount() { int result = 0; for (final CountingLock lock : key2lock.values()) { result += lock.getQueueLength(); } return result; } }
/** * Creates a new instance of {@link StripedKeyLockManager} with the given settings. * * @param lockTimeout * the time to wait for a lock before a Exception is thrown - must be greater than 0 * @param lockTimeoutUnit * the unit for lockTimeout - must not be null * @param numberOfStripes * the number of stripes used for locking */ public StripedKeyLockManager(final long lockTimeout, final TimeUnit lockTimeoutUnit, final int numberOfStripes) { Contract.isNotNull(lockTimeoutUnit, "lockTimeoutUnit != null"); Contract.isTrue(lockTimeout > 0, "lockTimeout > 0"); Contract.isTrue(numberOfStripes > 0, "numberOfStripes > 0"); this.lockTimeout = lockTimeout; this.lockTimeoutUnit = lockTimeoutUnit; this.stripes = new CountingLock[numberOfStripes]; setAll(stripes, i -> new CountingLock(lockTimeout, lockTimeoutUnit)); }
private void freeKeyLock(final Object key, final CountingLock lock) { assert key != null : "contract broken: key != null"; assert lock != null : "contract broken: lock != null"; getStripedLock(key).tryLock(); try { lock.decrementUses(); if (!lock.isUsed()) { key2lock.remove(key); } } finally { getStripedLock(key).unlock(); } }
private CountingLock getKeyLock(final Object key) { assert key != null : "contract broken: key != null"; getStripedLock(key).tryLock(); try { final CountingLock result; final CountingLock previousLock = key2lock.get(key); if (previousLock == null) { result = new CountingLock(lockTimeout, lockTimeoutUnit); key2lock.put(key, result); } else { result = previousLock; } result.incrementUses(); return result; } finally { getStripedLock(key).unlock(); } }
private <R> R executeLockedInternal(final Object key, final ReturnValueLockCallback<R> callback) { assert key != null : "contract broken: key != null"; assert callback != null : "contract broken: callback != null"; final CountingLock lock = getKeyLock(key); try { lock.tryLock(); try { return callback.doInLock(); } finally { lock.unlock(); } } finally { freeKeyLock(key, lock); } }
/** * Returns a new {@link KeyLockManager} with the given timeout settings. The best available multi purpose * implementation is used. * * @param lockTimeout * the time to wait for a lock before a Exception is thrown - must be greater than 0 * @param lockTimeoutUnit * the unit for lockTimeout - must not be null * * @return the newly created lock */ public static KeyLockManager newLock(final long lockTimeout, final TimeUnit lockTimeoutUnit) { return new StripedKeyLockManager(lockTimeout, lockTimeoutUnit); }
@Override public final <R> R executeLocked(final Object key, final ReturnValueLockCallback<R> callback) { Contract.isNotNull(key, "key != null"); Contract.isNotNull(callback, "callback != null"); return executeLockedInternal(key, callback); }
/** * for testing only * * @return the number of threads currently waiting in the queues of the key locks */ int waitingThreadsCount() { int result = 0; for (final CountingLock lock : key2lock.values()) { result += lock.getQueueLength(); } return result; } }
/** * Creates a new instance of {@link StripedKeyLockManager} with the given settings. * * @param lockTimeout * the time to wait for a lock before a Exception is thrown - must be greater than 0 * @param lockTimeoutUnit * the unit for lockTimeout - must not be null * @param numberOfStripes * the number of stripes used for locking */ public StripedKeyLockManager(final long lockTimeout, final TimeUnit lockTimeoutUnit, final int numberOfStripes) { Contract.isNotNull(lockTimeoutUnit, "lockTimeoutUnit != null"); Contract.isTrue(lockTimeout > 0, "lockTimeout > 0"); Contract.isTrue(numberOfStripes > 0, "numberOfStripes > 0"); this.lockTimeout = lockTimeout; this.lockTimeoutUnit = lockTimeoutUnit; this.stripes = new CountingLock[numberOfStripes]; setAll(stripes, i -> new CountingLock(lockTimeout, lockTimeoutUnit)); }
/** * Returns a new {@link KeyLockManager} with default settings. The best available multi purpose implementation is * used. * * @return the newly created lock */ public static KeyLockManager newLock() { return new StripedKeyLockManager(DEFAULT_LOCK_TIMEOUT, TimeUnit.HOURS); }
@Override public final void executeLocked(final Object key, final LockCallback callback) { Contract.isNotNull(key, "key != null"); Contract.isNotNull(callback, "callback != null"); executeLockedInternal(key, () -> { callback.doInLock(); return null; }); }
/** * Returns a new {@link KeyLockManager} with the given timeout settings. The best available multi purpose * implementation is used. * * @param lockTimeout * the time to wait for a lock before a Exception is thrown - must be greater than 0 * @param lockTimeoutUnit * the unit for lockTimeout - must not be null * * @return the newly created lock */ public static KeyLockManager newLock(final long lockTimeout, final TimeUnit lockTimeoutUnit) { return new StripedKeyLockManager(lockTimeout, lockTimeoutUnit); }
@Override public final void executeLocked(final Object key, final LockCallback callback) { Contract.isNotNull(key, "key != null"); Contract.isNotNull(callback, "callback != null"); executeLockedInternal(key, () -> { callback.doInLock(); return null; }); }