ExecutorService等待当前所有任务完成

如果需要等待ExecutorService中所有的任务都执行完毕,一般的处理方法是:

ExecutorService es = Executors.newFixedThreadPool(10);
es.shutdown();
es.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS)//永远等待

但这个方法有个弊端,用了之后就不能再添加新的任务了,必须得重新初始化

如果在知道具体任务数量的情况下,还可以通过CountDownLatch(或者Semaphore)来实现。

但如果不知道当前任务数,又需要等待当前任务完成,也不想关闭ExecutorService的话,下面是一个可能的方法(适用于知道具体的线程数):

ExecutorService executorService = Executors.newFixedThreadPool(threadNum);

public void wait() throws Exception{
    Object lock = new Object();
    CountDownLatch cdl = new CountDownLatch(threadNum);
    for (int i = 0; i < threadNum; i++) {
        executorService.execute(() -> {

            synchronized (lock) {
                cdl.countDown();
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        });
    }
    cdl.await();
    synchronized (lock) {
        lock.notifyAll();
    }
}

原理是阻塞线程池的所有线程,当线程池所有线程都被阻塞的时候,也意味着以前的所有任务都已经被执行完毕了(新加入的任务不会被等待),此时主线程解除阻塞,唤醒线程池所有的线程

了解ThreadPoolExecutor会知道,任务的执行并不是FIFO的,那么会不会所有造成线程等待的任务在原来任务之前执行呢?看了下它的实现后,发现并不会:

如果通过 Executors.newFixedThreadPool(10)创建ExecutorService,那么它的默认队列是FIFO的,但并不意味着任务的执行顺序也是FIFO,ThreadPoolExecutor简化如下:

List<Worker> workers = new ArrayList<>(10);

for(Worker worker : workers){
    new Thread(worker).start();
}

class Worker implements Runnable{
    public void run(){
        Runnable task = workQueue.take();
        task.run();
    }
}

可能的逻辑如下:

Runnable firstTask = workQueue.take();  //thread1
Runnable secondTask = workQueue.take(); //thread2
secondTask.run(); //thread2
firstTask.run(); //thread1

因此,存在多个线程的情况下,无法保证当前的ExecutorService任务执行是FIFO的,但这并不会对我们的方法造成什么本质的影响,因为 后面的任务有可能比前面的任务先执行,但是如果后面的任务被执行到,前面的任务一定会被执行到

camunda 利用 Parallel Gateway实现会签
把你的项目发布到maven中央仓库(OSSRH)