Tuesday, December 13, 2011

Breaking a Java HashSet

Can it be?

Set set1 = new HashSet(5); Set set2 = new HashSet(5); // add of bunch of strings to both sets assert set1.equals(set2) == false;

Yes it can!

We actually had this problem in an integration test. The cause was that the strings to one set were added concurrently. Interestingly, the sets seemed to be the same, when printed they contained the same strings, just in a different order (which is also interesting). However, the internals were apparently so damaged that an equals invocation return false.

We replaced the HashSet with a ConcurrentSkipSet, and all was fine again.

Conclusion: Okay, so this is a boring conclusion, but just be careful with using normal collections in concurrent situations.

2 comments:

  1. The javadocs are actually quite clear about this:

    "It makes no guarantees as to the iteration order of the set; in particular, it does not guarantee that the order will remain constant over time."

    and:

    "Note that this implementation is not synchronized. If multiple threads access a hash set concurrently, and at least one of the threads modifies the set, it must be synchronized externally."

    http://docs.oracle.com/javase/6/docs/api/java/util/HashSet.html

    ReplyDelete
  2. I know! (Our tester with 2 months of Java experience didn't.)

    The surprising thing is that the set starts behaving inconsistently, but doesn't outright fail with exceptions.

    ReplyDelete