2010-06-17 5 views
5

Ich habe mit einer Entscheidung zu kämpfen. Ich schreibe eine thread-sichere Bibliothek/API. Listener können registriert werden, sodass der Client benachrichtigt wird, wenn etwas Interessantes passiert. Welche der beiden Implementierungen ist am häufigsten anzutreffen?Benachrichtigen Hörer innerhalb oder außerhalb der inneren Synchronisation

class MyModule { 
    protected Listener listener; 

    protected void somethingHappens() { 
     synchronized(this) { 
      ... do useful stuff ... 
      listener.notify(); 
     } 
    } 
} 

oder

class MyModule { 
    protected Listener listener; 

    protected void somethingHappens() { 
     Listener l = null; 

     synchronized(this) { 
      ... do useful stuff ... 
      l = listener; 
     } 
     l.notify(); 
    } 
} 

In der ersten Implementierung wird der Zuhörer in der Synchronisation benachrichtigt. In der zweiten Implementierung erfolgt dies außerhalb der Synchronisation.

Ich glaube, dass der zweite empfohlen wird, da es weniger Platz für potenzielle Deadlocks bietet. Aber ich habe Schwierigkeiten, mich zu überzeugen.

Ein Nachteil der zweiten Implementation ist, dass der Client "inkorrekte" Benachrichtigungen erhalten kann, was passiert, wenn das Modul vor der l.notify() Anweisung aufgerufen und geändert wurde. Wenn beispielsweise das Modul aufgefordert wurde, keine Benachrichtigungen mehr zu senden, wird diese Benachrichtigung trotzdem gesendet. Dies ist bei der ersten Implementierung nicht der Fall.

Dank viel

Antwort

1

Es hängt davon ab, wo Sie Zuhörer in Ihrer Methode bekommen, wie viele Zuhörer Sie haben, wie der Hörer An-/Abmeldungen

aus Ihrem Beispiel Angenommen, Sie nur einen Zuhörer haben dann Es könnte besser sein, kritische Abschnitte (oder Monitore) für verschiedene Teile der Klasse zu verwenden, anstatt das gesamte Objekt zu sperren.

Sie können eine Sperre zum Ausführen von Aufgaben innerhalb der Methode verwenden, die für das jeweilige Objekt/Aufgabe spezifisch sind, und eine für den Listener subscribe/unsubscribe/notify (um sicherzustellen, dass der Listener während einer Benachrichtigung nicht geändert wird)).

Ich würde auch einen ReadWriteLock verwenden Sie Hörer Referenzen schützen (entweder einzelne oder eine Liste von Hörern)

Beantworten Sie Kommentar:

denke ich, dass Sie sollte den Hörer benachrichtigen, nachdem Sie freigeschaltet haben die Klasse. Dies liegt daran, dass das Ergebnis dieser Benachrichtigung dazu führen könnte, dass ein anderer Thread versucht, Zugriff auf die Klasse zu erhalten, was unter bestimmten Umständen möglicherweise nicht zu einem Deadlock führen kann.

Einen Listener benachrichtigen (wenn er wie beschrieben geschützt ist) sollte keinen anderen Thread halten, der die Einrichtungen der Klasse benötigt. Die beste Strategie besteht darin, Sperren zu erstellen, die für den Status der Klasse spezifisch sind, und Sperren, die für sichere Benachrichtigungen spezifisch sind.

Wenn Sie Ihr Beispiel für das Unterbrechen von Benachrichtigungen verwenden, könnte dies durch die Sperre für Benachrichtigungen abgedeckt sein. Wenn also ein anderer Thread Benachrichtigungen "aussetzt", wird entweder der Suspend verarbeitet oder die aktuelle Benachrichtigung abgeschlossen setzt die Benachrichtigung zwischen der zu bearbeitenden Aufgabe und der erfolgten Benachrichtigung aus, die l.notify() wird nicht ausgeführt.

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(); 
+0

Danke für Ihre Antwort. Ich erwähne absichtlich nicht den Subskribierungs-/Abmeldepart. Ich möchte annehmen, dass es einen festen Zuhörer gibt. Meine Frage ist eher, wenn es sinnvoll ist, die Synchronisation außerhalb der Klasse zu offenbaren oder nicht. –

+0

@Jary Zeels, siehe Ergänzungen zu beantworten –

+0

Danke Adrian für Ihre Klarstellung, ich verstehe es jetzt. Die Situation mit einem Zuhörer ist mir klar. Ich werde über die Situation nachdenken, wenn mehr Zuhörer registriert werden können, weil dann Wiedereintritt ein Problem sein kann. Sie möchten nicht, dass die Ereignisse in der falschen Reihenfolge übermittelt werden, wenn z. B. einer der angemeldeten Listener eine Aktion ausführt, die eine neue Benachrichtigung auslöst. Ich werde darüber nachdenken und bei Bedarf weitere Fragen stellen. Danke noch einmal. –

Verwandte Themen