KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > test > cache > test > generic > ReadWriteLockWithUpgradeUnitTestCase


1 /*
2 * JBoss, the OpenSource J2EE webOS
3 *
4 * Distributable under LGPL license.
5 * See terms of license at gnu.org.
6 */

7 package org.jboss.test.cache.test.generic;
8
9 import EDU.oswego.cs.dl.util.concurrent.Sync;
10 import junit.framework.Test;
11 import junit.framework.TestCase;
12 import junit.framework.TestSuite;
13 import org.jboss.cache.lock.ReadWriteLockWithUpgrade;
14 import java.io.*;
15 import java.util.*;
16
17 /**
18  * NonBlockingWriterLock is a read/write lock (with upgrade) that has
19  * non-blocking write lock acquisition on existing read lock(s).
20  * <p>Note that the write lock is exclusive among write locks, e.g.,
21  * only one write lock can be granted at one time, but the write lock
22  * is independent of the read locks. For example,
23  * a read lock to be acquired will be blocked if there is existing write lock, but
24  * will not be blocked if there are mutiple read locks already granted to other
25  * owners. On the other hand, a write lock can be acquired as long as there
26  * is no existing write lock, regardless how many read locks have been
27  * granted.
28  *
29  * @author <a HREF="mailto:cavin_song@yahoo.com">Cavin Song</a> April 22, 2004
30  * @version 1.0
31  */

32 public class ReadWriteLockWithUpgradeUnitTestCase extends TestCase
33 {
34    static final ReadWriteLockWithUpgrade lock_ = new ReadWriteLockWithUpgrade();
35    static long SLEEP_MSECS = 500;
36    Vector lockResult = new Vector();
37    int NO_MORE_OP = 0;
38    int INVOKE_READ = 1;
39    int INVOKE_WRITE = 2;
40    int INVOKE_UPGRADE = 3;
41
42    public ReadWriteLockWithUpgradeUnitTestCase(String JavaDoc name)
43    {
44       super(name);
45    }
46
47
48    public static void main(String JavaDoc[] args) throws Exception JavaDoc
49    {
50       log("\nBeginning ReadWriteLockWithUpgrade automated testing ...\n");
51
52       junit.textui.TestRunner.run(suite());
53    }
54
55    // Needed for JUnit.
56
public static Test suite()
57    {
58       TestSuite suite = new TestSuite();
59       // Adding test cases here ...
60
suite.addTestSuite(ReadWriteLockWithUpgradeUnitTestCase.class);
61       return suite;
62    }
63
64    public void setUp()
65    {
66       logX("\n");
67       log("Setting up test case ...");
68    }
69
70    public void tearDown()
71    {
72       log("Tearing down test case ...");
73    }
74
75    public static void _sleep(long msecs)
76    {
77       try {
78          Thread.sleep(msecs);
79       } catch (InterruptedException JavaDoc ex) {
80       }
81    }
82
83    public static void log(String JavaDoc str)
84    {
85       System.out.println(Thread.currentThread() + ": "
86             + java.util.Calendar.getInstance().getTime() + " : " + str);
87    }
88
89    // For debugging purpose
90
public static void logX(String JavaDoc str)
91    {
92       log(str);
93 // try {
94
// logToFile(str);
95
// } catch (IOException ioe) {
96
// }
97
}
98
99    // Debugging intrnal function
100
public static void logToFile(String JavaDoc str) throws IOException
101    {
102       Writer out = new FileWriter("./RepeatableLogs.txt", true/*append*/);
103       out.write(str);
104       out.close();
105    }
106
107    /***************************************************************/
108    /* Utility functions to creat threads for RL, WL and UL */
109    /***************************************************************/
110    /**
111     * Creates a new thread and acquires a read lock with a timeout
112     * value specified by the caller. Optionally, the caller can request
113     * a second read or write lock after the first read lock request.
114     * The locking result is stored in a vector with the following
115     * format:
116     * <p><DL>
117     * <DD>'case number'-'thread name'-[RL|WL|UL]-[0|1]
118     * </DL>
119     * <p>where:
120     * <DL>
121     * <DD> 'case number' is the passed in test case # by the caller.
122     * <DD> 'thread name' is the passed in thread name by the caller.
123     * <DD> RL - indicating was doing read lock request.
124     * <DD> WL - indicating was doing write lock request.
125     * <DD> UL - indicating was doing upgrade lock request.
126     * <DD> 0 - indicating the locking request failed.
127     * <DD> 1 - indicating the locking request succeeded.
128     * </DL>
129     * <p>
130     * After all threads in each test case terminate, the test case
131     * should make the following call to verify the test result:
132     * <DL>
133     * <DD> asssertTrue(checkLockingResult(expected-result-string);
134     * </DL>
135     * <p>
136     * 'expected-result-string' is the locking result string
137     * described above. For example, "8-t1-RL-0" means that thread
138     * t1 in test case #8 doing a Read Lock request expects the
139     * operation to fail. If the expected result string can't be
140     * found then the test case is considered FAILED (ie, either
141     * the read lock request was successful or did not complete).
142     * <p>
143     * Each test case should also call cleanLockingResult() to reset
144     * result vector for the next test cases.
145     * @param caseNum Arbitrary string for the test case number.
146     * @param name Arbitrary string for the calling thread name.
147     * @param msecs Milliseconds that the thread should sleep after
148     * acquiring the read lock.
149     * @param errMsg Error msg to log in case of error.
150     * @param secondOP Set to NO_MORE_OP if a 2nd lock request is not required.
151     * Set to INVOKE_READ, INVOKE_READ or INVOKE_UPGRADE
152     * respectively if the 2nd lock is a read, write or
153     * upgrade request respectively.
154     */

155   
156    protected Thread JavaDoc readThread(final String JavaDoc caseNum, final String JavaDoc name,
157                                final long msecs, final long sleepSecs,
158                                final String JavaDoc errMsg, final int secondOP)
159    {
160       return new Thread JavaDoc(name)
161       {
162          public void run()
163          {
164                Sync rlock = lock_.readLock();
165             try {
166                if (! rlock.attempt(msecs)) {
167                   logX(caseNum+"-"+name+" requesting read lock failed!\n");
168                   String JavaDoc str = caseNum + "-" + name + "-RL-0";
169                   postLockingResult(str);
170                   return;
171                }
172                // OK, read lock obtained, sleep and release it.
173
logX(caseNum+"-"+name+" requesting read lock succeeded!\n");
174                String JavaDoc str = caseNum + "-" + name + "-RL-1";
175                postLockingResult(str);
176                _sleep(sleepSecs);
177
178            if (secondOP == INVOKE_READ)
179                    acquireReadLock(caseNum, name, msecs, errMsg);
180                else if (secondOP == INVOKE_WRITE)
181                    acquireWriteLock(caseNum, name, msecs, errMsg);
182                else if (secondOP == INVOKE_UPGRADE)
183                    acquireUpgradeLock(caseNum, name, msecs, errMsg);
184                  
185                rlock.release();
186                logX(caseNum+"-"+name+" releasing read lock.\n");
187             } catch (Exception JavaDoc ex) {
188             }
189          }
190       };
191    }
192
193    /**
194     * Creates a new thread and acquires a write lock with a timeout
195     * value specified by the caller. Similar to {@link #readThread readThread()}
196     * except it's used for write locks.
197     * @see #readThread readThread()
198     */

199    protected Thread JavaDoc writeThread(final String JavaDoc caseNum, final String JavaDoc name,
200                                 final long msecs, final long sleepSecs,
201                                 final String JavaDoc errMsg, final int secondOP)
202    {
203       return new Thread JavaDoc(name)
204       {
205          public void run()
206          {
207             try {
208                Sync wlock = lock_.writeLock();
209                if (! wlock.attempt(msecs)) {
210                   logX(caseNum+"-"+name+" requesting write lock failed!\n");
211                   String JavaDoc str = caseNum + "-" + name + "-WL-0";
212                   postLockingResult(str);
213                   return;
214                }
215                // OK, write lock obtained, sleep and release it.
216
logX(caseNum+"-"+name+" requesting write lock succeeded!\n");
217                String JavaDoc str = caseNum + "-" + name + "-WL-1";
218                postLockingResult(str);
219                _sleep(sleepSecs);
220
221            if (secondOP == INVOKE_READ)
222                    acquireReadLock(caseNum, name, msecs, errMsg);
223                else if (secondOP == INVOKE_WRITE)
224                    acquireWriteLock(caseNum, name, msecs, errMsg);
225                else if (secondOP == INVOKE_UPGRADE)
226                    acquireUpgradeLock(caseNum, name, msecs, errMsg);
227
228                wlock.release();
229                logX(caseNum+"-"+name+" releasing write lock.\n");
230             } catch (Exception JavaDoc ex) {
231             }
232          }
233       };
234    }
235
236    /**
237     * Creates a new thread, acquires a read lock, sleeps for a while
238     * and then tries to upgrade the read lock to a write one. Similar
239     * to {@link #readThread readThread()} except it's used for upgrading
240     * locks.
241     * @see #readThread readThread()
242     */

243    protected Thread JavaDoc upgradeThread(final String JavaDoc caseNum, final String JavaDoc name,
244                                   final long msecs, final String JavaDoc errMsg)
245    {
246       return new Thread JavaDoc(name)
247       {
248          public void run()
249          {
250             try {
251                Sync rlock = lock_.readLock();
252                Sync wlock = null;
253                if (! rlock.attempt(msecs)) {
254                   logX(caseNum+"-"+name+" requesting read lock failed!\n");
255                   String JavaDoc str = caseNum + "-" + name + "-RL-0";
256                   postLockingResult(str);
257                   return;
258                }
259                // OK, read lock obtained, sleep and upgrade it later.
260
logX(caseNum+"-"+name+" requesting read lock succeeded (upgrade later)!\n");
261                _sleep(SLEEP_MSECS/2);
262                String JavaDoc str = caseNum + "-" + name + "-UL-";
263                if ((wlock = lock_.upgradeLockAttempt(msecs)) == null)
264                {
265                  logX(caseNum+"-"+name+" requesting upgrade lock failed!\n");
266                  str += "0";
267                }
268                else
269                {
270                  logX(caseNum+"-"+name+" requesting upgrade lock succeeded!\n");
271                  str += "1";
272                }
273                postLockingResult(str);
274                // Sleep again and then release the lock.
275
_sleep(SLEEP_MSECS);
276                if (wlock != null)
277                {
278                  wlock.release();
279                  logX(caseNum+"-"+name+" releasing upgrade lock.\n");
280                }
281                rlock.release();
282             } catch (Exception JavaDoc ex) {
283             }
284          }
285       };
286    }
287
288    /***************************************************************/
289    /* Utility functions to acquire RL and WL (no thread) */
290    /***************************************************************/
291    /**
292     * This routine tries to acquire a read lock with a timeout value
293     * passed in by the caller. Like {@link #readThread readThread()}
294     * it then stores the locking result in the result vector depending
295     * on the outcome of the request.
296     */

297   
298    protected void acquireReadLock(final String JavaDoc caseNum, final String JavaDoc name,
299                                   final long msecs, final String JavaDoc errMsg)
300    {
301             try {
302                Sync rlock = lock_.readLock();
303                if (! rlock.attempt(msecs)) {
304                   logX(caseNum+"-"+name+" requesting read lock failed!\n");
305                   String JavaDoc str = caseNum + "-" + name + "-RL-0";
306                   postLockingResult(str);
307                   return;
308                }
309                // OK, read lock obtained, sleep and release it.
310
logX(caseNum+"-"+name+" requesting read lock succeeded!\n");
311                String JavaDoc str = caseNum + "-" + name + "-RL-1";
312                postLockingResult(str);
313                _sleep(SLEEP_MSECS);
314                rlock.release();
315                logX(caseNum+"-"+name+" releasing read lock.\n");
316             } catch (Exception JavaDoc ex) {
317             }
318    }
319
320    /**
321     * Same as {@link #acquireReadLock acquireReadLock()} except
322     * it's for write lock request.
323     */

324    protected void acquireWriteLock(final String JavaDoc caseNum, final String JavaDoc name,
325                                    final long msecs, final String JavaDoc errMsg)
326    {
327             try {
328                Sync wlock = lock_.writeLock();
329                if (! wlock.attempt(msecs)) {
330                   logX(caseNum+"-"+name+" requesting write lock failed!\n");
331                   String JavaDoc str = caseNum + "-" + name + "-WL-0";
332                   postLockingResult(str);
333                   return;
334                }
335                // OK, write lock obtained, sleep and release it.
336
logX(caseNum+"-"+name+" requesting write lock succeeded!\n");
337                String JavaDoc str = caseNum + "-" + name + "-WL-1";
338                postLockingResult(str);
339                _sleep(SLEEP_MSECS);
340                wlock.release();
341                logX(caseNum+"-"+name+" releasing write lock.\n");
342             } catch (Exception JavaDoc ex) {
343             }
344    }
345
346    /**
347     * Same as {@link #acquireReadLock acquireReadLock()} except
348     * it's for upgrade lock request.
349     */

350    protected void acquireUpgradeLock(final String JavaDoc caseNum, final String JavaDoc name,
351                                      final long msecs, final String JavaDoc errMsg)
352    {
353             try {
354                Sync ulock = null;
355                if ((ulock = lock_.upgradeLockAttempt(msecs)) == null) {
356                   logX(caseNum+"-"+name+" requesting upgrade lock failed!\n");
357                   String JavaDoc str = caseNum + "-" + name + "-UL-0";
358                   postLockingResult(str);
359                   return;
360                }
361                // OK, write lock obtained, sleep and release it.
362
logX(caseNum+"-"+name+" requesting upgrade lock succeeded!\n");
363                String JavaDoc str = caseNum + "-" + name + "-UL-1";
364                postLockingResult(str);
365                _sleep(SLEEP_MSECS);
366                ulock.release();
367                logX(caseNum+"-"+name+" releasing upgrade lock.\n");
368             } catch (Exception JavaDoc ex) {
369             }
370    }
371
372    /***************************************************************/
373    /* Synchronized methods handling locking result vector */
374    /***************************************************************/
375    /**
376     * Clean/remove all locking results in the vector.
377     */

378    protected synchronized void cleanLockingResult()
379    {
380        lockResult.removeAllElements();
381    }
382
383    /**
384     * Post a locking result to the vector for later verification.
385     */

386    protected synchronized void postLockingResult(Object JavaDoc obj)
387    {
388        logX(" Added *" + (String JavaDoc)obj + "* to the result vector\n");
389        // Make sure we only have one in the vector
390
//if (!checkLockingResult((String)obj))
391
lockResult.addElement(obj);
392    }
393    
394    /**
395     * Check if a given expected locking result is in the vector.
396     */

397    protected synchronized boolean checkLockingResult(String JavaDoc expected)
398    {
399        boolean rc = false;
400        for (int i=0; i<lockResult.size(); i++)
401        {
402          Object JavaDoc ele = lockResult.elementAt(i);
403          String JavaDoc str = (String JavaDoc)ele;
404          if (expected.equals(str))
405          {
406             rc = true;
407             break;
408          }
409        }
410        if (rc)
411          logX(" Searching for *" + expected + "* SUCCEEDED.\n");
412        else
413          logX(" Searching for *" + expected + "* FAILED.\n");
414        return rc;
415    }
416
417    /***************************************************************/
418    /* T e s t C a s e s */
419    /***************************************************************/
420    /** Case #10 - T1 acquires RL, T2 acquires RL followed by WL. */
421    public void testWriteWithMultipleReaders() throws Exception JavaDoc
422    {
423       String JavaDoc caseNum = "10";
424       Thread JavaDoc t1=readThread(caseNum, "t1", 0, SLEEP_MSECS*2,
425                            "1st read lock attempt failed", NO_MORE_OP);
426       Thread JavaDoc t2=readThread(caseNum, "t2", 0, SLEEP_MSECS,
427                            "2nd read lock attempt failed", INVOKE_WRITE);
428
429       t1.start();
430       t2.start();
431       t1.join(3000);
432       t2.join(3000);
433       assertTrue(checkLockingResult(caseNum+"-t1-RL-1") &&
434                  checkLockingResult(caseNum+"-t2-RL-1") &&
435                  checkLockingResult(caseNum+"-t2-WL-0"));
436       cleanLockingResult();
437       // possilbe deadlock check
438
if (t1.isAlive() || t2.isAlive())
439          fail("Possible deadlock resulted in testRead.");
440    }
441
442    /** Case #11 - T1 acquires RL followed by WL, T2 acquires RL. */
443    public void testUpgradeWithMultipleReadersOn1() throws Exception JavaDoc
444    {
445       String JavaDoc caseNum = "11";
446       Thread JavaDoc t1=readThread(caseNum, "t1", 0, SLEEP_MSECS,
447                            "1st read lock attempt failed", INVOKE_WRITE);
448       Thread JavaDoc t2=readThread(caseNum, "t2", 0, SLEEP_MSECS*2,
449                            "2nd read lock attempt failed", NO_MORE_OP);
450
451       t1.start();
452       t2.start();
453       t1.join(3000);
454       t2.join(3000);
455       assertTrue(checkLockingResult(caseNum+"-t1-RL-1") &&
456                  checkLockingResult(caseNum+"-t2-RL-1") &&
457                  checkLockingResult(caseNum+"-t1-WL-0"));
458       cleanLockingResult();
459       // possilbe deadlock check
460
if (t1.isAlive() || t2.isAlive())
461          fail("Possible deadlock resulted in testRead.");
462    }
463
464    /** Case #2 - T1 acquires RL followed by UL. */
465    public void testUpgradeReadLock() throws Exception JavaDoc
466    {
467       String JavaDoc caseNum = "2";
468       Thread JavaDoc t1=readThread(caseNum, "t1", 0, SLEEP_MSECS,
469                            "1st read lock attempt failed", INVOKE_UPGRADE);
470
471       t1.start();
472       t1.join(3000);
473       assertTrue(checkLockingResult(caseNum+"-t1-RL-1") &&
474                  checkLockingResult(caseNum+"-t1-UL-1"));
475       cleanLockingResult();
476    }
477
478    /** Case #3 - T1 acquires RL followed by WL. */
479
480    public void testReadThenWrite() throws Exception JavaDoc
481    {
482       String JavaDoc caseNum = "3";
483       acquireReadLock(caseNum, "t1", 0, "1st read lock attempt failed");
484       acquireWriteLock(caseNum, "t1.1", 0, "2nd write lock attempt failed");
485       assertTrue(checkLockingResult(caseNum+"-t1-RL-1") &&
486                  checkLockingResult(caseNum+"-t1.1-WL-1"));
487       cleanLockingResult();
488    }
489
490
491    /** Case #5 - T1 acquires WL followed by RL.*/
492
493    public void testWriteThenRead() throws Exception JavaDoc
494    {
495       String JavaDoc caseNum = "5";
496       acquireWriteLock(caseNum, "t1", 0, "1st write lock attempt failed");
497       acquireReadLock(caseNum, "t1.1", 0, "2nd read lock attempt failed");
498       assertTrue(checkLockingResult(caseNum+"-t1-WL-1") &&
499                  checkLockingResult(caseNum+"-t1.1-RL-1"));
500       cleanLockingResult();
501    }
502
503    /** Case #6 - T1 acquires RL, T2 acquires RL.*/
504    public void testMultipleReadlock() throws Exception JavaDoc
505    {
506       String JavaDoc caseNum = "6";
507       Thread JavaDoc t1=readThread(caseNum, "t1", 0, SLEEP_MSECS,
508                            "1st read lock attempt failed", NO_MORE_OP);
509       Thread JavaDoc t2=readThread(caseNum, "t2", 0, SLEEP_MSECS,
510                            "2nd read lock attempt failed", NO_MORE_OP);
511
512       t1.start();
513       t2.start();
514       t1.join(3000);
515       t2.join(3000);
516       assertTrue(checkLockingResult(caseNum+"-t1-RL-1") &&
517                  checkLockingResult(caseNum+"-t2-RL-1"));
518       cleanLockingResult();
519       // possilbe deadlock check
520
if (t1.isAlive() || t2.isAlive())
521          fail("Possible deadlock resulted in testRead.");
522    }
523
524    /** Case #8 - T1 acquires WL, T2 acquires RL.*/
525    public void testWriteWithExistingReader() throws Exception JavaDoc
526    {
527       String JavaDoc caseNum = "8";
528       Thread JavaDoc t1=readThread(caseNum, "t1", 0, SLEEP_MSECS,
529                            "1st write lock attempt failed", NO_MORE_OP);
530       Thread JavaDoc t2=writeThread(caseNum, "t2", 0, SLEEP_MSECS,
531                            "2nd read lock attempt failed", NO_MORE_OP);
532
533       t1.start();
534       t2.start();
535       t1.join(3000);
536       t2.join(3000);
537       assertTrue(checkLockingResult(caseNum+"-t1-RL-1") &&
538                  checkLockingResult(caseNum+"-t2-WL-0"));
539       cleanLockingResult();
540       // possilbe deadlock check
541
if (t1.isAlive() || t2.isAlive())
542          fail("Possible deadlock resulted in testRead.");
543    }
544
545    /** Case #13 - T1 acquires RL, T2 acquires WL.*/
546    public void testReadWithExistingWriter() throws Exception JavaDoc
547    {
548       String JavaDoc caseNum = "13";
549       Thread JavaDoc t1=writeThread(caseNum, "t1", 0, SLEEP_MSECS,
550                            "1st write lock attempt failed", NO_MORE_OP);
551       Thread JavaDoc t2=readThread(caseNum, "t2", 0, SLEEP_MSECS,
552                            "2nd read lock attempt failed", NO_MORE_OP);
553
554       t1.start();
555       t2.start();
556       t1.join(3000);
557       t2.join(3000);
558       assertTrue(checkLockingResult(caseNum+"-t1-WL-1") &&
559                  checkLockingResult(caseNum+"-t2-RL-0"));
560       cleanLockingResult();
561       // possilbe deadlock check
562
if (t1.isAlive() || t2.isAlive())
563          fail("Possible deadlock resulted in testRead.");
564    }
565
566    /** Case #14 - T1 acquires WL, T2 acquires WL.*/
567    public void testMultipleWritelocks() throws Exception JavaDoc
568    {
569       String JavaDoc caseNum = "14";
570       Thread JavaDoc t1=writeThread(caseNum, "t1", 0, SLEEP_MSECS,
571                            "1st write lock attempt failed", NO_MORE_OP);
572       Thread JavaDoc t2=writeThread(caseNum, "t2", 0, SLEEP_MSECS,
573                            "2nd write lock attempt failed", NO_MORE_OP);
574
575       t1.start();
576       t2.start();
577       t1.join(3000);
578       t2.join(3000);
579       assertTrue(checkLockingResult(caseNum+"-t1-WL-1") &&
580                  checkLockingResult(caseNum+"-t2-WL-0"));
581       cleanLockingResult();
582       // possilbe deadlock check
583
if (t1.isAlive() || t2.isAlive())
584          fail("Possible deadlock resulted in testRead.");
585    }
586    /** Case #7 - T1 acquires RL, T2 acquires UL.*/
587
588    public void testUpgradeWithExistingReader() throws Exception JavaDoc
589    {
590       String JavaDoc caseNum = "7";
591       Thread JavaDoc t1=readThread(caseNum, "t1", 0, SLEEP_MSECS,
592                            "1st read lock attempt failed", NO_MORE_OP);
593       Thread JavaDoc t2=upgradeThread(caseNum, "t2", 0,
594                            "2nd upgrade lock attempt failed");
595
596       t1.start();
597       t2.start();
598       t1.join(3000);
599       t2.join(3000);
600       assertTrue(checkLockingResult(caseNum+"-t1-RL-1") &&
601                  checkLockingResult(caseNum+"-t2-UL-0"));
602       cleanLockingResult();
603       // possilbe deadlock check
604
if (t1.isAlive() || t2.isAlive())
605          fail("Possible deadlock resulted in testRead.");
606    }
607
608    /** Case #9 - T1 acquires RL, T2 acquires RL followed by UL.*/
609    public void testUpgradeWithMultipleReaders() throws Exception JavaDoc
610    {
611       String JavaDoc caseNum = "9";
612       Thread JavaDoc t1=readThread(caseNum, "t1", 0, SLEEP_MSECS*2,
613                            "1st read lock attempt failed", NO_MORE_OP);
614       Thread JavaDoc t2=readThread(caseNum, "t2", 0, SLEEP_MSECS,
615                            "2nd read lock attempt failed", INVOKE_UPGRADE);
616
617       t1.start();
618       t2.start();
619       t1.join(3000);
620       t2.join(3000);
621       assertTrue(checkLockingResult(caseNum+"-t1-RL-1") &&
622                  checkLockingResult(caseNum+"-t2-RL-1") &&
623                  checkLockingResult(caseNum+"-t2-UL-0"));
624       cleanLockingResult();
625       // possilbe deadlock check
626
if (t1.isAlive() || t2.isAlive())
627          fail("Possible deadlock resulted in testRead.");
628    }
629 }
630
631
Popular Tags