Java: How to do double-checked-locking with an array element?
-
29-09-2019 - |
Question
This is what my code currently looks like:
private boolean[] isInitialized = new boolean[COUNT];
private void ensureInitialized(int i) {
if (! isInitialized[i]) {
initialize(i);
isInitialized[i] = true;
}
}
Now I want to have it thread-safe. I know that double-checked-locking in Java is "teh 3vilness!!1", but since ensureInitialized
may be called very often, I don't want it to be synchronized. So I am thinking of doing this:
private boolean[] isInitialized = new boolean[COUNT];
private void ensureInitialized(int i) {
if (! isInitialized[i]) {
synchronized (this) {
if (! isInitialized[i]) {
initialize(i);
isInitialized[i] = true;
}
}
}
}
Now what do I have to do to make this actually thread safe?
Some subquestions:
- Making
isInitialized
volatile is not necessary, since the variable is not changed, right? - The array elements are changed, how can I make those volatile?
- Are there generally better ways to do this?
(Also notice that this is an instance method, so static initializer will no work)
Solution
Please note that java implementation of double-checking is called "broken pattern" because it was proven as fail (for example see http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html). To work around just use atomic operation. Follow is sample how to build thread safe singleton:
static AtomicReferenceArray<Boolean> instance =
new AtomicReferenceArray<Boolean>(COUNT);
private void ensure(int i)
{
if(!instance.get(i) )
{
synchronized(this){
if( !instance.get(i) ){
initialize(i);
instance.set(i, true);
}
}
}
OTHER TIPS
You could also consider using Suppliers.memoize(Supplier<T> delegate)
from guava library.