简体   繁体   中英

Java HashTable size() followed by values() safe in thread?

I have the following executing sequentially in the one thread:

int size = hashTable.size();

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

do something

My question will the foreach be executed size times ? (even if another thread puts/removes an element meanwhile ?

No, HashTable is thread-safe on method level (multiple threads can call any method at any time) but there is no cross-method synchronization. It's possible that between your two instructions other thread adds/removes or even clears the hashtable.

If you need to keep such invariant, make a defensive copy (doesn't have to be thread safe) and do size() /loop on that copy:

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

Here for-each is safe and it's guaranteed to run size-times. Also as noted in comments, you can just synchronize on hashTable :

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

However this solution means that only one thread at a time can perform the loop (this can become a bottleneck if your loop takes some time to complete). With defensive copy each thread has its own copy and several threads can loop at the same time. On the other hand this solution is better if hashTable is very big (expensive to copy) but the iteration is very fast.

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

Java HashTable size() followed by values() safe in thread?

So it's not values() method call that is unsafe. It's that you open an iterator on values() which is backed by the HashTable . It is the iterator which throws an exception if modifications are made to the table while it is iterating.

My question will the foreach be executed size times ? (even if another thread puts/removes an element meanwhile ?

As mentioned, the HashTable will throw an exception if it is modified while you are iterating across it.

HashTable has all but been deprecated. If you are looking for a modern, concurrent version of HashMap then you should be using ConcurrentHashMap which was added in Java 5. ConcurrentHashMap properly handles the case where modifications happen in the background as you iterate across it without extra synchronization or copying:

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

Your example is not thread safe, but it can be easily made thread safe like so:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM