Pure Danger Tech


navigation
home

Hashtable and synchronization

21 Feb 2008

Hashtable is, of course, the original synchronized Dictionary in Java. It’s now considered deprecated and Collections.synchronizedMap(new HashMap()) would generally be the preferred way to do it. But, code out there certainly still exists that uses Hashtable, especially on some older APIs.

Anyhow, Hashtable was retrofitted to implement Map and in particular the entrySet() method that returns Map.Entry objects. Map.Entry has methods to get the key and value and set the value. Since this is in the unlocked Map world, calling these methods would be a bad idea on an Entry from a Hashtable.

So, something like this would be broken (please excuse any typos, just doing this on the fly): [source:java]

Hashtable ht = new Hashtable();

ht.put(“k”, “v”);

Set entries = ht.entrySet();

Map.Entry entry = (Map.Entry) entries.iterator().next();

String k = (String)entry.getKey();

String v = (String)entry.getValue();

entry.setValue(“v2”);

[/source]

For the last 3 lines, all of these are touching state in the Hashtable that is protected there by synchronization on the Hashtable instance. So, the correct way to write this code is: [source:java]

Hashtable ht = new Hashtable();

ht.put(“k”, “v”);

Set entries = ht.entrySet();

Map.Entry entry = (Map.Entry) entries.iterator().next();

synchronized(ht) {

String k = (String)entry.getKey();

String v = (String)entry.getValue();

entry.setValue(“v2”);

}

[/source]

Note that even if you are only doing getKey() or getValue(), it’s still broken not to synchronize as the Java Memory Model will make no guarantee that you’ll ever see an update by another thread in this case.

There are some similar but different weird constraints when you use iterators on synchronized wrappers from Collections. The javadoc says:

It is imperative that the user manually synchronize on the returned list when iterating over it:

List list = Collections.synchronizedList(new ArrayList());

synchronized(list) {

Iterator i = list.iterator(); // Must be in synchronized block

while (i.hasNext())

foo(i.next());

}

Tricky. Surprising to me when I first saw it…