package com.renxo.cms.util; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; /** * An abstract LockManager implementation based on standard JDK * {@link Lock}s. * * @param * the type of the lock key. */ public abstract class AbstractJdkLockManager implements LockManager { // ---------------------------------------------------------------------- // Fields // ---------------------------------------------------------------------- private final ConcurrentMap locks = CollectionFactory .newConcurrentMap(); // ---------------------------------------------------------------------- // LockManager implementations // ---------------------------------------------------------------------- @Override public void ensureLock(K key) { Lock lock = cachedLock(key); lock.lock(); } @Override public void ensureLockInterruptibly(K key) throws InterruptedException { Lock lock = cachedLock(key); lock.lockInterruptibly(); } @Override public boolean acquireLock(K key) { long defaultTryLockTimeout = defaultTryLockTimeout(); if (defaultTryLockTimeout > 0L) { try { return acquireLock(key, defaultTryLockTimeout); } catch (InterruptedException e) { return false; } } else { Lock lock = cachedLock(key); return lock.tryLock(); } } @Override public boolean acquireLock(K key, long timeout) throws InterruptedException { Lock lock = cachedLock(key); return lock.tryLock(timeout, TimeUnit.MILLISECONDS); } @Override public void releaseLock(K key) { Lock lock = cachedLock(key); try { lock.unlock(); } catch (Exception e) { throw new IllegalMonitorStateException(e.getMessage()); } } @Override public void clearUnusedLocks() { Map acquiredLocks = new HashMap(); for (Entry entry : locks.entrySet()) { K key = entry.getKey(); Lock lock = entry.getValue(); if (lock.tryLock()) { acquiredLocks.put(key, lock); } } for (Entry entry : acquiredLocks.entrySet()) { K key = entry.getKey(); Lock lock = entry.getValue(); locks.remove(key); lock.unlock(); } } // ---------------------------------------------------------------------- // Private helper methods // ---------------------------------------------------------------------- private Lock cachedLock(K key) { Lock lock = locks.get(key); if (lock == null) { lock = getLock(key); Lock prevLock = locks.putIfAbsent(key, lock); if (prevLock != null) { lock = prevLock; } } return lock; } // ---------------------------------------------------------------------- // Template methods // ---------------------------------------------------------------------- /** * Gets a lock instance for the given key. * * @param key * the key for which to obtain the lock instance. * @return the requested lock instance. */ protected abstract Lock getLock(K key); /** * Returns the default {@link #acquireLock(Object)} timeout to use. * Implementations that do not require a default timeout should return zero. * * @return the default {@link #acquireLock(Object)} timeout to use. */ protected abstract long defaultTryLockTimeout(); }