Java HashTable size()后跟值()安全的线程?

时间:2012-08-29 17:21:13

标签: java multithreading thread-safety hashtable

我在一个帖子中按顺序执行以下操作:

int size = hashTable.size();

foreach .... in ... hasTable.values()

做点什么

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

4 个答案:

答案 0 :(得分:6)

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

如果您需要保持这样的不变量,请制作防御性副本(不必是线程安全的)并在该副本上执行size() /循环:

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

这里for-each是安全的,并且保证运行大小 - 次。同样如评论中所述,您只需在hashTable上进行同步:

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

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

答案 1 :(得分:1)

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

答案 2 :(得分:1)

  

Java HashTable size()后跟值()安全的线程?

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

  

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

如上所述,HashTable如果在迭代它时被修改,则会抛出异常。

HashTable几乎全部被弃用了。如果您正在寻找HashMap的现代并发版本,那么您应该使用在Java 5中添加的ConcurrentHashMap ConcurrentHashMap正确处理在后台进行修改的情况迭代它而无需额外的同步或复制:

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
    ...
}

答案 3 :(得分:1)

您的示例不是线程安全的,但它可以像这样轻松地保证线程安全:

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