Java HashTable size()后跟线程中安全的values()



我在一个线程中顺序执行以下操作:

int size=hashTable.size();

前臂。。。。在里面hasTable.values()

做点什么

我的问题是foreach会被执行大小倍吗?(即使另一个线程同时放入/删除一个元素?

否,HashTable在方法级别上是线程安全的(多个线程可以在任何时间调用任何方法),但不存在跨方法同步。在您的两个指令之间,其他线程可能会添加/删除甚至清除哈希表。

如果你需要保持这种不变,那么制作一个防御副本(不必是线程安全的),并对该副本执行size()/循环:

Map<K, V> map = null;
synchronized(hashTable) {
  map = new java.util.HashMap<>(hashTable);
}
map.size();
for(V v: map.values()) {
  //...
}

这里为每个都是安全的,它保证运行大小的时间。同样如评论中所述,您可以在hashTable:上同步

synchronized(hashTable) {
  int size = hashTable.size();
  for(V v: hashTable.values()) {
    //...
  }
}

然而,这种解决方案意味着一次只有一个线程可以执行循环(如果循环需要一些时间才能完成,这可能会成为瓶颈)。使用防御复制时,每个线程都有自己的副本,几个线程可以同时循环。另一方面,如果hashTable非常大(复制成本很高),但迭代非常快,则此解决方案更好。

如果另一个线程在执行foreach期间修改hashTable,那么您的代码将抛出ConcurrentModificationException

您的示例不是线程安全的,但可以很容易地使其成为线程安全的:

synchronized(hashTable) {
  int size = hashTable.size();
  foreach.... in ... hasTable.values() {
    // do something
  }
}

Java HashTable size()后跟values()在线程中是否安全?

所以不安全的不是values()方法调用。它是在values()上打开一个迭代器,该迭代器由HashTable支持。如果在迭代时对表进行了修改,则迭代器会抛出异常。

我的问题是foreach会被执行大小倍吗?(即使另一个线程同时放入/移除一个元素?

如前所述,如果HashTable在您对其进行迭代时被修改,它将抛出异常

HashTable几乎已被弃用。如果您正在寻找HashMap的现代并发版本,那么您应该使用在Java5中添加的ConcurrentHashMapConcurrentHashMap在没有额外同步或复制的情况下,正确地处理了在后台迭代时发生修改的情况:

ConcurrentHashMap<...> map = new ConcurrentHashMap<...>();
int size = map.size();
for (... value : map.values()) {
    // may be called more or less than size if other threads add or delete
    ...
}

最新更新