001: /**
002: * Copyright 2003-2007 Luck Consulting Pty Ltd
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */package net.sf.ehcache.constructs.concurrent;
016:
017: /**
018: * @version $Id: Mutex.java 519 2007-07-27 07:11:45Z gregluck $
019: * @author Doug Lea
020: * A simple non-reentrant mutual exclusion lock.
021: * The lock is free upon construction. Each acquire gets the
022: * lock, and each release frees it. Releasing a lock that
023: * is already free has no effect.
024: * <p/>
025: * This implementation makes no attempt to provide any fairness
026: * or ordering guarantees. If you need them, consider using one of
027: * the Semaphore implementations as a locking mechanism.
028: * <p/>
029: * <b>Sample usage</b><br>
030: * <p/>
031: * Mutex can be useful in constructions that cannot be
032: * expressed using java synchronized blocks because the
033: * acquire/release pairs do not occur in the same method or
034: * code block. For example, you can use them for hand-over-hand
035: * locking across the nodes of a linked list. This allows
036: * extremely fine-grained locking, and so increases
037: * potential concurrency, at the cost of additional complexity and
038: * overhead that would normally make this worthwhile only in cases of
039: * extreme contention.
040: * <pre>
041: * class Node {
042: * Object item;
043: * Node next;
044: * Mutex lock = new Mutex(); // each node keeps its own lock
045: * <p/>
046: * Node(Object x, Node n) { item = x; next = n; }
047: * }
048: * <p/>
049: * class List {
050: * protected Node head; // pointer to first node of list
051: * <p/>
052: * // Use plain java synchronization to protect head field.
053: * // (We could instead use a Mutex here too but there is no
054: * // reason to do so.)
055: * protected synchronized Node getHead() { return head; }
056: * <p/>
057: * boolean search(Object x) throws InterruptedException {
058: * Node p = getHead();
059: * if (p == null) return false;
060: * <p/>
061: * // (This could be made more compact, but for clarity of illustration,
062: * // all of the cases that can arise are handled separately.)
063: * <p/>
064: * p.lock.acquire(); // Prime loop by acquiring first lock.
065: * // (If the acquire fails due to
066: * // interrupt, the method will throw
067: * // InterruptedException now,
068: * // so there is no need for any
069: * // further cleanup.)
070: * for (;;) {
071: * if (x.equals(p.item)) {
072: * p.lock.release(); // release current before return
073: * return true;
074: * }
075: * else {
076: * Node nextp = p.next;
077: * if (nextp == null) {
078: * p.lock.release(); // release final lock that was held
079: * return false;
080: * }
081: * else {
082: * try {
083: * nextp.lock.acquire(); // get next lock before releasing current
084: * }
085: * catch (InterruptedException ex) {
086: * p.lock.release(); // also release current if acquire fails
087: * throw ex;
088: * }
089: * p.lock.release(); // release old lock now that new one held
090: * p = nextp;
091: * }
092: * }
093: * }
094: * }
095: * <p/>
096: * synchronized void add(Object x) { // simple prepend
097: * // The use of `synchronized' here protects only head field.
098: * // The method does not need to wait out other traversers
099: * // who have already made it past head.
100: * <p/>
101: * head = new Node(x, head);
102: * }
103: * <p/>
104: * // ... other similar traversal and update methods ...
105: * }
106: * </pre>
107: * <p/>
108: * <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>]
109: */
110: public class Mutex implements Sync {
111: /**
112: * The lock status *
113: */
114: protected boolean inUse;
115:
116: /**
117: * Wait (possibly forever) until successful passage.
118: * Fail only upon interuption. Interruptions always result in
119: * `clean' failures. On failure, you can be sure that it has not
120: * been acquired, and that no
121: * corresponding release should be performed. Conversely,
122: * a normal return guarantees that the acquire was successful.
123: * @see Sync#acquire()
124: */
125: public void acquire() throws InterruptedException {
126: if (Thread.interrupted()) {
127: throw new InterruptedException();
128: }
129: synchronized (this ) {
130: try {
131: while (inUse) {
132: wait();
133: }
134: inUse = true;
135: } catch (InterruptedException ex) {
136: notify();
137: throw ex;
138: }
139: }
140: }
141:
142: /**
143: * @param msecs the number of milleseconds to wait.
144: * An argument less than or equal to zero means not to wait at all.
145: * However, this may still require
146: * access to a synchronization lock, which can impose unbounded
147: * delay if there is a lot of contention among threads.
148: * @return true if acquired
149: * @see Sync#attempt(long)
150: */
151: public boolean attempt(long msecs) throws InterruptedException {
152: if (Thread.interrupted()) {
153: throw new InterruptedException();
154: }
155: synchronized (this ) {
156: if (!inUse) {
157: inUse = true;
158: return true;
159: } else if (msecs <= 0) {
160: return false;
161: } else {
162: long waitTime = msecs;
163: long start = System.currentTimeMillis();
164: try {
165: for (;;) {
166: wait(waitTime);
167: if (!inUse) {
168: inUse = true;
169: return true;
170: } else {
171: waitTime = msecs
172: - (System.currentTimeMillis() - start);
173: if (waitTime <= 0) {
174: return false;
175: }
176: }
177: }
178: } catch (InterruptedException ex) {
179: notify();
180: throw ex;
181: }
182: }
183: }
184: }
185:
186: /**
187: * Potentially enable others to pass.
188: * <p/>
189: * Because release does not raise exceptions,
190: * it can be used in `finally' clauses without requiring extra
191: * embedded try/catch blocks. But keep in mind that
192: * as with any java method, implementations may
193: * still throw unchecked exceptions such as Error or NullPointerException
194: * when faced with uncontinuable errors. However, these should normally
195: * only be caught by higher-level error handlers.
196: * @see Sync#release()
197: */
198: public synchronized void release() {
199: inUse = false;
200: notify();
201: }
202: }
|