暴露 keySet() 的线程安全方式

Jak*_*ake 5 java hashset

在我有一张地图并希望线程安全地公开其键集的情况下,这一定是相当普遍的情况:

public MyClass {
  Map<String,String> map = // ...
  public final Set<String> keys() {
     // returns key set
  }
}
Run Code Online (Sandbox Code Playgroud)

现在,如果我的“地图”不是线程安全的,这是不安全的:

  public final Set<String> keys() {
     return map.keySet();
  }
Run Code Online (Sandbox Code Playgroud)

两者都不是:

  public final Set<String> keys() {
     return Collections.unmodifiableSet(map.keySet());
  }
Run Code Online (Sandbox Code Playgroud)

所以我需要创建一个副本,例如:

  public final Set<String> keys() {
     return new HashSet(map.keySet());
  }
Run Code Online (Sandbox Code Playgroud)

但是,这似乎也不安全,因为该构造函数遍历参数的元素并将它们添加()。因此,在进行此复制时,可能会发生 ConcurrentModificationException。

那么:

  public final Set<String> keys() {
     synchronized(map) {
       return new HashSet(map.keySet());
     }
  }
Run Code Online (Sandbox Code Playgroud)

似乎是解决方案。这看起来对吗?

Aff*_*ffe 4

该解决方案并不是特别有用,除非您计划在地图上使用它的任何地方进行同步。同步它并不会阻止其他人同时调用它的方法。它只会阻止他们也能够在其上同步。

如果您知道在有人可能进行迭代时需要并发放置和删除,那么最好的解决方案似乎确实是ConcurrentHashMap首先使用。如果该类提供的并发行为不是您所需要的,您可能只需要使用完全同步的 Map。