@Test
  public void testReuseLatch() throws Exception {
    final ReusableLatch latch = new ReusableLatch(5);
    for (int i = 0; i < 5; i++) {
      latch.countDown();
    }

    latch.countUp();

    class ThreadWait extends Thread {
      private volatile boolean waiting = false;

      private volatile Exception e;

      private final CountDownLatch readyLatch = new CountDownLatch(1);

      @Override
      public void run() {
        waiting = true;
        readyLatch.countDown();
        try {
          if (!latch.await(1000)) {
            UnitTestLogger.LOGGER.error("Latch timed out!", new Exception("trace"));
          }
        } catch (Exception e) {
          UnitTestLogger.LOGGER.error(e);
          this.e = e;
        }
        waiting = false;
      }
    }

    ThreadWait t = new ThreadWait();
    t.start();

    t.readyLatch.await();

    Assert.assertEquals(true, t.waiting);

    latch.countDown();

    t.join();

    Assert.assertEquals(false, t.waiting);

    Assert.assertNull(t.e);

    latch.countUp();

    t = new ThreadWait();
    t.start();

    t.readyLatch.await();

    Assert.assertEquals(true, t.waiting);

    latch.countDown();

    t.join();

    Assert.assertEquals(false, t.waiting);

    Assert.assertNull(t.e);

    Assert.assertTrue(latch.await(1000));

    Assert.assertEquals(0, latch.getCount());

    latch.countDown();

    Assert.assertEquals(0, latch.getCount());
  }