tags:

views:

178

answers:

4
+5  Q: 

Volatile keyword

Say I have two threads and an object. One thread assigns the object:

public void assign(MyObject o) {
    myObject = o;
}

Another thread uses the object:

public void use() {
    myObject.use();
}

Does the variable myObject have to be declared as volatile? I am trying to understand when to use volatile and when not, and this is puzzling me. Is it possible that the second thread keeps a reference to an old object in its local memory cache? If not, why not?

Thanks a lot.

+2  A: 

Leaving the complicated technical details behind, you can see volatile less or more as a synchronized modifier for variables. When you'd like to synchronize access to methods or blocks, then you'd usually like to use the synchronized modifier as follows:

public synchronized void doSomething() {}

If you'd like to "synchronize" access to variables, then you'd like to use the volatile modifier:

private volatile SomeObject variable;

Behind the scenes they do different things, but the effect is the same: the changes are immediately visible for the next accessing thread.

In your specific case, I don't think that the volatile modifier has any value. The volatile does not guarantee in any way that the thread assigning the object will run before the thread using the object. It can be as good the other way round. You probably just want to do a nullcheck in use() method first.

Update: also see this article:

Access to the variable acts as though it is enclosed in a synchronized block, synchronized on itself. We say "acts as though" in the second point, because to the programmer at least (and probably in most JVM implementations) there is no actual lock object involved.

BalusC
This is wholly incorrect. Volatile is entirely about the memory effects and visibility of a variable, not concurrent access.
Kevin
I am confused. I have been reading and I read that volatile is typically used to share a flag between threads: one threads sets the thread to false, and the other notices that is has been set to false. If the boolean is not declared as volatile, the second thread will always notice that is has been set to false, because the value might have been stored in local thread cache. Is this not true or did I misunderstand that statement?
Tiyoal
@Kevin: Yes, that's the technical detail. I was talking about the **effect** so that it makes more sense for starters. The change in the variable is immediately visible for the next accessing thread.
BalusC
@BalusC Using synchronized has the *side effect* of updating the visibility of the variable but that is not its primary purpose. I think you're doing more harm than good by espousing this as a solution
Kevin
@Kevin: I am not sure if it will do more harm than good. That might depend on how one interprets this all. I however fully agree that you'd better to look for the great `java.util.concurrent` API, I upvoted your answer for the recommendation.
BalusC
Although I think you have a pretty explanation of the effects of using the various methods, your advice is just plain wrong. Without some form of memory synchronization between threads, the reader may never see the changes. Also your before/after scenario doesn't exist in the question. Both methods could be called multiple times for all we know and null may or may not be an acceptable value.
Robin
@Robin: you've made a good point. The OP should first clarify the functional requirements in more detail before we can give a solid advice. It's now too ambiguous.
BalusC
+5  A: 

I am trying to understand when to use volatile and when not

You should mostly avoid using it. Use an AtomicReference instead (or another atomic class where appropriate). The memory effects are the same and the intent is much clearer.

I highly suggest reading the excellent Java Concurrency in Practice for a better understanding.

Kevin
Thanks for the advice. I agree I don't have to use these 'low level stuff'. However, I feel the urge to understand how it works under the hood. The book is a very good suggestion for that. Thanks.
Tiyoal
@Tiyoal For the absolute nitty gritty, see section 17.4 of the JLS which discusses the Memory Model : http://java.sun.com/docs/books/jls/third_edition/html/memory.html#17.4
Kevin
Second the concurrency in practice. Volatile is a weaker form of synchronized.. okay to use if a variable is being written by 1 thread and read by many threads to ensure that the writes are seen immediately..
bwawok
http://www.javamex.com/tutorials/synchronization_volatile.shtml
Alerty
@Kevin: a cite from [this link](http://www.javamex.com/tutorials/synchronization_volatile.shtml) from @Alerty: *"Access to the variable **acts as though** it is enclosed in a synchronized block, synchronized on itself."*, that's basically what I am trying to tell in my answer.
BalusC
@bwawolk: well that is what my question is about. One thread writes, one (multiple) reads (read). Why do I not have to mark my shared object as volatile?
Tiyoal
I read in some online tutorials about the volatile keyword that threads might decide to store 'local values' of a variable in their local thread cache. To overcome this, you need to declare the variable as volatile. So I was wondering what happens if thread two decided to do that with myObject. He will keep using an outdated object? That's why I was wondering if I have it to declare it as volatile. Am I seeing this wrong?
Tiyoal
+2  A: 

You can use volatile in this case. You will require volatile, synchronization around the access to the variable or some similar mechanism (like AtomicReference) to guarantee that changes made on the assignment thread are actually visible to the reading thread.

Robin
But how does this take care that the thread assigning the object will run *before* the thread using the object?
BalusC
Why do I need synchronization here? Is declaring as volatile not enough?
Tiyoal
@Tiyoal - that is an either/or. You need to use one of those options.
Robin
@BalusC - It doesn't, but that has nothing to do with the threading, just simply check for null. There is no requirement stated that one has to be done before the other, or that they can't both be called multiple times. So the reading thread will have to check for null if it is considered a possible return value each time it is called. You are citing a producer/consumer scenario which would be a different solution altogether.
Robin
A: 

There are some confusing comments here: to clarify, your code is incorrect as it stands, assuming two different threads call assign() and use().

In the absence of volatile, or another happens-before relationship (for example, synchronization on a common lock) any write to myObject in assign() is not guaranteed to be seen by the thread calling use() -- not immediately, not in a timely fashion, and indeed not ever.

Yes, volatile is one way of correcting this (assuming this is incorrect behaviour -- there are plausible situations where you don't care about this!).

You are exactly correct that the 'use' thread can see any 'cached' value of myObject, including the one it was assigned at construction time and any intermediate value (again in the absence of other happens-before points).

Cowan