2016-08-01 2 views
0

Я использую время цикла, что проверка на условие, чтобы стать правдой:В то время как истинные циклы, которые проверяют только на одно условие безопасности потока?

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(); 
     } 
    } 
} 

Цикл работает бесперебойно без сна (если переподключения верно), и, следовательно, доступ к Game.gameState (типа Int) два раза в каждом цикле. Если gameState теперь изменяется во втором потоке (например, через сеть), условие while/if не обнаруживает его и продолжает отказываться выполнять код в блоке if, даже если это необходимо. Добавленная синхронизация (Game.gameStateLock) решает эту проблему. Также очень сложно отлаживать, вызывать печать gameState или что-то еще, что приведет к тому, что проблема будет несуществующей. Я предполагаю, что I/O прерывает/спит поток или заставляет его писать/читать много данных, что кеш процессора очищается, а переменная gameState, которая была прочитана из кеша, все время должна быть перезагружена из ОЗУ.

Возможно, это причина? Я предположил, что примитивные типы данных не являются проблемой, связанной с несколькими потоками (если вы не проверяете логическое значение, а затем устанавливаете его для блокировки других потоков). Являются ли примитивные типы данных в потоке Java безопасными? (я даже не могу синхронизировать их, нужен фиктивный объект)

+3

Возникает ли проблема в какой-либо мере, делая игру без изменений? –

+0

Если gameState не определяется как volatile, тогда у вас будет проблема с внешним циклом while. Вы можете получить доступ к его значению, в то время как он может быть установлен одновременно внешним потоком. См. Http://stackoverflow.com/questions/9278764 – mdewit

+1

Так что добавление изменчивости в переменную позволило бы решить мою проблему? – Geosearchef

ответ

2

«потолочный сейф» на самом деле не является термином, который вы ищете, и, возможно, именно поэтому вы боретесь. ваш код технически «потокобезопасен», поскольку вы не будете сталкиваться с каким-либо повреждением из-за многопоточности. тем не менее, вам не хватает гарантий, связанных с «видимостью». в вашей ситуации нет гарантии, что изменение, сделанное одним потоком, будет «видимым» для другого. существует множество способов сделать видимыми изменения. в вашей ситуации, сделать gameState volatile будет достаточно, чтобы заставить поперечную видимость изменений этого значения.

-1

Примитивные типы не являются потокобезопасными! Проверьте это: http://i-proving.com/2009/04/23/java-primitive-thread-safety/?showComments=true

+0

Это не проблема безопасности потоков, это вопрос видимости изменений. – jtahlborn

+0

предоставленные ссылки адресуют проблемы, связанные с атомарностью обновления значения, что здесь не является проблемой. – jtahlborn