PermitQueue { @SuppressWarnings("unchecked") public <RESP> CompletableFuture<RESP> runRequest(Supplier<CompletableFuture<RESP>> processor) { long countId = counter.getAndIncrement(); long time = System.currentTimeMillis(); CompletableFuture<RESP> future = new CompletableFuture<RESP>(); queue.add(new QueuedRequest<RESP>(future, processor, time)); QueuedRequest<RESP> item = (QueuedRequest<RESP>) queue.peek(); if(item != null) { long timeQueued = item.getTimeQueued(); long timeDelayed = time - timeQueued; if(timeDelayed > timeMsWarning) log.warn("id:"+logId+countId+" Your PermitQueue/Lock has the first item in the queue waiting "+timeDelayed+"ms so you may have deadlock or just a very contentious lock(you probably should look into this)"); if(backupSize() > queuedBackupWarnThreshold) log.warn("id:"+logId+countId+" Your lock is backing up with requests. either too much contention or deadlock occurred(either way, you should fix this)"); } processItemFromQueue(); return future; } PermitQueue(int numPermits);  PermitQueue(String logId, int numPermits, int timeMsWarning, int queuedBackupWarnThreshold); @SuppressWarnings("unchecked") CompletableFuture<RESP> runRequest(Supplier<CompletableFuture<RESP>> processor); int totalPermits(); int availablePermits(); void releasePermit(); void modifyPermitPoolSize(int permitCnt); int backupSize();  }
@Test public void testFuturePermitQueue() throws InterruptedException { CompletableFuture<Long> future1 = new CompletableFuture<Long>(); svc.addToReturn(future1); CompletableFuture<Long> future2 = new CompletableFuture<Long>(); svc.addToReturn(future2); CompletableFuture<Long> future3 = new CompletableFuture<Long>(); svc.addToReturn(future3); queue2.runRequest(() -> svc.runFunction(1)); queue2.runRequest(() -> svc.runFunction(2)); queue2.runRequest(() -> svc.runFunction(3)); List<Integer> results = svc.getAndClear(); Assert.assertEquals(1,results.size()); Assert.assertEquals(1, results.get(0).intValue()); future1.complete(3L); List<Integer> results2 = svc.getAndClear(); Assert.assertEquals(1,results2.size()); Assert.assertEquals(2, results2.get(0).intValue()); }