2015-09-08 15 views
0

我很清楚,在布爾上同步不是一種好的做法。 有很多的解釋,爲什麼它不是很好,如:它是否允許在新的布爾值(true)上同步

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

我感興趣的是,如果我們創建一個「新」的運營商,即成才這樣(這是從真正的代碼,我沒有寫,但我維護它,名字最終靜態布爾發生了什麼方法等發生變化):

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

難道是那麼「合法」使用它?一樣的,如果我們使用的對象,如:

private final Object lock = new Object(); 

private static final Object lock = new Object(); 

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

我不明白爲什麼不。畢竟,new Boolean()instanceof Object == true'。 – Siguza

+0

對鎖定使用'static final'有點沒有意義 - 您可以在類對象上同步以產生相同的鎖定語義('synchronized(SomethingGeneric.class){...}') –

+0

如果您顯式創建一個鎖定對象,你也可以使用「new Object()」,或者如果你想要更好的可讀性,爲此目的創建一個類LockObject(空主體)並使用該類型。 new Boolean()在語義上的工作原理相同,但您的代碼的讀者總是會想知道爲什麼選擇了Boolean。 – Durandal

回答

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會給你引用散列碼,告訴你哪些對象是==等於。

3

多數民衆贊成罰款。有兩個問題與你的第一個片段,而不是它是一個Boolean但首先,對象改變這一行:

inited = Boolean.TRUE; 

所以一些線程可以在舊的對象上同步,並在一些新的。這意味着兩組之間沒有同步。

而第二個,Boolean.TRUEBoolean.FALSE是全局對象,如果它們在其他地方以類似的方式使用,這將創建一些難以檢測同步問題(感謝Mark Rotteveel指出它)。

+0

有時候這種效果(鎖定在兩個不同的對象)可在'Boolean.TRUE'鎖定(或'Boolean.FALSE')時是有意的,但更大的問題是,你是在一個公共靜態最終可能也被濫用鎖定在其他領域,這可能會導致非常有趣且難以調試的死鎖。 –

2

由於new Boolean(...)給你一個全新的Object,使用您的locknew Boolean(...)new Object()將是Boolean具有與之相關聯的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

注:雖然做法似乎完全無害的,我看不出一點在嘗試在Boolean同步,一個Integer,一個String,或任何其他不可變對象,因爲它可以讓你沒有任何優勢超過上Object lock = new Object()同步,而不被認爲是一個成語。這反映了你的代碼的可讀性,因爲讀你代碼的程序員會對你鎖定new Boolean(...)的決定感到撓頭。

+0

您是否可以在布爾,整數,字符串上添加一點關於同步Object Lock = new Object()同步優點的更多解釋? –

+2

@NenadBulatovic主要區別在於可讀性:大多數處理安全同步的程序員會立即將'lock = new Object()'識別爲一個成語,而'lock = new Boolean(...)'缺少這種識別。最重要的是,有些程序員會懷疑你知道自己在做什麼,直到他們在Stack Overflow上運行搜索,並且看到這個問題的答案;-) – dasblinkenlight

2

由於new Boolean(true) != new Boolean(true),您可以使用這樣的鎖。請注意0​​。

如果您要維護該代碼,請按照您的建議將其替換爲lock = new Object()

相關問題