52

If in a class I have a ConcurrentHashMap instance that will be modified and read by multiple threads I might define like this:

public class My Class {

    private volatile ConcurrentHashMap<String,String> myMap = new ConcurrentHashMap<String,String>();
...
}

adding final to the myMap field results in an error saying I can only use final or volatile. Why can it not be both?

Victor Sorokin
  • 11,878
  • 2
  • 35
  • 51
Alb
  • 3,601
  • 6
  • 33
  • 38
  • somewhat related http://stackoverflow.com/questions/2964206/java-concurrency-volatile-vs-final-in-cascaded-variables – Jayan Feb 17 '12 at 12:38

8 Answers8

45

volatile only has relevance to modifications of the variable itself, not the object it refers to. It makes no sense to have a final volatile field because final fields cannot be modified. Just declare the field final and it should be fine.

Michael Borgwardt
  • 342,105
  • 78
  • 482
  • 720
  • 1
    just like to clarify your comment that "final fields cannot be modified"; final fields are, in fact, mutable, but that the final keyword only allows assignment to take place one time. – johntrepreneur Jan 16 '14 at 04:33
  • 5
    @johnterpreneur: that is not correct; final fields can be assigned to *only during construction of the object*, which is pretty much the definition of "immutable". – Michael Borgwardt Jan 16 '14 at 07:17
  • if use of keyword `final` made the objects immutable as you stated, then declaring a `StringBuilder` member variable final wouldn't allow you modify it. However you can modify it and call `.append` to change the object. – johntrepreneur Jan 17 '14 at 18:02
  • package test; public class FinalIsMutable { public static final StringBuilder MUTABLE_MEMBER = new StringBuilder("hello"); public static void main(String[] args) { MUTABLE_MEMBER.append("world"); System.out.println(MUTABLE_MEMBER.toString()); //prints "helloworld" } } – johntrepreneur Jan 17 '14 at 18:02
  • immutable and object assignment/re-assignment are not the same thing. If they were the same thing, then you'd only need to make a collection final to prevent it from being modified, but that is not the case and is why there are specific java APIs to accomplish this task for collections such as Collections.unmodifiableList(), 'Collections.unmodifiableMap()`, etc... – johntrepreneur Jan 17 '14 at 18:05
  • 3
    @johntrepreneur: Ah, now I see where the misunderstanding occurs. As I wrote in the answer, there is a difference between a field and the object it refers to - an important distinction that you're apparently missing (or using the wrong terminology for). `final` means the *field itself* cannot be modified, but it can still refer to a mutable object. The content of the field is just a reference (for non-primitive types), not an object. – Michael Borgwardt Jan 17 '14 at 20:33
  • @johntrepreneur, in other words, if you have a variable, final List fooList; you can add and remove members from the List, but you can not change the variable to refer to a different List. – Solomon Slow May 29 '14 at 20:21
  • @MichaelBorgwardt This can present a problem though. Imagine you have a constructor with a final boolean. As part of the construction, you have this object added to a cache. The boolean is true (for this object anyway - perhaps not for all objects of this class/superclass) but isn't set to true until after it's added to the cache. If the cache calls a method (getKey for example so it knows how to properly store the object) from another thread it may cache that value as false in its local thread context, since it's final. It then gets set to true at the end of the constructor. Rut roh! – corsiKa Oct 17 '14 at 21:39
  • I agree with @johntrepreneur that a reference field should only be considered immutable if it references an immutable object. On another note, `volatile` could still function as a read memory barrier, even on a `final` field. Though I admit that's a bit of a stretch. – shmosel May 16 '16 at 15:43
  • @shmosel You're both technically wrong, although your definition is more popular. A field is a reference to an object, not an actual object itself. So when you modify the object, you aren't modifying the reference/field. Consider a reference as equivalent to a pointer in C, and an object as a location in memory. Consider if Class A has a private field F1 that refers to an object O. Class B has a field F2 that refers to that same object O. Class B modifies O through its F2 reference. F1 in class A has obviously not been modified since it's not even visible to class B. –  Apr 30 '17 at 22:30
  • 1
    @corsiKa that’s why objects should never leak during construction. This problem is not exclusive to `final` fields… – Holger Jan 14 '20 at 08:24
  • 2
    @shmosel the Java standard does not define memory barriers. There’s a *happens-before* relationship between a read and the write of that value for *both*, `final` and `volatile` variables. A thread does not get additional guarantees by performing subsequent reads of the same value. Implementations like the HotSpot JVM may conservatively insert a barrier every time you read a `volatile` variable, but you still wouldn’t be able to build a correct program relying on that. when the value didn’t change. So for `final` variables which do not change again, `volatile` wouldn’t make any sense. – Holger Jan 14 '20 at 08:34
  • This answer doesn't make sense to me " because final fields cannot be modified" But container object (with its final field) can be constructed on one thread and accessed later from another... "modifications of the variable itself" is irrelevant to the question: question is about reference. – minsk Oct 02 '20 at 02:28
  • @minsk: the question is about a variable containing a reference. If the variable is final, its contents (the reference) can never change, which makes the volatile keyword, which only has an effect on variables whose contents *can* change, non-applicable. – Michael Borgwardt Oct 02 '20 at 14:58
39

It's because of Java Memory Model (JMM).

Essentially, 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. And JMM promises that after ctor is finished any thread will see the same (correct) value of final field. So, you won't need to use explicit synchronization, such as synchronize or Lock to allow all threads to see correct value of final field.

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, final and volatile achieve same purpose -- visibility of object's field value, but first is specifically used for a variable may only be assigned to once and second is used for a variable that can be changed many times.

References:

nish1013
  • 3,658
  • 8
  • 33
  • 46
Victor Sorokin
  • 11,878
  • 2
  • 35
  • 51
  • The explanation is quite fine for me, however I wouldn't say that final is used for 'constant' values. This statement is a bit misleading, though I understand what you wanted to say. – Łukasz Rzeszotarski Sep 11 '13 at 19:04
  • 3
    '"final and volatile" achieve same purpose...' I think that's putting the cart before the horse. The _purpose_ of `final` is to declare that a variable or field must not be assigned. The _purpose_ of `volatile` is to tell the compiler that the value can not be inferred by examining the code. The fact that the Java memory model has special rules about the visibility of each of those two kinds of variable is secondary to their non-overlapping purposes. – Solomon Slow May 29 '14 at 20:31
  • This is the only answer that actually addresses the core question, "JMM promises that after ctor is finished any thread will see the same (correct) value of final field." but provided docs references don't back it up – minsk Oct 02 '20 at 02:47
  • But what if we have `final int[] array`? Thread A assigns `array[index] = 42` and Thread B has no guarantee that it will see this value. – Nick Nick Nov 21 '21 at 22:44
9

Because volatile and final are two extreme ends in Java

volatile means the variable is bound to changes

final means the value of the variable will never change whatsoever

Sunil Kumar B M
  • 2,735
  • 1
  • 24
  • 31
  • The question arises when you create container object on one thread (with its final reference written, yes once, but on a certain thread) and then read that reference it from another thread – minsk Oct 02 '20 at 02:49
4

volatile is used for variables that their value may change, in certain cases, otherwise there is no need for volatile, and final means that the variable may not change, so there's no need for volatile.

Your concurrency concerns are important, but making the HashMap volatile will not solve the problem, for handling the concurrency issues, you already use ConcurrentHashMap.

MByD
  • 135,866
  • 28
  • 264
  • 277
  • 1
    You can't make a HashMap (or any other object) `volatile`. The 'volatile' keyword affects the variable, not the objects to which the variable may refer. – Solomon Slow May 29 '14 at 20:34
3

volatile modifier guarantees that all reads and writes go straight to main memory, i.e. like the variable access is almost into synchronized block. This is irrelevant for final variable that cannot be changed.

Vishal Yadav
  • 3,642
  • 3
  • 25
  • 42
AlexR
  • 114,158
  • 16
  • 130
  • 208
3

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 field cannot be changed (What the fields reference can be changed)

It makes no sense to have both.

Evgeniy Dorofeev
  • 133,369
  • 30
  • 199
  • 275
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • The question arises because you construct object on one thread and this is where the reference is originally set and then may read that reference on another thread. – minsk Oct 02 '20 at 02:37
2

Because it doesn't make any sense. Volatile affects object reference value, not the object's fields/etc.

In your situation (you have concurrent map) you should do the field final.

kan
  • 28,279
  • 7
  • 71
  • 101
0

In a multithread environment different threads will read a variable from main memory and add it to the CPU cache. It may result in two different threads making changes on the same variable, while ignoring each others results. enter image description here

We use word volatile to indicate that variable will be saved in main memory and will be read from main memory. Thus whenever a thread want to read/write a variable it will be done from main memory, essentially making a variable safe in multithread environment.

When we use final keyword we indicate that variable will not change. As you can see if a variable is unchangeable, than it doesn't matter if multiple threads will use it. No thread can change the variable, so even if variable is saved to CPU caches at different times, and threads will use this variable at different times than it's still ok, because the variable can only be read.

M1kyyy
  • 41
  • 5