SpreadZhao
SpreadZhao

Reputation: 41

Java ThreadPoolExecutor: How can it ensure the state check in execute() method is safe?

Basic:

// this.a is a shared variable.
AtomicInteger a = this.a;
int x = a.get();

In a multi-threaded condition, we cannot ensure that x is 1 because some other thread may call something like a.getAndIncrement() just before we load the stored value in a to x, which cause the final result of x to be 2.

So, in ThreadPoolExecutor:

public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    int c = ctl.get();
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        if (!isRunning(recheck) && remove(command))
            reject(command);
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
    else if (!addWorker(command, false))
        reject(command);
}

in the recheck routine:

    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        if (!isRunning(recheck) && remove(command))
            reject(command);
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }

we read from AtomicInteger ctl and load it into recheck. But it also may be changed by other threads at any time. Is there some mechanism which make this recheck to be absolutely reliable? Or do we just need to consider most of the cases?

Below is the occurrence I've talked about which is less possible to happen:

    if (isRunning(c) && workQueue.offer(command)) {   // RUNNING
        int recheck = ctl.get();                      // RUNNING
        if (!isRunning(recheck) && remove(command))   // RUNNING
            reject(command);
        else if (workerCountOf(recheck) == 0)         // RUNNING and workerCount is 0
            // SHUTDOWN by other thread
            addWorker(null, false);                   // SO?
    }

My thought: ThreadPools can't be restarted, so the state transmation can't be SHUTDOWN -> RUNNING. The question then become: if we shutdown the pool while rechecking, and it failed to load the instant state into recheck, what will happen?

I noticed that when the Pool wants to add a new Worker, it will check the current state again and acquire the mainLock before adding the worker into workers. So:

Upvotes: 2

Views: 73

Answers (0)

Related Questions