2016-08-01 34 views
0

Ich bin eine while-Schleife verwenden, die für eine Bedingung überprüft zu werden wahr:Sind während True Loops, die nur für eine Bedingung thread sicher sind?

while(Game.gameState != Game.CLOSING) 
{ 
    if(reconnecting) 
    { 
     time = System.currentTimeMillis(); 
    } 
    else 
    { 
     while(time + desiredWait > System.currentTimeMillis()) 
     { 
      try{Thread.sleep(5);}catch(InterruptedException e){} 
     } 

     time += desiredWait; 
    } 

    synchronized (Game.gameStateLock)//added to circumvent the problem 
    { 
     if(Game.gameState == Game.INPROGRESS)//problematic condition 
     { 
      while(true) 
      { 
       synchronized (Lockstep.nextTurns) 
       { 
        if(!Lockstep.nextTurns.isEmpty() || lockstep.currentTurn == 0) 
         break; 
       } 

       try{Thread.sleep(5);}catch(InterruptedException e){} 

       time = System.currentTimeMillis(); 
      } 

      Lockstep.attemptTurn(); 
     } 
    } 
} 

Die Schleife, ohne schlafen ununterbrochen läuft (wenn reconnecting wahr ist), und daher greift Game.gameState (vom Typ int) zweimal in jedem Zyklus. Wenn gameState nun in einem zweiten Thread geändert wird (z. B. über ein Netzwerk), erkennt die while-Schleife/if-Bedingung dies nicht und weigert sich weiterhin, den Code im if-Block auszuführen, selbst wenn dies der Fall ist. Die hinzugefügte Synchronisierung (Game.gameStateLock) löst dieses Problem. Es ist auch sehr schwer zu debuggen, weil das Drucken des Spielstatus oder irgendetwas anderes dazu führt, dass das Problem nicht existiert. Meine Vermutung ist, dass I/O den Thread unterbricht/unterbricht oder veranlasst, dass so viele Daten geschrieben/gelesen werden, dass der Cache der CPU gelöscht wird und die Variable gameState, die die ganze Zeit aus dem Cache gelesen wurde, neu geladen werden muss RAM.

Kann dies der Grund sein? Ich nahm an, dass primitive Datentypen im Umgang mit mehreren Threads kein großes Problem darstellen (es sei denn, Sie überprüfen einen booleschen Wert und setzen ihn dann so, dass er andere Threads blockiert). Sind primitive Datentypen in Java threadsicher? (Ich kann nicht einmal auf ihnen synchronisieren, benötigt ein Dummy-Objekt)

+3

Entwickelt sich das Problem in irgendeiner Weise, indem GameState instabil wird? –

+0

Wenn GameState nicht als flüchtig definiert ist, dann haben Sie ein Problem mit Ihrer äußeren while-Schleife. Sie könnten auf seinen Wert zugreifen, während er gleichzeitig von einem externen Thread gesetzt werden könnte. Siehe http://StackOverflow.com/Questions/9278764 – mdewit

+1

Also hinzufügen volatile zu der Variable würde mein Problem lösen? – Geosearchef

Antwort

2

"Thread sicher" ist nicht wirklich der Begriff, den Sie suchen, die möglicherweise warum Sie kämpfen. Ihr Code ist technisch "threadsicher", da Sie keine Beschädigung durch Multithreading feststellen können. Was Sie jedoch vermissen, sind Garantien in Bezug auf "Sichtbarkeit". In Ihrer Situation gibt es keine Garantie dafür, dass die Änderung eines Threads für einen anderen "sichtbar" ist. Es gibt eine Vielzahl von Möglichkeiten, Änderungen sichtbar zu machen. In Ihrer Situation würde es ausreichen, gameState volatile zu machen, um die Cross-Thread-Sichtbarkeit von Änderungen an diesem Wert zu erzwingen.