KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > ibm > icu > impl > ICURWLock


1 /**
2  *******************************************************************************
3  * Copyright (C) 2001-2006, International Business Machines Corporation and *
4  * others. All Rights Reserved. *
5  *******************************************************************************
6  */

7 package com.ibm.icu.impl;
8
9 // See Allan Holub's 1999 column in JavaWorld, and Doug Lea's code for RWLocks with writer preference.
10

11
12 /**
13  * <p>A simple Reader/Writer lock. This assumes that there will
14  * be little writing contention. It also doesn't allow
15  * active readers to acquire and release a write lock, or
16  * deal with priority inversion issues.</p>
17  *
18  * <p>Access to the lock should be enclosed in a try/finally block
19  * in order to ensure that the lock is always released in case of
20  * exceptions:<br><pre>
21  * try {
22  * lock.acquireRead();
23  * // use service protected by the lock
24  * }
25  * finally {
26  * lock.releaseRead();
27  * }
28  * </pre></p>
29  *
30  * <p>The lock provides utility methods getStats and clearStats
31  * to return statistics on the use of the lock.</p>
32  */

33 public class ICURWLock {
34     private Object JavaDoc writeLock = new Object JavaDoc();
35     private Object JavaDoc readLock = new Object JavaDoc();
36     private int wwc; // waiting writers
37
private int rc; // active readers, -1 if there's an active writer
38
private int wrc; // waiting readers
39

40     private Stats stats = new Stats(); // maybe don't init to start...
41

42     /**
43      * Internal class used to gather statistics on the RWLock.
44      */

45     public final static class Stats {
46         /**
47          * Number of times read access granted (read count).
48          */

49         public int _rc;
50
51         /**
52          * Number of times concurrent read access granted (multiple read count).
53          */

54         public int _mrc;
55
56         /**
57          * Number of times blocked for read (waiting reader count).
58          */

59         public int _wrc; // wait for read
60

61         /**
62          * Number of times write access granted (writer count).
63          */

64         public int _wc;
65
66         /**
67          * Number of times blocked for write (waiting writer count).
68          */

69         public int _wwc;
70
71         private Stats() {
72         }
73
74         private Stats(int rc, int mrc, int wrc, int wc, int wwc) {
75             this._rc = rc;
76             this._mrc = mrc;
77             this._wrc = wrc;
78             this._wc = wc;
79             this._wwc = wwc;
80         }
81
82         private Stats(Stats rhs) {
83             this(rhs._rc, rhs._mrc, rhs._wrc, rhs._wc, rhs._wwc);
84         }
85
86         /**
87          * Return a string listing all the stats.
88          */

89         public String JavaDoc toString() {
90             return " rc: " + _rc +
91                 " mrc: " + _mrc +
92                 " wrc: " + _wrc +
93                 " wc: " + _wc +
94                 " wwc: " + _wwc;
95         }
96     }
97
98     /**
99      * Reset the stats. Returns existing stats, if any.
100      */

101     public synchronized Stats resetStats() {
102         Stats result = stats;
103         stats = new Stats();
104         return result;
105     }
106
107     /**
108      * Clear the stats (stop collecting stats). Returns existing stats, if any.
109      */

110     public synchronized Stats clearStats() {
111         Stats result = stats;
112         stats = null;
113         return result;
114     }
115     
116     /**
117      * Return a snapshot of the current stats. This does not reset the stats.
118      */

119     public synchronized Stats getStats() {
120         return stats == null ? null : new Stats(stats);
121     }
122
123     // utilities
124

125     private synchronized boolean gotRead() {
126         ++rc;
127         if (stats != null) {
128             ++stats._rc;
129             if (rc > 1) ++stats._mrc;
130         }
131         return true;
132     }
133
134     private synchronized boolean getRead() {
135         if (rc >= 0 && wwc == 0) {
136             return gotRead();
137         }
138         ++wrc;
139         return false;
140     }
141
142     private synchronized boolean retryRead() {
143         if (stats != null) ++stats._wrc;
144         if (rc >= 0 && wwc == 0) {
145             --wrc;
146             return gotRead();
147         }
148         return false;
149     }
150
151     private synchronized boolean finishRead() {
152         if (rc > 0) {
153             return (0 == --rc && wwc > 0);
154         }
155         throw new IllegalStateException JavaDoc("no current reader to release");
156     }
157     
158     private synchronized boolean gotWrite() {
159         rc = -1;
160         if (stats != null) {
161             ++stats._wc;
162         }
163         return true;
164     }
165
166     private synchronized boolean getWrite() {
167         if (rc == 0) {
168             return gotWrite();
169         }
170         ++wwc;
171         return false;
172     }
173
174     private synchronized boolean retryWrite() {
175         if (stats != null) ++stats._wwc;
176         if (rc == 0) {
177             --wwc;
178             return gotWrite();
179         }
180         return false;
181     }
182
183     private static final int NOTIFY_NONE = 0;
184     private static final int NOTIFY_WRITERS = 1;
185     private static final int NOTIFY_READERS = 2;
186
187     private synchronized int finishWrite() {
188         if (rc < 0) {
189             rc = 0;
190             if (wwc > 0) {
191                 return NOTIFY_WRITERS;
192             } else if (wrc > 0) {
193                 return NOTIFY_READERS;
194             } else {
195                 return NOTIFY_NONE;
196             }
197         }
198         throw new IllegalStateException JavaDoc("no current writer to release");
199     }
200     
201     /**
202      * <p>Acquire a read lock, blocking until a read lock is
203      * available. Multiple readers can concurrently hold the read
204      * lock.</p>
205      *
206      * <p>If there's a writer, or a waiting writer, increment the
207      * waiting reader count and block on this. Otherwise
208      * increment the active reader count and return. Caller must call
209      * releaseRead when done (for example, in a finally block).</p>
210      */

211     public void acquireRead() {
212         if (!getRead()) {
213             for (;;) {
214                 try {
215                     synchronized (readLock) {
216                         readLock.wait();
217                     }
218                     if (retryRead()) {
219                         return;
220                     }
221                 }
222                 catch (InterruptedException JavaDoc e) {
223                 }
224             }
225         }
226     }
227
228     /**
229      * <p>Release a read lock and return. An error will be thrown
230      * if a read lock is not currently held.</p>
231      *
232      * <p>If this is the last active reader, notify the oldest
233      * waiting writer. Call when finished with work
234      * controlled by acquireRead.</p>
235      */

236     public void releaseRead() {
237         if (finishRead()) {
238             synchronized (writeLock) {
239                 writeLock.notify();
240             }
241         }
242     }
243
244     /**
245      * <p>Acquire the write lock, blocking until the write lock is
246      * available. Only one writer can acquire the write lock, and
247      * when held, no readers can acquire the read lock.</p>
248      *
249      * <p>If there are no readers and no waiting writers, mark as
250      * having an active writer and return. Otherwise, add a lock to the
251      * end of the waiting writer list, and block on it. Caller
252      * must call releaseWrite when done (for example, in a finally
253      * block).<p>
254      */

255     public void acquireWrite() {
256         if (!getWrite()) {
257             for (;;) {
258                 try {
259                     synchronized (writeLock) {
260                         writeLock.wait();
261                     }
262                     if (retryWrite()) {
263                         return;
264                     }
265                 }
266                 catch (InterruptedException JavaDoc e) {
267                 }
268             }
269         }
270     }
271
272     /**
273      * <p>Release the write lock and return. An error will be thrown
274      * if the write lock is not currently held.</p>
275      *
276      * <p>If there are waiting readers, make them all active and
277      * notify all of them. Otherwise, notify the oldest waiting
278      * writer, if any. Call when finished with work controlled by
279      * acquireWrite.</p>
280      */

281     public void releaseWrite() {
282         switch (finishWrite()) {
283         case NOTIFY_WRITERS:
284             synchronized (writeLock) {
285                 writeLock.notify();
286             }
287             break;
288         case NOTIFY_READERS:
289             synchronized (readLock) {
290                 readLock.notifyAll();
291             }
292             break;
293         case NOTIFY_NONE:
294             break;
295         }
296     }
297 }
298
Popular Tags