2015-10-13 7 views
5

Ich habe einen Jstack Dump, der scheinbar sagt, dass mehrere Threads eine Sperre für das gleiche Objekt erworben haben. Wie ich es verstehe, ist das unmöglich, aber ist es das?Können mehrere Threads auf dasselbe Objekt warten?

Hier ist der Code mit dem entscheidenden Warte Anruf innerhalb Try-Block:

protected boolean waitMaxWaitingTime(UserInfo aUserInfo) throws EventServiceException { 
    final int theMaxWaitingTime = myConfiguration.getMaxWaitingTime(); 
    if(theMaxWaitingTime <= 0) { 
     return true; 
    } 
    if(aUserInfo.isEventsEmpty()) { 
     //monitor for event notification and double checked 
     synchronized(aUserInfo) { 
      if(aUserInfo.isEventsEmpty()) { 
       try { 
        final long theStartTime = System.currentTimeMillis(); 
        // --- THE CRUCIAL WAIT CALL --- 
        aUserInfo.wait(theMaxWaitingTime); 
        return (System.currentTimeMillis() - theStartTime >= theMaxWaitingTime); 
       } catch(InterruptedException e) { 
        throw new EventServiceException("Error on waiting max. waiting time!", e); 
       } 
      } 
     } 
    } 
    return false; 
} 

Und hier ist der jstack dump (selektiv):

"thread-79" #161 daemon prio=5 os_prio=0 tid=0x000000005d63c000 nid=0x322c in Object.wait() [0x000000007e93c000] 
    java.lang.Thread.State: TIMED_WAITING (on object monitor) 
    at java.lang.Object.wait(Native Method) 
    at de.novanic.eventservice.service.connection.strategy.connector.ConnectionStrategyServerConnectorAdapter.waitMaxWaitingTime(ConnectionStrategyServerConnectorAdapter.java:92) 
    - locked <0x000000008b8de758> (a de.novanic.eventservice.service.registry.user.UserInfo) 

"thread-77" #159 daemon prio=5 os_prio=0 tid=0x000000005d63a800 nid=0x5384 in Object.wait() [0x000000007e83c000] 
    java.lang.Thread.State: TIMED_WAITING (on object monitor) 
    at java.lang.Object.wait(Native Method) 
    at de.novanic.eventservice.service.connection.strategy.connector.ConnectionStrategyServerConnectorAdapter.waitMaxWaitingTime(ConnectionStrategyServerConnectorAdapter.java:92) 
    - locked <0x000000008b8de758> (a de.novanic.eventservice.service.registry.user.UserInfo) 

"thread-74" #156 daemon prio=5 os_prio=0 tid=0x000000006efe6000 nid=0x4828 in Object.wait() [0x000000007e25c000] 
    java.lang.Thread.State: TIMED_WAITING (on object monitor) 
    at java.lang.Object.wait(Native Method) 
    at de.novanic.eventservice.service.connection.strategy.connector.ConnectionStrategyServerConnectorAdapter.waitMaxWaitingTime(ConnectionStrategyServerConnectorAdapter.java:92) 
    - locked <0x000000008b8de758> (a de.novanic.eventservice.service.registry.user.UserInfo) 

Wie Sie mehrere verschiedene Themen sehen (gehen durch Namen und tid Thread-IDs, in diesem Thread thread-79 und thread-74) haben offenbar eine Sperre für das gleiche UserInfo-Objekt (0x000000008b8de758) erworben und darauf gewartet. Habe ich mich geirrt oder haben mehrere Threads wirklich Lock erworben und warten auf ein einzelnes Objekt?

+2

Das 'if' sollte ein' while' sein. – EJP

+0

Außer wenn 'aUserInfo.isEventsEmpty()' ["happes-before"] hat (https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4.5) Einschränkungen. Sie dürfen DCL nicht verwenden. JVM ist frei, Anweisungen neu zu ordnen, solange Bedingungen erfüllt sind, bevor "passiert". Mit anderen Worten, Ihre Bedingung kann wahr sein, ohne dass alle angenommenen Operationen verarbeitet werden. Beispiel: Sie setzen einen booleschen Wert auf true, nachdem Sie ein Attribut festgelegt haben.JVM kann Boolean vor dem Setzen des Attributs setzen und kann sogar ein Attribut zuweisen, boolean auf true setzen und schließlich die Instanzinitialisierung (Konstruktoraufruf) verarbeiten. – LoganMzz

+0

@EJP Und 'return' muss nach der Schleife durchgeführt werden;) – LoganMzz

Antwort

5

Ihr Speicherauszug zeigt an, dass mehrere Threads auf dem Objektmonitor warten (warten, um ihn zu erfassen), und nicht, dass mehrere Threads (mehrere) ihn (gleichzeitig) erworben haben. Ersteres ist durchaus möglich und normal. Letzteres kann nicht passieren.

Mit anderen Worten, ja, mehrere Threads haben den Lock/Monitor erworben, aber das passiert seriell (nacheinander). Sobald ein Thread-Aufruf wartet, gibt er die Sperre frei, und dann kann ein anderer Thread sie erfassen (und dann wieder freigeben und so weiter).

+0

Darüber hinaus, ohne die Monitorsperre auf "warten" zu lösen, ist es unmöglich zu "benachrichtigen"! – LoganMzz

0

Die Threads sind auf dem Monitor des Objekts blockiert und besitzen zu keinem Zeitpunkt mehrere Eigentumsrechte. Um Fairness für den Erwerb von Objekten zu gewährleisten, können Sie die Verwendung von Lock in Erwägung ziehen hat ein Objekt Monitor über einen längeren Zeitraum erworben

5

Wie Sie mehr verschiedenen Threads (gehen nach Namen und tid Thread-IDs) haben sehen können erworben offenbar eine Sperre auf demselben UserInfo Objekt (0x000000008b8de758) und rief wait() drauf .

Das ist absolut richtig. Mehrere Threads haben wait() für dasselbe Objekt aufgerufen. Dies klingt zunächst nicht intuitiv, da der Code innerhalb eines synchronized Blocks liegt.

Die documentation erklärt dieses „Geheimnis“: den Ruf wait()gibt den Besitz des Monitors, andere Threads eingeben zu lassen und die Wartezeit starten, wenn sie

wollen die

Der aktuelle Thread besitzen muss dieses Objekt Monitor. Der Thread gibt den Besitzer dieses Monitors frei und wartet, bis ein anderer Thread Threads benachrichtigt, die auf dem Monitor dieses Objekts warten, entweder durch einen Aufruf der notify-Methode oder der notifyAll-Methode. Der Thread wartet dann, bis er den Besitz des Monitors wieder erlangen und die Ausführung fortsetzen kann. (Hervorhebung hinzugefügt)

Verwandte Themen