1 /*
2 File: Mutex.java
3
4 Originally written by Doug Lea and released into the public domain.
5 This may be used for any purposes whatsoever without acknowledgment.
6 Thanks for the assistance and support of Sun Microsystems Labs,
7 and everyone contributing, testing, and using this code.
8
9 History:
10 Date Who What
11 11Jun1998 dl Create public version
12 */
13
14 package EDU.oswego.cs.dl.util.concurrent;
15
16 /**
17 * A simple non-reentrant mutual exclusion lock.
18 * The lock is free upon construction. Each acquire gets the
19 * lock, and each release frees it. Releasing a lock that
20 * is already free has no effect.
21 * <p>
22 * This implementation makes no attempt to provide any fairness
23 * or ordering guarantees. If you need them, consider using one of
24 * the Semaphore implementations as a locking mechanism.
25 * <p>
26 * <b>Sample usage</b><br>
27 * <p>
28 * Mutex can be useful in constructions that cannot be
29 * expressed using java synchronized blocks because the
30 * acquire/release pairs do not occur in the same method or
31 * code block. For example, you can use them for hand-over-hand
32 * locking across the nodes of a linked list. This allows
33 * extremely fine-grained locking, and so increases
34 * potential concurrency, at the cost of additional complexity and
35 * overhead that would normally make this worthwhile only in cases of
36 * extreme contention.
37 * <pre>
38 * class Node {
39 * Object item;
40 * Node next;
41 * Mutex lock = new Mutex(); // each node keeps its own lock
42 *
43 * Node(Object x, Node n) { item = x; next = n; }
44 * }
45 *
46 * class List {
47 * protected Node head; // pointer to first node of list
48 *
49 * // Use plain java synchronization to protect head field.
50 * // (We could instead use a Mutex here too but there is no
51 * // reason to do so.)
52 * protected synchronized Node getHead() { return head; }
53 *
54 * boolean search(Object x) throws InterruptedException {
55 * Node p = getHead();
56 * if (p == null) return false;
57 *
58 * // (This could be made more compact, but for clarity of illustration,
59 * // all of the cases that can arise are handled separately.)
60 *
61 * p.lock.acquire(); // Prime loop by acquiring first lock.
62 * // (If the acquire fails due to
63 * // interrupt, the method will throw
64 * // InterruptedException now,
65 * // so there is no need for any
66 * // further cleanup.)
67 * for (;;) {
68 * if (x.equals(p.item)) {
69 * p.lock.release(); // release current before return
70 * return true;
71 * }
72 * else {
73 * Node nextp = p.next;
74 * if (nextp == null) {
75 * p.lock.release(); // release final lock that was held
76 * return false;
77 * }
78 * else {
79 * try {
80 * nextp.lock.acquire(); // get next lock before releasing current
81 * }
82 * catch (InterruptedException ex) {
83 * p.lock.release(); // also release current if acquire fails
84 * throw ex;
85 * }
86 * p.lock.release(); // release old lock now that new one held
87 * p = nextp;
88 * }
89 * }
90 * }
91 * }
92 *
93 * synchronized void add(Object x) { // simple prepend
94 * // The use of `synchronized' here protects only head field.
95 * // The method does not need to wait out other traversers
96 * // who have already made it past head.
97 *
98 * head = new Node(x, head);
99 * }
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()) throw new InterruptedException();
116 synchronized(this) {
117 try {
118 while (inuse_) wait();
119 inuse_ = true;
120 }
121 catch (InterruptedException ex) {
122 notify();
123 throw ex;
124 }
125 }
126 }
127
128 public synchronized void release() {
129 inuse_ = false;
130 notify();
131 }
132
133
134 public boolean attempt(long msecs) throws InterruptedException {
135 if (Thread.interrupted()) throw new InterruptedException();
136 synchronized(this) {
137 if (!inuse_) {
138 inuse_ = true;
139 return true;
140 }
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 }
153 else {
154 waitTime = msecs - (System.currentTimeMillis() - start);
155 if (waitTime <= 0)
156 return false;
157 }
158 }
159 }
160 catch (InterruptedException ex) {
161 notify();
162 throw ex;
163 }
164 }
165 }
166 }
167
168 }
169