Java 需要同步布尔成员变量的设置吗?

Java 需要同步布尔成员变量的设置吗?,java,multithreading,Java,Multithreading,嘿,我正在处理我继承的一些代码,看起来一个线程正在设置一个布尔成员变量,而另一个线程在while循环中检查它。这真的可以工作吗?或者我应该将其更改为在布尔变量上使用同步getter或setter吗?几乎可以肯定,您将需要在更高级别上添加锁定。仅仅在字段的单个访问周围添加synchronized,很少有帮助。如果组件操作是独立的线程安全的,那么复合操作将不是线程安全的 作为一个例子,考虑删除线程安全文档的内容。该文档提供了两个相关的线程安全操作:删除两个索引之间的内容和一个长度操作。所以你得到了长

嘿,我正在处理我继承的一些代码,看起来一个线程正在设置一个布尔成员变量,而另一个线程在while循环中检查它。这真的可以工作吗?或者我应该将其更改为在布尔变量上使用同步getter或setter吗?

几乎可以肯定,您将需要在更高级别上添加锁定。仅仅在字段的单个访问周围添加
synchronized
,很少有帮助。如果组件操作是独立的线程安全的,那么复合操作将不是线程安全的


作为一个例子,考虑删除线程安全文档的内容。该文档提供了两个相关的线程安全操作:删除两个索引之间的内容和一个长度操作。所以你得到了长度,然后从零删除到长度,对吗?在读取长度和删除内容之间,文档可能会改变长度,这是一种竞争。在给定操作的情况下,无法使操作线程安全。(示例取自Swing Text。)

我建议将布尔值声明为volatile,并同步读写访问

如果读写一个像bool或int这样声明为volatile的原语,那就足够了。当一个线程读取时,另一个线程将完成写入。变量永远不会处于无效状态

可以公平地说,总的来说,volatile关键字 Java缺乏文档,理解能力差,很少使用。使 更糟糕的是,从Java5开始,它的正式定义实际上发生了变化。 本质上,volatile用于指示变量的值将 可以被不同的线程修改

声明易失性Java变量意味着:

  • 此变量的值将 从不在本地缓存线程:全部 读和写将直接转到 “主存储器”
  • 对变量的访问就像 虽然它是封闭在一个 已同步块,已在上同步 本身
  • 我们在第二点中说“行为就像”,因为对程序员来说 至少(可能在大多数JVM实现中)没有实际的 锁定所涉及的对象


    如果使用Java1.5+,则应使用同步原语


    如果您遵循链接,它有一个很好的示例说明如何使用它。

    如果它是纯布尔值,则不能保证工作,因为java的内存模型,其中一个线程可能看不到更新的布尔值,您可以

    • 创建一个同步的getter/setter 或
    • 将布尔值声明为volatile,是理解volatile的好资源
    请记住,如果读取此布尔值的线程依赖于该布尔值的上一个值,则所有这些都不会“起作用”——它可能会错过对该布尔值的更改,例如

    线程1:

    while(foo.myVolatileBoolean) {
     ... 
    }
    
    线程2:

    foo.myVolatileBoolean = false; //thread 1 might never catch thisone.
     ... 
    foo.myVolatileBoolean = true;
    

    如果这是一个问题,你需要监视布尔值的变化,考虑使用WaIT()/NOTIFY()或

    这听起来很混乱。(另外,
    volatile
    是出人意料的无益(在低级别时除外),因为操作通常需要多个组件操作。)@tackline你的意思是因为它是皮带和支架方法而混淆吗?如果是这样,那么尽管我理解Java编程模型可能表明volatile本身就足够了,但对于我可能遇到的所有JVM实现,尤其是在多核环境中运行时,我仍然怀疑这种说法。在任何情况下,即使我的偏执狂没有被宣布,volatile本身通常都不是一个足够强烈的提示,提示维护人员,关于所讨论的布尔值,他们需要注意一些重要的事情。您应该声明一个变量
    volatile
    ,或者使用
    synchronized
    访问器。两者兼而有之只会降低性能并增加复杂性。Tom是对的,volatile的正确用法大部分是由java.concurrent gurus保留的。到目前为止,答案不错,伙计们,我想while循环可能正在缓存它试图在本地检查的变量。我现在添加volatile并将变量放入同步getter和setter中。我认为您没有正确阅读答案(和文档),尤其是Tom Hawtin的答案。同步访问volatile变量是一个矛盾的说法。我同意volatile将保护您的布尔变量,并确保它被正确更新和读取,但您需要从全局出发,确保对象始终处于一致状态。
    volatile
    在JLS和JVM规范中有明确规定。但是,它的使用频率似乎远远超过了人们对其后果的理解。@Tom Hawtin-我们需要了解它的局限性。在有限的情况下,它是一个强大的工具。虽然您所说的布尔(在某些情况下是int)原语是正确的,但在执行int++之类的操作时要小心使用int。虽然这看起来是一个单独的操作,但实际上并不是,在这种情况下仅仅使用volatile是不够的。@Jeff Storey int++实际上是读取变量、递增和写入,因此,+=N.B.这个答案似乎很大程度上是从我的网页上剽窃的:+1这是一个很好的观点,可以添加一些透视图来观察不仅仅是布尔变量。你的观点很好,但根据所问的问题,没有上下文来引入复合参数。这个问题是关于布尔型读写器的问题。Showboating?@bjg线程涉及上下文。它本质上是非本地的。我相信这个问题很可能不止一个布尔值。当然,对于这个领域的新手来说,用复杂的代码解决一个特例问题是毫无帮助的。