同步语句 - 同步方法和同步语句等效吗?

时间:2015-04-12 08:26:44

标签: java multithreading

对于这个简单的同步语句:

public void addName(String name) {
    synchronized(this) { // line1
        lastName = name;
        nameCount++;
    }
    nameList.add(name);
}

似乎两个线程允许'说t1t2可以同时调用addName方法,但一旦得到注释为line1的行,只有一个线程可以继续,这意味着其他线程将必须暂停。这意味着即使nameList被置于同步语句之外,也可以保证nameList不会被多个线程冲突。

这是真的吗?如果是,如果在synchronized语句之前不需要进行任何操作,则以下方法之间存在任何差异:

public void addName(String name) {
    synchronized(this) {  //line1
        lastName = name;
        nameCount++;

        nameList.add(name);
    }
}

或者:

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

我确切地知道

void synchronized add(){

}

与:

相同
void add(){
  synchronized(this){

  }
}

令我困惑的是,在addName示例中,我认为执行顺序可能是这样的:

t1:synchronized steatement
t1:nameList.add
t2:synchronized steatement
t2:nameList.add

这意味着synchronized statementnameList.add之间的其他线程没有执行更改。因此将nameList.add置于同步块外部并没有区别。

但事实上,执行可能看起来像是@JB Nizet的回答:

t1:synchronized steatement
t2:synchronized steatement

t2:nameList.add
t1:nameList.add

然后将nameList放在块外或内部非常重要。

1 个答案:

答案 0 :(得分:4)

最后两个片段是等效的,但第一个片段不是。

在第一个片段中,假设列表中的添加不是synchronized块的一部分,则两个线程可以同时执行该指令。如果列表不是线程安全的,那么这是一个问题。

即使列表是线程安全的,也可能是一个问题,因为状态的各个部分(计数,姓氏和列表)的更改不是原子的。因此,其他线程可能会看到姓氏的新值,但在列表中找不到此姓氏。