Explicit memory model - ahead of guarantees for thread pool interoperability

Is a Java memory model provided before guaranteeing pool thread interoperability? In particular, will the entries of the pool thread workflows until the end of the item start from the work queue be visible to the work thread starting the next item from the queue after this?

The specification (I personally find this FAQ useful: http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#synchronization ) states that the "start () call in the thread happens earlier any actions in the running thread. " or just put, any memory entries you made before starting the thread will be executed before and visible to the run () method, which will start the initial thread. For a thread pool, it differs from another, start () usually starts before you record. Consider a simple workflow in which a context object is mutated and passed to the following 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 writing to sharedObject.value on write.run() guaranteed visibility (without asking for ordering, this is obvious) to read.run() ?

(PS: I understand that creating value volatile provides this guarantee)

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

+6
source share
2 answers

I think this is guaranteed to be visible. ExecutorService extends Executor , and javadocs for Executor says:

Memory Consistency Effects: Actions in a thread before sending the Runnable Executor object are executed before it starts, possibly in another thread.

As far as I understand, this is consistent with what happens in your example. The write object passes a read accessible stream, so there is a connection between the event and the event between events before being sent to the write stream (i.e., the call to set ) and events in the read stream (i.e., the call to get ).

The fact that the write object is passed by itself means that a preview also occurs between the creation of the Container and the call to set .

+6
source

Quoting javadoc ExecutorService :

Memory consistency effects: Actions in the thread before sending the Runnable or Callable to the ExecutorService occur before any actions taken by this task, which in turn occurs - until the result is received via Future.get() .

But it does not say anything about the two tasks added to the queue, and whether the processing of task 1 is in progress before processing task 2, as can be seen from the task. It’s just that the task is added to the queue before the task is processed, and the task is completed before the result is received by the initial call.

Update

It doesn’t happen - until the correlation between two different independently assigned tasks, even if it is known that the launch is completed before the other starts working.

Of course, when one task sends another, as is done in the question, any action taken in task 1 before sending task 2 will occur before task 2 is completed.

If task 1 continues to do other things after sending task 2, then of course nothing happens - before the guarantee, because task 2 can be completed and completed before task 1 continues to work.

+2
source

All Articles