Java – immutable array thread safe
I have a question about the JAVA memory model This is a simple class introduction question:
public class ImmutableIntArray { private final int[] array; public ImmutableIntArray() { array = new int[10]; for (int i = 0; i < 10; i++) { array[i] = i; } } // Will always return the correct value? public int get(int index) { return array[index]; } }
As far as I know, JMM ensures that the value of the final field is visible to other threads after construction But I want to make sure that other threads will see the latest version of the data stored in the array after construction
Of course, the above code is only a simple example to raise this problem. In fact, I want to implement a simple cache for direct byte buffer. I don't want to rely on some collection classes I'm currently using reentrant read writelock to ensure correct behavior, but I want to avoid this if I can
Solution
In this case, everything will be fine (well, let's pause and judge) Immutability is a disadvantage in thread safety - if a value cannot be changed, most concurrency problems are no longer a problem
Volatile mentioned by Amir is usually useful - but constructors have similar semantics for final variables to ensure visibility For details, see JLS clause 17.5 – in essence, constructors form the relationship between writing to the final variable and any subsequent reads
Edit: so you set the reference of the array in the constructor, it is visible to all threads at that point, and then it will not change So we know that all other threads will see the same array But what about the contents of the array?
As it is now, array elements do not have any special semantics in terms of volatility, just like you just announced one similar to:
public class ArrayTen { private int _0; private int _1; // ... private int _9; public int get(int index) { if (index == 0) return _0; // etc. } }
So - another thread will only see these variables if we can do something to establish the relationship between events If I understand it correctly, I need to make some small changes to the original code
We already know that the setting of array references occurs before the end of the constructor An always true add - on point is that an action in a thread occurs in an action after the same thread So we can combine them by setting the array field first and then assigning the last field to obtain this transitivity guarantee of visibility This of course requires a temporary variable:
public class ImmutableIntArray { private final int[] array; public ImmutableIntArray() { int[] tmp = new int[10]; for (int i = 0; i < 10; i++) { tmp[i] = i; } array = tmp; } // get() etc. }
I think it's safe. Now we've changed the order of seemingly insignificant tasks and populations
But again, I may have some other errors, which means that concurrency assurance is not as strong as expected This question is a good example in my mind. Why writing bulletproof multithreaded code is difficult, even if you think you are doing something very simple, and it requires a lot of thinking and caution (and then error correction) to be correct