Does the volatile field prevent all memory visibility problems in a parallel situation?

Does the volatile class field prevent all memory visibility problems with it in a parallel situation? Is it possible that for a lower class, the thread that receives the Test object reference sees x as 0 first (the default value is int ) and then 10? I think this is possible if and only if the Test constructor returns this link without completion (incorrect publication). Can anyone confirm / correct me?

 class Test { volatile int x = 10; } 

Second question: what if it was final int x=10; ?

+6
source share
2 answers

In fact, you are not guaranteed to see x = 10 according to JMM.

For example, if you have

 Test test = null; Thread 1 -> test = new Test(); Thread 2 -> test.x == // even though test != null, x can be seen as 0 if the // write of x hasn't yet occur 

Now if you have

 class Test{ int y = 3; volatile x = 10; } 

If thread-2 reads x == 10, thread-2 is guaranteed to read y == 3

To answer the second question.

After the final field, you will get the repository after the constructor and before publishing, so the end of the field actually guarantees that you will see x = 10.

Edit: As noted by Ishavit. You lose the connection between the events that I mention in my first example with finite fields, i.e. as yshavit, put it if thread-2 reads x == 10, it might not read y == 3, where x is the final field.

+6
source

Even in a single-threaded implementation, you are not guaranteed the opportunity to see x = 10 if you miss this in the constructor. Thus, the problem you may encounter here is not directly related to the concurrency problem, but to the order in which the problem is executed (depending on when you proceed). For instance. if you skip this in the parent constructor for instace:

 public class TestParent { public TestParent() { if (this instanceof TestChild) { TestChild child = (TestChild) this; System.out.println(child.field); // will print 0 when TestChild is instantiated. } } } public class TestChild extends TestParent { volatile int field = 10; } public static void main(String[] args) { TestChild child = new TestChild(); System.out.println(child.field); // The above results in 0 (from TestParent constructor) then 10 being printed. } 

Final fields, on the other hand, are guaranteed to have an assigned initial value while this assignment is performed on the declaration line (if you make the field final, but initialize it in the constructor, then you can still skip it before and show the uninitialized value.

+3
source

Source: https://habr.com/ru/post/905360/


All Articles