This article says:
In this noncompliant code example, the Helper class is made immutable
by declaring its fields final. The JMM guarantees that immutable
objects are fully constructed before they become visible to any other
thread. The block synchronization in the getHelper() method guarantees
that all threads that can see a non-null value of the helper field
will also see the fully initialized Helper object.
public final class Helper {
private final int n;
public Helper(int n) {
this.n = n;
}
// Other fields and methods, all fields are final
}
final class Foo {
private Helper helper = null;
public Helper getHelper() {
if (helper == null) { // First read of helper
synchronized (this) {
if (helper == null) { // Second read of helper
helper = new Helper(42);
}
}
}
return helper; // Third read of helper
}
}
However, this code is not guaranteed to succeed on all Java Virtual
Machine platforms because there is no happens-before relationship
between the first read and third read of helper. Consequently, it is
possible for the third read of helper to obtain a stale null value
(perhaps because its value was cached or reordered by the compiler),
causing the getHelper() method to return a null pointer.
I don't know what to make of it. I can agree that there is no happens before relationship between first and third read, at least no immediate relationship. Isn't there a transitive happens-before relationship in a sense that first read must happen before second, and that second read has to happen before third, therefore first read has to happen before third
Could someone elaborate more proficiently?
No, there is no transitive relationship.
The idea behind the JMM is to define rules that JVM must respect. Providing the JVM follows these rules, they are authorized to reorder and execute code as they want.
In your example, the 2nd read and the 3rd read are not related - no memory barrier introduced by the use of synchronized or volatile for example. Thus, the JVM is allowed to execute it as follow:
public Helper getHelper() {
final Helper toReturn = helper; // "3rd" read, reading null
if (helper == null) { // First read of helper
synchronized (this) {
if (helper == null) { // Second read of helper
helper = new Helper(42);
}
}
}
return toReturn; // Returning null
}
Your call would then return a null value. Yet, a singleton value would have been created. However, sub-sequent calls may still get a null value.
As suggested, using a volatile would introduce new memory barrier. Another common solution is to capture the read value and return it.
public Helper getHelper() {
Helper singleton = helper;
if (singleton == null) {
synchronized (this) {
singleton = helper;
if (singleton == null) {
singleton = new Helper(42);
helper = singleton;
}
}
}
return singleton;
}
As your rely on a local variable, there is nothing to reorder. Everything is happening in the same thread.
No, there's no any transitive relationship between those reads. synchornized only guarantees visibility of changes that were made within synchronized blocks of the same lock. In this case all reads do not use the synchronized blocks on the same lock, hence this is flawed and visibility is not guaranteed.
Because there is no locking once the field is initialized, it is critical that the field be declared volatile. This will ensure the visibility.
private volatile Helper helper = null;
It's all explained here https://shipilev.net/blog/2014/safe-public-construction/#_singletons_and_singleton_factories, the issue simple.
... Notice that we do several reads of instance in this code, and at
least "read 1" and "read 3" are the reads without any
synchronization ... Specification-wise, as mentioned in happens-before
consistency rules, a read action can observe the unordered write via
the race. This is decided for each read action, regardless what other
actions have already read the same location. In our example, that
means that even though "read 1" could read non-null instance, the code
then moves on to returning it, then it does another racy read, and it
can read a null instance, which would be returned!
Related
I have a class whose instances are initialized and used by underlying flatform.
class MyAttributeConverter implements AttributeConverter<XX, YY> {
public YY convertToDatabaseColumn(XX attribute) { return null; }
public XX convertToEntityAttribute(YY dbData) { return null; }
}
Nothing's wrong and I thought I need to add some static methods for being used as method references.
private static MyAttributeConverter instance;
// just a lazy-initialization;
// no synchronization is required;
// multiple instantiation is not a problem;
private static MyAttributeConverter instance() {
if (instance == null) {
instance = new MyAttributeConverter();
}
return instance;
}
// do as MyAttributeConverter::toDatabaseColumn(xx)
public static YY toDatabaseColumn(XX attribute) {
return instance().convertToDatabaseColumn(attribute);
}
public static XX toEntityAttribute(YY dbData) {
return instance().convertToEntityAttribute(attribute);
}
Still nothing seems wrong (I believe) and I don't like the instance persisted with the class and that's why I'm trying to do this.
private static WeakReference<MyAttributeConverter> reference;
public static <R> R applyInstance(Function<? super MyAttributeConverter, ? extends R> function) {
MyAttributeConverter referent;
if (reference == null) {
referent = new MyAttributeConverter();
refernce = new WeakReference<>(referent);
return applyInstance(function);
}
referent = reference.get();
if (referent == null) {
referent = new MyAttributeConverter();
refernce = new WeakReference<>(referent);
return applyInstance(function);
}
return function.apply(referent); // ##?
}
I basically don't even know how to test this code. And I'm sorry for my questions which each might be somewhat vague.
Is this a (right/wrong) approach?
Is there any chance that reference.get() inside the function.apply idiom may be null?
Is there any chance that there may be some problems such as memory-leak?
Should I rely on SoftReference rather than WeakReference?
Thank you.
Note that a method like
// multiple instantiation is not a problem;
private static MyAttributeConverter instance() {
if (instance == null) {
instance = new MyAttributeConverter();
}
return instance;
}
is not thread safe, as it bears two reads of the instance field; each of them may perceive updates made by other threads or not. This implies that the first read in instance == null may perceive a newer value written by another thread whereas the second in return instance; could evaluate to the previous value, i.e. null. So this method could return null when more than one thread is executing it concurrently. This is a rare corner case, still, this method is not safe. You’d need a local variable to ensure that the test and the return statement use the same value.
// multiple instantiation is not a problem;
private static MyAttributeConverter instance() {
MyAttributeConverter current = instance;
if (current == null) {
instance = current = new MyAttributeConverter();
}
return current;
}
This still is only safe when MyAttributeConverter is immutable using only final fields. Otherwise, a thread may return an instance created by another thread in an incompletely constructed state.
You can use the simple way to make it safe without those constraints:
private static final MyAttributeConverter instance = new MyAttributeConverter();
private static MyAttributeConverter instance() {
return instance;
}
This still is lazy as class initialization only happens on one of the specified triggers, i.e. the first invocation of the method instance().
Your usage of WeakReference is subject to the same problems. Further, it’s not clear why you resort to a recursive invocation of your method at two points where you already have the required argument in a local variable.
A correct implementation can be far simpler:
private static WeakReference<MyAttributeConverter> reference;
public static <R> R applyInstance(
Function<? super MyAttributeConverter, ? extends R> function) {
WeakReference<MyAttributeConverter> r = reference;
MyAttributeConverter referent = r != null? r.get(): null;
if (referent == null) {
referent = new MyAttributeConverter();
reference = new WeakReference<>(referent);
}
return function.apply(referent);
}
But before you are going to use it, you should reconsider whether the complicated code is worth the effort. The fact that you are accepting the need to reconstruct the object when it has been garbage collected, even potentially constructing multiple instances on concurrent invocations, suggest that you know that the construction will be cheap. When the construction is cheap, you probably don’t need to cache an instance of it at all.
Just consider
public static <R> R applyInstance(
Function<? super MyAttributeConverter, ? extends R> function) {
return function.apply(new MyAttributeConverter());
}
It’s at least worth trying, measuring the application’s performance and comparing it with the other approaches.
On the other hand, it doesn’t look like the instance was occupying a significant amount of memory nor holding non-memory resources. As otherwise, you were more worried about the possibility of multiple instances flying around. So the other variant worth trying and comparing, is the one shown above using a static final field with lazy class initialization and no opportunity to garbage collect that small object.
One last clarification. You asked
Is there any chance that reference.get() inside the function.apply idiom may be null?
Since there is no reference.get() invocation inside the evaluation of function.apply, there is no chance that such an invocation may evaluate to null at this point. The function receives a strong reference and since the calling code ensured that this strong reference is not null, it will never become null during the invocation of the apply method.
Generally, the garbage collector will never alter the application state in a way that code using strong references will notice a difference (letting the availability of more memory aside).
But since you asked specifically about reference.get(), a garbage collector may collect an object after its last use, regardless of method executions or local scopes. So the referent could get collected during the execution of the apply method when this method does not use the object anymore. Runtime optimizations may allow this to happen earlier than you might guess by looking at the source code, because what may look like an object use (e.g. a field read) may not use the object at runtime (e.g. because that value is already held in a CPU register, eliminating the need to access the object’s memory). As said, all without altering the method’s behavior.
So a hypothetical reference.get() during the execution of the apply method could in principle evaluate to null, but there is no reason for concern, as said, the behavior of the apply method does not change. The JVM will retain the object’s memory as long as needed for ensuring this correct method execution.
But that explanation was just for completeness. As said, you should not use weak nor soft references for objects not holding expensive resources.
public class Factory {
private Singleton instance;
public Singleton getInstance() {
Singleton res = instance;
if (res == null) {
synchronized (this) {
res = instance;
if (res == null) {
res = new Singleton();
instance = res;
}
}
}
return res;
}
}
It is almost correct implementation of thread-safe Singleton. The only problem I see is:
The thread #1 that is initializing the instance field can published before it will be initialized completely. Now, the second thread can read instance in a inconsistent state.
But, for my eye it is only problem here. Is it only problem here?
(And we can make instance volatile).
You example is explained by Shipilev in Safe Publication and Safe Initialization in Java. I highly recommend to read the whole article, but to sum it up look at UnsafeLocalDCLFactory section there:
public class UnsafeLocalDCLFactory implements Factory {
private Singleton instance; // deliberately non-volatile
#Override
public Singleton getInstance() {
Singleton res = instance;
if (res == null) {
synchronized (this) {
res = instance;
if (res == null) {
res = new Singleton();
instance = res;
}
}
}
return res;
}
}
Above has following problems:
The introduction of local variable here is a correctness fix, but only partial: there still no happens-before between publishing the Singleton instance, and reading of any of its fields. We are only protecting ourselves from returning "null" instead of Singleton instance. The same trick can also be regarded as a performance optimization for SafeDCLFactory, i.e. doing only a single volatile read, yielding:
Shipilev suggests to fix as follows, by marking instance volatile:
public class SafeLocalDCLFactory implements Factory {
private volatile Singleton instance;
#Override
public Singleton getInstance() {
Singleton res = instance;
if (res == null) {
synchronized (this) {
res = instance;
if (res == null) {
res = new Singleton();
instance = res;
}
}
}
return res;
}
}
There are no other problems with this example.
Normally I would never use a double checked locking mechanism anymore. To create a thread safe singleton you should let the compiler do this:
public class Factory {
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return res;
}
}
Now you are talking to make the instance volatile. I don't think this is necessary with this solution as the jit compiler now handlers the synchronization of the threads when the object is constructed. But if you want to make it volatile, you can.
Finally I would make the getInstance() and the instance static. Then you can reference Factory.getInstance() directly without constructing the Factory class. Also: you will get the same instance across all threads in your application. Else every new Factory() will give you a new instance.
You can also look at Wikipedia. They have a clean solution if you need a lazy solution:
https://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java
// Correct lazy initialization in Java
class Foo {
private static class HelperHolder {
public static final Helper helper = new Helper();
}
public static Helper getHelper() {
return HelperHolder.helper;
}
}
EDIT I've written one more answer here that should clear all the confusion.
This is a good question, and I'll try to summarize my understanding here.
Suppose Thread1 is currently initializing Singleton instance and publishes the reference (unsafely obviously). Thread2 can see this un-safe published reference (meaning it sees a non-null reference), but that does not mean that the fields that it sees via that reference (Singleton fields that are initialized via the constructor) are initialized correctly too.
As far as I can see, this happens because there could be re-ordering of the stores of the fields happening inside the constructor. Since there is no "happens-before" rules (these are plain variables), this could be entirely possible.
But that is not the only problem here. Notice that you do two reads here:
if (res == null) { // read 1
return res // read 2
These reads have no synchronization protection, thus these are racy reads. AFAIK this means that read 1 is allowed to read a non-null reference, while read 2 is allowed to read a null reference.
This btw is the same thing that the ALL mighty Shipilev explains (even if I read this article once 1/2 year I still find something new every time).
Indeed making instance volatile would fix things. When you make it volatile, this happens:
instance = res; // volatile write, thus [LoadStore][StoreStore] barriers
All "other" actions (stores from within the constructor) can not pass this fence, there will be no re-orderings. It also means that when you read the volatile variable and see a non-null value, it means that every "write" that was done before writing the volatile itself has occurred for sure. This excellent post has the exact meaning of it
This also solves the second problem, since these operations can not be re-ordered, you are guaranteed to see the same value from read 1 and read 2.
No matter how much I read and try to understand these things are constantly complicated to me, there are very few people that I know that can write code like this and reason correctly about it too. When you can (I do!) please stick to the known and working examples of double check locking :)
I do that like this:
public class Factory {
private static Factory factor;
public static Factory getInstance() {
return factor==null ? factor = new Factory() : factor;
}
}
Just simply
After some time (yeah it took 2 years, I know), I think I have the proper answer. To take it literally, the answer to this:
But, for my eye it is only problem here. Is it only problem here?
Would be yes. The way you have it right now, callers of getInstance will never see a null. But if Singleton would have fields, there is no guarantee that those fields will be correctly initialized.
Let's take this slow, since the example is beautiful, IMHO. That code you showed does a single (racy) volatile read :
public class Factory {
private Singleton instance;
public Singleton getInstance() {
Singleton res = instance; // <-- volatile RACY read
if (res == null) {
synchronized (this) {
res = instance; // <-- volatile read under a lock, thus NOT racy
if (res == null) {
res = new Singleton();
instance = res;
}
}
}
return res;
}
}
Usually, the classical "double check locking" has two racy reads of volatile, for example:
public class SafeDCLFactory {
private volatile Singleton instance;
public Singleton get() {
if (instance == null) { // <-- RACY read 1
synchronized(this) {
if (instance == null) { // <-- non-racy read
instance = new Singleton();
}
}
}
return instance; // <-- RACY read 2
}
}
Because those two reads are racy, without volatile, this pattern is broken. You can read how we can break here, for example.
In your case, there is an optimization, that does one less reading of a volatile field. On some platforms this matters, afaik.
The other part of the question is more interesting. What if Singleton has some fields that we need to set?
static class Singleton {
//setter and getter also
private Object obj;
}
And a factory, where Singleton is volatile:
static class Factory {
private volatile Singleton instance;
public Singleton get(Object obj) {
if (instance == null) {
synchronized (this) {
if (instance == null) {
instance = new Singleton();
instance.setObj(obj);
}
}
}
return instance;
}
}
We have a volatile field, we are safe, right? Wrong. The assign of obj happens after the volatile write, as such there are no guarantees about it. In plain english: this should help you a lot.
The correct way to fix this is to do the volatile write with an already build instance (fully build):
if (instance == null) {
Singleton local = new Singleton();
local.setObj(obj);
instance = local;
}
Now, the second thread can read instance in a inconsistent state.
I'm pretty sure that really is the only issue in that code. The way I understand it, as soon as the line
instance = res;
is executed, another thread could read instance and see it as non-null, and thus skips the synchronized. This means there is no happens-before relation between those two threads, because those only exist if both threads synchronize on the same object or access the same volatile fields.
The other answers already linked to Safe Publication and Safe Initialization in Java, which offers the following ways to solve the unsafe publication:
Making the instance field volatile. All threads have to read the same volatile variable, which establishes a happens-before relation
A write to a volatile field (§8.3.1.4) happens-before every subsequent read of that field.
Wrapping the singleton into a wrapper which stores the singleton in a final field. The rules for final fields are not as formally specified as the happens-before relations, the best explanation I could find is in final Field Semantics
An object is considered to be completely initialized when its constructor finishes. A thread that can only see a reference to an object after that object has been completely initialized is guaranteed to see the correctly initialized values for that object's final fields.
(Not the emphasis and restriction to the final fields, other fields might be seen in inconsistent state at least theoretically)
Making sure the singleton itself only contains final fields. The explanation would be the same as the one above.
The problem with the code mentioned in the question is that reordering can happen and a thread can get a partially constructed object of the singleton class.
When I say reordering, I mean the following:
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
/* The above line executes the following steps:
1) memory allocation for Singleton class
2) constructor call ( it may have gone for some I/O like reading property file etc...
3) assignment ( look ahead shows it depends only on memory allocation which has already happened in 1st step.
If compiler changes the order, it might assign the memory allocated to the instance variable.
What may happen is half initialized object will be returned to a different thread )
*/
}
}
}
return instance;
}
Declaring the instance variable volatile ensures a happens-before/ordered relationship on the above mentioned 3 steps:
A write to a volatile field (§8.3.1.4) happens-before every subsequent read of that field.
From Wikipedia's Double-checked locking:
As of J2SE 5.0, this problem has been fixed. The volatile keyword now ensures that multiple threads handle the singleton instance correctly. This new idiom is described in The "Double-Checked Locking is Broken" Declaration:
// Works with acquire/release semantics for volatile
// Broken under Java 1.4 and earlier semantics for volatile
class Foo {
private volatile Helper helper = null;
public Helper getHelper() {
Helper result = helper;
if (result == null) {
synchronized(this) {
result = helper;
if (result == null) {
helper = result = new Helper();
}
}
}
return result;
}
// other functions and members...
}
If we have 2 classes that operate on the same object under different threads and we want to avoid race conditions, we'll have to use synchronized blocks with the same monitor like in the example below:
class A {
private DataObject mData; // will be used as monitor
// thread 3
public setObject(DataObject object) {
mData = object;
}
// thread 1
void operateOnData() {
synchronized(mData) {
mData.doSomething();
.....
mData.doSomethingElse();
}
}
}
class B {
private DataObject mData; // will be used as monitor
// thread 3
public setObject(DataObject object) {
mData = object;
}
// thread 2
void processData() {
synchronized(mData) {
mData.foo();
....
mData.bar();
}
}
}
The object we'll operate on, will be set by calling setObject() and it will not change afterwards. We'll use the object as a monitor. However, intelliJ will warn about synchronization on a non-final field.
In this particular scenario, is the non-local field an acceptable solution?
Another problem with the above approach is that it is not guaranteed that the monitor (mData) will be observed by thread 1 or thread 2 after it is set by thread 3, because a "happens-before" relationship hasn't been established between setting and reading the monitor. It could be still observed as null by thread 1 for example. Is my speculation correct?
Regarding possible solutions, making the DataObject thread-safe is not an option. Setting the monitor in the constructor of the classes and declaring it final can work.
EDIT Semantically, the mutual exclusion needed is related to the DataObject. This is the reason that I don't want to have a secondary monitor. One solution would be to add lock() and unlock() methods on DataObject that need to be called before working on it. Internally they would use a Lock Object. So, the operateOnData() method becomes:
void operateOnData() {
mData.lock()
mData.doSomething();
.....
mData.doSomethingElse();
mData.unlock();
}
You may create a wrapper
class Wrapper
{
DataObject mData;
synchronized public setObject(DataObject mData)
{
if(this.mData!=null) throw ..."already set"
this.mData = mData;
}
synchronized public void doSomething()
{
if(mData==null) throw ..."not set"
mData.doSomething();
}
A wrapper object is created and passed to A and B
class A
{
private Wrapper wrapper; // set by constructor
// thread 1
operateOnData()
{
wrapper.doSomething();
}
Thread 3 also has a reference to the wrapper; it calls setObject() when it's available.
Some platforms provide explicit memory-barrier primitives which will ensure that if one thread writes to a field and then does a write barrier, any thread which has never examined the object in question can be guaranteed to see the effect of that write. Unfortunately, as of the last time I asked such a question, Cheapest way of establishing happens-before with non-final field, the only time Java could offer any guarantees of threading semantics without requiring any special action on behalf of a reading thread was by using final fields. Java guarantees that any references made to an object through a final field will see any stores which were performed to final or non-fields of that object before the reference was stored in the final field but that relationship is not transitive. Thus, given
class c1 { public final c2 f;
public c1(c2 ff) { f=ff; }
}
class c2 { public int[] arr; }
class c3 { public static c1 r; public static c2 f; }
If the only thing that ever writes to c3 is a thread which performs the code:
c2 cc = new c2();
cc.arr = new int[1];
cc.arr[0] = 1234;
c3.r = new c1(cc);
c3.f = c3.r.f;
a second thread performs:
int i1=-1;
if (c3.r != null) i1=c3.r.f.arr[0];
and a third thread performs:
int i2=-1;
if (c3.f != null) i2=c3.f.arr[0];
The Java standard guarantees that the second thread will, if the if condition yields true, set i1 to 1234. The third thread, however, might possibly see a non-null value for c3.f and yet see a null value for c3.arr or see zero in c3.f.arr[0]. Even though the value stored into c3.f had been read from c3.r.f and anything that reads the final reference c3.r.f is required to see any changes made to that object identified thereby before the reference c3.r.f was written, nothing in the Java Standard would forbid the JIT from rearranging the first thread's code as:
c2 cc = new c2();
c3.f = cc;
cc.arr = new int[1];
cc.arr[0] = 1234;
c3.r = new c1(cc);
Such a rewrite wouldn't affect the second thread, but could wreak havoc with the third.
A simple solution is to just define a public static final object to use as the lock. Declare it like this:
/**Used to sync access to the {#link #mData} field*/
public static final Object mDataLock = new Object();
Then in the program synchronize on mDataLock instead of mData.
This is very useful, because in the future someone may change mData such that it's value does change then your code would have a slew of weird threading bugs.
This method of synchronization removes that possibility. It also is really low cost.
Also having the lock be static means that all instances of the class share a single lock. In this case, that seems like what you want.
Note that if you have many instances of these classes, this could become a bottleneck. Since all of the instances are now sharing a lock, only a single instance can change any mData at a single time. All other instances have to wait.
In general, I think something like a wrapper for the data you want to synchronize is a better approach, but I think this will work.
This is especially true if you have multiple concurrent instances of these classes.
FIRST OFF: Yes, I know that the best way in general to do singletons in Java is with enums, but if for some reason you need to subclass a singleton class, you can't use enums, so...
David Geary at JavaWorld published an article a long time ago on implementing singletons in Java. He argued that the following optimization to a thread-safe singleton implementation is problematic:
public static Singleton getInstance()
{
if (singleton == null)
{
synchronized(Singleton.class)
{
if(singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
(See more at: http://www.javaworld.com/javaworld/jw-04-2003/jw-0425-designpatterns.html?page=4#sthash.G8lzWOfT.dpuf)
Geary says that this 'double-checked locking' optimization
is not guaranteed to work because the compiler is free to assign a
value to the singleton member variable before the singleton's
constructor is called. If that happens, Thread 1 can be preempted
after the singleton reference has been assigned, but before the
singleton is initialized, so Thread 2 can return a reference to an
uninitialized singleton instance.
My question: Is the following change going to fix that problem or not? I've started reading Goetz's Java concurrency book and it seems that the compiler is allowed to shuffle within-thread operations, so I am not quite confident...Still, it seems to me that singleton = temp; is an atomic operation, in which case I think it should. Please explain.
public static Singleton getInstance()
{
if (singleton == null)
{
synchronized(Singleton.class)
{
if(singleton == null) {
Singleton temp = new Singleton();
singleton = temp;
}
}
}
return singleton;
}
The second code is sequentially consistent with the first code (they are strictly equivalent in a single threaded environment) and does not introduce any additional memory synchronisation points.
So yes, a compiler is authorised to rewrite the second code and turn it into the first one which means it is unsafe too.
The fact that singleton = temp; is atomic doesn't help here. It only means that singleton is either null or holds the same reference as temp. But that does not preclude temp/singleton from pointing to a "non-constructed" object.
The Java Memory Model works in terms of happens-before (HB) relationships. In both codes there is only one hb: the exit of the synchronized block hb a subsequent entry into that block. if (singleton == null) does not share any hb relationship with singleton=… so the reordering can happen.
The bottom line is that the only way to fix it is to introduce a hb between the two statements: by moving the if inside the synchronized block or by marking singleton volatile for example.
The answer depends on optimization which can be applied for the second code by compiler (it means that second one can be transformed to first one by compiler). You can write the code using AtomicReference which will allow to avoid the problem:
private static AtomicReference<Singleton> singleton = new AtomicReference<Singleton>(null);
...
public static Singleton getInstance()
{
if (singleton.get() == null)
{
synchronized(Singleton.class)
{
if(singleton.get() == null) {
singleton.compareAndSet(null, new Singleton());
}
}
}
return singleton.get();
}
Deleted as wrong, keeping the empty answer for its discussions. Wow, live and learn!
I have a code like the one below where an object is shared among two threads (the main thread and the Monitor thread). Do I have to declare MyObject globally and make it volatile to ensure it will be pushed to memory? Otherwise the if statement can print "Not null" if MyObject is only locally accessed by the thread and is not declared volatile, right?
public static void main(String[] args) {
MyObject obj = MyObjectFactory.createObject();
new Monitor(obj).start();
Thread.sleep(500);
if(obj == null)
System.out.println("Null");
else
System.out.println("Not null");
}
public void doSomethingWithObject(MyObject obj) {
obj = null;
}
private class Monitor extends Thread {
public Monitor(MyObject obj) {
this.obj=obj;
}
public void run() {
doSomethingWithObject(obj);
}
}
Note: The code example may not compile since I wrote it myself here on Stackoverflow. Consider it as a mix of pseudo code and real code.
The instance is shared but the references to it are not. Example:
String a = "hello";
String b = a;
b = null; // doesn't affect a
a and b are references to the same instance; changing one reference has no effect on the instance or any other references to the same instance.
So if you want to share state between threads, you will have to create a field inside MyObject which has to be volatile:
class MyObject { public volatile int shared; }
public void doSomethingWithObject(MyObject obj) {
obj.shared = 1; // main() can see this
}
Note that volatile just works for some types (references and all primitives except long). Since this is easy to get wrong, you should have a look at types in java.util.concurrent.atomic.
[EDIT] What I said above isn't correct. Instead, using volatile with long works as expected for Java 5 and better. This is the only way to ensure atomic read/writes for this type. See this question for references: Is there any point in using a volatile long?
Kudos go to Affe for pointing that out. Thanks.
You would rather have to synchronize on the object to ensure it will be set to null before the if check. Setting it to volatile only means changes will be "seen" immediately by other threads, but it is very likely that the if check will be executed before the doSomethingWithObject call.
If you want your object to go through a read-update-write scheme atomically, volatile won't cut it. You have to use synchronisation.
Volatility will ensure that the variable will not be cached in the current thread but it will not protect the variable from simultaneous updates, with the potential for the variable becoming something unexpected.
IBM's developerWorks has a useful article on the subject.
Your example consists only one thread, Monitor, which is created and run in main().
"make it volatile to ensure it will be pushed to memory?" - on the contrary, when you declare a variable as volatile - it ensures that it's NOT being "pushed" (cached) to the thread-local memory, cause there might be other threads that will change the value of the variable.
In order to make sure you print the correct value of a variable you should synchronize the method doSomethingWithObject (change the signature of the method to):
public synchronized void doSomethingWithObject(MyObject obj)
or create synchronized blocks around:
obj = null;
and
this.obj=obj;