2017-07-19 32 views
2

我從https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html特定碼同步聲明片斷

public void addName(String name) { 
    synchronized(this) { 
    lastName = name; 
    nameCount++; 
    } 
    nameList.add(name); 
} 
  1. 下面的代碼片段,我認爲nameList.add(name);還需要在synchronized塊,因爲名稱列表的內容也應該是這樣的集合發生,之前的關係。 synchronizedList(列表)。

對此有何看法?

  • 而且它也說
  • 在不同步的語句,就必須是用於調用nameList.add的唯一目的一個單獨的,非同步的 方法。

    我不明白爲什麼nameList.add應該在單獨的非同步方法中,如果沒有同步語句。

    +1

    是的,這有點奇怪。沒有更多細節(在文檔部分),很難知道。我認爲他們所得到的是在鎖定時應該小心調用第三方代碼,但這不是一個好例子。但是你可以想象一個'List'實現,例如,寫入一個RDBMS並等待響應 - 一個潛在的長操作,在此期間你持有該鎖。在最壞的情況下,如果List獲得一個鎖,然後調用一個在你的對象上同步的回調函數,你甚至可能會死鎖。 – yshavit

    回答

    4

    通過這個例子,他們試圖展示如何部分同步一個方法,特別是涉及lastNamenameCount的代碼。閱讀:

    在這個例子中,addName方法需要更改同步到 包含lastName和nameCount

    所以,也許nameList已經同步或改變它並不需要在同步與更改爲lastNamenameCount變量。因此,它不在同步塊中。

    +0

    重要的部分不是你引用的內容,而是後面的部分:「但是還需要避免同步其他對象方法的調用(從同步代碼中調用其他對象的方法可能會產生問題,這些問題將在活躍度)。」另一個對象的方法可能會對另一個再次調用addName - > Deadlock的線程執行阻塞調用。 – NickL

    1

    我明白這個例子是因爲試圖表明你應該避免從同步塊中調用其他對象的方法,因爲飢餓可能發生,因爲其他對象的方法可能需要很長時間才能完成。

    看起來並不關鍵(可能不是要求?)列表來保證訂單,而不是lastNamenameCount哪個應該。

    +0

    不僅僅是飢餓,也是死鎖和活鎖。另一個對象的方法可能會對另一個線程進行阻塞調用,該線程再次調用'addName' - > Deadlock。 – NickL

    +0

    @NickL是的,這是正確的。 – isah

    1

    我不明白爲什麼nameList.add應該在單獨的非同步方法中,如果沒有​​語句。

    他們只是說,如果語言沒有提供​​語句,然後同步什麼是寫​​方法的唯一途徑。他們說這樣會很笨拙,因爲有時候你想用同樣的方法混合同步和非同步的代碼。如果沒有這樣的事,作爲一個​​語句,那麼你就必須寫這樣的事情,而不是:

    public void addName(String name) { 
        addName_subroutine(name); 
        nameList.add(name); 
    } 
    
    private synchronized void addName_subroutine(String name) { 
        lastName = name; 
        nameCount++; 
    } 
    

    的片段應該是希望混合同步和非同步碼的例子,但他們不對於你爲什麼想要這樣寫的原因,你不會深究。

    +0

    它們給出了'nameList.add(name)'不同步的原因:「但是還需要避免同步其他對象方法的調用(從同步代碼中調用其他對象的方法可能會產生問題,生活節)。「 – NickL

    +1

    @NickL,這是一個公平的警察。改變了我的文字。 –