Variable assignment visibility in Java

I recently argued with a friend over code like this:

import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * See memory consistency effects in a Java Executor. */ public class PrivateFieldInEnclosing { private long value; PrivateFieldInEnclosing() {} void execute() { value = initializeValue(); ExecutorService executor = Executors.newCachedThreadPool(); executor.submit(new Y()); } class Y implements Runnable { @Override public void run() { System.out.println(value); } } private long initializeValue() { return 20; } public static void main(String[] args) { new PrivateFieldInEnclosing().execute(); } } 

I argued that it is possible that value can be considered as 0 in Y , because there is no guarantee that the assignment value = initializeValue() will be visible in the threads of the executors. I said that it needs to make value mutable field.

He contradicted me and said that since this is a private instance field with the value assigned before the stream was created, then this value is visible.

I looked through https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4 , but I could not say what I could use to support my application. Can someone help me? Thanks!

+8
java multithreading concurrency
source share
2 answers

It doesn't matter if it is private or not. What matters:

Effects of a memory sequence: actions in a stream before sending A predictable object for the Contractor - before it is launched, possibly in another stream.

From Documents Executor . This means that everything you do before the submit call is visible in runnable. You could even do this after creating the executor, and in this particular case it doesn't even matter when the executing thread actually starts, because the submit method provides a very strong guarantee on its own.

This is one of the features that make the java.util.concurrent package very useful.

+9
source share

Your friend will be right. IF the variable is initialized before calling Thread.start programmatically, according to JLS 17.4.5 this will happen - before Thread.start . The start of the stream also occurs before the first action in the stream. Therefore, this also happens - before calling doStuffWithValue .

This special case cannot be covered only by JLS due to the use of Executor : you do not know when it calls Thread.start for the threads that it uses. But from here you can read that the call to submit gives you the same guarantee as Thread.start : Actions in the thread before submitting Mileage to the executor - until it starts.

Since before-before is transitive, the variable is initialized - before doStuffWithValue . The bit about the variable, which is the private field of the instance, does not matter.

+1
source share

All Articles