线程安全的遍历LinkedHashMap

3

我有一个私有的LinkedHashMap,用于从不同的线程中读取(仅用于读取):

class foo {

  private LinkedHashMap map = ...;


  public publicMethodCalledFromDifferentThreads() {

     for (Object foo : map) {
        ...
     }
  }
}

这个实现不是线程安全的,所以 for 循环无法正确地工作。我尝试自己找到解决方案,唯一想到的是以下内容:

class foo {

  private LinkedHashMap map = ...;
  private Map.Entry[] mapEntries = map.entrySet().toArray() ...;

  public publicMethodCalledFromDifferentThreads() {

     for (int i = 0; i < mapEntries.length; i++) {
        mapEntries[i]...
        ...
     }
  }
}

最终我需要有两个变量而迭代变得非常复杂。有什么更好的方法来处理这种情况吗?

谢谢!


3
如果您只是从中读取内容(在读取时不进行修改),那么据我所知,它不需要线程安全。您看到了什么行为? - GreyBeardedGeek
我的问题是,一旦有两个线程在迭代地图,迭代器就会随机跳转到条目。我认为这是由于共享迭代器引起的,你是说这不可能是这种情况吗? - Vojtěch
3
在不对LinkedHashMap本身进行修改的情况下,至少在Sun版本中,迭代器似乎不会发生冲突:http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/LinkedHashMap.java#LinkedHashMap.LinkedHashIterator.nextEntry%28%29 (可以绝对保证对象没有以任何方式被改变吗?)重要的遍历是标准的:nextEntry = e.after;(其中nextEntry是新迭代器中的一个成员),除此之外不会产生任何副作用。 - user166390
好的,你是对的,问题出在其他地方,感谢你指引我走向正确的方向! - Vojtěch
2
@Vojtěch,问题是什么? - assylias
有另一个变量被覆盖了,似乎是迭代器的问题。 - Vojtěch
2个回答

3

如果您只是阅读,并且未修改基础对象列表及其内容,则不应出现线程问题。

您实际遇到了什么问题?

我认为您可能以某种方式修改了您的LinkedHashMap。

此外,您如何确定线程正在跳转?您确定您没有只看到两个线程混合的输出,这看起来像是跳动,即使每个线程都是按顺序迭代的?例如,如果每个线程打印其当前条目,则可能会看到类似于

123 12 45 345 6....

这是顺序的....


1
@hvgotcodes,你引用的文档仅适用于需要在构建映射时显式声明的访问顺序链式哈希映射。默认情况下是插入顺序,调用get不会造成结构性修改。鉴于症状,这似乎是情况,但我想指出区别。 - Jeremy
谢谢您的建议,您让我知道问题出在其他地方,这对我很有帮助!谢谢! - Vojtěch

0
你可以使用同步映射
private final Map<K, V> map = Collections.synchronizedMap(new LinkedHashMap<K, V>());

public void foo() {
    synchronized(map) {
        for(K key : map.keySet()) {
            // thread safe iteration
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接