8020860: cluster Hashtable/Vector field updates for better transactional memory behaviour

Co-authored-by: Sandhya Viswanathan <sandhya.viswanathan@intel.com>
Reviewed-by: mduigou, martin, psandoz
This commit is contained in:
Mike Duigou 2014-05-05 09:52:24 -07:00
parent a3798db37e
commit f31e156be3
2 changed files with 72 additions and 49 deletions

View File

@ -26,7 +26,6 @@
package java.util;
import java.io.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.BiFunction;
@ -92,8 +91,10 @@ import java.util.function.BiFunction;
* ConcurrentModificationException}. Thus, in the face of concurrent
* modification, the iterator fails quickly and cleanly, rather than risking
* arbitrary, non-deterministic behavior at an undetermined time in the future.
* The Enumerations returned by Hashtable's keys and elements methods are
* <em>not</em> fail-fast.
* The Enumerations returned by Hashtable's {@link #keys keys} and
* {@link #elements elements} methods are <em>not</em> fail-fast; if the
* Hashtable is structurally modified at any time after the enumeration is
* created then the results of enumerating are undefined.
*
* <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
* as it is, generally speaking, impossible to make any hard guarantees in the
@ -115,6 +116,9 @@ import java.util.function.BiFunction;
* to use {@link java.util.concurrent.ConcurrentHashMap} in place of
* {@code Hashtable}.
*
* @param <K> the type of keys maintained by this map
* @param <V> the type of mapped values
*
* @author Arthur van Hoff
* @author Josh Bloch
* @author Neal Gafter
@ -246,6 +250,9 @@ public class Hashtable<K,V>
/**
* Returns an enumeration of the keys in this hashtable.
* Use the Enumeration methods on the returned object to fetch the keys
* sequentially. If the hashtable is structurally modified while enumerating
* over the keys then the results of enumerating are undefined.
*
* @return an enumeration of the keys in this hashtable.
* @see Enumeration
@ -260,7 +267,8 @@ public class Hashtable<K,V>
/**
* Returns an enumeration of the values in this hashtable.
* Use the Enumeration methods on the returned object to fetch the elements
* sequentially.
* sequentially. If the hashtable is structurally modified while enumerating
* over the values then the results of enumerating are undefined.
*
* @return an enumeration of the values in this hashtable.
* @see java.util.Enumeration
@ -417,8 +425,6 @@ public class Hashtable<K,V>
}
private void addEntry(int hash, K key, V value, int index) {
modCount++;
Entry<?,?> tab[] = table;
if (count >= threshold) {
// Rehash the table if the threshold is exceeded
@ -434,6 +440,7 @@ public class Hashtable<K,V>
Entry<K,V> e = (Entry<K,V>) tab[index];
tab[index] = new Entry<>(hash, key, value, e);
count++;
modCount++;
}
/**
@ -494,12 +501,12 @@ public class Hashtable<K,V>
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)) {
modCount++;
if (prev != null) {
prev.next = e.next;
} else {
tab[index] = e.next;
}
modCount++;
count--;
V oldValue = e.value;
e.value = null;
@ -528,9 +535,9 @@ public class Hashtable<K,V>
*/
public synchronized void clear() {
Entry<?,?> tab[] = table;
modCount++;
for (int index = tab.length; --index >= 0; )
tab[index] = null;
modCount++;
count = 0;
}
@ -719,14 +726,14 @@ public class Hashtable<K,V>
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.equals(entry)) {
modCount++;
if (prev != null)
prev.next = e.next;
else
tab[index] = e.next;
e.value = null; // clear for gc.
modCount++;
count--;
e.value = null;
return true;
}
}
@ -939,14 +946,14 @@ public class Hashtable<K,V>
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) && e.value.equals(value)) {
modCount++;
if (prev != null) {
prev.next = e.next;
} else {
tab[index] = e.next;
}
e.value = null; // clear for gc
modCount++;
count--;
e.value = null;
return true;
}
}
@ -1030,12 +1037,12 @@ public class Hashtable<K,V>
if (e.hash == hash && e.key.equals(key)) {
V newValue = remappingFunction.apply(key, e.value);
if (newValue == null) {
modCount++;
if (prev != null) {
prev.next = e.next;
} else {
tab[index] = e.next;
}
modCount++;
count--;
} else {
e.value = newValue;
@ -1059,12 +1066,12 @@ public class Hashtable<K,V>
if (e.hash == hash && Objects.equals(e.key, key)) {
V newValue = remappingFunction.apply(key, e.value);
if (newValue == null) {
modCount++;
if (prev != null) {
prev.next = e.next;
} else {
tab[index] = e.next;
}
modCount++;
count--;
} else {
e.value = newValue;
@ -1094,12 +1101,12 @@ public class Hashtable<K,V>
if (e.hash == hash && e.key.equals(key)) {
V newValue = remappingFunction.apply(e.value, value);
if (newValue == null) {
modCount++;
if (prev != null) {
prev.next = e.next;
} else {
tab[index] = e.next;
}
modCount++;
count--;
} else {
e.value = newValue;
@ -1298,24 +1305,24 @@ public class Hashtable<K,V>
* by passing an Enumeration.
*/
private class Enumerator<T> implements Enumeration<T>, Iterator<T> {
Entry<?,?>[] table = Hashtable.this.table;
final Entry<?,?>[] table = Hashtable.this.table;
int index = table.length;
Entry<?,?> entry;
Entry<?,?> lastReturned;
int type;
final int type;
/**
* Indicates whether this Enumerator is serving as an Iterator
* or an Enumeration. (true -> Iterator).
*/
boolean iterator;
final boolean iterator;
/**
* The modCount value that the iterator believes that the backing
* Hashtable should have. If this expectation is violated, the iterator
* has detected concurrent modification.
*/
protected int expectedModCount = modCount;
protected int expectedModCount = Hashtable.this.modCount;
Enumerator(int type, boolean iterator) {
this.type = type;
@ -1360,7 +1367,7 @@ public class Hashtable<K,V>
}
public T next() {
if (modCount != expectedModCount)
if (Hashtable.this.modCount != expectedModCount)
throw new ConcurrentModificationException();
return nextElement();
}
@ -1381,14 +1388,14 @@ public class Hashtable<K,V>
Entry<K,V> e = (Entry<K,V>)tab[index];
for(Entry<K,V> prev = null; e != null; prev = e, e = e.next) {
if (e == lastReturned) {
modCount++;
expectedModCount++;
if (prev == null)
tab[index] = e.next;
else
prev.next = e.next;
count--;
expectedModCount++;
lastReturned = null;
Hashtable.this.modCount++;
Hashtable.this.count--;
return;
}
}

View File

@ -56,7 +56,9 @@ import java.util.function.UnaryOperator;
* concurrent modification, the iterator fails quickly and cleanly, rather
* than risking arbitrary, non-deterministic behavior at an undetermined
* time in the future. The {@link Enumeration Enumerations} returned by
* the {@link #elements() elements} method are <em>not</em> fail-fast.
* the {@link #elements() elements} method are <em>not</em> fail-fast; if the
* Vector is structurally modified at any time after the enumeration is
* created then the results of enumerating are undefined.
*
* <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
* as it is, generally speaking, impossible to make any hard guarantees in the
@ -74,6 +76,8 @@ import java.util.function.UnaryOperator;
* implementation is not needed, it is recommended to use {@link
* ArrayList} in place of {@code Vector}.
*
* @param <E> Type of component elements
*
* @author Lee Boynton
* @author Jonathan Payne
* @see Collection
@ -330,7 +334,9 @@ public class Vector<E>
* Returns an enumeration of the components of this vector. The
* returned {@code Enumeration} object will generate all items in
* this vector. The first item generated is the item at index {@code 0},
* then the item at index {@code 1}, and so on.
* then the item at index {@code 1}, and so on. If the vector is
* structurally modified while enumerating over the elements then the
* results of enumerating are undefined.
*
* @return an enumeration of the components of this vector
* @see Iterator
@ -553,7 +559,6 @@ public class Vector<E>
* ({@code index < 0 || index >= size()})
*/
public synchronized void removeElementAt(int index) {
modCount++;
if (index >= elementCount) {
throw new ArrayIndexOutOfBoundsException(index + " >= " +
elementCount);
@ -565,6 +570,7 @@ public class Vector<E>
if (j > 0) {
System.arraycopy(elementData, index + 1, elementData, index, j);
}
modCount++;
elementCount--;
elementData[elementCount] = null; /* to let gc do its work */
}
@ -593,7 +599,6 @@ public class Vector<E>
* ({@code index < 0 || index > size()})
*/
public synchronized void insertElementAt(E obj, int index) {
modCount++;
if (index > elementCount) {
throw new ArrayIndexOutOfBoundsException(index
+ " > " + elementCount);
@ -601,6 +606,7 @@ public class Vector<E>
ensureCapacityHelper(elementCount + 1);
System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
elementData[index] = obj;
modCount++;
elementCount++;
}
@ -616,8 +622,8 @@ public class Vector<E>
* @param obj the component to be added
*/
public synchronized void addElement(E obj) {
modCount++;
ensureCapacityHelper(elementCount + 1);
modCount++;
elementData[elementCount++] = obj;
}
@ -653,11 +659,11 @@ public class Vector<E>
* method (which is part of the {@link List} interface).
*/
public synchronized void removeAllElements() {
modCount++;
// Let gc do its work
for (int i = 0; i < elementCount; i++)
elementData[i] = null;
modCount++;
elementCount = 0;
}
@ -705,12 +711,15 @@ public class Vector<E>
* of the Vector <em>only</em> if the caller knows that the Vector
* does not contain any null elements.)
*
* @param <T> type of array elements. The same type as {@code <E>} or a
* supertype of {@code <E>}.
* @param a the array into which the elements of the Vector are to
* be stored, if it is big enough; otherwise, a new array of the
* same runtime type is allocated for this purpose.
* @return an array containing the elements of the Vector
* @throws ArrayStoreException if the runtime type of a is not a supertype
* of the runtime type of every element in this Vector
* @throws ArrayStoreException if the runtime type of a, {@code <T>}, is not
* a supertype of the runtime type, {@code <E>}, of every element in this
* Vector
* @throws NullPointerException if the given array is null
* @since 1.2
*/
@ -778,8 +787,8 @@ public class Vector<E>
* @since 1.2
*/
public synchronized boolean add(E e) {
modCount++;
ensureCapacityHelper(elementCount + 1);
modCount++;
elementData[elementCount++] = e;
return true;
}
@ -879,14 +888,18 @@ public class Vector<E>
* @throws NullPointerException if the specified collection is null
* @since 1.2
*/
public synchronized boolean addAll(Collection<? extends E> c) {
modCount++;
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityHelper(elementCount + numNew);
System.arraycopy(a, 0, elementData, elementCount, numNew);
elementCount += numNew;
return numNew != 0;
if (numNew > 0) {
synchronized (this) {
ensureCapacityHelper(elementCount + numNew);
System.arraycopy(a, 0, elementData, elementCount, numNew);
modCount++;
elementCount += numNew;
}
}
return numNew > 0;
}
/**
@ -951,22 +964,25 @@ public class Vector<E>
* @since 1.2
*/
public synchronized boolean addAll(int index, Collection<? extends E> c) {
modCount++;
if (index < 0 || index > elementCount)
throw new ArrayIndexOutOfBoundsException(index);
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityHelper(elementCount + numNew);
int numMoved = elementCount - index;
if (numMoved > 0)
System.arraycopy(elementData, index, elementData, index + numNew,
numMoved);
if (numNew > 0) {
ensureCapacityHelper(elementCount + numNew);
System.arraycopy(a, 0, elementData, index, numNew);
elementCount += numNew;
return numNew != 0;
int numMoved = elementCount - index;
if (numMoved > 0)
System.arraycopy(elementData, index, elementData,
index + numNew, numMoved);
System.arraycopy(a, 0, elementData, index, numNew);
elementCount += numNew;
modCount++;
}
return numNew > 0;
}
/**
@ -1047,12 +1063,12 @@ public class Vector<E>
* (If {@code toIndex==fromIndex}, this operation has no effect.)
*/
protected synchronized void removeRange(int fromIndex, int toIndex) {
modCount++;
int numMoved = elementCount - toIndex;
System.arraycopy(elementData, toIndex, elementData, fromIndex,
numMoved);
// Let gc do its work
modCount++;
int newElementCount = elementCount - (toIndex-fromIndex);
while (elementCount != newElementCount)
elementData[--elementCount] = null;
@ -1420,7 +1436,7 @@ public class Vector<E>
}
public long estimateSize() {
return (long) (getFence() - index);
return getFence() - index;
}
public int characteristics() {