ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/tck/AbstractQueuedSynchronizerTest.java
(Generate patch)

Comparing jsr166/src/test/tck/AbstractQueuedSynchronizerTest.java (file contents):
Revision 1.5 by dl, Tue Dec 30 15:48:38 2003 UTC vs.
Revision 1.13 by dl, Fri Jan 9 15:39:10 2004 UTC

# Line 22 | Line 22 | public class AbstractQueuedSynchronizerT
22      }
23  
24      /**
25 <     * A simple mutex class, from the AbstractQueuedSynchronizer
26 <     * javadoc.  All tests exercise this as a sample user extension.
27 <     * Other methods/features of AbstractQueuedSynchronizerTest are
28 <     * tested implicitly in ReentrantLock, ReentrantReadWriteLock, and
29 <     * Semaphore test classes
30 <     */
31 <    static class Mutex implements Lock, java.io.Serializable {
32 <        private static class Sync extends AbstractQueuedSynchronizer {
33 <            public int acquireExclusiveState(boolean isQueued, int acquires) {
34 <                assert acquires == 1; // Does not use multiple acquires
35 <                return compareAndSet(0, 1)? 0 : -1;
36 <            }
37 <            
38 <            public boolean releaseExclusiveState(int releases) {
39 <                set(0);
40 <                return true;
41 <            }
42 <            
43 <            public void checkConditionAccess(Thread thread, boolean waiting) {
44 <                if (get() == 0) throw new IllegalMonitorStateException();
45 <            }
46 <            
47 <            Condition newCondition() { return new ConditionObject(); }
48 <            
49 <            private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
50 <                s.defaultReadObject();
51 <                set(0); // reset to unlocked state
52 <            }
25 >     * A simple mutex class, adapted from the
26 >     * AbstractQueuedSynchronizer javadoc.  Exclusive acquire tests
27 >     * exercise this as a sample user extension.  Other
28 >     * methods/features of AbstractQueuedSynchronizerTest are tested
29 >     * via other test classes, including those for ReentrantLock,
30 >     * ReentrantReadWriteLock, and Semaphore
31 >     */
32 >    static class Mutex extends AbstractQueuedSynchronizer {
33 >        public boolean isLocked() { return getState() == 1; }
34 >        
35 >        public boolean tryAcquireExclusive(int acquires) {
36 >            assertTrue(acquires == 1);
37 >            return compareAndSetState(0, 1);
38 >        }
39 >        
40 >        public boolean tryReleaseExclusive(int releases) {
41 >            setState(0);
42 >            return true;
43          }
44          
45 <        private final Sync sync = new Sync();
46 <        public boolean tryLock() {
57 <            return sync.acquireExclusiveState(false, 1) >= 0;
45 >        public void checkConditionAccess(Thread thread) {
46 >            if (getState() == 0) throw new IllegalMonitorStateException();
47          }
48 +        
49 +        public ConditionObject newCondition() { return new ConditionObject(); }
50 +        
51          public void lock() {
52 <            sync.acquireExclusiveUninterruptibly(1);
52 >            acquireExclusiveUninterruptibly(1);
53          }
54 <        public void lockInterruptibly() throws InterruptedException {
55 <            sync.acquireExclusiveInterruptibly(1);
54 >
55 >    }
56 >
57 >    
58 >    /**
59 >     * A simple latch class, to test shared mode.
60 >     */
61 >    static class BooleanLatch extends AbstractQueuedSynchronizer {
62 >        public boolean isSignalled() { return getState() != 0; }
63 >
64 >        public int tryAcquireShared(int ignore) {
65 >            return isSignalled()? 1 : -1;
66          }
67 <        public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
68 <            return sync.acquireExclusiveTimed(1, unit.toNanos(timeout));
67 >        
68 >        public boolean tryReleaseShared(int ignore) {
69 >            setState(1);
70 >            return true;
71          }
68        public void unlock() { sync.releaseExclusive(1); }
69        public Condition newCondition() { return sync.newCondition(); }
70        public boolean isLocked() { return sync.get() != 0; }
71        public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); }
72      }
73  
74      /**
75 <     * A runnable calling lockInterruptibly
75 >     * A runnable calling acquireExclusiveInterruptibly
76       */
77      class InterruptibleLockRunnable implements Runnable {
78          final Mutex lock;
79          InterruptibleLockRunnable(Mutex l) { lock = l; }
80          public void run() {
81              try {
82 <                lock.lockInterruptibly();
82 >                lock.acquireExclusiveInterruptibly(1);
83              } catch(InterruptedException success){}
84          }
85      }
86  
87  
88      /**
89 <     * A runnable calling lockInterruptibly that expects to be
89 >     * A runnable calling acquireExclusiveInterruptibly that expects to be
90       * interrupted
91       */
92      class InterruptedLockRunnable implements Runnable {
# Line 94 | Line 94 | public class AbstractQueuedSynchronizerT
94          InterruptedLockRunnable(Mutex l) { lock = l; }
95          public void run() {
96              try {
97 <                lock.lockInterruptibly();
97 >                lock.acquireExclusiveInterruptibly(1);
98                  threadShouldThrow();
99              } catch(InterruptedException success){}
100          }
101      }
102      
103      /**
104 <     * locking an unlocked lock succeeds
104 >     * acquireExclusiveUninterruptiblying an releaseExclusiveed lock succeeds
105       */
106 <    public void testLock() {
106 >    public void testAcquireExclusiveUninterruptibly() {
107          Mutex rl = new Mutex();
108 <        rl.lock();
108 >        rl.acquireExclusiveUninterruptibly(1);
109          assertTrue(rl.isLocked());
110 <        rl.unlock();
110 >        rl.releaseExclusive(1);
111      }
112  
113      /**
114 <     * tryLock on an unlocked lock succeeds
114 >     * tryAcquireExclusive on an releaseExclusiveed lock succeeds
115       */
116 <    public void testTryLock() {
116 >    public void testTryAcquireExclusive() {
117          Mutex rl = new Mutex();
118 <        assertTrue(rl.tryLock());
118 >        assertTrue(rl.tryAcquireExclusive(1));
119          assertTrue(rl.isLocked());
120 <        rl.unlock();
120 >        rl.releaseExclusive(1);
121      }
122  
123      /**
# Line 129 | Line 129 | public class AbstractQueuedSynchronizerT
129          Thread t2 = new Thread(new InterruptibleLockRunnable(lock));
130          try {
131              assertFalse(lock.hasQueuedThreads());
132 <            lock.lock();
132 >            lock.acquireExclusiveUninterruptibly(1);
133              t1.start();
134              Thread.sleep(SHORT_DELAY_MS);
135              assertTrue(lock.hasQueuedThreads());
# Line 139 | Line 139 | public class AbstractQueuedSynchronizerT
139              t1.interrupt();
140              Thread.sleep(SHORT_DELAY_MS);
141              assertTrue(lock.hasQueuedThreads());
142 <            lock.unlock();
142 >            lock.releaseExclusive(1);
143              Thread.sleep(SHORT_DELAY_MS);
144              assertFalse(lock.hasQueuedThreads());
145              t1.join();
# Line 150 | Line 150 | public class AbstractQueuedSynchronizerT
150      }
151  
152      /**
153 <     * timed tryLock is interruptible.
153 >     * isQueued(null) throws NPE
154 >     */
155 >    public void testIsQueuedNPE() {
156 >        final Mutex lock = new Mutex();
157 >        try {
158 >            lock.isQueued(null);
159 >            shouldThrow();
160 >        } catch (NullPointerException success) {
161 >        }
162 >    }
163 >
164 >    /**
165 >     * isQueued reports whether a thread is queued.
166 >     */
167 >    public void testIsQueued() {
168 >        final Mutex lock = new Mutex();
169 >        Thread t1 = new Thread(new InterruptedLockRunnable(lock));
170 >        Thread t2 = new Thread(new InterruptibleLockRunnable(lock));
171 >        try {
172 >            assertFalse(lock.isQueued(t1));
173 >            assertFalse(lock.isQueued(t2));
174 >            lock.acquireExclusiveUninterruptibly(1);
175 >            t1.start();
176 >            Thread.sleep(SHORT_DELAY_MS);
177 >            assertTrue(lock.isQueued(t1));
178 >            t2.start();
179 >            Thread.sleep(SHORT_DELAY_MS);
180 >            assertTrue(lock.isQueued(t1));
181 >            assertTrue(lock.isQueued(t2));
182 >            t1.interrupt();
183 >            Thread.sleep(SHORT_DELAY_MS);
184 >            assertFalse(lock.isQueued(t1));
185 >            assertTrue(lock.isQueued(t2));
186 >            lock.releaseExclusive(1);
187 >            Thread.sleep(SHORT_DELAY_MS);
188 >            assertFalse(lock.isQueued(t1));
189 >            assertFalse(lock.isQueued(t2));
190 >            t1.join();
191 >            t2.join();
192 >        } catch(Exception e){
193 >            unexpectedException();
194 >        }
195 >    }
196 >
197 >    /**
198 >     * getFirstQueuedThread returns first waiting thread or null is none
199 >     */
200 >    public void testGetFirstQueuedThread() {
201 >        final Mutex lock = new Mutex();
202 >        Thread t1 = new Thread(new InterruptedLockRunnable(lock));
203 >        Thread t2 = new Thread(new InterruptibleLockRunnable(lock));
204 >        try {
205 >            assertNull(lock.getFirstQueuedThread());
206 >            lock.acquireExclusiveUninterruptibly(1);
207 >            t1.start();
208 >            Thread.sleep(SHORT_DELAY_MS);
209 >            assertEquals(t1, lock.getFirstQueuedThread());
210 >            t2.start();
211 >            Thread.sleep(SHORT_DELAY_MS);
212 >            assertEquals(t1, lock.getFirstQueuedThread());
213 >            t1.interrupt();
214 >            Thread.sleep(SHORT_DELAY_MS);
215 >            assertEquals(t2, lock.getFirstQueuedThread());
216 >            lock.releaseExclusive(1);
217 >            Thread.sleep(SHORT_DELAY_MS);
218 >            assertNull(lock.getFirstQueuedThread());
219 >            t1.join();
220 >            t2.join();
221 >        } catch(Exception e){
222 >            unexpectedException();
223 >        }
224 >    }
225 >
226 >
227 >    /**
228 >     * hasContended reports false if no thread has ever blocked, else true
229 >     */
230 >    public void testHasContended() {
231 >        final Mutex lock = new Mutex();
232 >        Thread t1 = new Thread(new InterruptedLockRunnable(lock));
233 >        Thread t2 = new Thread(new InterruptibleLockRunnable(lock));
234 >        try {
235 >            assertFalse(lock.hasContended());
236 >            lock.acquireExclusiveUninterruptibly(1);
237 >            t1.start();
238 >            Thread.sleep(SHORT_DELAY_MS);
239 >            assertTrue(lock.hasContended());
240 >            t2.start();
241 >            Thread.sleep(SHORT_DELAY_MS);
242 >            assertTrue(lock.hasContended());
243 >            t1.interrupt();
244 >            Thread.sleep(SHORT_DELAY_MS);
245 >            assertTrue(lock.hasContended());
246 >            lock.releaseExclusive(1);
247 >            Thread.sleep(SHORT_DELAY_MS);
248 >            assertTrue(lock.hasContended());
249 >            t1.join();
250 >            t2.join();
251 >        } catch(Exception e){
252 >            unexpectedException();
253 >        }
254 >    }
255 >
256 >    /**
257 >     * acquireExclusiveNanos is interruptible.
258       */
259      public void testInterruptedException2() {
260          final Mutex lock = new Mutex();
261 <        lock.lock();
261 >        lock.acquireExclusiveUninterruptibly(1);
262          Thread t = new Thread(new Runnable() {
263                  public void run() {
264                      try {
265 <                        lock.tryLock(MEDIUM_DELAY_MS,TimeUnit.MILLISECONDS);
265 >                        lock.acquireExclusiveNanos(1, MEDIUM_DELAY_MS * 1000 * 1000);
266                          threadShouldThrow();
267                      } catch(InterruptedException success){}
268                  }
# Line 173 | Line 277 | public class AbstractQueuedSynchronizerT
277  
278  
279      /**
280 <     * TryLock on a locked lock fails
280 >     * TryAcquireExclusive on a locked lock fails
281       */
282 <    public void testTryLockWhenLocked() {
282 >    public void testTryAcquireExclusiveWhenLocked() {
283          final Mutex lock = new Mutex();
284 <        lock.lock();
284 >        lock.acquireExclusiveUninterruptibly(1);
285          Thread t = new Thread(new Runnable() {
286                  public void run() {
287 <                    threadAssertFalse(lock.tryLock());
287 >                    threadAssertFalse(lock.tryAcquireExclusive(1));
288                  }
289              });
290          try {
291              t.start();
292              t.join();
293 <            lock.unlock();
293 >            lock.releaseExclusive(1);
294          } catch(Exception e){
295              unexpectedException();
296          }
297      }
298  
299      /**
300 <     * Timed tryLock on a locked lock times out
300 >     * acquireExclusiveNanos on a locked lock times out
301       */
302 <    public void testTryLock_Timeout() {
302 >    public void testAcquireExclusiveNanos_Timeout() {
303          final Mutex lock = new Mutex();
304 <        lock.lock();
304 >        lock.acquireExclusiveUninterruptibly(1);
305          Thread t = new Thread(new Runnable() {
306                  public void run() {
307                      try {
308 <                        threadAssertFalse(lock.tryLock(1, TimeUnit.MILLISECONDS));
308 >                        threadAssertFalse(lock.acquireExclusiveNanos(1, 1000 * 1000));
309                      } catch (Exception ex) {
310                          threadUnexpectedException();
311                      }
# Line 210 | Line 314 | public class AbstractQueuedSynchronizerT
314          try {
315              t.start();
316              t.join();
317 <            lock.unlock();
317 >            lock.releaseExclusive(1);
318          } catch(Exception e){
319              unexpectedException();
320          }
# Line 218 | Line 322 | public class AbstractQueuedSynchronizerT
322      
323    
324      /**
325 <     * isLocked is true when locked and false when not
325 >     * getState is true when acquired and false when not
326       */
327 <    public void testIsLocked() {
327 >    public void testGetState() {
328          final Mutex lock = new Mutex();
329 <        lock.lock();
329 >        lock.acquireExclusiveUninterruptibly(1);
330          assertTrue(lock.isLocked());
331 <        lock.unlock();
331 >        lock.releaseExclusive(1);
332          assertFalse(lock.isLocked());
333          Thread t = new Thread(new Runnable() {
334                  public void run() {
335 <                    lock.lock();
335 >                    lock.acquireExclusiveUninterruptibly(1);
336                      try {
337                          Thread.sleep(SMALL_DELAY_MS);
338                      }
339                      catch(Exception e) {
340                          threadUnexpectedException();
341                      }
342 <                    lock.unlock();
342 >                    lock.releaseExclusive(1);
343                  }
344              });
345          try {
# Line 251 | Line 355 | public class AbstractQueuedSynchronizerT
355  
356  
357      /**
358 <     * lockInterruptibly is interruptible.
358 >     * acquireExclusiveInterruptibly is interruptible.
359       */
360 <    public void testLockInterruptibly1() {
360 >    public void testAcquireInterruptibly1() {
361          final Mutex lock = new Mutex();
362 <        lock.lock();
362 >        lock.acquireExclusiveUninterruptibly(1);
363          Thread t = new Thread(new InterruptedLockRunnable(lock));
364          try {
365              t.start();
366              t.interrupt();
367 <            lock.unlock();
367 >            lock.releaseExclusive(1);
368              t.join();
369          } catch(Exception e){
370              unexpectedException();
# Line 268 | Line 372 | public class AbstractQueuedSynchronizerT
372      }
373  
374      /**
375 <     * lockInterruptibly succeeds when unlocked, else is interruptible
375 >     * acquireExclusiveInterruptibly succeeds when released, else is interruptible
376       */
377 <    public void testLockInterruptibly2() {
377 >    public void testAcquireInterruptibly2() {
378          final Mutex lock = new Mutex();
379          try {
380 <            lock.lockInterruptibly();
380 >            lock.acquireExclusiveInterruptibly(1);
381          } catch(Exception e) {
382              unexpectedException();
383          }
# Line 289 | Line 393 | public class AbstractQueuedSynchronizerT
393      }
394  
395      /**
396 +     * owns is true for a condition created by lock else false
397 +     */
398 +    public void testOwns() {
399 +        final Mutex lock = new Mutex();
400 +        final AbstractQueuedSynchronizer.ConditionObject c = lock.newCondition();
401 +        final Mutex lock2 = new Mutex();
402 +        assertTrue(lock.owns(c));
403 +        assertFalse(lock2.owns(c));
404 +    }
405 +
406 +    /**
407       * Calling await without holding lock throws IllegalMonitorStateException
408       */
409      public void testAwait_IllegalMonitor() {
# Line 329 | Line 444 | public class AbstractQueuedSynchronizerT
444          final Mutex lock = new Mutex();
445          final Condition c = lock.newCondition();
446          try {
447 <            lock.lock();
447 >            lock.acquireExclusiveUninterruptibly(1);
448              long t = c.awaitNanos(100);
449              assertTrue(t <= 0);
450 <            lock.unlock();
450 >            lock.releaseExclusive(1);
451          }
452          catch (Exception ex) {
453              unexpectedException();
# Line 346 | Line 461 | public class AbstractQueuedSynchronizerT
461          final Mutex lock = new Mutex();
462          final Condition c = lock.newCondition();
463          try {
464 <            lock.lock();
464 >            lock.acquireExclusiveUninterruptibly(1);
465              assertFalse(c.await(SHORT_DELAY_MS, TimeUnit.MILLISECONDS));
466 <            lock.unlock();
466 >            lock.releaseExclusive(1);
467          }
468          catch (Exception ex) {
469              unexpectedException();
# Line 362 | Line 477 | public class AbstractQueuedSynchronizerT
477          final Mutex lock = new Mutex();
478          final Condition c = lock.newCondition();
479          try {
480 <            lock.lock();
480 >            lock.acquireExclusiveUninterruptibly(1);
481              java.util.Date d = new java.util.Date();
482              assertFalse(c.awaitUntil(new java.util.Date(d.getTime() + 10)));
483 <            lock.unlock();
483 >            lock.releaseExclusive(1);
484          }
485          catch (Exception ex) {
486              unexpectedException();
# Line 381 | Line 496 | public class AbstractQueuedSynchronizerT
496          Thread t = new Thread(new Runnable() {
497                  public void run() {
498                      try {
499 <                        lock.lock();
499 >                        lock.acquireExclusiveUninterruptibly(1);
500                          c.await();
501 <                        lock.unlock();
501 >                        lock.releaseExclusive(1);
502                      }
503                      catch(InterruptedException e) {
504                          threadUnexpectedException();
# Line 394 | Line 509 | public class AbstractQueuedSynchronizerT
509          try {
510              t.start();
511              Thread.sleep(SHORT_DELAY_MS);
512 <            lock.lock();
512 >            lock.acquireExclusiveUninterruptibly(1);
513              c.signal();
514 <            lock.unlock();
514 >            lock.releaseExclusive(1);
515              t.join(SHORT_DELAY_MS);
516              assertFalse(t.isAlive());
517          }
# Line 404 | Line 519 | public class AbstractQueuedSynchronizerT
519              unexpectedException();
520          }
521      }
522 +
523 +
524 +    /**
525 +     * Latch isSignalled initially returns false, then true after release
526 +     */
527 +    public void testLatchIsSignalled() {
528 +        final BooleanLatch l = new BooleanLatch();
529 +        assertFalse(l.isSignalled());
530 +        l.releaseShared(0);
531 +        assertTrue(l.isSignalled());
532 +    }
533 +
534 +    /**
535 +     * release and has no effect when already signalled
536 +     */
537 +    public void testReleaseShared() {
538 +        final BooleanLatch l = new BooleanLatch();
539 +        assertFalse(l.isSignalled());
540 +        l.releaseShared(0);
541 +        assertTrue(l.isSignalled());
542 +        l.releaseShared(0);
543 +        assertTrue(l.isSignalled());
544 +    }
545 +
546 +    /**
547 +     * acquireSharedInterruptibly returns after release, but not before
548 +     */
549 +    public void testAcquireSharedInterruptibly() {
550 +        final BooleanLatch l = new BooleanLatch();
551 +
552 +        Thread t = new Thread(new Runnable() {
553 +                public void run() {
554 +                    try {
555 +                        threadAssertFalse(l.isSignalled());
556 +                        l.acquireSharedInterruptibly(0);
557 +                        threadAssertTrue(l.isSignalled());
558 +                    } catch(InterruptedException e){
559 +                        threadUnexpectedException();
560 +                    }
561 +                }
562 +            });
563 +        try {
564 +            t.start();
565 +            assertFalse(l.isSignalled());
566 +            Thread.sleep(SHORT_DELAY_MS);
567 +            l.releaseShared(0);
568 +            assertTrue(l.isSignalled());
569 +            t.join();
570 +        } catch (InterruptedException e){
571 +            unexpectedException();
572 +        }
573 +    }
574 +    
575 +
576 +    /**
577 +     * acquireSharedTimed returns after release
578 +     */
579 +    public void testAsquireSharedTimed() {
580 +        final BooleanLatch l = new BooleanLatch();
581 +
582 +        Thread t = new Thread(new Runnable() {
583 +                public void run() {
584 +                    try {
585 +                        threadAssertFalse(l.isSignalled());
586 +                        threadAssertTrue(l.acquireSharedNanos(0, MEDIUM_DELAY_MS* 1000 * 1000));
587 +                        threadAssertTrue(l.isSignalled());
588 +
589 +                    } catch(InterruptedException e){
590 +                        threadUnexpectedException();
591 +                    }
592 +                }
593 +            });
594 +        try {
595 +            t.start();
596 +            assertFalse(l.isSignalled());
597 +            Thread.sleep(SHORT_DELAY_MS);
598 +            l.releaseShared(0);
599 +            assertTrue(l.isSignalled());
600 +            t.join();
601 +        } catch (InterruptedException e){
602 +            unexpectedException();
603 +        }
604 +    }
605 +    
606 +    /**
607 +     * acquireSharedInterruptibly throws IE if interrupted before released
608 +     */
609 +    public void testAcquireSharedInterruptibly_InterruptedException() {
610 +        final BooleanLatch l = new BooleanLatch();
611 +        Thread t = new Thread(new Runnable() {
612 +                public void run() {
613 +                    try {
614 +                        threadAssertFalse(l.isSignalled());
615 +                        l.acquireSharedInterruptibly(0);
616 +                        threadShouldThrow();
617 +                    } catch(InterruptedException success){}
618 +                }
619 +            });
620 +        t.start();
621 +        try {
622 +            assertFalse(l.isSignalled());
623 +            t.interrupt();
624 +            t.join();
625 +        } catch (InterruptedException e){
626 +            unexpectedException();
627 +        }
628 +    }
629 +
630 +    /**
631 +     * acquireSharedTimed throws IE if interrupted before released
632 +     */
633 +    public void testAcquireSharedNanos_InterruptedException() {
634 +        final BooleanLatch l = new BooleanLatch();
635 +        Thread t = new Thread(new Runnable() {
636 +                public void run() {
637 +                    try {
638 +                        threadAssertFalse(l.isSignalled());
639 +                        l.acquireSharedNanos(0, SMALL_DELAY_MS* 1000 * 1000);
640 +                        threadShouldThrow();                        
641 +                    } catch(InterruptedException success){}
642 +                }
643 +            });
644 +        t.start();
645 +        try {
646 +            Thread.sleep(SHORT_DELAY_MS);
647 +            assertFalse(l.isSignalled());
648 +            t.interrupt();
649 +            t.join();
650 +        } catch (InterruptedException e){
651 +            unexpectedException();
652 +        }
653 +    }
654 +
655 +    /**
656 +     * acquireSharedTimed times out if not released before timeout
657 +     */
658 +    public void testAcquireSharedNanos_Timeout() {
659 +        final BooleanLatch l = new BooleanLatch();
660 +        Thread t = new Thread(new Runnable() {
661 +                public void run() {
662 +                    try {
663 +                        threadAssertFalse(l.isSignalled());
664 +                        threadAssertFalse(l.acquireSharedNanos(0, SMALL_DELAY_MS* 1000 * 1000));
665 +                    } catch(InterruptedException ie){
666 +                        threadUnexpectedException();
667 +                    }
668 +                }
669 +            });
670 +        t.start();
671 +        try {
672 +            Thread.sleep(SHORT_DELAY_MS);
673 +            assertFalse(l.isSignalled());
674 +            t.join();
675 +        } catch (InterruptedException e){
676 +            unexpectedException();
677 +        }
678 +    }
679      
680   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines