【问题标题】:Are while true loops that check only for one condition thread safe? [duplicate]仅检查一个条件线程安全的 while true 循环是否安全? [复制]
【发布时间】: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


【解决方案1】:

原始类型不是线程安全的!检查这个:http://i-proving.com/2009/04/23/java-primitive-thread-safety/?showComments=true

【讨论】:

  • 这不是线程安全问题,而是更改可见性的问题。
  • 提供的链接解决了与更新值的原子性相关的问题,这不是真正的问题。
【解决方案2】:

“线程安全”并不是您真正要寻找的术语,这可能就是您苦苦挣扎的原因。您的代码在技术上是“线程安全的”,因为您不会因多线程而遇到任何损坏。但是,您缺少的是与“可见性”相关的保证。在您的情况下,不能保证一个线程所做的更改对另一个线程“可见”。有多种方法可以使更改可见。在您的情况下,使gameState volatile 足以强制对该值的更改进行跨线程可见性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-06
    • 1970-01-01
    • 2013-01-31
    • 2015-06-10
    相关资源
    最近更新 更多