简体   繁体   中英

Java Memory Model happens-before guarantees for Thread Pool interactions

Does Java Memory Model provide happens-before guarantee for Thread Pool interactions? In particular, will writes made by a thread pool worker thread before the end of running an item from a work queue be visible to a worker thread running the next item from the queue after that?

The specification (I personally find this FAQ useful: http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#synchronization ) states that " A call to start() on a thread happens before any actions in the started thread. " or simply put, any memory writes you make before starting a thread will be executed before and visible to the run() method the started thread is going to execute. It is different for a thread pool, the start() would normally run before you make a write. Consider a simple workflow where a context object is mutated and passed to the next action:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main {

    private static class Container<T> {
        private T value;
        public T get() {
            return value;
        }
        public void set(T newValue) {
            value = newValue;
        }
    }

    public static void main(String[] args) {
        final Container<Integer> sharedObject = new Container<>();
        final ExecutorService executor = Executors.newFixedThreadPool(10);
        // SKIPPED: pre-warm the executor so all worker threads are start()'ed
        final Runnable read = () -> System.out.println("Got " + sharedObject.get());
        Runnable write = () -> {
            sharedObject.set(35);
            executor.execute(read);
        };
        executor.execute(write);
        // SKIPPED: wait until done
    }
}

Is the write to sharedObject.value by write.run() guaranteed to be visible (not asking about ordering, this is obvious) to read.run() ?

(PS: I understand that making value volatile does provide this guarantee)

Update (complements the answer): Package summary documentation for java.util.concurrent summarizes memory consistency guarantees provided by the language and extended by the framework: https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/package-summary.html#MemoryVisibility

I think that it is guaranteed to be visible. ExecutorService extends Executor , and the javadocs for Executor say:

Memory consistency effects: Actions in a thread prior to submitting a Runnable object to an Executor happen-before its execution begins, perhaps in another thread.

By my reading, that matches what is going on in your example. The write runnable is submitting the read runnable, so there is a happens-before relationship between events before the submission in the write thread (ie the set call) and the events afterwards in the read thread (ie the get call).

The fact that the write runnable is itself submitted means that there is also a happens-before between the creation of the Container object and the call to set .

Quoting javadoc of ExecutorService :

Memory consistency effects: Actions in a thread prior to the submission of a Runnable or Callable task to an ExecutorService happen-before any actions taken by that task, which in turn happen-before the result is retrieved via Future.get() .

But, it says nothing about two tasks added to the queue, and whether processing of task 1 happens-before processing of task 2, as seen from the task. Only that adding the task to the queue happens before the task processing it, and the task execution happens before the result is retrieved by the original invoker.

Update

There is no happens-before correlation between two different, independently submitted tasks, even if somehow one is known the run to completion before the other begins running.

Of course, when one task submits another, as is done in the question, any action taken in task 1 before it submits task 2, will happen-before the execution of task 2.

If task 1 continues to do other stuff after submitting task 2, there is of course no happen-before guarantee, because task 2 may run and complete before task 1 gets to continue it's work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM