AwaitableExecutorService extends ForwardingExecutorService { public final boolean await(Runnable... tasks) throws InterruptedException { return await((task, error) -> { throw CheckedExceptions.wrapAsRuntimeException(error); }, tasks); } AwaitableExecutorService(ExecutorService delegate); final boolean await(Runnable... tasks); final boolean await(BiConsumer<Runnable, Throwable> errorHandler,
            Runnable... tasks);  }
@Test public void testServiceDoesntPreventJVMShutdown() throws InterruptedException { service.await(new Runnable() { @Override public void run() { for (int i = 0; i < 100; i++) {} } }); }
@Test public void testCallingThreadIsBlockedUntilTaskCompletes() throws InterruptedException { long ts = Time.now(); service.await(new Runnable() { @Override public void run() { Threads.sleep(100); } }); long elapsed = Time.now() - ts; Assert.assertTrue(TimeUnit.MILLISECONDS.convert(elapsed, TimeUnit.MILLISECONDS) >= 100); }
@Test public void testCallingThreadIsBlockedUntilAllTaskCompletes() throws InterruptedException { long ts = Time.now(); service.await(new Runnable() { @Override public void run() { Threads.sleep(100); } }, new Runnable() { @Override public void run() { Threads.sleep(50); } }, new Runnable() { @Override public void run() { Threads.sleep(150); } }); long elapsed = Time.now() - ts; Assert.assertTrue(TimeUnit.MILLISECONDS.convert(elapsed, TimeUnit.MICROSECONDS) >= 150); Assert.assertTrue(TimeUnit.MILLISECONDS.convert(elapsed, TimeUnit.MICROSECONDS) <= 300); }
@Test public void testThreadIsNotAffectedByBlockingInAnotherThread() { final AtomicBoolean aDone = new AtomicBoolean(false); final AtomicBoolean aSelfDone = new AtomicBoolean(false); final AtomicBoolean bDone = new AtomicBoolean(false); Thread a = new Thread(new Runnable() { @Override public void run() { try { service.await(new Runnable() { @Override public void run() { while (!aDone.get()) { continue; } aSelfDone.set(true); } }); } catch (InterruptedException e) { throw CheckedExceptions.wrapAsRuntimeException(e); } } }); Thread b = new Thread(new Runnable() { @Override public void run() { try { service.await(new Runnable() { @Override public void run() { Threads.sleep(100); } }, new Runnable() { @Override public void run() { Threads.sleep(50); } }, new Runnable() { @Override public void run() { Threads.sleep(150); } }); } catch (InterruptedException e) { throw CheckedExceptions.wrapAsRuntimeException(e); } bDone.set(true); } }); a.start(); b.start(); Threads.sleep(300); Assert.assertTrue(bDone.get()); Assert.assertFalse(aSelfDone.get()); aDone.set(true); Threads.sleep(10); Assert.assertTrue(aSelfDone.get()); }