KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > rice > cs > util > ReaderWriterLockTest


1 /*BEGIN_COPYRIGHT_BLOCK
2  *
3  * This file is part of DrJava. Download the current version of this project from http://www.drjava.org/
4  * or http://sourceforge.net/projects/drjava/
5  *
6  * DrJava Open Source License
7  *
8  * Copyright (C) 2001-2006 JavaPLT group at Rice University (javaplt@rice.edu). All rights reserved.
9  *
10  * Developed by: Java Programming Languages Team, Rice University, http://www.cs.rice.edu/~javaplt/
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
13  * documentation files (the "Software"), to deal with the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
15  * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
16  *
17  * - Redistributions of source code must retain the above copyright notice, this list of conditions and the
18  * following disclaimers.
19  * - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
20  * following disclaimers in the documentation and/or other materials provided with the distribution.
21  * - Neither the names of DrJava, the JavaPLT, Rice University, nor the names of its contributors may be used to
22  * endorse or promote products derived from this Software without specific prior written permission.
23  * - Products derived from this software may not be called "DrJava" nor use the term "DrJava" as part of their
24  * names without prior written permission from the JavaPLT group. For permission, write to javaplt@rice.edu.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
27  * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28  * CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
29  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30  * WITH THE SOFTWARE.
31  *
32  *END_COPYRIGHT_BLOCK*/

33
34 package edu.rice.cs.util;
35
36 import edu.rice.cs.drjava.DrJavaTestCase;
37
38 /** Attempts to test the correctness of the ReaderWriterLock class, which allows multiple reader and writer threads to
39   * safely access a shared resource. (Multiple readers can be active at a time, but only one writer can be active,
40   * during which time no readers can be active.) This can be difficult to test because there is little control over
41   * how the threads are actually scheduled.
42   * @version $Id: ReaderWriterLockTest.java 4031 2006-11-15 22:09:06Z rcartwright $
43   */

44 public class ReaderWriterLockTest extends DrJavaTestCase {
45
46   protected ReaderWriterLock _lock;
47
48   /** Creates a new lock for the tests. */
49   public void setUp() throws Exception JavaDoc {
50     super.setUp();
51     _lock = new ReaderWriterLock();
52   }
53
54   // TO DO: Pull the next few lines out into a Semaphore class
55

56   /** Number of notifications expected before we actually notify. */
57   private int _notifyCount = 0;
58
59   /** Object to provide semaphore-like synchronization. */
60   private final Object JavaDoc _notifyObject = new Object JavaDoc();
61
62   /** Notifies the _notifyObject (semaphore) when the _notifyCount reaches 0. (Decrements the count on each call.) */
63   private void _notify() {
64     synchronized(_notifyObject) {
65       _notifyCount--;
66       if (_notifyCount <= 0) {
67         _notifyObject.notify();
68         _notifyCount = 0;
69       }
70     }
71   }
72
73   /** Tests that multiple readers can run without causing deadlock. We can't really impose any ordering on their output.
74     */

75   public void testMultipleReaders() throws InterruptedException JavaDoc {
76     final StringBuilder JavaDoc buf = new StringBuilder JavaDoc();
77
78     // Create three threads
79
ReaderThread r1 = new PrinterReaderThread("r1 ", buf);
80     ReaderThread r2 = new PrinterReaderThread("r2 ", buf);
81     ReaderThread r3 = new PrinterReaderThread("r3 ", buf);
82
83     // Init the count
84
_notifyCount = 3;
85
86     // Start the readers
87
synchronized(_notifyObject) {
88       r1.start();
89       r2.start();
90       r3.start();
91       _notifyObject.wait();
92     }
93 // String output = buf.toString();
94
// System.out.println(output);
95
}
96
97   /** Tests that multiple writers run in mutually exclusive intervals without causing deadlock. */
98   public void testMultipleWriters() throws InterruptedException JavaDoc {
99     final StringBuilder JavaDoc buf = new StringBuilder JavaDoc();
100
101     // Create three threads
102
WriterThread w1 = new PrinterWriterThread("w1 ", buf);
103     WriterThread w2 = new PrinterWriterThread("w2 ", buf);
104     WriterThread w3 = new PrinterWriterThread("w3 ", buf);
105
106     // Init the count
107
_notifyCount = 3;
108
109     // Start the readers
110
synchronized(_notifyObject) {
111       w1.start();
112       w2.start();
113       w3.start();
114       _notifyObject.wait();
115     }
116     String JavaDoc output = buf.toString();
117     //System.out.println(output);
118

119     // Writer output should never be interspersed.
120
assertTrue("w1 writes should happen in order", output.indexOf("w1 w1 w1 ") != -1);
121     assertTrue("w2 writes should happen in order", output.indexOf("w2 w2 w2 ") != -1);
122     assertTrue("w1 writes should happen in order", output.indexOf("w3 w3 w3 ") != -1);
123   }
124
125   /** Ensure that a single thread can perform multiple reads. */
126   public void testReaderMultipleReads() throws InterruptedException JavaDoc {
127     // Simulate a reader that performs multiple reads in one thread
128
_lock.startRead();
129     _lock.startRead();
130     _lock.endRead();
131     _lock.endRead();
132
133     // Test that a reading thread can perform an additional read even if
134
// a writing thread is waiting.
135
_lock.startRead();
136     Thread JavaDoc w = new Thread JavaDoc() {
137       public void run() {
138         synchronized(_lock) {
139           _lock.notifyAll();
140           _lock.startWrite();
141           // Waits here and releases _lock...
142
_lock.endWrite();
143         }
144       }
145     };
146     synchronized(_lock) {
147       w.start();
148       _lock.wait();
149     }
150     _lock.startRead();
151     _lock.endRead();
152     _lock.endRead();
153   }
154
155   /** Ensure that a reading thread cannot perform a write. */
156   public void testCannotWriteInARead() {
157     try {
158       _lock.startRead();
159       _lock.startWrite();
160       fail("Should have caused an IllegalStateException!");
161     }
162     catch (IllegalStateException JavaDoc ise) {
163       // Good, that's what we want
164
}
165   }
166
167   /** Ensure that a writing thread cannot perform an additional write. */
168   public void testCannotWriteInAWrite() {
169     try {
170       _lock.startWrite();
171       _lock.startWrite();
172       fail("Should have caused an IllegalStateException!");
173     }
174     catch (IllegalStateException JavaDoc ise) {
175       // Good, that's what we want
176
}
177   }
178
179   /** Ensure that a writing thread cannot perform a read. */
180   public void testCannotReadInAWrite() {
181     try {
182       _lock.startWrite();
183       _lock.startRead();
184       fail("Should have caused an IllegalStateException!");
185     }
186     catch (IllegalStateException JavaDoc ise) {
187       // Good, that's what we want
188
}
189   }
190
191
192   /**
193    * We would like to test the following schedule.
194    *
195    * <pre>
196    * W1 |***********|
197    * W2 |..........*****|
198    * R1 |..............********|
199    * R2 |............****|
200    * W3 |...................***|
201    * R3 |.....................****|
202    * R4 |................*******|
203    * R5 |***|
204    * </pre>
205    *
206    * Key: "." means waiting, "*" means running
207    *
208    * This is next to impossible to set up in Java. What we'd really
209    * like is a unit-testing framework that allows us to easily specify
210    * such a schedule in a test. (Conveniently, Corky Cartwright has
211    * applied for a Texas ATP grant to develop just such a framework.)
212    *
213    *
214    * So, instead, we'll just set up these threads, let them run, and
215    * enforce that no one interferes with output from a writer.
216    */

217   public void testMultipleReadersAndWriters() throws InterruptedException JavaDoc {
218     final StringBuilder JavaDoc buf = new StringBuilder JavaDoc();
219
220     // Create threads
221
WriterThread w1 = new PrinterWriterThread("w1 ", buf);
222     WriterThread w2 = new PrinterWriterThread("w2 ", buf);
223     WriterThread w3 = new PrinterWriterThread("w3 ", buf);
224
225     ReaderThread r1 = new PrinterReaderThread("r1 ", buf);
226     ReaderThread r2 = new PrinterReaderThread("r2 ", buf);
227     ReaderThread r3 = new PrinterReaderThread("r3 ", buf);
228     ReaderThread r4 = new PrinterReaderThread("r4 ", buf);
229     ReaderThread r5 = new PrinterReaderThread("r5 ", buf);
230
231     // Init the count
232
_notifyCount = 8;
233
234     // Start the readers
235
synchronized(_notifyObject) {
236       w1.start();
237       w2.start();
238       r1.start();
239       r2.start();
240       w3.start();
241       r3.start();
242       r4.start();
243       r5.start();
244       _notifyObject.wait();
245     }
246     String JavaDoc output = buf.toString();
247     //System.out.println(output);
248

249     // Writer output should never be interspersed.
250
assertTrue("w1 writes should happen in order", output.indexOf("w1 w1 w1 ") != -1);
251     assertTrue("w2 writes should happen in order", output.indexOf("w2 w2 w2 ") != -1);
252     assertTrue("w1 writes should happen in order", output.indexOf("w3 w3 w3 ") != -1);
253   }
254
255
256   /** A reader thread. */
257   public abstract class ReaderThread extends Thread JavaDoc {
258     public abstract void read() throws Throwable JavaDoc;
259     public void run() {
260       _lock.startRead();
261       try { read(); }
262       catch (Throwable JavaDoc t) { t.printStackTrace(); }
263       _lock.endRead();
264     }
265   }
266
267   /** A writer thread. */
268   public abstract class WriterThread extends Thread JavaDoc {
269     public abstract void write() throws Throwable JavaDoc;
270     public void run() {
271       _lock.startWrite();
272       try { write(); }
273       catch (Throwable JavaDoc t) { t.printStackTrace(); }
274       _lock.endWrite();
275     }
276   }
277
278   /** A ReaderThread which repeatedly prints to a buffer. */
279   public class PrinterReaderThread extends ReaderThread {
280     PrintCommand _command;
281     public PrinterReaderThread(String JavaDoc msg, final StringBuilder JavaDoc buf) { _command = new PrintCommand(msg, buf); }
282     public void read() { _command.print(); }
283   }
284
285   /** A WriterThread which repeatedly prints to a buffer. */
286   public class PrinterWriterThread extends WriterThread {
287     PrintCommand _command;
288     public PrinterWriterThread(String JavaDoc msg, final StringBuilder JavaDoc buf) { _command = new PrintCommand(msg, buf); }
289     public void write() { _command.print(); }
290   }
291
292   /** Command pattern class to print to a buffer. */
293   public class PrintCommand {
294     /** Number of times to print */
295     int _numIterations = 3;
296     /** Number of milliseconds to wait between iterations */
297     int _waitMillis = 5;
298     /** Buffer to print to */
299     final StringBuilder JavaDoc _buf;
300     /** Message to print */
301     final String JavaDoc _msg;
302     /** Creates a new command to print to a buffer during a read or write. */
303     public PrintCommand(String JavaDoc msg, StringBuilder JavaDoc buf) {
304       _msg = msg;
305       _buf = buf;
306     }
307     /** Prints the message to the buffer. */
308     public void print() {
309       for (int i=0; i < _numIterations; i++) {
310         _buf.append(_msg);
311         try { Thread.sleep(_waitMillis); }
312         catch (InterruptedException JavaDoc e) { _buf.append(e); }
313       }
314       _notify();
315     }
316   }
317 }
318
Popular Tags