public class BlockedThreadPoolExecutor extends ThreadPoolExecutor { private final Semaphore semaphore; public BlockedThreadPoolExecutor(int poolSize) { super(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<>()); semaphore = new Semaphore(poolSize); } @Override public void execute(Runnable command) { try { semaphore.acquire(); super.execute(command); } catch (InterruptedException e) { e.printStackTrace(); } } @Override protected void afterExecute(Runnable r, Throwable t) { super.afterExecute(r, t); semaphore.release(); } }