KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > corba > se > impl > orbutil > concurrent > ReentrantMutex


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 com.sun.corba.se.impl.orbutil.concurrent;
15
16 import com.sun.corba.se.impl.orbutil.ORBUtility ;
17
18 /**
19  * A simple reentrant mutual exclusion lock.
20  * The lock is free upon construction. Each acquire gets the
21  * lock, and each release frees it. Releasing a lock that
22  * is already free has no effect.
23  * <p>
24  * This implementation makes no attempt to provide any fairness
25  * or ordering guarantees. If you need them, consider using one of
26  * the Semaphore implementations as a locking mechanism.
27  * <p>
28  * <b>Sample usage</b><br>
29  * <p>
30  * Mutex can be useful in constructions that cannot be
31  * expressed using java synchronized blocks because the
32  * acquire/release pairs do not occur in the same method or
33  * code block. For example, you can use them for hand-over-hand
34  * locking across the nodes of a linked list. This allows
35  * extremely fine-grained locking, and so increases
36  * potential concurrency, at the cost of additional complexity and
37  * overhead that would normally make this worthwhile only in cases of
38  * extreme contention.
39  * <pre>
40  * class Node {
41  * Object item;
42  * Node next;
43  * Mutex lock = new Mutex(); // each node keeps its own lock
44  *
45  * Node(Object x, Node n) { item = x; next = n; }
46  * }
47  *
48  * class List {
49  * protected Node head; // pointer to first node of list
50  *
51  * // Use plain java synchronization to protect head field.
52  * // (We could instead use a Mutex here too but there is no
53  * // reason to do so.)
54  * protected synchronized Node getHead() { return head; }
55  *
56  * boolean search(Object x) throws InterruptedException {
57  * Node p = getHead();
58  * if (p == null) return false;
59  *
60  * // (This could be made more compact, but for clarity of illustration,
61  * // all of the cases that can arise are handled separately.)
62  *
63  * p.lock.acquire(); // Prime loop by acquiring first lock.
64  * // (If the acquire fails due to
65  * // interrupt, the method will throw
66  * // InterruptedException now,
67  * // so there is no need for any
68  * // further cleanup.)
69  * for (;;) {
70  * if (x.equals(p.item)) {
71  * p.lock.release(); // release current before return
72  * return true;
73  * }
74  * else {
75  * Node nextp = p.next;
76  * if (nextp == null) {
77  * p.lock.release(); // release final lock that was held
78  * return false;
79  * }
80  * else {
81  * try {
82  * nextp.lock.acquire(); // get next lock before releasing current
83  * }
84  * catch (InterruptedException ex) {
85  * p.lock.release(); // also release current if acquire fails
86  * throw ex;
87  * }
88  * p.lock.release(); // release old lock now that new one held
89  * p = nextp;
90  * }
91  * }
92  * }
93  * }
94  *
95  * synchronized void add(Object x) { // simple prepend
96  * // The use of `synchronized' here protects only head field.
97  * // The method does not need to wait out other traversers
98  * // who have already made it past head.
99  *
100  * head = new Node(x, head);
101  * }
102  *
103  * // ... other similar traversal and update methods ...
104  * }
105  * </pre>
106  * <p>
107  * <p>This version adds some debugging capability: it will detect
108  * an attempt by a thread that does not hold the mutex to release it.
109  * This version is reentrant: the same thread may acquire a mutex multiple
110  * times, in which case it must release the mutex the same number of times
111  * as it was acquired before another thread can acquire the mutex.
112  * @see Semaphore
113  * <p>[<a HREF="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>]
114 **/

115
116 import org.omg.CORBA.INTERNAL JavaDoc ;
117
118 public class ReentrantMutex implements Sync {
119
120     /** The thread holding the lock **/
121     protected Thread JavaDoc holder_ = null;
122
123     /** number of times thread has acquired the lock **/
124     protected int counter_ = 0 ;
125
126     protected boolean debug = false ;
127
128     public ReentrantMutex()
129     {
130     this( false ) ;
131     }
132
133     public ReentrantMutex( boolean debug )
134     {
135     this.debug = debug ;
136     }
137
138     public void acquire() throws InterruptedException JavaDoc {
139     if (Thread.interrupted())
140         throw new InterruptedException JavaDoc();
141
142     synchronized(this) {
143         try {
144         if (debug)
145             ORBUtility.dprintTrace( this,
146             "acquire enter: holder_=" +
147             ORBUtility.getThreadName(holder_) +
148             " counter_=" + counter_ ) ;
149
150         Thread JavaDoc thr = Thread.currentThread();
151         if (holder_ != thr) {
152             try {
153             while (counter_ > 0)
154                 wait();
155
156             // This can't happen, but make sure anyway
157
if (counter_ != 0)
158                 throw new INTERNAL JavaDoc(
159                 "counter not 0 when first acquiring mutex" ) ;
160             
161             holder_ = thr;
162             } catch (InterruptedException JavaDoc ex) {
163             notify();
164             throw ex;
165             }
166         }
167
168         counter_ ++ ;
169         } finally {
170         if (debug)
171             ORBUtility.dprintTrace( this, "acquire exit: holder_=" +
172             ORBUtility.getThreadName(holder_) + " counter_=" +
173             counter_ ) ;
174         }
175     }
176     }
177
178     void acquireAll( int count ) throws InterruptedException JavaDoc
179     {
180     if (Thread.interrupted())
181         throw new InterruptedException JavaDoc();
182
183     synchronized(this) {
184         try {
185         if (debug)
186             ORBUtility.dprintTrace( this,
187             "acquireAll enter: count=" + count + " holder_=" +
188             ORBUtility.getThreadName(holder_) + " counter_=" +
189             counter_ ) ;
190         Thread JavaDoc thr = Thread.currentThread();
191         if (holder_ == thr) {
192             throw new INTERNAL JavaDoc(
193             "Cannot acquireAll while holding the mutex" ) ;
194         } else {
195             try {
196             while (counter_ > 0)
197                 wait();
198
199             // This can't happen, but make sure anyway
200
if (counter_ != 0)
201                 throw new INTERNAL JavaDoc(
202                 "counter not 0 when first acquiring mutex" ) ;
203             
204             holder_ = thr;
205             } catch (InterruptedException JavaDoc ex) {
206             notify();
207             throw ex;
208             }
209         }
210
211         counter_ = count ;
212         } finally {
213         if (debug)
214             ORBUtility.dprintTrace( this, "acquireAll exit: count=" +
215             count + " holder_=" + ORBUtility.getThreadName(holder_) +
216             " counter_=" + counter_ ) ;
217         }
218     }
219     }
220
221     public synchronized void release()
222     {
223     try {
224         if (debug)
225         ORBUtility.dprintTrace( this, "release enter: " +
226             " holder_=" + ORBUtility.getThreadName(holder_) +
227             " counter_=" + counter_ ) ;
228
229         Thread JavaDoc thr = Thread.currentThread();
230         if (thr != holder_)
231         throw new INTERNAL JavaDoc(
232             "Attempt to release Mutex by thread not holding the Mutex" ) ;
233         else
234         counter_ -- ;
235
236         if (counter_ == 0) {
237         holder_ = null;
238         notify();
239         }
240     } finally {
241         if (debug)
242         ORBUtility.dprintTrace( this, "release exit: " +
243             " holder_=" + ORBUtility.getThreadName(holder_) +
244             " counter_=" + counter_ ) ;
245     }
246     }
247
248     synchronized int releaseAll()
249     {
250     try {
251         if (debug)
252         ORBUtility.dprintTrace( this, "releaseAll enter: " +
253             " holder_=" + ORBUtility.getThreadName(holder_) +
254             " counter_=" + counter_ ) ;
255
256         Thread JavaDoc thr = Thread.currentThread();
257         if (thr != holder_)
258         throw new INTERNAL JavaDoc(
259             "Attempt to releaseAll Mutex by thread not holding the Mutex" ) ;
260
261         int result = counter_ ;
262         counter_ = 0 ;
263         holder_ = null ;
264         notify() ;
265         return result ;
266     } finally {
267         if (debug)
268         ORBUtility.dprintTrace( this, "releaseAll exit: " +
269             " holder_=" + ORBUtility.getThreadName(holder_) +
270             " counter_=" + counter_ ) ;
271     }
272     }
273
274     public boolean attempt(long msecs) throws InterruptedException JavaDoc {
275     if (Thread.interrupted())
276         throw new InterruptedException JavaDoc();
277
278     synchronized(this) {
279         try {
280         if (debug)
281             ORBUtility.dprintTrace( this, "attempt enter: msecs=" +
282             msecs + " holder_=" +
283             ORBUtility.getThreadName(holder_) +
284             " counter_=" + counter_ ) ;
285
286         Thread JavaDoc thr = Thread.currentThread() ;
287
288         if (counter_==0) {
289             holder_ = thr;
290             counter_ = 1 ;
291             return true;
292         } else if (msecs <= 0) {
293             return false;
294         } else {
295             long waitTime = msecs;
296             long start = System.currentTimeMillis();
297             try {
298             for (;;) {
299                 wait(waitTime);
300                 if (counter_==0) {
301                 holder_ = thr;
302                 counter_ = 1 ;
303                 return true;
304                 } else {
305                 waitTime = msecs -
306                     (System.currentTimeMillis() - start);
307
308                 if (waitTime <= 0)
309                     return false;
310                 }
311             }
312             } catch (InterruptedException JavaDoc ex) {
313             notify();
314             throw ex;
315             }
316         }
317         } finally {
318         if (debug)
319             ORBUtility.dprintTrace( this, "attempt exit: " +
320             " holder_=" + ORBUtility.getThreadName(holder_) +
321             " counter_=" + counter_ ) ;
322         }
323     }
324     }
325 }
326
327
Popular Tags