Java 列表上同步的这两种用法在行为上有什么区别 List List=new ArrayList(); 列表。添加(“a”); ... 列表。添加(“z”); 已同步(列表){ 迭代器i=list.Iterator(); while(i.hasNext()){ ... } }

Java 列表上同步的这两种用法在行为上有什么区别 List List=new ArrayList(); 列表。添加(“a”); ... 列表。添加(“z”); 已同步(列表){ 迭代器i=list.Iterator(); while(i.hasNext()){ ... } },java,concurrency,synchronized,Java,Concurrency,Synchronized,及 List List=new ArrayList(); 列表。添加(“a”); ... 列表。添加(“z”); List synchronizedList=集合。synchronizedList(列表); 已同步(synchronizedList){ 迭代器i=synchronizedList.Iterator(); while(i.hasNext()){ ... } } 具体地说,我不清楚为什么在第二个实例中,当同步列表提供对列表的线程安全访问时,需要使用synchronized。如果不锁

List List=new ArrayList();
列表。添加(“a”);
...
列表。添加(“z”);
List synchronizedList=集合。synchronizedList(列表);
已同步(synchronizedList){
迭代器i=synchronizedList.Iterator();
while(i.hasNext()){
...
}
}

具体地说,我不清楚为什么在第二个实例中,当同步列表提供对列表的线程安全访问时,需要使用
synchronized

如果不锁定迭代,如果另一个线程在循环期间修改它,您将得到ConcurrentModificationException

同步所有的方法丝毫不能阻止这一点

这就是为什么
Collections.synchronized*
完全无用的原因。
您应该使用
java.util.concurrent
中的类。(你应该仔细考虑如何保证自己的安全)

作为一般经验法则:

在每个方法上都使用锁并不足以保证线程安全


有关更多信息,请参见

synchronizedList
仅使每个调用原子化。在您的情况下,循环进行多个调用,因此在每次调用/迭代之间,另一个线程可以修改列表。如果使用其中一个并发集合,则不会出现此问题

查看此集合与ArrayList的区别

List<String> list = new ArrayList<String>();
list.add("a");
...
list.add("z");

List<String> synchronizedList = Collections.synchronizedList(list);

synchronized(synchronizedList) {
    Iterator<String> i = synchronizedList.iterator();
    while(i.hasNext()) {
        ...
    }
}

由于同步列表的实现方式,第二个代码需要同步。解释如下:

用户在遍历返回的列表时,必须手动同步该列表

两个代码段之间的主要区别在于
add
操作的效果:

  • 对于同步列表,您有一个可见性保证:例如,如果其他线程调用
    synchronizedList.get(…)
    ,它们将看到新添加的项
  • 使用ArrayList,其他线程可能不会立即看到新添加的项—实际上可能永远也看不到它们

Ah,所以基本上,如果有多个线程试图修改同步列表,它就会爆炸。除了让您知道有多个线程正在试图访问列表外,它实际上并不能以任何方式保护您?@VivinPaliath:synchronizedList将确保调用单个方法不会因为相互竞争而破坏集合。它不能帮助您确保您的结构是安全的。+1 synchronizedList()并非完全无用,它通常不是一个完整的解决方案。@fd.:如果您使用
synchronizedList()
,您将需要提供更高级别的同步(这意味着您将拥有足够的自己的锁,而不需要它),或者您将有竞争条件。@SLaksL:我的观点是这一点的反映-如果您不使用synchronizedList(),除了需要的其他锁定之外,您还需要实现synchronizedList()提供的锁定。但我同意,您确实需要考虑所需的锁定,而不是使用诸如synchronizedList之类的便利设施作为支撑。因此,当您使用
java.util.concurrent
中的一个集合时,您根本不需要显式地在列表上设置锁定?只是想让我遵循正确的顺序…@Windle不,您不需要,迭代将在列表上完成,就像迭代开始时一样-迭代期间对列表所做的任何更改都将被忽略(在您的迭代中)。对于并发集合,如果使用锁,则无法访问任何锁。如果您想锁定它,您无法锁定它,但您不需要锁定它。;)@PeterLawrey
Arrays.asList(“a,b,c,d,e,f,g,h,z”。split(“,”)
这是我见过的最懒的事情!;-)@亚西莉亚:还有更多来自哪里的信息
List<String> list = new ArrayList<String>();
list.add("a");
...
list.add("z");

List<String> synchronizedList = Collections.synchronizedList(list);

synchronized(synchronizedList) {
    Iterator<String> i = synchronizedList.iterator();
    while(i.hasNext()) {
        ...
    }
}
List<String> list = new CopyOnWriteArrayList<String>();
list.addAll(Arrays.asList("a,b,c,d,e,f,g,h,z".split(",")));

for(String s: list) {
    System.out.print(s+" ");
    // would trigger a ConcurrentModifcationException with ArrayList
    list.clear(); 
}
a b c d e f g h z