Java concurrency: is final field (initialized in constructor) thread-safe?

|▌冷眼眸甩不掉的悲伤 提交于 2019-11-27 01:51:27

As already pointed out it's absolutely thread-safe, and final is important here due to its memory visibility effects.

Presence of final guarantees that other threads would see values in the map after constructor finished without any external synchronization. Without final it cannot be guaranteed in all cases, and you would need to use safe publication idioms when making newly constructed object available to other threads, namely (from Java Concurrency in Practice):

  • Initializing an object reference from a static initializer;
  • Storing a reference to it into a volatile field or AtomicReference;
  • Storing a reference to it into a final field of a properly constructed object; or
  • Storing a reference to it into a field that is properly guarded by a lock.

Yes it is. There is no way to modify the reference aMap itself, or add to the map after the constructor (barring reflection).

If you expose aMap it will not be, because two threads could then modify the map at the same time.

You could improve your class by making aMap unmodifiable via Collections.unmodifiableCollection or Collections.unmodifiableMap.

Guava has immutable classes for making this sort of thing easier and guaranteed immutable:

private final ImmutableMap<String, String> aMap = ImmutableMap.of(
    "1", "a",
    "2", "b",
    "3", "c");

This class has no concurrency issue cause you expose only a get method. If you add some method that modify the map you have to mark this method as synchronized.

Yes it is, provided this is the entire class definition and not a snippet thereof.

The key fact is that there is no way the contents of aMap can be modified post-construction.

As it is now it should be thread-safe. However if you add other methods which modify the hashmap then no.

I don't think the above code snippet is thread safe. The only line that is code safe is

aMap = new HashMap<String, String>();

As per example given in http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html,

class FinalFieldExample {
    final int x;
    int y;
    static FinalFieldExample f;
    public FinalFieldExample() {
      x = 3;
      y = 4;
    }

    static void writer() {
       f = new FinalFieldExample();
    }

   static void reader() {
     if (f != null) {
       int i = f.x; // x is guaranteed to be 3
       int j = f.y; // y can have any value 
     }
   }
}

This means that once the final fields are initialized there is no thread safety guaranteed. Since only the reference assignment is guaranteed to be thread safe and object itself can be mutable as per your example. Following statement might not be thread safe

aMap.put("1", "a");
aMap.put("2", "b");
aMap.put("3", "c");

EDIT My bad saw the comments below the code later

The ability to see the correctly constructed value for the field is nice, but if the field itself is a reference, then you also want your code to see the up to date values for the object (or array) to which it points. If your field is a final field, this is also guaranteed. So, you can have a final pointer to an array and not have to worry about other threads seeing the correct values for the array reference, but incorrect values for the contents of the array. Again, by "correct" here, we mean "up to date as of the end of the object's constructor", not "the latest value available".

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!