2015-05-14 223 views
0

代碼示例1:的Java多線程混亂

class Test { 
    MyObj myObj = new MyObj(); 

    public void test() { 
     // doing my other stuff 
     synchronized (myObj) { 
      // accessing myObj 
     } 
    } 
} 

代碼示例2:

class Test { 
    MyObj myObj = new MyObj(); 

    public void test() { 
     synchronized (myObj) { 
      // doing my other stuff 

      // accessing myObj 
     } 
    } 
} 

代碼示例3:

class Test { 
    MyObj myObj = new MyObj(); 

    public synchronized void test() { 
     // doing my other stuff 

     // accessing myObj 
    } 
} 

我想保持線程在上面的代碼快照中可安全到myObj。那麼上面哪個代碼捕捉更可取,爲什麼?

+0

代碼示例1是優選的。 代碼示例1 - >監視器在myObj上獲得,因此它是線程安全的 代碼示例2 - >監視器在myObj上獲得,因此它是線程安全的,其他內部或外部的東西無關 代碼示例3 - >鎖定/監視器是在調用test()方法的對象上獲得的,無論是myObj還是其他,都取決於調用 – user1933888

+2

這些都不是最好的選擇,因爲你使'myObj'包被保護而不是private = P – Ordous

回答

3

代碼示例1是合適的。 ,因爲把對象鎖住,然後做一些其他的東西是不合適的。

1

根據我在開源項目中看到的代碼,第一個代碼示例更好,因爲當您不再需要對象時,您可以釋放它,以便其他線程可以訪問它。

1

你的例子都沒有包含足夠的信息。

數據在哪裏?什麼是不變量?何時/何地/線程如何訪問數據?

「線程安全」在沒有數據的情況下意味着什麼。有狀態類的文檔通常會爲其方法如何推進實例狀態提供保證。 「線程安全」意味着即使在許多線程調用方法時也能滿足這些保證。但是,如果班級不是有狀態的,或者如果沒有這種保證,那麼「線程安全」就意味着什麼。


P.S。:代碼示例1具有優於其他一個重要的優點:互斥鎖(即,​​塊)較小。作爲一個經驗法則,你希望你的互斥量儘可能小。如果「我的其他東西」不關心被互斥鎖保護的數據,那麼它不應該發生互斥鎖,因爲這會阻止其他線程訪問數據,並且會因爲無用的原因而阻止它們。


P.P.S:+1 @ Ordous的評論:有沒有辦法知道一些對象的狀態是否是線程安全與否,除非你可以看到代碼可以修改或檢查狀態,每個塊。由於myObj在您的示例中不是private,因此我們必須假定其他地方有代碼可以修改或檢查其狀態。由於我們無法看到該代碼,因此我們必須假設myObj而不是線程安全。

1

對整個方法持有一個鎖(如果它很長)是非常昂貴的。它不僅可以阻止整個威脅,還可以阻止不需要同步的代碼。其次有時你可能不會使用你的omyObj,在這種情況下,例子2和3會很糟糕。

簡而言之:只同步塊的一部分,在那裏你是與你的對象一起工作。你也可以在你的對象上使用volatile來檢查它的值,而不用同步塊。記住鎖定可能會很昂貴

但是,當你的方法足夠短,或只包含myObj的代碼,那麼使整個方法synchonized是一個很好的解決方案。

public void test() { 
    // doing my other stuff, not concernign myObj 
    synchronized (myObj) { 
     // do things with myObj (read/write) 
    } 
    // doing my other stuff, not concernign myObj 
} 

看看這個singleton的例子。