我无法理解为什么我们应该“永远不要在布尔值上同步”
应始终位于常量对象实例上。如果您在要分配的任何对象上进行同步(即将对象更改为新对象),则它不是恒定的,并且不同的线程将在不同的对象实例上进行同步。由于它们在不同的对象实例上同步,因此多个线程将同时进入受保护的块,并且将发生争用情况。这与 同步 上 、等的答案相同。synchronize
Long
Integer
// this is not final so it might reference different objects
Boolean isOn = true;
...
synchronized (isOn) {
if (isOn) {
// this changes the synchronized object isOn to another object
// so another thread can then enter the synchronized with this thread
isOn = false;
更糟糕的是,通过自动装箱 () 创建的任何内容都与 (或 ) 是同一对象,后者是所有对象中的单例。您的 lock 对象应该是使用它的类的本地对象,否则,如果其他类犯了相同的错误,您将锁定在其他锁定情况下可能锁定的同一单例对象。Boolean
isOn = true
Boolean.TRUE
.FALSE
ClassLoader
如果您需要在布尔值周围锁定,正确的模式是定义一个锁定对象:private final
private final Object lock = new Object();
...
synchronized (lock) {
...
或者,您还应该考虑使用该对象,这意味着您可能根本不需要使用它。AtomicBoolean
synchronize
private final AtomicBoolean isOn = new AtomicBoolean(false);
...
// if it is set to false then set it to true, no synchronization needed
if (isOn.compareAndSet(false, true)) {
statusMessage = "I'm now on";
} else {
// it was already on
statusMessage = "I'm already on";
}
在你的例子中,由于看起来你需要用线程打开/关闭它,那么你仍然需要在对象上设置布尔值并避免测试/设置争用条件:synchronize
lock
synchronized (lock) {
if (isOn) {
isOn = false;
statusMessage = "I'm off";
// Do everything else to turn the thing off
} else {
isOn = true;
statusMessage = "I'm on";
// Do everything else to turn the thing on
}
}
最后,如果您希望从其他线程访问,则应将其标记为,除非您在get期间也这样做。statusMessage
volatile
synchronize