java.util.concurrent.locks.AbstractQueuedSynchronizer Example
AbstractQueuedSynchronizer
class has support for exclusive and shared mode of locks and synchronizers. It provides methods for inspection, instrumentation and monitoring methods for condition objects.
To implement, the following methods for releasing, acquiring shared, releasing shared, exclusively holding, getting state, setting state and comparing state have to be reimplemented:
tryAcquire(int)
tryRelease(int)
tryAcquireShared(int)
tryReleaseShared(int)
isHeldExclusively()
getState()
setState(int)
compareAndSetState(int,int)
Exception UnsupportedOperationException
is thrown by these methods. Implementations of the methods need to be thread safe internally and be short and not block.
Source Code Example
The example below has a non reentrant mutual exclusion lock class that has unlocked state, locked state. Zero and one represents unlocked and locked state.
MutexObjectSynchronizer.java
package com.architectcorner.locks; import java.io.IOException; import java.io.ObjectInputStream; import java.io.Serializable; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.AbstractQueuedSynchronizer; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; /** * */ /** * MutexObjectSynchronizer class has support * for exclusive and shared mode of locks and synchronizers. * It provides methods for inspection, instrumentation and * monitoring methods for condition objects. * @author Bhagvan Kommadi * */ public class MutexObjectSynchronizer implements Lock, Serializable { /** * serialization ID */ private static final long serialVersionUID = -4832743297432717114L; // Our internal helper class /** * Sync Class has support * for exclusive and shared mode of synchronizers. * @author bhagvank * */ private static class Sync extends AbstractQueuedSynchronizer { /** * serialization ID */ private static final long serialVersionUID = -4558858029181648609L; // Report whether in locked state protected boolean isHeldExclusively() { return getState() == 1; } /** * Acquire the lock if state is zero * @param acquires integer for lock state tracking * @return true if acquired else false */ public boolean tryAcquire(int acquires) { assert acquires == 1; // Otherwise unused if (compareAndSetState(0, 1)) { setExclusiveOwnerThread(Thread.currentThread()); return true; } return false; } /** * Release the lock by setting state to zero * @param releases integer for releasing the lock * @return true if it is released else false */ protected boolean tryRelease(int releases) { assert releases == 1; // Otherwise unused if (getState() == 0) throw new IllegalMonitorStateException(); setExclusiveOwnerThread(null); setState(0); return true; } // Provide a Condition Condition newCondition() { return new ConditionObject(); } // Deserialize properly private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); setState(0); // reset to unlocked state } } // The sync object does all the hard work. We just forward to it. private final Sync sync = new Sync(); /** * lock the object */ public void lock() { sync.acquire(1); } /** * acquiring the lock * @return true if lock acquired else false */ public boolean tryLock() { return sync.tryAcquire(1); } /** * unlock the object */ public void unlock() { sync.release(1); } /** * creating a new condition * @return condition object */ public Condition newCondition() { return sync.newCondition(); } /** * check if it is locked * @return true if it is locked */ public boolean isLocked() { return sync.isHeldExclusively(); } /** * check if it has queued threads * @return true if there are queued threads */ public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); } /** * locking the object interruptibly */ public void lockInterruptibly() throws InterruptedException { sync.acquireInterruptibly(1); } /** * try acquiring the lock * @param timeout timeout in seconds * @param unit timeunit object * @return true if lock is acquired else false */ public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); } }
AbstractQueuedSynchronizer
is an efficient and scalable synchronization mechanism. It can be used to implement synchronizers that can rely on int state, acquire and release parameters and an internal FIFO wait queue.
Conclusion
Queue Synchronization can be done by implementing AbstractQueuedSynchronizer
class methods for blocking locks and related semaphores and events.
You can download the source code of the example here: AbstractQueuedSynchronizerExample.zip