使用Collections.synchronizedSet的每个语法

时间:2010-02-15 03:08:27

标签: java collections synchronization

问题是这个。我做了一套

Set<User> users = Collections.synchronizedSet(new HashSet<User>())
...
for(User u : users){
   //do something with u
} 

现在,根据Java文档。

  

用户势在必行   手动同步返回   迭代它时排序的集合   任何subSet,headSet或tailSet   视图。

 SortedSet s = Collections.synchronizedSortedSet(new HashSortedSet());
 ...
 synchronized(s) {
    Iterator i = s.iterator(); // Must be in the synchronized block
    while (i.hasNext())
       foo(i.next());
 }

我很确定每个语法使用迭代器,但我不确定是否应该使用synchronized块为每个循环包装每个语句。

另一件事,我的IDE(IntelliJ IDEA)继续报告说,在非最终字段上使用synchronized块不太可能具有有用的语义,因为不同的线程可能是不同的对象,即使在处理同一个对象时也是如此。

3 个答案:

答案 0 :(得分:3)

文档清楚地表明,你应该在面对并发访问时这样做。这也是你应该这样做的一个很好的理由:

  

面对并发访问时,用户必须在迭代时手动同步返回的集合。原因是迭代是通过对集合的多次调用来完成的,集合必须组成一个单独的原子操作。以下是迭代包装器同步集合的习惯用法。

http://java.sun.com/docs/books/tutorial/collections/implementations/wrapper.html

要了解更多“同步块中的最终变量”,请看一下:Final variable and synchronized block in java

答案 1 :(得分:3)

  1. 我是否应该为每个for循环包装... 不,你不需要用同步块包装每个for循环,事实上你甚至不应该这样做,因为它伴随着性能损失。您需要仅包含那些迭代可能同时由多个线程访问的集合的循环。

  2. 我的IDE(IntelliJ IDEA)不断报告.... 在您的特定情况下,这不是问题,因为如果不同的线程有不同的s实例,那么显然迭代器将会也有所不同。

答案 2 :(得分:1)

由于每个人都使用了Iterator,如果你的ConcurrentModificationException在结构上被修改,那么在处理a Set期间,你仍需要s

关于IDE提供的警告,如果要重新分配s,则尝试在volatile上同步时,不同的线程可能会看到不同的对象。使用{{1}}应该有帮助。