2011-09-30 24 views
9

Estoy haciendo una revisión de código para un cambio en un producto Java que no sea de mi propiedad. No soy un experto en Java, pero sospecho que esto no tiene sentido e indica un malentendido fundamental sobre cómo funciona la sincronización.Uso confuso de sincronizado en Java: ¿patrón o antipatrón?

synchronized (this) { 
    this.notify(); 
} 

Pero podría estar equivocado, ya que Java no es mi patio de recreo principal. Tal vez hay una razón por la que esto está hecho. Si puedes aclararme lo que el desarrollador estaba pensando, te lo agradecería.

+6

I * * pensar que esto es más apropiado para http://codereview.stackexchange.com – BalusC

+1

Material de lectura: http://stackoverflow.com/questions/442564/avoid-synchronizedthis-in- java – claymore1977

+3

¿Se está preguntando si la sincronización es necesaria antes de la llamada a 'notify()'? El hilo ** debe ** sostener el monitor del objeto cuando llama a 'notify()', por lo que esto es obligatorio en general. –

Respuesta

10

Ciertamente, no es inútil, puede tener otro hilo que tiene una referencia al objeto que contiene el código anterior haciendo

synchronized(foo) { 
    foo.wait(); 
} 

con el fin de ser despertado cuando sucede algo. Sin embargo, en muchos casos se considera una buena práctica sincronizar en un objeto de bloqueo interno/privado en lugar de this.

Sin embargo, única haciendo un .notify() dentro del bloque de sincronización podría ser bastante mal - por lo general tienen mucho trabajo por hacer y notificar cuando se hace, que en casos normales También hay que hacer atómicamente en lo que respecta a otros hilos Tendríamos que ver más código para determinar si realmente está mal.

+0

Parece obvio en retrospectiva. Ahora tengo que desentrañar cómo funciona todo esto. –

+0

Bueno, no puedo encontrar dónde él llama this.wait(), así que he enviado comentarios preguntándome si esto es realmente necesario en absoluto. –

1

Por lo general, este no es un antipatrón si aún desea utilizar bloqueos intrínsecos. Algunos pueden considerar esto como un patrón anti, ya que los nuevos bloqueos explícitos de java.util.concurrent son más finos.

Pero su código sigue siendo válido. Por ejemplo, dicho código se puede encontrar en una cola de bloqueo, cuando una operación de bloqueo ha tenido éxito y se debe notificar a otro hilo en espera. Sin embargo, tenga en cuenta que los problemas de concurrencia dependen en gran medida del uso y del código que lo rodea, por lo que su fragmento simple no es tan significativo.

1

La documentación de la API de Java para Object.notify() indica que el método "solo debe ser llamado por un hilo que sea el propietario del monitor de este objeto". Entonces el uso podría ser legítimo dependiendo del contexto circundante.

2

Esto está perfectamente bien. De acuerdo con Java 6 Object#notify() api documentation:

Este método solo debe ser llamado por un hilo que sea el propietario del monitor de este objeto.

+0

"Fino" como en un uso correcto de la API. Pero el OP estaba preguntando algo si era un * patrón * o * antipatrón *. – Raedwald

3

Si eso es todo lo que se encuentra en el bloque sincronizado entonces es un anti patrón, el punto de sincronización es hacer algo dentro del bloque, el establecimiento de alguna condición, a continuación, llamar notify o notifyAll para despertar una o más hilos de espera.

Cuando se utiliza de espera y notificar usted tiene que utilizar una variable de estado, ver this Oracle tutorial:

Nota: Siempre invocar espera dentro de un bucle que las pruebas para la enfermedad que se esperaban. No suponga que la interrupción fue para la condición particular que estaba esperando, o que la condición sigue siendo verdadera.

Usted no debe asumir que ha recibido una notificación sólo porque salía un hilo de una llamada a objeto # esperan, por múltiples razones:

  • Al llamar a la versión de esperar que toma un valor de tiempo de espera No hay forma de saber si la espera terminó debido a recibir una notificación o debido a un tiempo de espera.

  • Tiene que permitir la posibilidad de que un subproceso pueda despertar sin haber recibido una notificación (el "despertador espurio").

  • El hilo de espera que recibe una notificación todavía tiene que volver a adquirir el bloqueo que abandonó cuando comenzó a esperar, no hay un enlace atómico de estos dos eventos; en el intervalo entre la notificación y la readquisición del bloqueo, otro subproceso puede actuar y posiblemente cambiar el estado del sistema para que la notificación no sea válida.

  • Puede tener un caso donde el hilo notificador actúa antes de que un hilo esté esperando para que la notificación no tenga ningún efecto. Suponiendo que un hilo entrará en espera antes de que el otro hilo lo notifique sea peligroso, si está equivocado, el hilo de espera se colgará indefinidamente.

Así una notificación por sí sola no es suficiente, se termina tratando de adivinar si una notificación ocurrió cuando la espera/notificar a la API no le da suficiente información para saber lo que está pasando. Incluso si otro trabajo que realiza el hilo de notificación no requiere sincronización, la actualización de la variable de condición sí lo requiere; al menos debería haber una actualización de la variable de condición compartida en el bloque sincronizado.

+0

Esto es lo que pensé, pero parece que a veces es posible que desee sincronizar la sincronización. –

+1

Eso definitivamente no siempre es cierto. Tal vez lo que se hace antes de la notificación no necesita ser sincronizado. No hay daño en la sincronización granular, eso suele ser algo bueno. Un ejemplo simple podría ser un hilo de fondo que está esperando que el usuario haga clic en un botón (a través de esperar en un objeto). Cuando Swing notifica al ActionListener, puede realizar la notificación utilizando el código anterior. –

+0

@Mark suena muy peligroso si la condición se actualiza sin protección; el otro hilo que examina la condición puede ver un estado inconsistente. – irreputable

Cuestiones relacionadas