我很清楚在布尔值上同步是不好的做法。 有很多解释为什么它不好,例如:
Why is it not a good practice to synchronize on Boolean?
等
所以,很明显这是不良行为:
代码在盒装原始常量上同步,例如 布尔值。
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) {
// ...
}
}
答案 0 :(得分:3)
很好。您的第一个代码段存在两个问题,而不是Boolean
,但首先,该对象在此行中发生了变化:
inited = Boolean.TRUE;
因此可以在旧对象上同步一些线程,在新对象上同步一些线程。这意味着两组之间没有同步。
第二,Boolean.TRUE
和Boolean.FALSE
是全局对象,如果它们以类似的方式在其他地方使用,则会产生一些难以检测的同步问题(感谢Mark Rotteveel指出它)
答案 1 :(得分:3)
您正在同步对象引用。创建private final Object lock = new Object();
与private final static Boolean lock = new Boolean(true);
具有相同的效果。在这种情况下你想要的只是一个独特的对象。
您应该小心,因为new Boolean(true)
会创建 新 对象引用。如果您尝试使用Boolean.TRUE
或true
,则它们实质上是实习并将使用相同的实例,例如:
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
上的同步将与bool2
和bool3
相互排斥,但2& 3将分享排他性。
注意 identityHashCode
会为您提供参考哈希码,告诉您哪些对象==
相等。
答案 2 :(得分:2)
由于new Boolean(...)
为您提供了全新的Object
,因此new Boolean(...)
使用new Object()
和lock
与Boolean
之间的唯一区别就在于{ {1}}具有与之关联的true
或false
值,而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.TRUE
和Boolean.FALSE
不同。
注意:虽然这种做法看起来完全无害,但我认为尝试同步Boolean
,Integer
,String
或任何其他不可变对象,因为它没有优于Object lock = new Object()
上的同步,而不是一个可识别的成语。这反映了您的代码的可读性,因为阅读代码的程序员会对您锁定new Boolean(...)
的决定感到头疼。
答案 3 :(得分:2)
自new Boolean(true) != new Boolean(true)
以来,您可以使用此类锁定。
从Boolean.valueOf(true) == Boolean.valueOf(true)
开始要小心。
如果您要维护该代码,只需将锁定替换为您建议的lock = new Object()
。