jdk/src/java.base/share/classes/java/util/Hashtable.java
changeset 29743 981893a47bec
parent 28559 e4d6d177eef0
child 32108 aa5490a167ee
--- a/jdk/src/java.base/share/classes/java/util/Hashtable.java	Thu Apr 02 11:54:33 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/Hashtable.java	Thu Apr 02 12:33:03 2015 -0700
@@ -1000,6 +1000,16 @@
         return null;
     }
 
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This method will, on a best-effort basis, throw a
+     * {@link java.util.ConcurrentModificationException} if the mapping
+     * function modified this map during computation.
+     *
+     * @throws ConcurrentModificationException if it is detected that the
+     * mapping function modified this map
+     */
     @Override
     public synchronized V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
         Objects.requireNonNull(mappingFunction);
@@ -1016,7 +1026,9 @@
             }
         }
 
+        int mc = modCount;
         V newValue = mappingFunction.apply(key);
+        if (mc != modCount) { throw new ConcurrentModificationException(); }
         if (newValue != null) {
             addEntry(hash, key, newValue, index);
         }
@@ -1024,6 +1036,16 @@
         return newValue;
     }
 
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This method will, on a best-effort basis, throw a
+     * {@link java.util.ConcurrentModificationException} if the remapping
+     * function modified this map during computation.
+     *
+     * @throws ConcurrentModificationException if it is detected that the
+     * remapping function modified this map
+     */
     @Override
     public synchronized V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
         Objects.requireNonNull(remappingFunction);
@@ -1035,14 +1057,18 @@
         Entry<K,V> e = (Entry<K,V>)tab[index];
         for (Entry<K,V> prev = null; e != null; prev = e, e = e.next) {
             if (e.hash == hash && e.key.equals(key)) {
+                int mc = modCount;
                 V newValue = remappingFunction.apply(key, e.value);
+                if (mc != modCount) {
+                    throw new ConcurrentModificationException();
+                }
                 if (newValue == null) {
                     if (prev != null) {
                         prev.next = e.next;
                     } else {
                         tab[index] = e.next;
                     }
-                    modCount++;
+                    modCount = mc + 1;
                     count--;
                 } else {
                     e.value = newValue;
@@ -1052,7 +1078,16 @@
         }
         return null;
     }
-
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This method will, on a best-effort basis, throw a
+     * {@link java.util.ConcurrentModificationException} if the remapping
+     * function modified this map during computation.
+     *
+     * @throws ConcurrentModificationException if it is detected that the
+     * remapping function modified this map
+     */
     @Override
     public synchronized V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
         Objects.requireNonNull(remappingFunction);
@@ -1064,14 +1099,18 @@
         Entry<K,V> e = (Entry<K,V>)tab[index];
         for (Entry<K,V> prev = null; e != null; prev = e, e = e.next) {
             if (e.hash == hash && Objects.equals(e.key, key)) {
+                int mc = modCount;
                 V newValue = remappingFunction.apply(key, e.value);
+                if (mc != modCount) {
+                    throw new ConcurrentModificationException();
+                }
                 if (newValue == null) {
                     if (prev != null) {
                         prev.next = e.next;
                     } else {
                         tab[index] = e.next;
                     }
-                    modCount++;
+                    modCount = mc + 1;
                     count--;
                 } else {
                     e.value = newValue;
@@ -1080,7 +1119,9 @@
             }
         }
 
+        int mc = modCount;
         V newValue = remappingFunction.apply(key, null);
+        if (mc != modCount) { throw new ConcurrentModificationException(); }
         if (newValue != null) {
             addEntry(hash, key, newValue, index);
         }
@@ -1088,6 +1129,16 @@
         return newValue;
     }
 
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This method will, on a best-effort basis, throw a
+     * {@link java.util.ConcurrentModificationException} if the remapping
+     * function modified this map during computation.
+     *
+     * @throws ConcurrentModificationException if it is detected that the
+     * remapping function modified this map
+     */
     @Override
     public synchronized V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
         Objects.requireNonNull(remappingFunction);
@@ -1099,14 +1150,18 @@
         Entry<K,V> e = (Entry<K,V>)tab[index];
         for (Entry<K,V> prev = null; e != null; prev = e, e = e.next) {
             if (e.hash == hash && e.key.equals(key)) {
+                int mc = modCount;
                 V newValue = remappingFunction.apply(e.value, value);
+                if (mc != modCount) {
+                    throw new ConcurrentModificationException();
+                }
                 if (newValue == null) {
                     if (prev != null) {
                         prev.next = e.next;
                     } else {
                         tab[index] = e.next;
                     }
-                    modCount++;
+                    modCount = mc + 1;
                     count--;
                 } else {
                     e.value = newValue;