这可能看起来是一个非常愚蠢的问题。 考虑以下:
我有一个简单的布尔对象,它有一个getter和一个setter。现在,这两个方法都经常从很多线程中调用。
- 我需要为此布尔值同步吗?
- 布尔赋值是原子操作吗?
[更新]: 我已经知道了Atomic Boolean。我已经有了很多不同的解决方案,但我特别想要得到上面2个问题的答案和理由。
这可能看起来是一个非常愚蠢的问题。 考虑以下:
我有一个简单的布尔对象,它有一个getter和一个setter。现在,这两个方法都经常从很多线程中调用。
[更新]: 我已经知道了Atomic Boolean。我已经有了很多不同的解决方案,但我特别想要得到上面2个问题的答案和理由。
Boolean.TRUE
、(Boolean) true
和Boolean.valueOf(true)
很可能都引用同一个对象,这是完全有效的。 - Matthew T. StaeblerBoolean
对象是不可变的。Boolean
对象的所有方法都可以保证是原子性的。 - Matthew T. Staebler是的。但如果它是由一个线程编写的标志,并且您想确保所有线程都能看到它,那么一种廉价的替代方法是使用volatile
。
是的 - 即使对象的内部表示(即Boolean
包装器中实际的boolean
标志)为64位,并且因此可能在并发情况下被“拆分”,布尔值只能具有两个值,对吧?因此,普通的赋值(获取或设置)是原子的,但如果您正在执行其他任何操作(例如检查-然后-操作),例如x = !x
,则除非同步,否则它当然不是原子的。
volatile
不是有效的解决方案? - Matthew T. Staeblervolatile
不适用于多线程写入。但当然它也有其用途。 - Joonas Pulakka更新:让我详细解释一下需要happens-before边缘的原因。如果没有happens-before边缘,则一个线程对变量所做的更改不能保证被其他线程感知。问题不仅在于变化可能在坏时机(例如在读取和写入之间)被察觉。变化也可能永远不会被感知。
假设我们有一个布尔变量,将其初始化为false。然后我们启动两个线程。第一个线程将变量设置为true并停止。第二个线程不断检查变量,直到它变为真,然后停止。不能保证第二个线程将永远看到变量为true。
不需要,但是要声明变量为volatile
,这样所有访问该布尔值的线程都能反映出其值。如果你看一下AtomicBoolean
的set(..)
方法,它也没有同步。
是的,实际上赋值是原子性的。只是简单地设置值并不需要同步。然而,如果你想做像这样的事情:
if (!bool) {
bool = false;
}
那么你就需要同步(或者使用比同步更高效的AtomicBoolean
)。
http://docs.oracle.com/javase/tutorial/essential/concurrency/atomic.html说原始变量的读写是原子性的。
因此,可以使用布尔值(或在缓存效应的情况下使用易失性布尔值)来强制执行严格的交替或发生后关系。
即使它是原子的,由于您可能会在某个时候检查该值,因此仍然存在同步问题。 例如: if (boolVar==true) -> 其他线程接管 do_something();
java.lang.Boolean
类的Boolean
类? - Matthew T. Staebler