我无法理解为什么我们应该“永远不要在布尔同步”的原因
你应该总是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;
更糟糕的是,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
}
}
最后,如果您希望statusMessage
从其他线程访问它,那么它应该被标记为volatile
除非您synchronize
在获取期间也会这样做。