【问题标题】:volatile boolean易失的布尔值
【发布时间】:2009-12-13 18:10:22
【问题描述】:

如果我有一个 volatile 布尔值(我们称之为有效),那么下面这段代码在 Java 中是线程安全的吗?

if (valid)
  return;
valid = true;

或者,我是否需要同步,因为仅当它为假时才将有效设置为真(因此有效的集合取决于其当前值)?

【问题讨论】:

  • Volatile 不能解决竞争条件。 Volatile 解决了存储在“valid”中的值被共享给所有其他线程有权访问valid的问题。因此,如果“valid”不是静态的,并且没有对包含“valid”的对象的静态引用,那么其他线程将不会知道“valid”。

标签: java synchronization volatile


【解决方案1】:

这需要同步,因为如果一个线程将valid评估为false,然后在分配之前暂停执行,那么另一个线程也会出现并检查valid为false,在将valid设置为true之前,您将有两个线程在运行从这里开始的代码(大概是你不想要的)。

【讨论】:

  • 只有当实际上有两个线程执行相同的代码(或执行写操作,无论如何)时,这才是正确的
  • 如果您的代码假设一次只有一个线程可以运行它,那么它不是“线程安全的”。如果您假设该值不能被其他线程在可以访问此变量的一小部分代码中写入,则同样的问题必须为整个模块保留!
  • 更明确地说,如果所有线程都只做读操作,一切都很好;如果其中只有一个有能力改写该值,则需要在所有使用它的代码上进行同步,如果出现一致性问题。
【解决方案2】:

使用 AtomicBoolean。可以同时检查和设置实例。

【讨论】:

  • 是的,很好的建议...但首先需要您意识到您需要同步:-)。
【解决方案3】:

它不是线程安全的。但是,如果这是整个代码,那就没关系了。

【讨论】:

    【解决方案4】:

    编辑:一个全面的优越替代方案是AtomicBoolean,它使用低级操作来实现不同步的条件更新。

    对标志有两个单独的(即非原子)访问,因此同步是必要的除非这个线程是唯一对标志进行写操作的线程。即使这样,为了确保将来发生变化,进行同步也可能是件好事。

    【讨论】:

      【解决方案5】:

      您的代码不是线程安全的,但这样做是否安全确实取决于您的其他代码。

      您是否要求valid = true 之后的代码只能由单个线程执行一次?如果是这样,那么您的代码是不安全的,因为任何数量的线程都可以读取false 的值valid,然后最终将其设置为true。例如:

      if (valid)
        return;
      // Imagine every single one of your threads stops and blocks here.
      // They will all wake up again and set valid to true and then
      // execute the code to follow.
      valid = true;
      

      但如果你只是想保证valid = true 之后的代码最多由any 线程执行一次......那么你所拥有的就可以了。但如果这是您需要的行为,我会通过其他方式实现,因为在这种情况下使用 volatile 看起来就像您不知道自己在做什么。例如,您可以不跨线程共享valid 变量,并允许每个线程只执行一次代码。

      另外,当在推理同步和易失性时有疑问时......只需使用同步。它通常更清晰,并且可以通过使用 volatile 为您提供所需的一切,但更容易推理代码的工作原理。

      【讨论】:

        【解决方案6】:

        线程安全是系统范围的属性。您不能孤立地查看一段代码并将其称为线程安全/不安全。这取决于其他线程如何与之交互以及一致性要求是什么。话虽如此,大多数线程安全设计都有 while() 循环而不是 if() 块,因此,您的设计很可能是不正确的:)

        【讨论】:

        • 线程安全通过使用原子或同步操作,而不是使用 while 循环。你是对的,线程安全是一个系统属性,但是如果 valid 是一个共享变量,那么这段代码本质上不适合多线程。
        • 我并不是说使用 while 循环使其线程安全。我说线程安全代码通常有while循环,if-block通常表示错误。
        【解决方案7】:

        根据 Brian Goetz 的精彩论文 https://www.ibm.com/developerworks/java/library/j-jtp06197/ “您只能在有限的一组情况下使用 volatile 变量而不是锁。必须满足以下两个条件才能使 volatile 变量提供所需的线程安全:

        • 对变量的写入不依赖于其当前值。
        • 该变量不参与其他变量的不变量。

        基本上,这些条件表明可写入 volatile 变量的有效值集独立于任何其他程序状态,包括变量的当前状态。” 所以它必须与锁同步。它不是线程安全的。

        【讨论】:

          猜你喜欢
          • 2019-11-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-04-13
          • 2017-04-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多