2017-07-19 41 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,这是一个公平的警察。改变了我的文字。 –