17

I would like to understand why a Reference that is declared as final cannot be declared as Volatile. There is a similar question on SO [Why can an Object member variable not be both final and volatile in Java?

[1]: Why can an Object member variable not be both final and volatile in Java? but I am not sure if the FINAL is understood in that answer.

Now The state of a final variable can definitely be changed after it has been initialized. Only the reference cannot be initialized to another object.

For eg consider the below member variable

final StringBuilder sb = new StringBuilder("CAT");

Now another thread changes sb as :

sb.append("S");

Will this change be available to different threads as per Java memory model if this variable is Non-Volatile ?

EDIT : I changed StringBuffer to StringBuilder for some people to make my point clear.

Community
  • 1
  • 1
Geek
  • 23,089
  • 20
  • 71
  • 85
  • 3
    `sb.append("S")` is a change to the referenced object, not to the field, so it would not be affected by declaring the field volatile. – Patricia Shanahan Sep 11 '13 at 18:44
  • so you mean to say the variable sb is essentially theadsafe ?? – Geek Sep 11 '13 at 18:45
  • Whether, in general, such a modification is thread safe depends on the class of the object being modified. Declaring a reference to that object volatile is simply irrelevant. The [StringBuffer documentation](http://docs.oracle.com/javase/7/docs/api/java/lang/StringBuffer.html) says "String buffers are safe for use by multiple threads." so it is thread safe. – Patricia Shanahan Sep 11 '13 at 18:51
  • Sorry Patricia, I just removed StringBuffer :-) – Geek Sep 11 '13 at 18:54
  • That makes a big difference. Your append call is no longer multi-thread safe. The [StringBuilder documentation](http://docs.oracle.com/javase/7/docs/api/java/lang/StringBuilder.html) says "Instances of StringBuilder are not safe for use by multiple threads. If such synchronization is required then it is recommended that StringBuffer be used.". The point is that the `volatile` on the reference is irrelevant to the safety of calling a method declared in the referenced object. You need to look at the behavior of the referenced object's class. – Patricia Shanahan Sep 11 '13 at 18:56
  • so you are essentially saying : If I declare a Non-Thread safe class reference as volatile and keep updating the reference via getter-setter methods I am not guaranteed to see the most updated state of such a reference ? – Geek Sep 11 '13 at 18:59
  • Are you updating the reference, as in `sb=new StringBuilder()` or updating the object it references, as in `sb.append("S")`? – Patricia Shanahan Sep 11 '13 at 19:01
  • I am updating the Object. So are other threads guaranteed to see my updates ? – Geek Sep 11 '13 at 19:02
  • Not if you use the unsafe StringBuilder, rather than the safe StringBuffer. – Patricia Shanahan Sep 11 '13 at 19:04
  • @ŁukaszRzeszotarski I don't think it is quite a duplicate, because that question does not deal with the false assumption that `volatile` on a reference that is not changing affects visibility of changes in the object it references. – Patricia Shanahan Sep 11 '13 at 19:16

7 Answers7

16

volatile implies the field will change. If it is final you will never change it and such doesn't make sense.

Will this change be available to different threads as per Java memory model if this variable is Non-Volatile ?

Declaring a field volatile has no effects on its content or modifications after the volatile write occurs. If the field is volatile or non-volatile the memory effects of append are dictated by the implementation of StringBuffer.

So in the case of StringBuffer it does ensure memory visibility but not for the reason you think. StringBuffer is syncrhonized (thread-safe) so you will have an always up to date value of the content.

StringBuilder on the other hand is not synchronized and memory visibility is not guaranteed. So if you tried to swap the two out for a multihreaded test, you would see different results.

John Vint
  • 39,695
  • 7
  • 78
  • 108
9

Because volatile affects the behavior of how Threads access and edit the variable. In your code example, the variable is a reference (sb) to an object. So this means volatile has no effect on the object. final locks the reference. So if you append text, you are not changing the reference. Thus, it makes no sense to use volatile and final at the same time.

Will this change be available to different threads as per Java memory model if this variable is Non-Volatile ?

Because you are using a non thread safe implementation by using StringBuilder, there is no guarantee that all Threads are having the latest state of the StringBuilder.

Martijn Courteaux
  • 67,591
  • 47
  • 198
  • 287
6

Will this change be available to different threads as per Java memory model if this variable is Non-Volatile

Yes, but that's because StringBuffer is thread safe - meaning that it internally provides locking, which will cause memory barriers so other threads see the update.

A reference being volatile doesn't affect the operations on the object, it affects the reference.

So you could do

 volatile StringBuilder b = new StringBuilder();

 b = someOtherStringBuilder;

now since b is volatile, other threads would see this update of the reference.

However doing

 b.append("foo");

There's no guarantee the other threads would see the change to the existing b object. StringBuilder is, unlike StringBuffer not threadsafe, so you shouldn't do that without providing your own locking anyway.

If you wanted to guarantee b.append("foo"); to be visible to other threads without any locking, each member field in StringBuilder would need to be volatile too. (Though that doesn't make it thread safe)

nos
  • 223,662
  • 58
  • 417
  • 506
  • 1
    Ok, I will use a StringBuilder for this example. Whats your answer now ? And How ? – Geek Sep 11 '13 at 18:46
  • Dear nos are you sure about "There's no guarantee the other threads would see the change to the existing b object". Most of the world works this way. Of course I could be wrong too. – Geek Sep 11 '13 at 18:53
  • 2
    @Geek Yes I am sure about that. And as mentioned, if you need to share this StringBuilder with other threads, you would anyway need to provide your own locking/synchronizing when using that StringBuilder object. Those locks will provide the memory barriers needed so the changes would be visible. – nos Sep 11 '13 at 18:57
  • Thanks nos, I get it now. The answer is well written. – Geek Sep 11 '13 at 19:13
5

Remember that volatile and final affect the variable/member but do not affect the mutability of (or the thread-safety of actions upon) the object named/referenced therein! (The other answers explain why the modifiers do not make sense together.)

In the given case, sb.append(..) modifies the named/referenced object (although it does not modify the variable/member) and is not safe for cross-threading using either modifier.


While, as others have pointed out, StringBuilder adds some internal synchronization this only implies that it won't "become corrupted" at its internal data-structure level.

However, switching to a StringBuilder is still not [inherently] thread-safe. Thread-safety has a lot to do with the atomic scope of various actions - and to make a judgement without seeing everything in play and how to it is permitted to interact in a valid exectuion would be misleading.

For instance, consider the following code executed from multiple threads (and assume that sb is now a StringBuilder object). What will the order be?

sb.append("a").append("b");

What would happen if the code was changed as follows? Which is [more] "thread-safe"?

synchronized (this) {
  sb.append("a").append("b");
}
user2246674
  • 7,621
  • 25
  • 28
  • so basically volatile does not guarantee that I see all updates to a Non-Threadsafe object. Correct ? – Geek Sep 11 '13 at 19:10
  • @Geek Correct. `volatile` *only* guarantees that the value ("reference of" for objects) assigned to the variable/member is done atomically and made immediately visible among threads. It says nothing about the object that is named by (who's "reference is stored in") the variable. I prefer to consider that "variables name objects" (as this can be used correctly and consistently among numerous languages), but the JLS is filled with discussion about references. – user2246674 Sep 11 '13 at 19:18
  • @Geek Note that by saying that a "variable *names* an object" it is implied that a "variable *is not* an object" (for simplicity take the previous only in context of object/reference types). Rather, a variable is just a monikor/name for an object - and just like a person, an object can have many names. – user2246674 Sep 11 '13 at 19:21
3

The question completely misunderstands the implications of an object reference across multiple threads. In general volatile is most interesting around primitives, and that is generally where you see it.

Final and volatile only impact the variable as it contains an object reference, which is a handle to the Object's location in memory, nothing more. So for illustration, let's say a reference to a StringBuilder (or whatever) is 9AF5. If that is final, it will not change after the object is constructed. It is therefore (at least since Java 1.5, don't remember before that) thread safe, as any thread can reference that variable, reference a copy of that, or whatever the CPU wants to do about optimizing that access, because at the end of the day, it will not change, and as such if you look at 9AF5, you don't have to check if the value of the reference contained in the object with a final declaration actually changed.

Since final guarantees the thread safety to the same level that volatile would, the volatile is superfluous.

If the variable is non-final, then volatile ensures that all threads see the 9AF5 consistently, and that if you change the value (by assigning a new StringBuilder, for example) so the value now becomes 1D7C, no thread will be holding on to an invalid old copy and think the value is still 9AF5.

None of this affects the content of the StringBuilder object, just the Handle to its location in memory.

Yishai
  • 90,445
  • 31
  • 189
  • 263
  • Removed my +1 again: `final` does not guarantee Thread safety when we talk about object references. Content can change. Why do you say: "*you don't have to check if the object's value actually changed.*" The object members are not declared as final or volatile. – Martijn Courteaux Sep 11 '13 at 19:05
  • Final guarantees the thread saftey of the reference. In other words it guarantees the same thread saftey that volatile would guarantee. I touched up the answer to make that clearer. – Yishai Sep 11 '13 at 19:06
  • Okay, but I still do not agree with "*you don't have to check if the object's value actually changed.*". Did you mean the "reference value"? Of course the "value" (which is a bad word in so many ways in this case) can change: you can change the underlying string. – Martijn Courteaux Sep 11 '13 at 19:11
  • Okay, the object in that statement refers to the object who's class contains the final reference declaration, not any other object. I tried to edit the answer to make that clearer. – Yishai Sep 11 '13 at 19:14
  • Now you've got my +1 back :) – Martijn Courteaux Sep 11 '13 at 19:24
2

Memory visibility guarantees provided by volatile and final are actually quite similar:

  • volatile guarantees that any change made by Thread A before write to volatile variable will be seen by Thread B after subsequent read from that variable

  • final guarantees that any change made by Thread A to the state of the object referenced by final field before initialization of that field will be seen by Thread B, if Thread B accesses that object via that field

As you can see, given the fact that final field can be normally initialized only once, these guarantees are very similar - the only major difference is that guarantee provided by final field covers only objects referenced by that field.

Therefore it doesn't make much sense to combine these guarantees on the same field.

Also both guarantees don't cover the situation in question, when state of the referenced object is changed without changing the field itself.

axtavt
  • 239,438
  • 41
  • 511
  • 482
  • So I get that. The guarantees are for Reference ONLY. What happens to the state of the object ? Does the guarantee to "Reference ONLY" also ensure that updates to the object via setter methods will be seen by other threads ? It seems like it should else volatile doesn't make much sense on an object of type say Employee which has lot of members inside it. – Geek Sep 11 '13 at 19:07
  • 1
    @Geek, you are starting to understand. Volatile doesn't make much sense around object references (with some exceptions around its instruction reordering protection as of Java 1.5, but that is a whole other discussion). – Yishai Sep 11 '13 at 19:09
  • Yes, guarantees provided by `volatile` only work when you update the field itself. However, I've seen a trick (perhaps even in JRE code) to assign the same value to `volatile` variable in order to enforce memory visibility. – axtavt Sep 11 '13 at 19:11
0

when you declare object field as final you need to initialize it in object's constructor and then final field won't change it's value. When you declare object's field as volatile, field's value can change, but still every read of value from any thread will see latest value written to it.

So, a volatile field gives you guarantees as what happens when you change it. (No an object which it might be a reference to). A final fields cannot be chanced (What the fields reference can be changed) . It makes no sense to have both.

Gyanendra Dwivedi
  • 5,511
  • 2
  • 27
  • 53