Harish
Harish

Reputation: 495

Memory visibility guarantees with ThreadPoolExecutor.execute()

If you execute a Runnable with a ThreadPoolExecutor, and if this Runnable modifies some shared state, is there any guarantee as to whether these changes to the shared state will be visible in the original thread that submitted the runnable to the pool? Assume there's only 1 writer to shared state and 1 reader. I know that when you use the ExecutorService which returns a Future, doing a Future.get() will guarantee visibility.


class State {
    private int x;
    public State(int y) { x = y; }
    public void setX(int y) { x = y; }
    public int getX() { return x; }
}

main() {
    threadPool = new ThreadPoolExecutor(8, 16, 100, TimeUnit.SECONDS, new ArrayBlockingQueue(...))

    final State myState = new State(1);

    threadPool.execute(new Runnable() {
        public void run() {
            myState.setX(50);
        }
    });

    while (true) {
        if (myState.getX() == 50) {
             break;
        }
        sleep();
    } // would this loop terminate?
}

Upvotes: 2

Views: 556

Answers (2)

David Schwartz
David Schwartz

Reputation: 182819

Pretty much any sane way to detect that the thread has finished its work (other than volatile which only synchronizes that one variable) will also guarantee a synchronized view of memory. Your example has no way to be sure the thread has finished, so it obviously won't work. C# doesn't provide any particular timeliness guarantees, so you can't use sleep as a form of sychronization.

Upvotes: 1

aroth
aroth

Reputation: 54836

It depends, there is no implicit guarantee that the change in state will be immediately reflected in the original thread, primarily because the original thread may have a cached copy of the value of x that will not be updated when another thread changes the value of x in main memory.

You can work around this by adding an explicit guarantee using the volatile keyword, like:

class State {
    private volatile int x;
    public State(int y) { x = y; }
    public void setX(int y) { x = y; }
    public int getX() { return x; }
}

This tells the compiler that it cannot cache the value of x, and that every time the program reads x it must check the value that is in main memory. This will cause the original thread to see the new value of x as soon as any other thread modifies it.

More details here:

http://www.javamex.com/tutorials/synchronization_volatile.shtml

Upvotes: 5

Related Questions