Home > database >  wait for all jobs in a ScheduledExecutorService to finish, while allowing new jobs to be added
wait for all jobs in a ScheduledExecutorService to finish, while allowing new jobs to be added

Time:06-19

I am using a ScheduledExecutorService to schedule and process jobs across several threads. In my application, a job can schedule a new job (on the same ScheduledExecutorService), as some kind of follow-up action.

In the main thread, I want to wait until all jobs are finished, as a synchronization point. There are the shutdown() and awaitTermination() methods, but this disallows any running or pending job to schedule a new job. In my case, I actually want to allow this, accepting the risk that we will never finish (or hit some timeout).

How do I wait for all jobs and possibly their follow-up jobs to finish?

CodePudding user response:

It's possible by keeping track of the number of active jobs. Effectively, each job that you submit must be wrapped as follows (pseudo code):

increase active jobs by one
try {
    run actual job
} finally {
    decrease active jobs by one
}

Of course the ScheduledExecutorService needs to be fully encapsulated for this to work.

The next step is to find the right concurrent mechanism for this, that doesn't introduce any busy waiting.

A quick and dirty attempt using a Lock with a Condition that signals no more jobs:

private final Lock lock = new ReentrantLock();
private final Condition noJobs = lock.newCondition();

private long jobCount = 0;

private void increaseJobCount() {
    lock.lock();
    try {
        jobCount  ;
    } finally {
        lock.unlock();
    }
}

private void decreaseJobCount() {
    lock.lock();
    try {
        jobCount--;
        if (jobCount == 0) {
            noJobs.signalAll();
        }
    } finally {
        lock.unlock();
    }
}

public void awaitNoJobs() throws InterruptedException {
    lock.lock();
    try {
        while (jobCount > 0) {
            noJobs.await();
        }
    } finally {
        lock.unlock();
    }
}

I checked some other known concurrent classes, but apart from a BlockingQueue / BlockingDeque I couldn't find any. Those take up more memory though, as you'd have to add and remove something for each job that's submitted. A CountDownLatch comes close but doesn't allow increasing the count.

  • Related