2012-05-24 13 views
5

me encontré con algunos (producción!) De código que se ve como el siguiente fragmento:Asignación de un objeto dentro de un bloque sincronizado sobre la base de ese objeto (Java)

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

Yo esperaría que esto sea objeto de todo tipo de condiciones de carrera horribles, y que un segundo subproceso podría entrar en este bloque cuando se crea el nuevo objeto. Mis chuletas de Java no son lo suficientemente buenas como para indicar definitivamente el comportamiento esperado de arriba, por lo que es curioso lo que ustedes tienen que decir antes de refactorizar esto.

Respuesta

2

Como dice Francis, esto puede no ser un problema. Su fragmento es equivalente a esto:

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

No está escrito así. En mi caso, la clase tiene la variable some_object que se usa para el bloque de sincronización, y esta variable se reasigna dentro de ese mismo bloque. –

+0

+1 la clave aquí es que la sincronización se refiere al objeto, no a la referencia. Después de que se ejecuta y asigna el 'nuevo', todavía está bloqueado en el objeto viejo. El nuevo objeto no está bloqueado en este punto. Cuando se sale del bloque sincronizado, se libera el bloqueo del antiguo objeto, y si no existen otras referencias a él, es elegible para gc. Si hay más código en el bloque sychronized real y depende de que el bloqueo se transfiera de alguna manera al nuevo objeto, entonces es posible que tenga un problema. –

+1

Gracias Jim. El hecho de que el bloqueo esté en el objeto y no en la referencia tiene sentido para mí. Lo que me confundió fue cuando el objeto referenciado por esa variable cambió, ¿otro hilo vería un objeto desbloqueado diferente y entraría en el bloque nuevamente, o los mecanismos de un bloqueo sincronizado evitarían que eso sucediera? –

4

Esto realmente podría estar bien dependiendo de lo que esté pasando. Necesitarías entender el contexto más amplio. La sincronización se realizará en el objeto apuntado por some_object al comienzo del bloque. No hay suficiente información de tu descripción para ver si se trata de un error.

La sincronización en sí funcionará perfectamente.

1

La sincronización se realiza en el objeto al que se hizo referencia al ingresar al bloque sincronizado. Apuntar la referencia a otro objeto dentro del bloque sincronizado no afecta la sincronización en absoluto. Todavía está sincronizado sobre el objeto "viejo".

1

Esto es bastante malo. sincronizado se usa mejor en los miembros finales de la clase.

El enfoque moderno para crear un objeto de manera segura para hilos es utilizar AtomicReference compareAndSet en un bucle como se discutió en Java Concurrency in Action de Goetz (capítulo 15). Esto no bloquea tus hilos y ofrece un rendimiento mucho mayor que un bloque sincronizado.

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; 
    } 
} 
Cuestiones relacionadas