2012-05-24 17 views
5

mi sono imbattuto in alcuni (produzione!) Il codice che appare come il frammento di seguito:Assegnazione di un oggetto all'interno di un blocco sincronizzato in base a tale oggetto (Java)

synchronized(some_object) { 
    some_object = new some_object() 
} 

mi aspetterei questo per essere oggetto di ogni sorta di orribili condizioni di gara, e che un secondo thread potrebbe entrare in questo blocco quando viene creato il nuovo oggetto. Le mie costolette di Java non sono abbastanza buone per affermare in modo definitivo il comportamento atteso di sopra, così curioso di cosa tu abbia da dire prima di rifarlo.

risposta

2

Come dice Francis, questo potrebbe non essere un problema. Il tuo snippet è equivalente a questo:

SomeObject saved = some_object; 
synchronized(saved) { 
    some_object = new SomeObject() 
} 
+0

Non è scritto esattamente così. Nel mio caso la classe ha la variabile some_object che viene utilizzata per il blocco di sincronizzazione e questa variabile viene riassegnata all'interno dello stesso blocco. –

+0

+1 la chiave qui è che la sincronizzazione si riferisce all'oggetto, non al riferimento. Dopo che il 'new' è stato eseguito e assegnato, sei ancora bloccato sul vecchio oggetto. Il nuovo oggetto non è bloccato a questo punto. Quando il blocco sincronizzato viene chiuso, viene rilasciato il blocco sul vecchio oggetto e, se non vi sono altri riferimenti, è idoneo per gc. Se c'è più codice nel vero blocco sincronizzato e dipende dal blocco in qualche modo trasferito al nuovo oggetto, allora potresti avere un problema. –

+1

Grazie Jim. Il fatto che il lucchetto sia sull'oggetto e non sul riferimento ha senso per me. Quello su cui ero indifferente era quando l'oggetto referenziato da quella variabile era cambiato, un altro thread avrebbe visto un altro oggetto sbloccato e sarebbe entrato di nuovo nel blocco, o fare in modo che i meccanismi di un blocco sincronizzato impedissero che ciò accadesse? –

4

Questo potrebbe effettivamente essere OK a seconda di cosa sta succedendo. Dovresti capire il contesto più ampio. La sincronizzazione sarà sull'oggetto puntato da some_object all'inizio del blocco. Non ci sono abbastanza informazioni dalla tua descrizione per vedere che si tratta di un bug.

La sincronizzazione funzionerà correttamente.

1

La sincronizzazione si trova sull'oggetto a cui è stato fatto il riferimento quando si entra nel blocco sincronizzato. Puntare il riferimento a un altro oggetto all'interno del blocco sincronizzato non influisce affatto sulla sincronizzazione. È ancora sincronizzato sull'oggetto "vecchio".

1

Questo è piuttosto male. sincronizzato è meglio utilizzato sui membri della classe finale.

L'approccio moderno alla creazione di un oggetto in modalità thread safe sta utilizzando AtomicReference compareAndSet in un ciclo come discusso in Concorrenza in azione Java di Goetz (cap. 15). Questo non blocca i thread e offre prestazioni di gran lunga superiori rispetto a un blocco sincronizzato.

private final AtomicReference<SomeObject> someObject = new AtomicReference<>(); 


void buildIt() { 
    SomeObject obj = new SomeObject(); 
    SomeObject current = someObject.get(); //probably null, but doesn't matter 
    while (true) { 
     if (someObject.compareAndSet(current, obj)) 
      break; 
    } 
} 
Problemi correlati