KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > de > schlichtherle > io > ReentrantReadWriteLock


1 /*
2  * ReentrantReadWriteLock.java
3  *
4  * Created on 25. Juli 2006, 13:39
5  */

6 /*
7  * Copyright 2006 Schlichtherle IT Services
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */

21
22 package de.schlichtherle.io;
23
24 import de.schlichtherle.util.ThreadLocalCounter;
25
26 import java.util.logging.Level JavaDoc;
27 import java.util.logging.Logger JavaDoc;
28
29 /**
30  * Similar to <code>java.util.concurrent.locks.ReentrantReadWriteLock</code>
31  * with the following differences:
32  * <ul>
33  * <li>This class requires J2SE 1.4 only.
34  * <li>This class performs better than its overengineered colleague in JSE 1.5.
35  * <li>This class provides locks which provide a different set of methods
36  * (with the same functionality in the common subset) in order to suit
37  * the particular needs of TrueZIP (see {@link ReentrantLock}).
38  * </ul>
39  * <p>
40  * <b>Note:</b> In accordance with JSE 1.5, upgrading a read lock to a write
41  * lock is not possible. Any attempt to do so will lock the current thread.
42  * This is a constraint which can't be fixed properly: If this constraint
43  * would not exist, two reader threads could try to upgrade from a read lock
44  * to a write lock concurrently, effectively dead locking them.
45  * By locking this thread immediately on any attempt to do so, this is
46  * considered to be a programming error which can be easily fixed without
47  * affecting any other thread.
48  * <p>
49  * On the other hand, it is possible to downgrade from a write lock to a
50  * read lock. Please consult the JSE 1.5 Javadoc of the class
51  * <code>java.util.concurrent.locks.ReentrantReadWriteLock</code>
52  * for more information.
53  *
54  * @author Christian Schlichtherle
55  * @version @version@
56  * @since TrueZIP 6.2
57  */

58 final class ReentrantReadWriteLock implements ReadWriteLock {
59
60     private static final String JavaDoc CLASS_NAME
61             = "de/schlichtherle/io/ReentrantReadWriteLock".replace('/', '.'); // beware of code obfuscation!
62
private static final Logger JavaDoc logger
63             = Logger.getLogger(CLASS_NAME, CLASS_NAME);
64
65     private final ReadLock readLock = new ReadLock();
66     private final WriteLock writeLock = new WriteLock();
67
68     private int totalWriteLockCount;
69     private int totalReadLockCount;
70
71     //
72
// Methods.
73
//
74

75     /**
76      * Returns the lock for reading.
77      * Like its cousin in JSE 1.5, the returned lock does <em>not</em>
78      * support upgrading to a write lock.
79      */

80     public ReentrantLock readLock() {
81         return readLock;
82     }
83
84     /**
85      * Returns the lock for writing.
86      * Like its cousin in JSE 1.5, the returned lock <em>does</em>
87      * support downgrading to a read lock.
88      */

89     public ReentrantLock writeLock() {
90         return writeLock;
91     }
92
93     private synchronized void lockRead() {
94         // The code repetetition in these methods isn't elegant, but it's
95
// faster than the use of the strategy pattern and performance is
96
// critical in this class.
97
final int threadWriteLockCount = writeLock.lockCount();
98         if (threadWriteLockCount <= 0) { // If I'm not the writer...
99
// ... wait until no other writer has acquired a lock.
100
while (totalWriteLockCount - threadWriteLockCount > 0) {
101                 try {
102                     wait();
103                 } catch (InterruptedException JavaDoc ex) {
104                     logger.log(Level.FINE, "interrupted", ex);
105                     logger.log(Level.FINE, "continuing");
106                 }
107             }
108         }
109         totalReadLockCount++;
110     }
111
112     private synchronized void lockReadInterruptibly()
113     throws InterruptedException JavaDoc {
114         // The code repetetition in these methods isn't elegant, but it's
115
// faster than the use of the strategy pattern and performance is
116
// critical in this class.
117
final int threadWriteLockCount = writeLock.lockCount();
118         if (threadWriteLockCount <= 0) { // If I'm not the writer...
119
// ... wait until no other writer has acquired a lock.
120
while (totalWriteLockCount - threadWriteLockCount > 0) {
121                 wait();
122             }
123         }
124         totalReadLockCount++;
125     }
126
127     private synchronized boolean tryLockRead() {
128         // The code repetetition in these methods isn't elegant, but it's
129
// faster than the use of the strategy pattern and performance is
130
// critical in this class.
131
final int threadWriteLockCount = writeLock.lockCount();
132         if (threadWriteLockCount <= 0) { // If I'm not the writer...
133
// ... assert that no other writer has acquired a lock.
134
if (totalWriteLockCount - threadWriteLockCount > 0) {
135                 return false;
136             }
137         }
138         totalReadLockCount++;
139         return true;
140     }
141
142     private synchronized void unlockRead() {
143         totalReadLockCount--;
144         notifyAll();
145     }
146
147     private synchronized void lockWrite() {
148         // The code repetetition in these methods isn't elegant, but it's
149
// faster than the use of the strategy pattern and performance is
150
// critical in this class.
151
final int threadWriteLockCount = writeLock.lockCount();
152         if (threadWriteLockCount <= 0) { // If I'm not the writer...
153
// ... wait until no other writer and no readers have acquired a lock.
154
// Commented out to mimic behaviour of JSE 1.5!
155
//final int threadReadLockCount = readLock.lockCount();
156
while (totalReadLockCount /*- threadReadLockCount*/ > 0
157                     || totalWriteLockCount - threadWriteLockCount > 0) {
158                 try {
159                     wait();
160                 } catch (InterruptedException JavaDoc ex) {
161                     logger.log(Level.FINE, "interrupted", ex);
162                     logger.log(Level.FINE, "continuing");
163                 }
164             }
165         }
166         totalWriteLockCount++;
167     }
168
169     private synchronized void lockWriteInterruptibly()
170     throws InterruptedException JavaDoc {
171         // The code repetetition in these methods isn't elegant, but it's
172
// faster than the use of the strategy pattern and performance is
173
// critical in this class.
174
final int threadWriteLockCount = writeLock.lockCount();
175         if (threadWriteLockCount <= 0) { // If I'm not the writer...
176
// ... wait until no other writer and no readers have acquired a lock.
177
// Commented out to mimic behaviour of JSE 1.5!
178
//final int threadReadLockCount = readLock.lockCount();
179
while (totalReadLockCount /*- threadReadLockCount*/ > 0
180                     || totalWriteLockCount - threadWriteLockCount > 0) {
181                 wait();
182             }
183         }
184         totalWriteLockCount++;
185     }
186
187     private synchronized boolean tryLockWrite() {
188         // The code repetetition in these methods isn't elegant, but it's
189
// faster than the use of the strategy pattern and performance is
190
// critical in this class.
191
final int threadWriteLockCount = writeLock.lockCount();
192         if (threadWriteLockCount <= 0) { // If I'm not the writer...
193
// ... wait until no other writer and no readers have acquired a lock.
194
// Commented out to mimic behaviour of JSE 1.5!
195
//final int threadReadLockCount = readLock.lockCount();
196
if (totalReadLockCount /*- threadReadLockCount*/ > 0
197                     || totalWriteLockCount - threadWriteLockCount > 0) {
198                 return false;
199             }
200         }
201         totalWriteLockCount++;
202         return true;
203     }
204
205     private synchronized void unlockWrite() {
206         totalWriteLockCount--;
207         notifyAll();
208     }
209
210     //
211
// Inner classes.
212
//
213

214     private static abstract class AbstractLock
215             extends ThreadLocalCounter
216             implements ReentrantLock {
217
218         public final boolean isLocked() {
219             return getCounter() > 0;
220         }
221
222         public final int lockCount() {
223             return getCounter();
224         }
225
226         public void lock() {
227             increment();
228         }
229
230         public void unlock() {
231             int lockCount = getCounter();
232             if (lockCount <= 0)
233                 throw new IllegalMonitorStateException JavaDoc();
234             setCounter(lockCount - 1);
235         }
236     }
237
238     private class ReadLock extends AbstractLock {
239         public void lock() {
240             lockRead();
241             super.lock();
242         }
243
244         public void lockInterruptibly() throws InterruptedException JavaDoc {
245             lockReadInterruptibly();
246             super.lock();
247         }
248
249         public boolean tryLock() {
250             boolean locked = tryLockRead();
251             if (locked)
252                 super.lock();
253             return locked;
254         }
255
256         public void unlock() {
257             super.unlock();
258             unlockRead();
259         }
260     }
261
262     private class WriteLock extends AbstractLock {
263         public void lock() {
264             lockWrite();
265             super.lock();
266         }
267
268         public void lockInterruptibly() throws InterruptedException JavaDoc {
269             lockWriteInterruptibly();
270             super.lock();
271         }
272
273         public boolean tryLock() {
274             boolean locked = tryLockWrite();
275             if (locked)
276                 super.lock();
277             return locked;
278         }
279
280         public void unlock() {
281             super.unlock();
282             unlockWrite();
283         }
284     }
285 }
286
Popular Tags