Usually when we write a statement like Object o=new Object(); it is a three step process of CPU instruction
Let's see an example
When we write something like MyClass clazz=new MyClass();
The following steps should ideally happen as per our assumption
But the reordering of statements by compiler affects the thread safety.Assume that one thread is in the process of creating the MyClass object and it just completed the step 1.Now another thread came and saw the object is not null because of thread 1 completed step 1.And tried to clazz.i and will get the wrong value,since thread1 has not completed step 2 yet.
Thread 1:
MyClass clazz = new MyClass ();
Thread 2:
if (clazz != null) {
System.out.println(clazz .i);
}
So there is no guarantee that thread 2 will print 1.
Here this is a concern of thready safety.
- Allocate space for new object
- Store the unconstructed object in variable
- Initialise object
Let's see an example
class MyClass {
int i;
MyClass () {
i = 1;
}
}
When we write something like MyClass clazz=new MyClass();
The following steps should ideally happen as per our assumption
- var= Allocate space for MyClass
- var.i = 1;
- clazz= var;
- clazz= Allocate space for MyClass
- clazz.i = 1;
But the reordering of statements by compiler affects the thread safety.Assume that one thread is in the process of creating the MyClass object and it just completed the step 1.Now another thread came and saw the object is not null because of thread 1 completed step 1.And tried to clazz.i and will get the wrong value,since thread1 has not completed step 2 yet.
Thread 1:
MyClass clazz = new MyClass ();
Thread 2:
if (clazz != null) {
System.out.println(clazz .i);
}
So there is no guarantee that thread 2 will print 1.
Here this is a concern of thready safety.
Prevent Compiler Reordering:
1.final
If we redesign our class like
If we redesign our class like
class MyClass {
final int i;
MyClass () {
i = 1;
}
}
Here note that we changed the modifier of the variable i as final.Now we can say this class is thread safe.
Without the final modifier, the compiler and JVM are allowed to move the
write to i so that it occurs after the reference to the new object is
written to clazz.But the final modifier will restrict the compiler to do such type of reordering.
2.volatile
If you refer one of my series double check locking for singleton you will see in line number 2 we have used the keyword volatile for our singletonTest instance.Without the volatile keyword this code will not work in java.The basic rule is that compiler reordering can change the code so that the code in the SingletonTest constructor occur after the write to the instance variable in line number 11.If this will happen then there will be thread safety issue.
Just assume we have two threads Thread1 and Thread2.Now Thread1 will come and see instance is null in getInstance method and proceed to execute line 11 , but as we know line 11 is not an atomic operation , so just after assigning to instance variable and before constructing the SingletonTest object completely , Thread2 can come along and read the instance before Thread1 finished the construction in line number 7 of getInstance method..
If we make the instance field volatile in line no 2 , the actions that should happen before the write to instance in the code must actually happen before the write to instance .No compiler reordering is allowed.
2.volatile
If you refer one of my series double check locking for singleton you will see in line number 2 we have used the keyword volatile for our singletonTest instance.Without the volatile keyword this code will not work in java.The basic rule is that compiler reordering can change the code so that the code in the SingletonTest constructor occur after the write to the instance variable in line number 11.If this will happen then there will be thread safety issue.
Just assume we have two threads Thread1 and Thread2.Now Thread1 will come and see instance is null in getInstance method and proceed to execute line 11 , but as we know line 11 is not an atomic operation , so just after assigning to instance variable and before constructing the SingletonTest object completely , Thread2 can come along and read the instance before Thread1 finished the construction in line number 7 of getInstance method..
If we make the instance field volatile in line no 2 , the actions that should happen before the write to instance in the code must actually happen before the write to instance .No compiler reordering is allowed.
No comments:
Post a Comment