2 *******************************************************************************
3 * Copyright (C) 2001-2013, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 *******************************************************************************
7 package com.ibm.icu.impl;
9 import java.util.concurrent.locks.ReentrantReadWriteLock;
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)
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>
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>
27 * // use service protected by the lock
34 * <p>The lock provides utility methods getStats and clearStats
35 * to return statistics on the use of the lock.</p>
37 public class ICURWLock {
38 private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
40 private Stats stats = null;
43 * Internal class used to gather statistics on the RWLock.
45 public final static class Stats {
47 * Number of times read access granted (read count).
52 * Number of times concurrent read access granted (multiple read count).
57 * Number of times blocked for read (waiting reader count).
59 public int _wrc; // wait for read
62 * Number of times write access granted (writer count).
67 * Number of times blocked for write (waiting writer count).
74 private Stats(int rc, int mrc, int wrc, int wc, int wwc) {
82 private Stats(Stats rhs) {
83 this(rhs._rc, rhs._mrc, rhs._wrc, rhs._wc, rhs._wwc);
87 * Return a string listing all the stats.
89 public String toString() {
90 return " rc: " + _rc +
99 * Reset the stats. Returns existing stats, if any.
101 public synchronized Stats resetStats() {
102 Stats result = stats;
108 * Clear the stats (stop collecting stats). Returns existing stats, if any.
110 public synchronized Stats clearStats() {
111 Stats result = stats;
117 * Return a snapshot of the current stats. This does not reset the stats.
119 public synchronized Stats getStats() {
120 return stats == null ? null : new Stats(stats);
124 * <p>Acquire a read lock, blocking until a read lock is
125 * available. Multiple readers can concurrently hold the read
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>
133 public void acquireRead() {
134 if (stats != null) { // stats is null by default
135 synchronized (this) {
137 if (rwl.getReadLockCount() > 0) {
140 if (rwl.isWriteLocked()) {
145 rwl.readLock().lock();
149 * <p>Release a read lock and return. An error will be thrown
150 * if a read lock is not currently held.</p>
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>
156 public void releaseRead() {
157 rwl.readLock().unlock();
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>
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
171 public void acquireWrite() {
172 if (stats != null) { // stats is null by default
173 synchronized (this) {
175 if (rwl.getReadLockCount() > 0 || rwl.isWriteLocked()) {
180 rwl.writeLock().lock();
184 * <p>Release the write lock and return. An error will be thrown
185 * if the write lock is not currently held.</p>
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
192 public void releaseWrite() {
193 rwl.writeLock().unlock();