2 * Copyright 2005 the original author or authors.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org.wamblee.concurrency;
18 import junit.framework.Assert;
19 import junit.framework.TestCase;
23 * Testing the read-write lock class. Note: in case of problems, test cases
28 public class ReadWriteLockTest extends TestCase {
29 private ReadWriteLock _lock;
34 * Constructor for ReadWriteLockTest.
38 public ReadWriteLockTest(String aName) {
42 private synchronized int getReaderCount() {
46 private synchronized int getWriterCount() {
50 synchronized void incrementReaderCount() {
54 synchronized void incrementWriterCount() {
58 synchronized void decrementReaderCount() {
62 synchronized void decrementWriterCount() {
67 * @see TestCase#setUp()
69 protected void setUp() throws Exception {
71 _lock = new ReadWriteLock();
75 * @see TestCase#tearDown()
77 protected void tearDown() throws Exception {
83 * Acquire and release a read lock.
85 public void testRead() {
91 * Acquire and release a write lock.
93 public void testWrite() {
99 * Verify concurrent access by multiple readers is possible.
101 * @throws InterruptedException May not occur.
103 public void testMultipleReaders() throws InterruptedException {
104 Runnable runnable = new ReadLocker(_lock, this, 2000);
106 Thread t1 = new Thread(runnable);
109 Thread t2 = new Thread(runnable);
112 assertTrue("Not enough readers!", getReaderCount() == 2);
118 * Verify that only one writer at a time can acquire the write lock.
120 * @throws InterruptedException May not occur.
122 public void testSingleWriter() throws InterruptedException {
123 WriteLocker writer = new WriteLocker(_lock, this, 1000);
124 Thread t1 = new Thread(writer);
125 Thread t2 = new Thread(writer);
130 assertTrue("Wrong writer count: " + getWriterCount(),
131 getWriterCount() == 1);
137 * Verify that multiple writers cannot acquire the write lock concurrently.
139 * @throws InterruptedException May not occur.
141 public void testMultipleWriters() throws InterruptedException {
142 WriteLocker writer1 = new WriteLocker(_lock, this, 1500);
143 WriteLocker writer2 = new WriteLocker(_lock, this, 1000);
144 Thread t1 = new Thread(writer1);
145 Thread t2 = new Thread(writer2);
149 assertTrue(getWriterCount() == 1);
152 assertTrue(getWriterCount() == 1); // first writer still
157 // at t = 2, the second writer still must have
159 assertTrue(getWriterCount() == 1);
165 * Verify that after the first reader acquires a lock, a subsequent writer
166 * can only acquire the lock after the reader has released it.
168 * @throws InterruptedException May not occur.
170 public void testReadWrite1() throws InterruptedException {
171 ReadLocker readLocker = new ReadLocker(_lock, this, 2000);
172 Thread t1 = new Thread(readLocker);
173 WriteLocker writeLocker = new WriteLocker(_lock, this, 2000);
174 Thread t2 = new Thread(writeLocker);
176 t1.start(); // acquire read lock
178 assertTrue(getReaderCount() == 1);
182 // 1 second underway, reader still holding the
183 // lock so write lock cannot be acquired.
184 assertTrue(getReaderCount() == 1);
185 assertTrue(getWriterCount() == 0);
188 // 2.5 seconds underway, read lock released and
189 // write lock must be acquired.
190 assertTrue("Wrong no. of readers: " + getReaderCount(),
191 getReaderCount() == 0);
192 assertTrue(getWriterCount() == 1);
198 * Verify that when multiple readers have acquired a read lock, the writer
199 * can only acquire the lock after all readers have released it.
201 * @throws InterruptedException May not occur.
203 public void testReadWrite2() throws InterruptedException {
204 ReadLocker readLocker1 = new ReadLocker(_lock, this, 2500);
205 ReadLocker readLocker2 = new ReadLocker(_lock, this, 2500);
206 Thread t1 = new Thread(readLocker1);
207 Thread t2 = new Thread(readLocker2);
208 WriteLocker writeLocker = new WriteLocker(_lock, this, 2000);
209 Thread t3 = new Thread(writeLocker);
211 t1.start(); // acquire read lock
213 assertTrue(getReaderCount() == 1);
216 assertTrue(getReaderCount() == 2);
221 assertTrue(getReaderCount() == 2);
222 assertTrue(getWriterCount() == 0);
225 // 3 seconds underway, first read lock must
226 // have been released.
227 assertTrue(getReaderCount() == 1);
228 assertTrue(getWriterCount() == 0);
231 // 4 seconds underway, write lock must have
233 assertTrue(getReaderCount() == 0);
234 assertTrue(getWriterCount() == 1);
242 * Verify that after a writer acquires a lock, a subsequent reader can
243 * only acquire the lock after the writer has released it.
245 * @throws InterruptedException May not occur.
247 public void testReadWrite3() throws InterruptedException {
248 ReadLocker readLocker = new ReadLocker(_lock, this, 2000);
249 Thread t1 = new Thread(readLocker);
250 WriteLocker writeLocker = new WriteLocker(_lock, this, 2000);
251 Thread t2 = new Thread(writeLocker);
253 t2.start(); // acquire write lock
255 assertTrue(getWriterCount() == 1);
259 // 1 second underway, writer still holding the
260 // lock so read lock cannot be acquired.
261 assertTrue(getWriterCount() == 1);
262 assertTrue(getReaderCount() == 0);
265 // 2.5 seconds underway, write lock released and
266 // read lock must be acquired.
267 assertTrue("Wrong no. of writers: " + getReaderCount(),
268 getWriterCount() == 0);
269 assertTrue(getReaderCount() == 1);
275 * The following test cases are for testing whether or not
276 * the read write lock checks the locking correctly.
277 * Strictly speaking, these checks wouldn't be necessary
278 * because it involves the contract of the ReadWriteLock which
279 * must be obeyed by users of the ReadWriteLock. Nevertheless,
280 * this is tested anyway to be absolutely sure.
284 * Acquire a read lock from one thread, release it from another. Verify
285 * that a RuntimeException is thrown.
287 * @throws InterruptedException May not occur.
289 public void testReleaseReadFromWrongThread() throws InterruptedException {
293 t1 = new Thread(new Runnable() {
295 ReadWriteLockTest.this._lock.acquireRead();
299 Thread.sleep(1000); // wait until thread is started
300 _lock.releaseRead(); // release lock from wrong thread.
301 } catch (RuntimeException e) {
311 * Acquire a write lock from one thread, release it from another. Verify
312 * that a RuntimeException is thrown.
314 * @throws InterruptedException May not occur.
316 public void testReleaseWriteFromWrongThread() throws InterruptedException {
320 t1 = new Thread(new Runnable() {
322 ReadWriteLockTest.this._lock.acquireWrite();
326 Thread.sleep(1000); // wait until thread is started
327 _lock.releaseWrite(); // release lock from wrong thread.
328 } catch (RuntimeException e) {
338 * Try to acquire a read lock multiple times. Verify that a
339 * RuntimeException is thrown.
341 public void testAcquireReadTwice() {
345 } catch (RuntimeException e) {
354 * Try to acquire a write lock multiple times. Verify that a
355 * RuntimeException is thrown.
357 public void testAcquireWriteTwice() {
359 _lock.acquireWrite();
360 _lock.acquireWrite();
361 } catch (RuntimeException e) {
369 * Acquire the lock for reading and directly afterwards acquire it for
370 * writing. Verify that a RuntimeException is thrown.
372 public void testAcquireReadFollowedByWrite() {
375 _lock.acquireWrite();
376 } catch (RuntimeException e) {
384 * Acquire the lock for writing and directly afterwards acquire it for
385 * reading. Verify that a RuntimeException is thrown.
387 public void testAcquireWriteFollowedByRead() {
389 _lock.acquireWrite();
391 } catch (RuntimeException e) {
399 * Acquire a read lock and release it as a write lock. Verify that a
400 * RuntimeException is thrown.
402 public void testAcquireReadFollowedByReleaseaWrite() {
405 _lock.releaseWrite();
406 } catch (RuntimeException e) {
414 * Acquire a write lock and release it as a read lock. Verify that a
415 * RuntimeException is thrown.
417 public void testAcquireWriteFollowedByReleaseRead() {
419 _lock.acquireWrite();
421 } catch (RuntimeException e) {
431 * ReadLocker acquires a read lock and performs a callback when the lock as
432 * been acquired, sleeps for a designated amount of time, releases the read
433 * lock, and performs a callback after the lock has been released.
435 class ReadLocker implements Runnable {
437 ReadWriteLockTest _lockTest;
440 public ReadLocker(ReadWriteLock lock, ReadWriteLockTest lockTest,
443 _lockTest = lockTest;
444 _sleepTime = sleepTime;
449 _lockTest.incrementReaderCount();
452 Thread.sleep(_sleepTime);
453 } catch (InterruptedException e) {
454 Assert.fail("ReadLocker thread was interrupted."
455 + Thread.currentThread());
459 _lockTest.decrementReaderCount();
465 * WriteLocker acquires a write lock and performs a callback when the lock as
466 * been acquired, sleeps for a designated amount of time, releases the write
467 * lock, and performs a callback after the lock has been released.
469 class WriteLocker implements Runnable {
471 ReadWriteLockTest _lockTest;
474 public WriteLocker(ReadWriteLock lock, ReadWriteLockTest lockTest,
477 _lockTest = lockTest;
478 _sleepTime = sleepTime;
482 _lock.acquireWrite();
483 _lockTest.incrementWriterCount();
486 Thread.sleep(_sleepTime);
487 } catch (InterruptedException e) {
488 Assert.fail("WriteLocker thread was interrupted: "
489 + Thread.currentThread());
492 _lock.releaseWrite();
493 _lockTest.decrementWriterCount();