2017-08-13 60 views
2

我們可以同步一個類中的函數,或者我們可以在線程中鎖定它的對象,以在對象上創建線程安全。同步函數,或鎖定線程中的對象?

class DBresource { 

     synchronized public void dosomething() throws InterruptedException { 
      ... 
      ... 
     } 
    } 

OR

class MyThread extends Thread { 

    public void run() { 
     synchronized (r) { 
      r.dosomething(); 
     } 
} 

這是可取的,爲什麼呢?

此外,我也可以鎖定類DBResource。這將如何不同?

或者,使用專用鎖對象。這是不是氣餒或首選,爲什麼?

謝謝。

+0

@Makoto:我不同意,我認爲這是關於鎖定代碼所屬的位置,在資源被保護或訪問資源的任務中。 –

回答

3

如果您使用第二種方法,將鎖定邏輯放入線程中,則每次需要使用不同的任務來訪問該資源時,都必須將鎖定代碼添加到新任務中。如果任何觸摸該資源的任務不執行鎖定或弄亂他們如何執行操作,則該資源可能會損壞。這將導致一個脆弱的應用程序,如果添加代碼的人沒有完全鎖定鎖定,添加功能可能會導致破損。這也是DRY的反面。

通過第一種方法,對象通過實現訪問它所需的任何鎖定來保護自己。訪問該對象的任何線程都必須獲取該類指定的鎖。任何線程都沒有機會繞過對資源的鎖定。

使用專用鎖(例如使用私有最終實例成員)可以使無關代碼難以獲取對象的鎖。惡意代碼仍然可以使用反射,但會阻止意外訪問。

使用類級鎖可防止多個線程訪問資源,即使有多個資源。你可以通過這種方式製造一個瓶頸。

+0

同意。並被接受爲答案。謝謝。 請問您可以擴大班級鎖嗎? 如果一個線程獲得對某個對象的鎖定,則只有等待同一對象鎖定的線程將等待。同樣,如果一個線程在Class本身上獲得一個鎖,那麼只有想要在這個Class上加鎖的線程將會等待。沒有? 如果是,類級鎖如何比對象級鎖更糟? – jforex78

+0

@ jforex78是的,是更糟糕的,因爲如果用一個類級別的鎖代替實例級別的鎖,那麼您將鎖定所有線程,而不是所有實例的所有方法中的一個,即使它們只是用於玩一個實例並且沒有靜態變量。 – EJP

0

使方法​​最簡單,並且不會對調用者施加任何要求,除了它們以通常方式避免死鎖之外。

但是它並沒有涵蓋所有情況。例如,如果您正在迭代集合,則應該在集合中進行同步的塊中執行此操作,以防止在迭代過程中對其進行修改(除非您使用的併發安全集合類似於java.util.concurrent)。一般情況下,如果要以對所有調用保持一致狀態的方式調用對象上的多個方法,則需要在外部對其進行同步。

所以,哪個更好的問題並沒有真正的答案。這取決於你在做什麼。

+0

同意,謝謝。 – jforex78