对于这个简单的同步语句:
public void addName(String name) {
synchronized(this) { // line1
lastName = name;
nameCount++;
}
nameList.add(name);
}
似乎两个线程允许'说t1
和t2
可以同时调用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 statement
和nameList.add
之间的其他线程没有执行更改。因此将nameList.add
置于同步块外部并没有区别。
但事实上,执行可能看起来像是@JB Nizet的回答:
t1:synchronized steatement
t2:synchronized steatement
t2:nameList.add
t1:nameList.add
然后将nameList
放在块外或内部非常重要。
答案 0 :(得分:4)
最后两个片段是等效的,但第一个片段不是。
在第一个片段中,假设列表中的添加不是synchronized块的一部分,则两个线程可以同时执行该指令。如果列表不是线程安全的,那么这是一个问题。
即使列表是线程安全的,也可能是一个问题,因为状态的各个部分(计数,姓氏和列表)的更改不是原子的。因此,其他线程可能会看到姓氏的新值,但在列表中找不到此姓氏。