Unstable for reference type. Does it always avoid posting link issues due to JMM?

Assuming this class:

public class AmIThreadSafe { private int a; private int b; AmIThreadSafe(int a, int b) { this.a = a; this.b = b; } } 

Assuming that an instance reference of this class (declared as volatile ) is available for some threads (resulting in a race condition), as soon as this (reference) escapes:

 volatile AmIThreadSafe instance = new AmIThreadSafe(1,2); 

Here I am sure that the fact of assigning an instance link occurs before reading through streams.

But what about AmIThreadSafe's fields?

Does the volatile external keyword match the happens-before relation with respect to fields a and b ? Or is it possible that eventually any thread will see stale values ​​(the default value is 0 in this case, since int ) due to a potential reordering operator during the constructor?

In other words, should you declare a and b final or volatile to prevent any surprises in JMM, or just pointing volatile on the reference link is enough?

---------------- UPDATED POST - GOOD ANSWER: ----------------- -----------

The following article confirms with its sample that, in my case, a and b are protected from JMM optimizations that prevent a constant relationship from happening until .

http://jeremymanson.blogspot.fr/2008/11/what-volatile-means-in-java.html

+6
source share
6 answers

Declaring instance as volatile does not create its volatile fields, but if I understood your question correctly, then yes, that's enough in your case.

Per & sect; 17.4.5 specifications :

  • a volatile written to one stream - before any subsequent volatile read in another stream. Operators
  • in one thread have the relationships you expect.
  • happens when the relationship is transitive.

So, if the stream perceives instance as initialized, then instance was initialized - before it and instance fields were initialized - before that, so the stream will perceive instance fields as initialized.

+4
source

There is not enough to make it unstable. However, thread safety is usage dependent. For example, this may lead to unexpected results if another thread changes values.

assuming public variables for simplicity

 volatile AmIThreadSafe instance = new AmIThreadSafe(1,2); if (instance.x == 0) { // instance.x might have changed between checking and assigning instance.x = instance.x + 1; } 

volatile applies only to a variable (for example, x and y are not automatically volatile just because instance is). This should be clear from JLS 8.3.1.4

+4
source

volatile in your case applies only to the AmlThreadSafe link. You still need to make instance variables ( a and b ) volatile or access them in a synchronized block. Otherwise, you may receive outdated data.

+2
source

Yes.

 thread 1 thread 2 1 write(a) 2 write(instance) 3 read(instance) 4 read(a) 

Since the instance is unstable, [2] happens before [3].

Since trans-trans is transitive, hb (1,2), hb (2,3), hb (3,4), therefore hb (1,4)

+2
source

If a and b changed only in the constructor, then in this case you should be fine, because the object is created (and a and b set). BEFORE the instance delivered, and any other threads will not have locally cached copies of memory in these places, because this is a new object that the thread has not seen before. In other words, I do not think it is possible that another thread will ever be able to see the default value of 0 for a and b , because the constructor will work completely before the object reference is assigned to instance .

However, if a and b can be changed after the constructor, then the other answers here are correct - you need synchronization around them.

If you assume that a and b will not be modified outside of the constructor, then there is no reason not to make them final anyway, just to be safe.

0
source

Example:

 class Something{ private volatile static Something instance = null; private int x; private int y; private Something(){ this.x = 1; this.y = 2; } public static Something getInstance() { if (instance == null) { synchronized (Something.class) { if (instance == null) instance = new Something(); } } } return instance; } } 

Explanation:


Let's say we have the code above:

Now suppose the instance is unstable for some time:

Theme number 1:
The getInstance method comes to invoke, checks the value of the {{zero} instance, enters the IF condition, Access Lock now again detects that the instance == null, calls the constructor something. Now it goes inside the body of the constructor.

As soon as Thread # 1 enters the body of the constructor, Context Switch occurs, and now Thread # 2 gets a move to execute.

Theme number 2:
Invokes get Instance, but suddenly discovers that the instance is not null? Why {Reason will be discussed only after this} and, therefore, assign a partially constructed object to the link and return it.

Now the situation is as follows: Thread # 1 You still need to build an Object Completely (you need to completely build it), and Thread # 2 got a link to a partially constructed Object, and if it uses it, like reference.x // will print "x "Default value, not" 1 "

Why is a partially constructed object reference returned in the case of Thread # 2? The reason is simple: Regulation of expressions . The steps are easy to create an object and a link:

  • Allocate memory in a heap.
  • Run the body of the constructor that initializes the members of the class.
  • Upon completion of the above Step, a link to the newly created object.

But sometimes the compiler can execute these instructions out of order , which means:
This could happen something like this:

  • Allocate memory in a heap.
  • Link to the newly created object.
  • Run the body of the constructor that initializes the members of the class.

As soon as the previous two steps have occurred, and if the context switch occurs, the link refers to an Object that is not initialized, or it may be that inside the context switch Body Constructor occurs when the link refers to a partially initialized object.

If such a scenario occurs, the link will be neither null nor complete, and therefore it will violate our Singleton motivation.

Now that Volatile will save our Life from such embarrassment:
As we know, volatile work with two principles: 1) Visibility 2) It happens before a relationship . Now happens before contact .

Thus, the reference is volatile Write, so all statements must be executed before any volatile write.Again. If we look at our stages of building an object:

  • Allocate memory for an object
  • Initialize member variables {constructor body}
  • Assign an object reference to an instance of a mutable variable.

Step 3 has Volatile Variable write and, as before. All message records are guaranteed to be available for step 3. And since it is unstable, therefore, permutations will not change between volatile and non-volatile operators, which was not in the Java memory model. Thus, before performing step 3, steps 1 and 2 are guaranteed to be performed and become available for step 3. {In what order are steps 1 and 2 performed, we don’t worry about that.}

So, from this stream you will see either a Completely created object or null

0
source

All Articles