Java 用于Collections.synchronizedSet的每个语法

Java 用于Collections.synchronizedSet的每个语法,java,collections,synchronization,Java,Collections,Synchronization,问题是这个。我做了一套 Set<User> users = Collections.synchronizedSet(new HashSet<User>()) ... for(User u : users){ //do something with u } 我非常确定for-each语法使用迭代器,但我不确定是否应该用同步块包装每个for-each循环 另一件事,我的IDE(IntelliJ IDEA)不断报告,在非最终字段上使用同步块不太可能具有有用的语义,因为

问题是这个。我做了一套

Set<User> users = Collections.synchronizedSet(new HashSet<User>())
...
for(User u : users){
   //do something with u
} 
我非常确定for-each语法使用迭代器,但我不确定是否应该用同步块包装每个for-each循环


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

文档中明确指出,面对并发访问,您应该这样做。这也为您提供了一个很好的理由:

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


要了解更多关于“同步块中的最终变量”的信息,请查看以下内容:

由于for-each在封面下使用迭代器,如果您的
集合
在结构上被修改,则在处理for-each的过程中,您仍然会遇到
ConcurrentModificationException

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

  • 我是否应该包装每个for循环…不,您不需要使用同步块包装每个for循环,事实上,您甚至不应该这样做,因为这会带来性能损失。您只需要为循环包装那些可能由多个线程并发访问的集合

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


  • 不知道,我是从文件上抄的。这可能是一个遗留的例子。
     SortedSet s = Collections.synchronizedSortedSet(new HashSortedSet());
     ...
     synchronized(s) {
        Iterator i = s.iterator(); // Must be in the synchronized block
        while (i.hasNext())
           foo(i.next());
     }