/** * Test that no more than 1 task runs at a time when using a {@link WithinThreadExecutor}. */ public void testConcurrencyLimitWithinThread() throws Exception { LimitedExecutor limitedExecutor = new LimitedExecutor(NAME, new WithinThreadExecutor(), 1); CompletableFuture<String> blocker1 = new CompletableFuture<>(); CompletableFuture<String> blocker2 = new CompletableFuture<>(); CompletableFuture<String> cf1 = new CompletableFuture<>(); // execute() will block Future<?> fork1 = fork(() -> { limitedExecutor.execute(() -> { blocker2.complete("blocking"); try { cf1.complete(blocker1.get(10, SECONDS)); } catch (Exception e) { cf1.completeExceptionally(e); } }); }); assertEquals("blocking", blocker2.get(10, SECONDS)); verifyTaskIsBlocked(limitedExecutor, blocker1, cf1); fork1.get(10, SECONDS); }
private void verifyTaskIsBlocked(LimitedExecutor limitedExecutor, CompletableFuture<String> blocker1, CompletableFuture<String> cf1) throws Exception { CompletableFuture<String> blocker2 = new CompletableFuture<>(); CompletableFuture<String> cf2 = new CompletableFuture<>(); // execute() may block Future<?> fork2 = fork(() -> { limitedExecutor.execute(() -> { try { cf2.complete(cf1.getNow("task 2 ran too early") + " " + blocker2.get(10, SECONDS)); } catch (Exception e) { cf2.completeExceptionally(e); } }); }); assertFalse(cf1.isDone()); assertFalse(cf2.isDone()); blocker1.complete("value1"); assertEquals("value1", cf1.get(10, SECONDS)); assertFalse(cf2.isDone()); blocker2.complete("value2"); assertEquals("value1 value2", cf2.get(10, SECONDS)); fork2.get(10, SECONDS); eventuallyEquals(0, executor::getActiveCount); } }