50 |
|
* <p> Like Hashtable but unlike java.util.HashMap, this class does |
51 |
|
* NOT allow <tt>null</tt> to be used as a key or value. |
52 |
|
* |
53 |
< |
**/ |
53 |
> |
* @since 1.5 |
54 |
> |
* @author Doug Lea |
55 |
> |
*/ |
56 |
|
public class ConcurrentHashMap<K, V> extends AbstractMap<K, V> |
57 |
|
implements ConcurrentMap<K, V>, Cloneable, Serializable { |
58 |
|
|
67 |
|
* The default initial number of table slots for this table (32). |
68 |
|
* Used when not otherwise specified in constructor. |
69 |
|
*/ |
70 |
< |
static int DEFAULT_INITIAL_CAPACITY = 16; |
70 |
> |
private static int DEFAULT_INITIAL_CAPACITY = 16; |
71 |
|
|
72 |
|
/** |
73 |
|
* The maximum capacity, used if a higher value is implicitly |
116 |
|
/** |
117 |
|
* Return a hash code for non-null Object x. |
118 |
|
* Uses the same hash code spreader as most other j.u hash tables. |
119 |
+ |
* @param x the object serving as a key |
120 |
+ |
* @return the hash code |
121 |
|
*/ |
122 |
|
private static int hash(Object x) { |
123 |
|
int h = x.hashCode(); |
163 |
|
* subclasses from ReentrantLock opportunistically, just to |
164 |
|
* simplify some locking and avoid separate construction. |
165 |
|
**/ |
166 |
< |
private final static class Segment<K,V> extends ReentrantLock implements Serializable { |
166 |
> |
private static final class Segment<K,V> extends ReentrantLock implements Serializable { |
167 |
|
/* |
168 |
|
* Segments maintain a table of entry lists that are ALWAYS |
169 |
|
* kept in a consistent state, so can be read without locking. |
218 |
|
* (The value of this field is always (int)(capacity * |
219 |
|
* loadFactor).) |
220 |
|
*/ |
221 |
< |
transient private int threshold; |
221 |
> |
private transient int threshold; |
222 |
|
|
223 |
|
/** |
224 |
|
* The per-segment table |
370 |
|
// Clone all remaining nodes |
371 |
|
for (HashEntry<K,V> p = e; p != lastRun; p = p.next) { |
372 |
|
int k = p.hash & sizeMask; |
373 |
< |
newTable[k] = new HashEntry<K,V>(p.hash, p.key, |
374 |
< |
p.value, newTable[k]); |
373 |
> |
newTable[k] = new HashEntry<K,V>(p.hash, |
374 |
> |
p.key, |
375 |
> |
p.value, |
376 |
> |
newTable[k]); |
377 |
|
} |
378 |
|
} |
379 |
|
} |
408 |
|
// all preceeding ones need to be cloned. |
409 |
|
HashEntry<K,V> newFirst = e.next; |
410 |
|
for (HashEntry<K,V> p = first; p != e; p = p.next) |
411 |
< |
newFirst = new HashEntry<K,V>(p.hash, p.key, p.value, newFirst); |
411 |
> |
newFirst = new HashEntry<K,V>(p.hash, p.key, |
412 |
> |
p.value, newFirst); |
413 |
|
tab[index] = newFirst; |
414 |
|
|
415 |
|
count--; // write-volatile |
500 |
|
* negative or the load factor or number of segments are |
501 |
|
* nonpositive. |
502 |
|
*/ |
503 |
< |
public ConcurrentHashMap(int initialCapacity, float loadFactor, int segments) { |
503 |
> |
public ConcurrentHashMap(int initialCapacity, |
504 |
> |
float loadFactor, int segments) { |
505 |
|
if (!(loadFactor > 0) || initialCapacity < 0 || segments <= 0) |
506 |
|
throw new IllegalArgumentException(); |
507 |
|
|
513 |
|
ssize <<= 1; |
514 |
|
} |
515 |
|
segmentShift = sshift; |
516 |
< |
segmentMask = ssize-1; |
516 |
> |
segmentMask = ssize - 1; |
517 |
|
this.segments = new Segment<K,V>[ssize]; |
518 |
|
|
519 |
|
if (initialCapacity > MAXIMUM_CAPACITY) |
585 |
|
* @return the value to which the key is mapped in this table; |
586 |
|
* <code>null</code> if the key is not mapped to any value in |
587 |
|
* this table. |
588 |
< |
* @exception NullPointerException if the key is |
588 |
> |
* @throws NullPointerException if the key is |
589 |
|
* <code>null</code>. |
590 |
|
* @see #put(Object, Object) |
591 |
|
*/ |
601 |
|
* @return <code>true</code> if and only if the specified object |
602 |
|
* is a key in this table, as determined by the |
603 |
|
* <tt>equals</tt> method; <code>false</code> otherwise. |
604 |
< |
* @exception NullPointerException if the key is |
604 |
> |
* @throws NullPointerException if the key is |
605 |
|
* <code>null</code>. |
606 |
|
* @see #contains(Object) |
607 |
|
*/ |
619 |
|
* @param value value whose presence in this map is to be tested. |
620 |
|
* @return <tt>true</tt> if this map maps one or more keys to the |
621 |
|
* specified value. |
622 |
< |
* @exception NullPointerException if the value is <code>null</code>. |
622 |
> |
* @throws NullPointerException if the value is <code>null</code>. |
623 |
|
*/ |
624 |
|
public boolean containsValue(Object value) { |
625 |
|
if (value == null) |
644 |
|
* <code>value</code> argument in this table as |
645 |
|
* determined by the <tt>equals</tt> method; |
646 |
|
* <code>false</code> otherwise. |
647 |
< |
* @exception NullPointerException if the value is <code>null</code>. |
647 |
> |
* @throws NullPointerException if the value is <code>null</code>. |
648 |
|
* @see #containsKey(Object) |
649 |
|
* @see #containsValue(Object) |
650 |
< |
* @see Map |
650 |
> |
* @see Map |
651 |
|
*/ |
652 |
|
public boolean contains(Object value) { |
653 |
|
return containsValue(value); |
665 |
|
* @param value the value. |
666 |
|
* @return the previous value of the specified key in this table, |
667 |
|
* or <code>null</code> if it did not have one. |
668 |
< |
* @exception NullPointerException if the key or value is |
668 |
> |
* @throws NullPointerException if the key or value is |
669 |
|
* <code>null</code>. |
670 |
|
* @see Object#equals(Object) |
671 |
|
* @see #get(Object) |
716 |
|
* @param t Mappings to be stored in this map. |
717 |
|
*/ |
718 |
|
public <K1 extends K, V1 extends V> void putAll(Map<K1,V1> t) { |
719 |
< |
Iterator<Map.Entry<K1,V1>> it = t.entrySet().iterator(); |
720 |
< |
while (it.hasNext()) { |
721 |
< |
Entry<K,V> e = (Entry) it.next(); |
719 |
> |
Iterator<Map.Entry<K1,V1>> it = t.entrySet().iterator(); |
720 |
> |
while (it.hasNext()) { |
721 |
> |
Entry<K,V> e = (Entry) it.next(); |
722 |
|
put(e.getKey(), e.getValue()); |
723 |
|
} |
724 |
|
} |
730 |
|
* @param key the key that needs to be removed. |
731 |
|
* @return the value to which the key had been mapped in this table, |
732 |
|
* or <code>null</code> if the key did not have a mapping. |
733 |
< |
* @exception NullPointerException if the key is |
733 |
> |
* @throws NullPointerException if the key is |
734 |
|
* <code>null</code>. |
735 |
|
*/ |
736 |
|
public V remove(Object key) { |
748 |
|
* it means "any value". |
749 |
|
* @return the value to which the key had been mapped in this table, |
750 |
|
* or <code>null</code> if the key did not have a mapping. |
751 |
< |
* @exception NullPointerException if the key is |
751 |
> |
* @throws NullPointerException if the key is |
752 |
|
* <code>null</code>. |
753 |
|
*/ |
754 |
|
public V remove(Object key, Object value) { |
798 |
|
*/ |
799 |
|
public Set<K> keySet() { |
800 |
|
Set<K> ks = keySet; |
801 |
< |
return (ks != null)? ks : (keySet = new KeySet()); |
801 |
> |
return (ks != null) ? ks : (keySet = new KeySet()); |
802 |
|
} |
803 |
|
|
804 |
|
|
815 |
|
*/ |
816 |
|
public Collection<V> values() { |
817 |
|
Collection<V> vs = values; |
818 |
< |
return (vs != null)? vs : (values = new Values()); |
818 |
> |
return (vs != null) ? vs : (values = new Values()); |
819 |
|
} |
820 |
|
|
821 |
|
|
875 |
|
private HashEntry<K, V> lastReturned; |
876 |
|
|
877 |
|
private HashIterator() { |
878 |
< |
nextSegmentIndex = segments.length-1; |
878 |
> |
nextSegmentIndex = segments.length - 1; |
879 |
|
nextTableIndex = -1; |
880 |
|
advance(); |
881 |
|
} |
895 |
|
Segment<K,V> seg = segments[nextSegmentIndex--]; |
896 |
|
if (seg.count != 0) { |
897 |
|
currentTable = seg.table; |
898 |
< |
for (int j = currentTable.length-1; j >= 0; --j) { |
898 |
> |
for (int j = currentTable.length - 1; j >= 0; --j) { |
899 |
|
if ( (nextEntry = currentTable[j]) != null) { |
900 |
< |
nextTableIndex = j-1; |
900 |
> |
nextTableIndex = j - 1; |
901 |
|
return; |
902 |
|
} |
903 |
|
} |
1001 |
|
* Save the state of the <tt>ConcurrentHashMap</tt> |
1002 |
|
* instance to a stream (i.e., |
1003 |
|
* serialize it). |
1004 |
+ |
* @param s the stream |
1005 |
|
* @serialData |
1006 |
|
* the key (Object) and value (Object) |
1007 |
|
* for each key-value mapping, followed by a null pair. |
1034 |
|
* Reconstitute the <tt>ConcurrentHashMap</tt> |
1035 |
|
* instance from a stream (i.e., |
1036 |
|
* deserialize it). |
1037 |
+ |
* @param s the stream |
1038 |
|
*/ |
1039 |
|
private void readObject(java.io.ObjectInputStream s) |
1040 |
|
throws IOException, ClassNotFoundException { |