为什么在布尔值上同步不是一个好习惯? [英] Why is it not a good practice to synchronize on Boolean?

查看:27
本文介绍了为什么在布尔值上同步不是一个好习惯?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的建筑师总是说

从不同步布尔值

我无法理解原因,如果有人能举例说明为什么这不是一个好的做法,我将不胜感激.参考示例代码

I am not able to understand the reason why and would really appreciate if someone could explain with an example as to why it is not a good practice. 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"

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

You should always synchronize on a constant object instance. If you synchronized on any object that you are assigning (i.e. changing the object to a new object) then it is not constant and different threads will be synchronizing on different object instances. Because they are synchronizing on different object instances, multiple threads will be entering the protected block at the same time and race conditions will happen. This is the same answer for synchronizing on Long, Integer, etc..

// 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) 创建的 BooleanBoolean.TRUE (或 .FALSE),它是 ClassLoader所有对象的单例.你的锁对象应该是它所使用的类的本地对象,否则你会锁定同一个单例对象,而其他类如果犯了同样的错误,可能会在其他锁定情况下锁定.

To make matters worse, any Boolean that is created through autoboxing (isOn = true) is the same object as Boolean.TRUE (or .FALSE) which is a singleton in the ClassLoader across all objects. Your lock object should be local to the class it is used in otherwise you will be locking on the same singleton object that other classes might be locking on in other lock cases if they are making the same mistake.

如果你需要锁定一个布尔值,正确的模式是定义一个 private final 锁定对象:

The proper pattern if you need to lock around a boolean is to define a private final lock object:

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

synchronized (lock) {
   ...

或者你也应该考虑使用 AtomicBoolean 对象,这意味着你可能根本不需要同步.

Or you should also consider using the AtomicBoolean object which means you may not have to synchronize on it at all.

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 并设置布尔值并避免测试/设置竞争条件:

In your case, since it looks like you need to toggle it on/off with threads then you will still need to synchronize on the lock object and set the boolean and avoid the test/set race condition:

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也一样.

Lastly, if you expect the statusMessage to be accessed from other threads then it should be marked as volatile unless you will synchronize during the get as well.

这篇关于为什么在布尔值上同步不是一个好习惯?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆