列表中这两个同步用法之间的行为有何不同?

List list = new ArrayList(); list.add("a"); ... list.add("z"); synchronized(list) { Iterator i = list.iterator(); while(i.hasNext()) { ... } } 

 List list = new ArrayList(); list.add("a"); ... list.add("z"); List synchronizedList = Collections.synchronizedList(list); synchronized(synchronizedList) { Iterator i = synchronizedList.iterator(); while(i.hasNext()) { ... } } 

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

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

同步所有方法并不能防止这种情况发生。

这(以及许多其他事情)是Collections.synchronized*完全无用的原因。
您应该使用java.util.concurrent的类。 (你应该仔细考虑如何保证你的安全)

一般的经验法则是:

对每个方法进行拍打锁定都不足以使线程安全。

有关更多信息,请参阅我的博客

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

要查看此集合与ArrayList的不同之处。

 List list = new CopyOnWriteArrayList(); 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(); } 

即使重复清除列表,它也会打印以下内容,因为在创建迭代器时会删除内容。

 abcdefghz 

由于实现了同步列表的方式,需要同步第二个代码。 这在javadoc中解释:

当迭代时,用户必须手动同步返回的列表

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

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