Synchronize hash resizing, to avoid hangs under concurrent load.

This change, suggested by Masayuki Onjo, improves the thread-
safety of Hash by preventing two resizes from occurring at the
same time. Such a situation can lead to a bucket's chain of nodes
looping back on itself in the following way:

* Thread A begins re-inserting elements from the old bucket
  list into the new bucket list. Elements that will go into
  the same bucket in the new list must be chained. As they
  are inserted, they become the new bucket head, pointing at
  whatever was in the bucket already.
* Nodes X and Y would go into the same bucket in the new hash.
* Thread A proceeds to puts X into the bucket; X.next = null.
* Thread A proceeds with Y. Y.next = X.
* At the same time, thread B begins performing the same resize
  operation against its own new bucket list.
* Thread B proceeds to insert X. X.next = null.
* Thread B proceeds with Y, saving its next value X. Y.next = X.
* Thread B continues to X, because it must handle all chained
  nodes in the bucket where it found Y. It finds Y already in the
  new bucket where it inserts X. X.next = Y.
* At this point, X.next = Y and Y.next = X, so walking the bucket
  will cause an infinite loop. The Hash is broken.

Making the resize operation synchronized prevents two resizing
threads from mixing old node chaining with new node chaining,
reducing the likelihood of a broken hash.

This does not, however, make Hash thread-safe. Inserts can still
be lost if one thread adds an element during a resize operation,
or elements can end up in the wrong buckets if updated during
a resize (because their effective hash will change after the
resize has already re-inserted the element). We will continue to
explore ways to improve the thread-safety of Hash.