United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-5073546 : Minor ConcurrentHashMap constructor spec tweaks

Details
Type:
Bug
Submit Date:
2004-07-13
Status:
Resolved
Updated Date:
2005-09-04
Project Name:
JDK
Resolved Date:
2005-09-04
Component:
core-libs
OS:
generic
Sub-Component:
java.util.concurrent
CPU:
generic
Priority:
P3
Resolution:
Fixed
Affected Versions:
5.0
Fixed Versions:

Related Reports

Sub Tasks

Description
The problem:

ConcurrentHashMap's constructors have a number of weaknesses.
The only way to create a map with a non-default concurrency level is
to use the constructor

ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel)

Unfortunately, there is no guidance for what the value of loadFactor might mean
exactly, and no way to determine the default value.  A user who wants to use
a concurrencyLevel of 1 would have to read the source to discover that the
default initialCapacity and loadFactor are 16 and .75, respectively.

The javadoc for constructor

ConcurrentHashMap(Map<? extends K, ? extends V> t) 

states 
     * The
     * map is created with a capacity of twice the number of mappings in
     * the given map or 11 (whichever is greater)

First of all, this is a bad idea, since an access pattern that repeatedly
"copies" maps using
ConcurrentHashMap m = new ConcurrentHashMap(oldmap)
will cause exponential waste of space.

Secondly, the implementation does the more sensible thing of using a
more rational initial capacity, just enough to hold the elements of
the source map.  The magic number 11 should be replaced by the
default initial capacity of 16 since it is counterintuitive that
in the sequence

ConcurrentHashMap m1 = new ConcurrentHashMap();
ConcurrentHashMap m2 = new ConcurrentHashMap(m1);

m2 would have a smaller capacity than m1.

###@###.### 2004-07-13

                                    

Comments
EVALUATION

One can understand ConcurrentHashMap better if one realizes that
the design is an engineering compromise between incompatible goals:

- to have a "modern" design with as much hiding of implementation as possible.
- to be a "drop-in replacement" for Hashtable, with as few caveats as possible.

Given the conflicting goals, it seems best to explicitly specify
the default values in the javadoc, so that a user who wants a
concurrencyLevel of 1 with otherwise default values can do:

new ConcurrentHashMap(16, 0.75, 1)

###@###.### 2004-07-13
                                     
2004-07-13
PUBLIC COMMENTS

-
                                     
2004-07-16
SUGGESTED FIX

--- /tmp/geta21916	2004-07-13 13:54:33.565696600 -0700
+++ ConcurrentHashMap.java	2004-07-13 13:54:29.405306000 -0700
@@ -602,43 +602,45 @@
 
         for (int i = 0; i < this.segments.length; ++i)
             this.segments[i] = new Segment<K,V>(cap, loadFactor);
     }
 
     /**
      * Creates a new, empty map with the specified initial
-     * capacity, and with default load factor and concurrencyLevel.
+     * capacity, and with default load factor (<tt>0.75f</tt>)
+     * and concurrencyLevel (<tt>16</tt>).
      *
      * @param initialCapacity the initial capacity. The implementation
      * performs internal sizing to accommodate this many elements.
      * @throws IllegalArgumentException if the initial capacity of
      * elements is negative.
      */
     public ConcurrentHashMap(int initialCapacity) {
         this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_SEGMENTS);
     }
 
     /**
-     * Creates a new, empty map with a default initial capacity,
-     * load factor, and concurrencyLevel.
+     * Creates a new, empty map with a default initial capacity
+     * (<tt>16</tt>), load factor (<tt>0.75f</tt>) and
+     * concurrencyLevel (<tt>16</tt>).
      */
     public ConcurrentHashMap() {
         this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_SEGMENTS);
     }
 
     /**
      * Creates a new map with the same mappings as the given map.  The
-     * map is created with a capacity of twice the number of mappings in
-     * the given map or 11 (whichever is greater), and a default load factor
-     * and concurrencyLevel.
+     * map is created with a capacity consistent with the default load
+     * factor (<tt>0.75f</tt>) and uses the default concurrencyLevel
+     * (<tt>16</tt>).
      * @param t the map
      */
     public ConcurrentHashMap(Map<? extends K, ? extends V> t) {
         this(Math.max((int) (t.size() / DEFAULT_LOAD_FACTOR) + 1,
-                      11),
+                      DEFAULT_INITIAL_CAPACITY),
              DEFAULT_LOAD_FACTOR, DEFAULT_SEGMENTS);
         putAll(t);
     }
 
     // inherit Map javadoc
     public boolean isEmpty() {
         final Segment[] segments = this.segments;
                                     
2004-07-16



Hardware and Software, Engineered to Work Together