001: /*
002: File: Mutex.java
003:
004: Originally written by Doug Lea and released into the public domain.
005: This may be used for any purposes whatsoever without acknowledgment.
006: Thanks for the assistance and support of Sun Microsystems Labs,
007: and everyone contributing, testing, and using this code.
008:
009: History:
010: Date Who What
011: 11Jun1998 dl Create public version
012: */
013:
014: package EDU.oswego.cs.dl.util.concurrent;
015:
016: /**
017: * A simple non-reentrant mutual exclusion lock.
018: * The lock is free upon construction. Each acquire gets the
019: * lock, and each release frees it. Releasing a lock that
020: * is already free has no effect.
021: * <p>
022: * This implementation makes no attempt to provide any fairness
023: * or ordering guarantees. If you need them, consider using one of
024: * the Semaphore implementations as a locking mechanism.
025: * <p>
026: * <b>Sample usage</b><br>
027: * <p>
028: * Mutex can be useful in constructions that cannot be
029: * expressed using java synchronized blocks because the
030: * acquire/release pairs do not occur in the same method or
031: * code block. For example, you can use them for hand-over-hand
032: * locking across the nodes of a linked list. This allows
033: * extremely fine-grained locking, and so increases
034: * potential concurrency, at the cost of additional complexity and
035: * overhead that would normally make this worthwhile only in cases of
036: * extreme contention.
037: * <pre>
038: * class Node {
039: * Object item;
040: * Node next;
041: * Mutex lock = new Mutex(); // each node keeps its own lock
042: *
043: * Node(Object x, Node n) { item = x; next = n; }
044: * }
045: *
046: * class List {
047: * protected Node head; // pointer to first node of list
048: *
049: * // Use plain java synchronization to protect head field.
050: * // (We could instead use a Mutex here too but there is no
051: * // reason to do so.)
052: * protected synchronized Node getHead() { return head; }
053: *
054: * boolean search(Object x) throws InterruptedException {
055: * Node p = getHead();
056: * if (p == null) return false;
057: *
058: * // (This could be made more compact, but for clarity of illustration,
059: * // all of the cases that can arise are handled separately.)
060: *
061: * p.lock.acquire(); // Prime loop by acquiring first lock.
062: * // (If the acquire fails due to
063: * // interrupt, the method will throw
064: * // InterruptedException now,
065: * // so there is no need for any
066: * // further cleanup.)
067: * for (;;) {
068: * if (x.equals(p.item)) {
069: * p.lock.release(); // release current before return
070: * return true;
071: * }
072: * else {
073: * Node nextp = p.next;
074: * if (nextp == null) {
075: * p.lock.release(); // release final lock that was held
076: * return false;
077: * }
078: * else {
079: * try {
080: * nextp.lock.acquire(); // get next lock before releasing current
081: * }
082: * catch (InterruptedException ex) {
083: * p.lock.release(); // also release current if acquire fails
084: * throw ex;
085: * }
086: * p.lock.release(); // release old lock now that new one held
087: * p = nextp;
088: * }
089: * }
090: * }
091: * }
092: *
093: * synchronized void add(Object x) { // simple prepend
094: * // The use of `synchronized' here protects only head field.
095: * // The method does not need to wait out other traversers
096: * // who have already made it past head.
097: *
098: * head = new Node(x, head);
099: * }
100: *
101: * // ... other similar traversal and update methods ...
102: * }
103: * </pre>
104: * <p>
105: * @see Semaphore
106: * <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>]
107: **/
108:
109: public class Mutex implements Sync {
110:
111: /** The lock status **/
112: protected boolean inuse_ = false;
113:
114: public void acquire() throws InterruptedException {
115: if (Thread.interrupted())
116: throw new InterruptedException();
117: synchronized (this ) {
118: try {
119: while (inuse_)
120: wait();
121: inuse_ = true;
122: } catch (InterruptedException ex) {
123: notify();
124: throw ex;
125: }
126: }
127: }
128:
129: public synchronized void release() {
130: inuse_ = false;
131: notify();
132: }
133:
134: public boolean attempt(long msecs) throws InterruptedException {
135: if (Thread.interrupted())
136: throw new InterruptedException();
137: synchronized (this ) {
138: if (!inuse_) {
139: inuse_ = true;
140: return true;
141: } else if (msecs <= 0)
142: return false;
143: else {
144: long waitTime = msecs;
145: long start = System.currentTimeMillis();
146: try {
147: for (;;) {
148: wait(waitTime);
149: if (!inuse_) {
150: inuse_ = true;
151: return true;
152: } else {
153: waitTime = msecs
154: - (System.currentTimeMillis() - start);
155: if (waitTime <= 0)
156: return false;
157: }
158: }
159: } catch (InterruptedException ex) {
160: notify();
161: throw ex;
162: }
163: }
164: }
165: }
166:
167: }
|