api - comandos - clusvcadm
notificar al oyente dentro o fuera de la sincronización interna (1)
Estoy luchando con una decisión. Estoy escribiendo una biblioteca / API segura para subprocesos. Los oyentes pueden registrarse, por lo que se notifica al cliente cuando sucede algo interesante. ¿Cuál de las dos implementaciones es la más común?
class MyModule {
protected Listener listener;
protected void somethingHappens() {
synchronized(this) {
... do useful stuff ...
listener.notify();
}
}
}
o
class MyModule {
protected Listener listener;
protected void somethingHappens() {
Listener l = null;
synchronized(this) {
... do useful stuff ...
l = listener;
}
l.notify();
}
}
En la primera implementación, el oyente recibe una notificación dentro de la sincronización. En la segunda implementación, esto se hace fuera de la sincronización.
Siento que el segundo es aconsejable, ya que deja menos espacio para bloqueos potenciales. Pero estoy teniendo problemas para convencerme a mí mismo.
Una desventaja de la segunda imlementación es que el cliente podría recibir notificaciones ''incorrectas'', lo que sucede si accede y cambia el módulo antes de la instrucción l.notify (). Por ejemplo, si le pide al módulo que deje de enviar notificaciones, esta notificación se envía de todos modos. Este no es el caso en la primera implementación.
muchas gracias
Depende de dónde obtiene oyente en su método, cuántos oyentes tiene, cómo el oyente suscribe / anula la suscripción
Asumiendo por su ejemplo, usted solo tiene un oyente, entonces sería mejor usar secciones críticas (o monitores) para diferentes partes de la clase en lugar de bloquear todo el objeto.
Puede tener un bloqueo para realizar tareas dentro del método que sean específicas del objeto / tarea en cuestión, y otro para el oyente suscribirse / cancelar suscripción / notificar (esto es para garantizar que el oyente no se modifique durante una notificación).
También usaría ReadWriteLock para proteger tus referencias de oyentes (ya sea solo o lista de oyentes)
Respondiendo tu comentario:
Creo que deberías notificar al oyente después de que hayas desbloqueado la clase. Esto se debe a que el resultado de esa notificación podría dar como resultado un hilo diferente al tratar de obtener acceso a la clase, lo que podría no ser capaz, bajo ciertas circunstancias, de llevar a un punto muerto.
Notificar a un oyente (si está protegido como he descrito) no debe contener ningún otro hilo que requiera las instalaciones de la clase. La mejor estrategia es crear bloqueos que sean específicos del estado de la clase y bloqueos específicos de la notificación segura.
Si toma su ejemplo de suspensión de notificaciones, esto podría estar cubierto por el bloqueo que rige las notificaciones, por lo que si un hilo diferente ''suspende'' las notificaciones, se procesará la suspensión o se completará la notificación actual, si el otro hilo suspende la notificación entre el la tarea que se está procesando y la notificación que está ocurriendo, el l.notify () no sucederá.
Listener l = null;
synchronised(processLock_) {
... do stuff....
synchronised(notifyLock_) {
l = listener;
}
}
//
// current thread preempted by other thread that suspends notification here.
//
synchronised(notifyLock_) { // ideally use a readwritelock here...
l = allowNotify_ ? l: null;
}
if(l)
l.notify();