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 {
32 private static final int HALF_SECOND = 500;
37 private static final int ONE_SECOND = 1000;
42 private static final int TWO_SECONDS = 2000;
43 private ReadWriteLock lock;
48 * Constructor for ReadWriteLockTest.
52 public ReadWriteLockTest(String aName) {
56 private synchronized int getReaderCount() {
60 private synchronized int getWriterCount() {
64 synchronized void incrementReaderCount() {
68 synchronized void incrementWriterCount() {
72 synchronized void decrementReaderCount() {
76 synchronized void decrementWriterCount() {
81 * @see TestCase#setUp()
83 protected void setUp() throws Exception {
85 lock = new ReadWriteLock();
89 * @see TestCase#tearDown()
91 protected void tearDown() throws Exception {
97 * Acquire and release a read lock.
99 public void testRead() {
105 * Acquire and release a write lock.
107 public void testWrite() {
113 * Verify concurrent access by multiple readers is possible.
115 * @throws InterruptedException May not occur.
117 public void testMultipleReaders() throws InterruptedException {
118 Runnable runnable = new ReadLocker(lock, this, TWO_SECONDS);
120 Thread t1 = new Thread(runnable);
123 Thread t2 = new Thread(runnable);
125 Thread.sleep(ONE_SECOND);
126 assertTrue("Not enough readers!", getReaderCount() == 2);
132 * Verify that only one writer at a time can acquire the write lock.
134 * @throws InterruptedException May not occur.
136 public void testSingleWriter() throws InterruptedException {
137 WriteLocker writer = new WriteLocker(lock, this, ONE_SECOND);
138 Thread t1 = new Thread(writer);
139 Thread t2 = new Thread(writer);
143 Thread.sleep(HALF_SECOND);
144 assertTrue("Wrong writer count: " + getWriterCount(),
145 getWriterCount() == 1);
151 * Verify that multiple writers cannot acquire the write lock concurrently.
153 * @throws InterruptedException May not occur.
155 public void testMultipleWriters() throws InterruptedException {
156 WriteLocker writer1 = new WriteLocker(lock, this,
157 HALF_SECOND + ONE_SECOND);
158 WriteLocker writer2 = new WriteLocker(lock, this, ONE_SECOND);
159 Thread t1 = new Thread(writer1);
160 Thread t2 = new Thread(writer2);
163 Thread.sleep(HALF_SECOND);
164 assertTrue(getWriterCount() == 1);
166 Thread.sleep(HALF_SECOND);
167 assertTrue(getWriterCount() == 1); // first writer still
170 Thread.sleep(ONE_SECOND);
172 // at t = 2, the second writer still must have
174 assertTrue(getWriterCount() == 1);
180 * Verify that after the first reader acquires a lock, a subsequent writer
181 * can only acquire the lock after the reader has released it.
183 * @throws InterruptedException May not occur.
185 public void testReadWrite1() throws InterruptedException {
186 ReadLocker readLocker = new ReadLocker(lock, this, TWO_SECONDS);
187 Thread t1 = new Thread(readLocker);
188 WriteLocker writeLocker = new WriteLocker(lock, this, TWO_SECONDS);
189 Thread t2 = new Thread(writeLocker);
191 t1.start(); // acquire read lock
192 Thread.sleep(HALF_SECOND);
193 assertTrue(getReaderCount() == 1);
195 Thread.sleep(HALF_SECOND);
197 // 1 second underway, reader still holding the
198 // lock so write lock cannot be acquired.
199 assertTrue(getReaderCount() == 1);
200 assertTrue(getWriterCount() == 0);
201 Thread.sleep(ONE_SECOND + HALF_SECOND);
203 // 2.5 seconds underway, read lock released and
204 // write lock must be acquired.
205 assertTrue("Wrong no. of readers: " + getReaderCount(),
206 getReaderCount() == 0);
207 assertTrue(getWriterCount() == 1);
213 * Verify that when multiple readers have acquired a read lock, the writer
214 * can only acquire the lock after all readers have released it.
216 * @throws InterruptedException May not occur.
218 public void testReadWrite2() throws InterruptedException {
219 ReadLocker readLocker1 = new ReadLocker(lock, this,
220 TWO_SECONDS + HALF_SECOND);
221 ReadLocker readLocker2 = new ReadLocker(lock, this,
222 TWO_SECONDS + HALF_SECOND);
223 Thread t1 = new Thread(readLocker1);
224 Thread t2 = new Thread(readLocker2);
225 WriteLocker writeLocker = new WriteLocker(lock, this, TWO_SECONDS);
226 Thread t3 = new Thread(writeLocker);
228 t1.start(); // acquire read lock [0, 2.5]
229 Thread.sleep(ONE_SECOND);
231 assertTrue(getReaderCount() == 1);
232 t2.start(); // acquire read lock [1, 3.5]
233 Thread.sleep(HALF_SECOND);
235 assertTrue(getReaderCount() == 2);
236 t3.start(); // write lock
237 Thread.sleep(HALF_SECOND);
240 assertTrue(getReaderCount() == 2);
241 assertTrue(getWriterCount() == 0);
242 Thread.sleep(ONE_SECOND);
244 // 3 seconds underway, first read lock must
245 // have been released.
246 assertTrue(getReaderCount() == 1);
247 assertTrue(getWriterCount() == 0);
248 Thread.sleep(ONE_SECOND);
250 // 4 seconds underway, write lock must have
252 assertTrue(getReaderCount() == 0);
253 assertTrue(getWriterCount() == 1);
261 * Verify that after a writer acquires a lock, a subsequent reader can
262 * only acquire the lock after the writer has released it.
264 * @throws InterruptedException May not occur.
266 public void testReadWrite3() throws InterruptedException {
267 ReadLocker readLocker = new ReadLocker(lock, this, TWO_SECONDS);
268 Thread t1 = new Thread(readLocker);
269 WriteLocker writeLocker = new WriteLocker(lock, this, TWO_SECONDS);
270 Thread t2 = new Thread(writeLocker);
272 t2.start(); // acquire write lock
273 Thread.sleep(HALF_SECOND);
274 assertTrue(getWriterCount() == 1);
276 Thread.sleep(HALF_SECOND);
278 // 1 second underway, writer still holding the
279 // lock so read lock cannot be acquired.
280 assertTrue(getWriterCount() == 1);
281 assertTrue(getReaderCount() == 0);
282 Thread.sleep(ONE_SECOND + HALF_SECOND);
284 // 2.5 seconds underway, write lock released and
285 // read lock must be acquired.
286 assertTrue("Wrong no. of writers: " + getReaderCount(),
287 getWriterCount() == 0);
288 assertTrue(getReaderCount() == 1);
294 * The following test cases are for testing whether or not
295 * the read write lock checks the locking correctly.
296 * Strictly speaking, these checks wouldn't be necessary
297 * because it involves the contract of the ReadWriteLock which
298 * must be obeyed by users of the ReadWriteLock. Nevertheless,
299 * this is tested anyway to be absolutely sure.
303 * Acquire a read lock from one thread, release it from another. Verify
304 * that a RuntimeException is thrown.
306 * @throws InterruptedException May not occur.
308 public void testReleaseReadFromWrongThread() throws InterruptedException {
312 t1 = new Thread(new Runnable() {
314 ReadWriteLockTest.this.lock.acquireRead();
318 Thread.sleep(ONE_SECOND); // wait until thread is started
319 lock.releaseRead(); // release lock from wrong thread.
320 } catch (RuntimeException e) {
330 * Acquire a write lock from one thread, release it from another. Verify
331 * that a RuntimeException is thrown.
333 * @throws InterruptedException May not occur.
335 public void testReleaseWriteFromWrongThread() throws InterruptedException {
339 t1 = new Thread(new Runnable() {
341 ReadWriteLockTest.this.lock.acquireWrite();
345 Thread.sleep(ONE_SECOND); // wait until thread is started
346 lock.releaseWrite(); // release lock from wrong thread.
347 } catch (RuntimeException e) {
357 * Try to acquire a read lock multiple times. Verify that a
358 * RuntimeException is thrown.
360 public void testAcquireReadTwice() {
364 } catch (RuntimeException e) {
373 * Try to acquire a write lock multiple times. Verify that a
374 * RuntimeException is thrown.
376 public void testAcquireWriteTwice() {
380 } catch (RuntimeException e) {
388 * Acquire the lock for reading and directly afterwards acquire it for
389 * writing. Verify that a RuntimeException is thrown.
391 public void testAcquireReadFollowedByWrite() {
395 } catch (RuntimeException e) {
403 * Acquire the lock for writing and directly afterwards acquire it for
404 * reading. Verify that a RuntimeException is thrown.
406 public void testAcquireWriteFollowedByRead() {
410 } catch (RuntimeException e) {
418 * Acquire a read lock and release it as a write lock. Verify that a
419 * RuntimeException is thrown.
421 public void testAcquireReadFollowedByReleaseaWrite() {
425 } catch (RuntimeException e) {
433 * Acquire a write lock and release it as a read lock. Verify that a
434 * RuntimeException is thrown.
436 public void testAcquireWriteFollowedByReleaseRead() {
440 } catch (RuntimeException e) {
450 * ReadLocker acquires a read lock and performs a callback when the lock as
451 * been acquired, sleeps for a designated amount of time, releases the read
452 * lock, and performs a callback after the lock has been released.
454 class ReadLocker implements Runnable {
455 private ReadWriteLock lock;
456 private ReadWriteLockTest lockTest;
457 private int sleepTime;
459 public ReadLocker(ReadWriteLock aLock, ReadWriteLockTest aLockTest,
462 lockTest = aLockTest;
463 sleepTime = aSleepTime;
468 lockTest.incrementReaderCount();
471 Thread.sleep(sleepTime);
472 } catch (InterruptedException e) {
473 Assert.fail("ReadLocker thread was interrupted." +
474 Thread.currentThread());
478 lockTest.decrementReaderCount();
484 * WriteLocker acquires a write lock and performs a callback when the lock as
485 * been acquired, sleeps for a designated amount of time, releases the write
486 * lock, and performs a callback after the lock has been released.
488 class WriteLocker implements Runnable {
489 private ReadWriteLock lock;
490 private ReadWriteLockTest lockTest;
491 private int sleepTime;
493 public WriteLocker(ReadWriteLock aLock, ReadWriteLockTest aLockTest,
496 lockTest = aLockTest;
497 sleepTime = aSleepTime;
502 lockTest.incrementWriterCount();
505 Thread.sleep(sleepTime);
506 } catch (InterruptedException e) {
507 Assert.fail("WriteLocker thread was interrupted: " +
508 Thread.currentThread());
512 lockTest.decrementWriterCount();