java - 为什么在 boolean 值上同步不是一个好的做法?

标签 java multithreading synchronization boolean

我的建筑师总是这么说

Never synchronize on Boolean

我无法理解原因,如果有人能用例子解释为什么这不是一个好的做法,我将非常感激。 Reference Sample Code

private Boolean isOn = false;
private String statusMessage = "I'm off";
public void doSomeStuffAndToggleTheThing(){

   // Do some stuff
   synchronized(isOn){
      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
      }
   }
}

最佳答案

I am not able to understand the reason why we should "never synchronize on Boolean"

您应该始终在常量对象实例上同步。如果您对正在分配的任何对象进行同步(即将对象更改为新对象),则它不是恒定的,并且不同的线程将在不同的对象实例上进行同步。因为它们在不同的对象实例上同步,所以多个线程将同时进入 protected block ,并且会发生竞争条件。这与 LongInteger 等同步的答案相同。

// 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;

更糟糕的是,通过自动装箱 (isOn = true) 创建的任何 Boolean 都是与 Boolean.TRUE 相同的对象(或.FALSE),它是ClassLoader中跨所有对象的单例。您的锁定对象应该是它所使用的类的本地对象,否则您将锁定同一个单例对象,而其他类在其他锁定情况下可能会锁定相同的单例对象(如果它们犯了同样的错误)。

如果您需要锁定 boolean 值,正确的模式是定义一个私有(private)最终锁定对象:

private final Object lock = new Object();
...

synchronized (lock) {
   ...

或者您还应该考虑使用 AtomicBoolean 对象,这意味着您可能根本不需要同步它。

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";
}

就您而言,由于您似乎需要使用线程打开/关闭它,因此您仍然需要在lock对象上进行synchronize并设置 boolean 值并避免测试/设置竞争条件:

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 ,除非您在执行期间同步也得到。

关于java - 为什么在 boolean 值上同步不是一个好的做法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56428653/

相关文章:

java - 仅对最新的异步更新数据运行计算

java - 对单例模式使用双重检查锁定习惯用法是否最佳?

mysql - 如何让MySQL Workbench忘记我重命名了一个表?

java - 通过 Java 从 Windows 远程发送命令到 Linux

java - 运行程序

java - 时间变化会影响 Java 日期比较功能吗?

java - 在 Java 中等待条件

C# 监听器线程上的 CPU 使用率高,休眠未命中断开连接

java - 无循环死锁

java - 是否可以在条件内声明变量?