1 /**
2 * Copyright 2003-2007 Greg Luck
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package net.sf.ehcache.constructs.concurrent;
18
19 /**
20 * @version $Id: Mutex.java 512 2007-07-10 09:18:45Z gregluck $
21 * @author Doug Lea
22 * A simple non-reentrant mutual exclusion lock.
23 * The lock is free upon construction. Each acquire gets the
24 * lock, and each release frees it. Releasing a lock that
25 * is already free has no effect.
26 * <p/>
27 * This implementation makes no attempt to provide any fairness
28 * or ordering guarantees. If you need them, consider using one of
29 * the Semaphore implementations as a locking mechanism.
30 * <p/>
31 * <b>Sample usage</b><br>
32 * <p/>
33 * Mutex can be useful in constructions that cannot be
34 * expressed using java synchronized blocks because the
35 * acquire/release pairs do not occur in the same method or
36 * code block. For example, you can use them for hand-over-hand
37 * locking across the nodes of a linked list. This allows
38 * extremely fine-grained locking, and so increases
39 * potential concurrency, at the cost of additional complexity and
40 * overhead that would normally make this worthwhile only in cases of
41 * extreme contention.
42 * <pre>
43 * class Node {
44 * Object item;
45 * Node next;
46 * Mutex lock = new Mutex(); // each node keeps its own lock
47 * <p/>
48 * Node(Object x, Node n) { item = x; next = n; }
49 * }
50 * <p/>
51 * class List {
52 * protected Node head; // pointer to first node of list
53 * <p/>
54 * // Use plain java synchronization to protect head field.
55 * // (We could instead use a Mutex here too but there is no
56 * // reason to do so.)
57 * protected synchronized Node getHead() { return head; }
58 * <p/>
59 * boolean search(Object x) throws InterruptedException {
60 * Node p = getHead();
61 * if (p == null) return false;
62 * <p/>
63 * // (This could be made more compact, but for clarity of illustration,
64 * // all of the cases that can arise are handled separately.)
65 * <p/>
66 * p.lock.acquire(); // Prime loop by acquiring first lock.
67 * // (If the acquire fails due to
68 * // interrupt, the method will throw
69 * // InterruptedException now,
70 * // so there is no need for any
71 * // further cleanup.)
72 * for (;;) {
73 * if (x.equals(p.item)) {
74 * p.lock.release(); // release current before return
75 * return true;
76 * }
77 * else {
78 * Node nextp = p.next;
79 * if (nextp == null) {
80 * p.lock.release(); // release final lock that was held
81 * return false;
82 * }
83 * else {
84 * try {
85 * nextp.lock.acquire(); // get next lock before releasing current
86 * }
87 * catch (InterruptedException ex) {
88 * p.lock.release(); // also release current if acquire fails
89 * throw ex;
90 * }
91 * p.lock.release(); // release old lock now that new one held
92 * p = nextp;
93 * }
94 * }
95 * }
96 * }
97 * <p/>
98 * synchronized void add(Object x) { // simple prepend
99 * // The use of `synchronized' here protects only head field.
100 * // The method does not need to wait out other traversers
101 * // who have already made it past head.
102 * <p/>
103 * head = new Node(x, head);
104 * }
105 * <p/>
106 * // ... other similar traversal and update methods ...
107 * }
108 * </pre>
109 * <p/>
110 * <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>]
111 */
112 public class Mutex implements Sync {
113 /**
114 * The lock status *
115 */
116 protected boolean inUse;
117
118 /**
119 * Wait (possibly forever) until successful passage.
120 * Fail only upon interuption. Interruptions always result in
121 * `clean' failures. On failure, you can be sure that it has not
122 * been acquired, and that no
123 * corresponding release should be performed. Conversely,
124 * a normal return guarantees that the acquire was successful.
125 * @see Sync#acquire()
126 */
127 public void acquire() throws InterruptedException {
128 if (Thread.interrupted()) {
129 throw new InterruptedException();
130 }
131 synchronized (this) {
132 try {
133 while (inUse) {
134 wait();
135 }
136 inUse = true;
137 } catch (InterruptedException ex) {
138 notify();
139 throw ex;
140 }
141 }
142 }
143
144 /**
145 * @param msecs the number of milleseconds to wait.
146 * An argument less than or equal to zero means not to wait at all.
147 * However, this may still require
148 * access to a synchronization lock, which can impose unbounded
149 * delay if there is a lot of contention among threads.
150 * @return true if acquired
151 * @see Sync#attempt(long)
152 */
153 public boolean attempt(long msecs) throws InterruptedException {
154 if (Thread.interrupted()) {
155 throw new InterruptedException();
156 }
157 synchronized (this) {
158 if (!inUse) {
159 inUse = true;
160 return true;
161 } else if (msecs <= 0) {
162 return false;
163 } else {
164 long waitTime = msecs;
165 long start = System.currentTimeMillis();
166 try {
167 for (;;) {
168 wait(waitTime);
169 if (!inUse) {
170 inUse = true;
171 return true;
172 } else {
173 waitTime = msecs - (System.currentTimeMillis() - start);
174 if (waitTime <= 0) {
175 return false;
176 }
177 }
178 }
179 } catch (InterruptedException ex) {
180 notify();
181 throw ex;
182 }
183 }
184 }
185 }
186
187 /**
188 * Potentially enable others to pass.
189 * <p/>
190 * Because release does not raise exceptions,
191 * it can be used in `finally' clauses without requiring extra
192 * embedded try/catch blocks. But keep in mind that
193 * as with any java method, implementations may
194 * still throw unchecked exceptions such as Error or NullPointerException
195 * when faced with uncontinuable errors. However, these should normally
196 * only be caught by higher-level error handlers.
197 * @see Sync#release()
198 */
199 public synchronized void release() {
200 inUse = false;
201 notify();
202 }
203 }
204