]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-52_1/main/classes/core/src/com/ibm/icu/impl/ICURWLock.java
Clean up imports.
[Dictionary.git] / jars / icu4j-52_1 / main / classes / core / src / com / ibm / icu / impl / ICURWLock.java
1 /**
2  *******************************************************************************
3  * Copyright (C) 2001-2013, International Business Machines Corporation and    *
4  * others. All Rights Reserved.                                                *
5  *******************************************************************************
6  */
7 package com.ibm.icu.impl;
8
9 import java.util.concurrent.locks.ReentrantReadWriteLock;
10
11
12 /**
13  * <p>A Reader/Writer lock originally written for ICU service
14  * implementation. The internal implementation was replaced
15  * with the JDK's stock read write lock (ReentrantReadWriteLock)
16  * for ICU 52.</p>
17  *
18  * <p>This assumes that there will be little writing contention.
19  * It also doesn't allow active readers to acquire and release
20  * a write lock, or deal with priority inversion issues.</p>
21  *
22  * <p>Access to the lock should be enclosed in a try/finally block
23  * in order to ensure that the lock is always released in case of
24  * exceptions:<br><pre>
25  * try {
26  *     lock.acquireRead();
27  *     // use service protected by the lock
28  * }
29  * finally {
30  *     lock.releaseRead();
31  * }
32  * </pre></p>
33  *
34  * <p>The lock provides utility methods getStats and clearStats
35  * to return statistics on the use of the lock.</p>
36  */
37 public class ICURWLock {
38     private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
39
40     private Stats stats = null;
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 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     /**
124      * <p>Acquire a read lock, blocking until a read lock is
125      * available.  Multiple readers can concurrently hold the read
126      * lock.</p>
127      *
128      * <p>If there's a writer, or a waiting writer, increment the
129      * waiting reader count and block on this.  Otherwise
130      * increment the active reader count and return.  Caller must call
131      * releaseRead when done (for example, in a finally block).</p> 
132      */
133     public void acquireRead() {
134         if (stats != null) {    // stats is null by default
135             synchronized (this) {
136                 stats._rc++;
137                 if (rwl.getReadLockCount() > 0) {
138                     stats._mrc++;
139                 }
140                 if (rwl.isWriteLocked()) {
141                     stats._wrc++;
142                 }
143             }
144         }
145         rwl.readLock().lock();
146     }
147
148     /**
149      * <p>Release a read lock and return.  An error will be thrown
150      * if a read lock is not currently held.</p>
151      *
152      * <p>If this is the last active reader, notify the oldest
153      * waiting writer.  Call when finished with work
154      * controlled by acquireRead.</p>
155      */
156     public void releaseRead() {
157         rwl.readLock().unlock();
158     }
159
160     /**
161      * <p>Acquire the write lock, blocking until the write lock is
162      * available.  Only one writer can acquire the write lock, and
163      * when held, no readers can acquire the read lock.</p>
164      *
165      * <p>If there are no readers and no waiting writers, mark as
166      * having an active writer and return.  Otherwise, add a lock to the
167      * end of the waiting writer list, and block on it.  Caller
168      * must call releaseWrite when done (for example, in a finally
169      * block).<p> 
170      */
171     public void acquireWrite() {
172         if (stats != null) {    // stats is null by default
173             synchronized (this) {
174                 stats._wc++;
175                 if (rwl.getReadLockCount() > 0 || rwl.isWriteLocked()) {
176                     stats._wwc++;
177                 }
178             }
179         }
180         rwl.writeLock().lock();
181     }
182
183     /**
184      * <p>Release the write lock and return.  An error will be thrown
185      * if the write lock is not currently held.</p>
186      *
187      * <p>If there are waiting readers, make them all active and
188      * notify all of them.  Otherwise, notify the oldest waiting
189      * writer, if any.  Call when finished with work controlled by
190      * acquireWrite.</p> 
191      */
192     public void releaseWrite() {
193         rwl.writeLock().unlock();
194     }
195 }