是否允许在新布尔值上同步(true)

时间:2015-09-08 15:50:52

标签: java concurrency synchronized

我很清楚在布尔值上同步是不好的做法。 有很多解释为什么它不好,例如:

Why is it not a good practice to synchronize on Boolean?

http://telliott.io/node/40/

https://www.securecoding.cert.org/confluence/display/java/LCK01-J.+Do+not+synchronize+on+objects+that+may+be+reused

所以,很明显这是不良行为:

  

代码在盒装原始常量上同步,例如   布尔值。

private static Boolean inited = Boolean.FALSE; 
...
    synchronized(inited) 
    { 
        if (!inited) 
        { 
            init(); 
            inited = Boolean.TRUE; 
        } 
    } 
... 

如果我们使用" new"创建最终的静态布尔值会发生什么?运算符,即像这样的某种(这是来自我还没写过的真实代码,但是我维护它,方法的名称等都改变了):

private final static Boolean lock = new Boolean(true);
...
  public static SomethingGeneric getSomething()
  {
    synchronized(lock)
    {
      if (somethingElse == null)
      {
        try
        {
          somethingElse = persistence.valueobject.getSomeValue(GET_THAT);
          System.out.println("blah blah");
        }
        catch (ObjectCreationException oce)
        {
          // report the error
          log.error("There was this and that error", oce);
          System.out.println("Could not create it");
        }
      }
      return somethingElse;
    }
  }

那么"合法"使用它?就像我们使用Object一样,如:

private final Object lock = new Object();

private static final Object lock = new Object();

public void doSomething() {
  synchronized (lock) {
    // ...
  }
}

4 个答案:

答案 0 :(得分:3)

很好。您的第一个代码段存在两个问题,而不是Boolean,但首先,该对象在此行中发生了变化:

 inited = Boolean.TRUE;

因此可以在旧对象上同步一些线程,在新对象上同步一些线程。这意味着两组之间没有同步。

第二,Boolean.TRUEBoolean.FALSE是全局对象,如果它们以类似的方式在其他地方使用,则会产生一些难以检测的同步问题(感谢Mark Rotteveel指出它)

答案 1 :(得分:3)

您正在同步对象引用。创建private final Object lock = new Object();private final static Boolean lock = new Boolean(true);具有相同的效果。在这种情况下你想要的只是一个独特的对象。

您应该小心,因为new Boolean(true)会创建 对象引用。如果您尝试使用Boolean.TRUEtrue,则它们实质上是实习并将使用相同的实例,例如:

Boolean bool1 = new Boolean(true);
Boolean bool2 = Boolean.TRUE;
Boolean bool3 = true;

System.out.println(System.identityHashCode(bool1));
System.out.println(System.identityHashCode(bool2));
System.out.println(System.identityHashCode(bool3));

将打印

1433743869
19203296
19203296

因此bool1上的同步将与bool2bool3相互排斥,但2& 3将分享排他性。

注意 identityHashCode会为您提供参考哈希码,告诉您哪些对象==相等。

答案 2 :(得分:2)

由于new Boolean(...)为您提供了全新的Object,因此new Boolean(...)使用new Object()lockBoolean之间的唯一区别就在于{ {1}}具有与之关联的truefalse值,而Object则没有。

您可以通过running此代码段来检查您是否通过new Boolean(...)来调用新对象:

Boolean bt = Boolean.TRUE;
Boolean bf = Boolean.FALSE;
for (int i = 0 ; i != 20 ; i++) {
    Boolean b = new Boolean(i % 2 == 0);
    System.out.println(b);
    System.out.println("==true : "+(b==bt));
    System.out.println("==false: "+(b==bf));
}

打印

true
==true : false
==false: false
false
==true : false
==false: false
true
==true : false
==false: false
false
==true : false
==false: false
...

意味着您获得的对象与Boolean.TRUEBoolean.FALSE不同。

注意:虽然这种做法看起来完全无害,但我认为尝试同步BooleanIntegerString或任何其他不可变对象,因为它没有优于Object lock = new Object()上的同步,而不是一个可识别的成语。这反映了您的代码的可读性,因为阅读代码的程序员会对您锁定new Boolean(...)的决定感到头疼。

答案 3 :(得分:2)

new Boolean(true) != new Boolean(true)以来,您可以使用此类锁定。

Boolean.valueOf(true) == Boolean.valueOf(true)开始要小心。

如果您要维护该代码,只需将锁​​定替换为您建议的lock = new Object()