void (String msg) { long start = System.currentTimeMillis(); while (true) { List<Thread> alive = Thread.getAllStackTraces().keySet().stream() .filter(thread -> thread.getName().startsWith(AppScheduledExecutorService.POOLED_THREAD_PREFIX)) .filter(thread -> thread.getState() == Thread.State.RUNNABLE) .filter(thread -> thread.getStackTrace().length != 0) // there can be RUNNABLE zombies with empty stacktrace .toList(); long finish = System.currentTimeMillis(); if (alive.isEmpty()) break; if (finish-start > 10000) { System.err.println(ThreadDumper.dumpThreadsToString()); throw new RuntimeException(msg+alive.size() +" threads are still alive: "+alive); } } }