Java: Come fare un doppio controllo di blocco con un elemento array?
-
29-09-2019 - |
Domanda
Questo è ciò che il mio codice attualmente appare come:
private boolean[] isInitialized = new boolean[COUNT];
private void ensureInitialized(int i) {
if (! isInitialized[i]) {
initialize(i);
isInitialized[i] = true;
}
}
Ora voglio avere è thread-safe. So che ricontrollato-bloccaggio in Java è "teh 3vilness !! 1", ma dal momento che ensureInitialized
può essere chiamato molto spesso, non voglio che sia sincronizzato. Così sto pensando di fare questo:
private boolean[] isInitialized = new boolean[COUNT];
private void ensureInitialized(int i) {
if (! isInitialized[i]) {
synchronized (this) {
if (! isInitialized[i]) {
initialize(i);
isInitialized[i] = true;
}
}
}
}
Ora che cosa devo fare per rendere questo in realtà thread-safe?
Alcuni subquestions:
- Fare
isInitialized
volatile non è necessaria, dal momento che la variabile non è cambiata, giusto? - Gli elementi dell'array sono cambiati, come posso fare quelle volatili?
- Ci sono modi generalmente migliori per farlo?
(Si noti inoltre che si tratta di un metodo di istanza, di inizializzazione in modo statico non sarà lavoro)
Soluzione
Si prega di notare che l'attuazione java di duplice controllo è chiamato "modello rotto", perché è stato dimostrato come Fail (per esempio vedere http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html ). Per risolvere basta usare operazione atomica. Seguire è campione come filo accumulo Singleton sicuro:
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);
}
}
}
Altri suggerimenti
Si potrebbe anche considerare l'utilizzo di Suppliers.memoize(Supplier<T> delegate)
da biblioteca guava .