为什么nameList.add不同步?

时间:2014-10-04 17:56:51

标签: java multithreading

以下是Oracle Java教程中的一小段文本:

“同步语句

创建同步代码的另一种方法是使用synchronized语句。与synchronized方法不同,synchronized语句必须指定提供内部锁的对象:

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

在此示例中,addName方法需要将更改同步到lastName和nameCount,但还需要避免同步其他对象的调用。方法。 (从同步代码中调用其他对象&#39;方法可能会产生实时部分中描述的问题。)如果没有synchronized语句,则必须有一个单独的,不同步的方法,仅用于调用nameList.add。“< / p>

我理解他们关于Synchronized给出的灵活性的观点。但是为什么Oracle决定不需要同步nameList.add?更一般地说,我如何确定需要同步哪些对象方法以及哪些方法不是?

3 个答案:

答案 0 :(得分:0)

同步有其性价比,性能明智。一般的经验法则(JDK本身也遵循,在这种情况下也是如此)不是同步,除非它是绝对必要的。

由于很多很多情况下您想要在不需要同步的情况下将元素添加到列表中(例如,如果所述列表是局部变量),则不会将其定义为已同步。当您需要同步此类操作时,您始终可以使用CopyOnWWriteArrayList,或明确同步您的访问权限。

答案 1 :(得分:0)

根据您知道线程将访问的内容进行同步

  • 如果他们试图访问列表,则同步getter。在这种情况下,Oracle正在同步调用方法。
  • 如果他们正在尝试修改列表,请将引用同步到块内的列表!

所以:

synchronized(this.nameList){
 //now I'm safe to modify
  nameList.add(name);
 } 

答案 2 :(得分:0)

您可以像这样创建一个线程安全的字符串ArrayList:

ArrayList<String> list = Collections.synchronizedList(new ArrayList<String>());

方法add()和remove()是线程安全的。如果你不需要迭代这些元素就可以了。

注意:在迭代时,必须手动同步返回的集合

synchronized (list) {
  Iterator i = list.iterator(); // Must be in the synchronized block
  while (list.hasNext())
     yourmethod(list.next()); // Your logic on elements...
}

在使用之前阅读文档:Synchronized Collection