【发布时间】:2016-12-06 19:38:09
【问题描述】:
我正在使用一个 while 循环来检查条件是否为真:
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 块中的代码,即使它应该执行。添加的 synchronized(Game.gameStateLock) 解决了这个问题。调试起来也很困难,因为打印 gameState 或其他任何东西都会导致问题不存在。我的猜测是 I/O 中断/休眠线程或导致它写入/读取那么多数据,cpu 的缓存被清除,并且一直从缓存中读取的 gameState 变量必须从内存。
这可能是原因吗?在处理多个线程时,我假设原始数据类型不是什么大问题(除非您正在检查布尔值,然后将其设置为阻塞其他线程)。 Java线程中的原始数据类型是否安全? (我什至无法同步它们,需要一个虚拟对象)
【问题讨论】:
-
通过使 gameState 不稳定,问题是否会以任何方式演变?
-
如果 gameState 没有被定义为 volatile,那么你的外部 while 循环就会有问题。您可以访问它的值,同时它可以由外部线程同时设置。见stackoverflow.com/questions/9278764
-
那么在变量中添加 volatile 会解决我的问题吗?
-
添加 volatile 会阻止您获得 ConcurrentModificationException。您还必须确保仅在标记为 final 的对象上进行同步,并且在其他类中正确使用同步。
-
好的,它有帮助,我不再遇到问题了。
标签: java multithreading thread-safety primitive-types