简体   繁体   中英

java.util.Hashtable implementation code local variable to elements table reassignment

I wonder why java.util.Hashtable methods perform operations on elements array through locally assigned variable, instead of accessing class member directly. Does it has something to do with synchronization (keeping elements array in consistent state between method calls?)

For example : Entry<?,?> tab[] = table;

in

 private void addEntry(int hash, K key, V value, int index) {
420         modCount++;
421 
422         Entry<?,?> tab[] = table;
423         if (count >= threshold) {
424             // Rehash the table if the threshold is exceeded
425             rehash();
426 
427             tab = table;
428             hash = key.hashCode();
429             index = (hash & 0x7FFFFFFF) % tab.length;
430         } 

or in

456     public synchronized V put(K key, V value) {
457         // Make sure the value is not null
458         if (value == null) {
459             throw new NullPointerException();
460         }
461 
462         // Makes sure the key is not already in the hashtable.
463         Entry<?,?> tab[] = table;
464         int hash = key.hashCode();
465         int index = (hash & 0x7FFFFFFF) % tab.length;
466         @SuppressWarnings("unchecked")
467         Entry<K,V> entry = (Entry<K,V>)tab[index];
468         for(; entry != null ; entry = entry.next) {
469             if ((entry.hash == hash) && entry.key.equals(key)) {
470                 V old = entry.value;
471                 entry.value = value;
472                 return old;
473             }
474         }
475 
476         addEntry(hash, key, value, index);
477         return null;
478     }

I feel bad leaving only comments, this question deserves a proper answer, so here's a quick attempt to rehash (ha) those comments.

  • Hashtable is synchronized (all public methods are synchronized , or return a synchronized collection ( keySet() , entrySet() , values() )), which makes it thread safe (Some rules & restrictions may apply)
  • The rehash() method is protected : it can be invoked from a subclass.
  • But it is not synchronized , so an instance of a subclass could invoke rehash() concurrently to another of those methods that need to access table .
    So, to avoid a race condition on table , those methods save a local copy of the reference to the array, and then can safely work with that local array: if rehash() is called, it will build a new array without interfering with other threads working on the old one.

Version from JDK 1.0.2 was already like that (found it here , the Windows .exe is self-extractible zip file, so unzip deals with that, and in there you'll find src.zip -- interesting to see Hashtable.java with 3 classes inside, no inner classes as those were introduced in 1.1).

This design encourages inheriting Hashtable to benefit from its functionality, but composition should be favored instead. I found a bug entry that is specific to subclasses of Hashtable (although not about thread safety), in which Josh Bloch says:

This sort of problem can be avoided by using delegation rather than subclassing.

Quoting @pvg in comments, for a nice summary:

A somewhat broader answer is that this is basically an early 90s design that has just had a long life and it shows. It's a class that tries to be both threadsafe and extensible through subclassing at the same time, something the class library avoids in later design iterations.

这很简单 - rehash()将重写table字段,因此将它们保存到临时变量以便以后访问。

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