70 |
|
* @since 1.5 |
71 |
|
* @author Doug Lea |
72 |
|
* @param <K> the type of keys maintained by this map |
73 |
< |
* @param <V> the type of mapped values |
73 |
> |
* @param <V> the type of mapped values |
74 |
|
*/ |
75 |
|
public class ConcurrentHashMap<K, V> extends AbstractMap<K, V> |
76 |
|
implements ConcurrentMap<K, V>, Serializable { |
107 |
|
* be a power of two <= 1<<30 to ensure that entries are indexible |
108 |
|
* using ints. |
109 |
|
*/ |
110 |
< |
static final int MAXIMUM_CAPACITY = 1 << 30; |
110 |
> |
static final int MAXIMUM_CAPACITY = 1 << 30; |
111 |
|
|
112 |
|
/** |
113 |
|
* The maximum number of segments to allow; used to bound |
175 |
|
|
176 |
|
/** |
177 |
|
* ConcurrentHashMap list entry. Note that this is never exported |
178 |
< |
* out as a user-visible Map.Entry. |
179 |
< |
* |
178 |
> |
* out as a user-visible Map.Entry. |
179 |
> |
* |
180 |
|
* Because the value field is volatile, not final, it is legal wrt |
181 |
|
* the Java Memory Model for an unsynchronized reader to see null |
182 |
|
* instead of initial value when read via a data race. Although a |
353 |
|
HashEntry[] tab = table; |
354 |
|
int len = tab.length; |
355 |
|
for (int i = 0 ; i < len; i++) { |
356 |
< |
for (HashEntry<K,V> e = (HashEntry<K,V>)tab[i]; |
357 |
< |
e != null ; |
356 |
> |
for (HashEntry<K,V> e = (HashEntry<K,V>)tab[i]; |
357 |
> |
e != null ; |
358 |
|
e = e.next) { |
359 |
|
V v = e.value; |
360 |
|
if (v == null) // recheck |
436 |
|
} |
437 |
|
|
438 |
|
void rehash() { |
439 |
< |
HashEntry[] oldTable = table; |
439 |
> |
HashEntry[] oldTable = table; |
440 |
|
int oldCapacity = oldTable.length; |
441 |
|
if (oldCapacity >= MAXIMUM_CAPACITY) |
442 |
|
return; |
524 |
|
++modCount; |
525 |
|
HashEntry<K,V> newFirst = e.next; |
526 |
|
for (HashEntry<K,V> p = first; p != e; p = p.next) |
527 |
< |
newFirst = new HashEntry<K,V>(p.key, p.hash, |
527 |
> |
newFirst = new HashEntry<K,V>(p.key, p.hash, |
528 |
|
newFirst, p.value); |
529 |
|
tab[index] = newFirst; |
530 |
|
count = c; // write-volatile |
567 |
|
* bin exceeds this threshold. |
568 |
|
* @param concurrencyLevel the estimated number of concurrently |
569 |
|
* updating threads. The implementation performs internal sizing |
570 |
< |
* to try to accommodate this many threads. |
570 |
> |
* to try to accommodate this many threads. |
571 |
|
* @throws IllegalArgumentException if the initial capacity is |
572 |
|
* negative or the load factor or concurrencyLevel are |
573 |
|
* nonpositive. |
606 |
|
|
607 |
|
/** |
608 |
|
* Creates a new, empty map with the specified initial capacity |
609 |
< |
* and load factor and with the default concurrencyLevel |
609 |
> |
* and load factor and with the default concurrencyLevel |
610 |
|
* (<tt>16</tt>). |
611 |
|
* |
612 |
|
* @param initialCapacity The implementation performs internal |
635 |
|
|
636 |
|
/** |
637 |
|
* Creates a new, empty map with a default initial capacity |
638 |
< |
* (<tt>16</tt>), load factor |
639 |
< |
* (<tt>0.75f</tt>), and concurrencyLevel |
638 |
> |
* (<tt>16</tt>), load factor |
639 |
> |
* (<tt>0.75f</tt>), and concurrencyLevel |
640 |
|
* (<tt>16</tt>). |
641 |
|
*/ |
642 |
|
public ConcurrentHashMap() { |
647 |
|
* Creates a new map with the same mappings as the given map. The |
648 |
|
* map is created with a capacity of 1.5 times the number of |
649 |
|
* mappings in the given map or <tt>16</tt> |
650 |
< |
* (whichever is greater), and a default load factor |
650 |
> |
* (whichever is greater), and a default load factor |
651 |
|
* (<tt>0.75f</tt>) and concurrencyLevel |
652 |
|
* (<tt>16</tt>). |
653 |
|
* @param t the map |
680 |
|
for (int i = 0; i < segments.length; ++i) { |
681 |
|
if (segments[i].count != 0) |
682 |
|
return false; |
683 |
< |
else |
683 |
> |
else |
684 |
|
mcsum += mc[i] = segments[i].modCount; |
685 |
|
} |
686 |
|
// If mcsum happens to be zero, then we know we got a snapshot |
689 |
|
if (mcsum != 0) { |
690 |
|
for (int i = 0; i < segments.length; ++i) { |
691 |
|
if (segments[i].count != 0 || |
692 |
< |
mc[i] != segments[i].modCount) |
692 |
> |
mc[i] != segments[i].modCount) |
693 |
|
return false; |
694 |
|
} |
695 |
|
} |
727 |
|
} |
728 |
|
} |
729 |
|
} |
730 |
< |
if (check == sum) |
730 |
> |
if (check == sum) |
731 |
|
break; |
732 |
|
} |
733 |
|
if (check != sum) { // Resort to locking all segments |
734 |
|
sum = 0; |
735 |
< |
for (int i = 0; i < segments.length; ++i) |
735 |
> |
for (int i = 0; i < segments.length; ++i) |
736 |
|
segments[i].lock(); |
737 |
< |
for (int i = 0; i < segments.length; ++i) |
737 |
> |
for (int i = 0; i < segments.length; ++i) |
738 |
|
sum += segments[i].count; |
739 |
< |
for (int i = 0; i < segments.length; ++i) |
739 |
> |
for (int i = 0; i < segments.length; ++i) |
740 |
|
segments[i].unlock(); |
741 |
|
} |
742 |
|
if (sum > Integer.MAX_VALUE) |
790 |
|
public boolean containsValue(Object value) { |
791 |
|
if (value == null) |
792 |
|
throw new NullPointerException(); |
793 |
< |
|
793 |
> |
|
794 |
|
// See explanation of modCount use above |
795 |
|
|
796 |
|
final Segment[] segments = this.segments; |
820 |
|
return false; |
821 |
|
} |
822 |
|
// Resort to locking all segments |
823 |
< |
for (int i = 0; i < segments.length; ++i) |
823 |
> |
for (int i = 0; i < segments.length; ++i) |
824 |
|
segments[i].lock(); |
825 |
|
boolean found = false; |
826 |
|
try { |
831 |
|
} |
832 |
|
} |
833 |
|
} finally { |
834 |
< |
for (int i = 0; i < segments.length; ++i) |
834 |
> |
for (int i = 0; i < segments.length; ++i) |
835 |
|
segments[i].unlock(); |
836 |
|
} |
837 |
|
return found; |
859 |
|
/** |
860 |
|
* Maps the specified <tt>key</tt> to the specified |
861 |
|
* <tt>value</tt> in this table. Neither the key nor the |
862 |
< |
* value can be <tt>null</tt>. |
862 |
> |
* value can be <tt>null</tt>. |
863 |
|
* |
864 |
|
* <p> The value can be retrieved by calling the <tt>get</tt> method |
865 |
|
* with a key that is equal to the original key. |
883 |
|
* with a value, associate it with the given value. |
884 |
|
* This is equivalent to |
885 |
|
* <pre> |
886 |
< |
* if (!map.containsKey(key)) |
886 |
> |
* if (!map.containsKey(key)) |
887 |
|
* return map.put(key, value); |
888 |
|
* else |
889 |
|
* return map.get(key);</pre> |
891 |
|
* @param key key with which the specified value is to be associated. |
892 |
|
* @param value value to be associated with the specified key. |
893 |
|
* @return previous value associated with specified key, or <tt>null</tt> |
894 |
< |
* if there was no mapping for key. |
894 |
> |
* if there was no mapping for key. |
895 |
|
* @throws NullPointerException if the specified key or value is |
896 |
|
* <tt>null</tt>. |
897 |
|
*/ |
936 |
|
/** |
937 |
|
* Remove entry for key only if currently mapped to given value. |
938 |
|
* Acts as |
939 |
< |
* <pre> |
939 |
> |
* <pre> |
940 |
|
* if (map.get(key).equals(value)) { |
941 |
|
* map.remove(key); |
942 |
|
* return true; |
957 |
|
/** |
958 |
|
* Replaces entry for key only if currently mapped to given value. |
959 |
|
* Acts as |
960 |
< |
* <pre> |
960 |
> |
* <pre> |
961 |
|
* if (map.get(key).equals(oldValue)) { |
962 |
|
* map.put(key, newValue); |
963 |
|
* return true; |
980 |
|
/** |
981 |
|
* Replaces entry for key only if currently mapped to some value. |
982 |
|
* Acts as |
983 |
< |
* <pre> |
983 |
> |
* <pre> |
984 |
|
* if (map.containsKey(key)) { |
985 |
|
* return map.put(key, value); |
986 |
|
* } else return null;</pre> |
988 |
|
* @param key key with which the specified value is associated. |
989 |
|
* @param value value to be associated with the specified key. |
990 |
|
* @return previous value associated with specified key, or <tt>null</tt> |
991 |
< |
* if there was no mapping for key. |
991 |
> |
* if there was no mapping for key. |
992 |
|
* @throws NullPointerException if the specified key or value is |
993 |
|
* <tt>null</tt>. |
994 |
|
*/ |
1163 |
|
public V nextElement() { return super.nextEntry().value; } |
1164 |
|
} |
1165 |
|
|
1166 |
< |
|
1166 |
> |
|
1167 |
|
|
1168 |
|
/** |
1169 |
|
* Entry iterator. Exported Entry objects must write-through |