aboutsummaryrefslogtreecommitdiff
path: root/src/share/classes/java/util/concurrent
diff options
context:
space:
mode:
authorlana <none@none>2013-10-31 16:44:18 -0700
committerlana <none@none>2013-10-31 16:44:18 -0700
commitca2ffe49b592002569e0323386a9a08208f8fc2c (patch)
tree2e71b3581c6e4fc7d844271f3888ffec58b81ed5 /src/share/classes/java/util/concurrent
parentfd6a8874d5b2239fc31bd1469d8fc07f605d95c9 (diff)
parentb350ac29f85e987abd17c6bc9ce07274668df96c (diff)
downloadjdk8u_jdk-ca2ffe49b592002569e0323386a9a08208f8fc2c.tar.gz
Merge
Diffstat (limited to 'src/share/classes/java/util/concurrent')
-rw-r--r--src/share/classes/java/util/concurrent/BlockingDeque.java2
-rw-r--r--src/share/classes/java/util/concurrent/BlockingQueue.java1
-rw-r--r--src/share/classes/java/util/concurrent/ConcurrentMap.java335
-rw-r--r--src/share/classes/java/util/concurrent/Future.java4
-rw-r--r--src/share/classes/java/util/concurrent/atomic/DoubleAccumulator.java71
-rw-r--r--src/share/classes/java/util/concurrent/atomic/DoubleAdder.java58
-rw-r--r--src/share/classes/java/util/concurrent/atomic/LongAccumulator.java70
-rw-r--r--src/share/classes/java/util/concurrent/atomic/LongAdder.java58
-rw-r--r--src/share/classes/java/util/concurrent/locks/ReentrantReadWriteLock.java1
9 files changed, 545 insertions, 55 deletions
diff --git a/src/share/classes/java/util/concurrent/BlockingDeque.java b/src/share/classes/java/util/concurrent/BlockingDeque.java
index d98586a95b..0a26fa8dee 100644
--- a/src/share/classes/java/util/concurrent/BlockingDeque.java
+++ b/src/share/classes/java/util/concurrent/BlockingDeque.java
@@ -50,7 +50,6 @@ import java.util.*;
* and the fourth blocks for only a given maximum time limit before giving
* up. These methods are summarized in the following table:
*
- * <p>
* <table BORDER CELLPADDING=3 CELLSPACING=1>
* <caption>Summary of BlockingDeque methods</caption>
* <tr>
@@ -126,7 +125,6 @@ import java.util.*;
* {@code BlockingQueue} interface are precisely equivalent to
* {@code BlockingDeque} methods as indicated in the following table:
*
- * <p>
* <table BORDER CELLPADDING=3 CELLSPACING=1>
* <caption>Comparison of BlockingQueue and BlockingDeque methods</caption>
* <tr>
diff --git a/src/share/classes/java/util/concurrent/BlockingQueue.java b/src/share/classes/java/util/concurrent/BlockingQueue.java
index 8eb3ce2c98..3d097079f6 100644
--- a/src/share/classes/java/util/concurrent/BlockingQueue.java
+++ b/src/share/classes/java/util/concurrent/BlockingQueue.java
@@ -53,7 +53,6 @@ import java.util.Queue;
* and the fourth blocks for only a given maximum time limit before giving
* up. These methods are summarized in the following table:
*
- * <p>
* <table BORDER CELLPADDING=3 CELLSPACING=1>
* <caption>Summary of BlockingQueue methods</caption>
* <tr>
diff --git a/src/share/classes/java/util/concurrent/ConcurrentMap.java b/src/share/classes/java/util/concurrent/ConcurrentMap.java
index 6c902fa686..3cb1fe7ea8 100644
--- a/src/share/classes/java/util/concurrent/ConcurrentMap.java
+++ b/src/share/classes/java/util/concurrent/ConcurrentMap.java
@@ -36,7 +36,9 @@
package java.util.concurrent;
import java.util.Map;
import java.util.Objects;
+import java.util.function.BiConsumer;
import java.util.function.BiFunction;
+import java.util.function.Function;
/**
* A {@link java.util.Map} providing thread safety and atomicity
@@ -64,9 +66,13 @@ public interface ConcurrentMap<K, V> extends Map<K, V> {
* {@inheritDoc}
*
* @implNote This implementation assumes that the ConcurrentMap cannot
- * contain null values and get() returning null unambiguously means the key
- * is absent. Implementations which support null values must override this
- * default implementation.
+ * contain null values and {@code get()} returning null unambiguously means
+ * the key is absent. Implementations which support null values
+ * <strong>must</strong> override this default implementation.
+ *
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
+ * @since 1.8
*/
@Override
default V getOrDefault(Object key, V defaultValue) {
@@ -74,6 +80,41 @@ public interface ConcurrentMap<K, V> extends Map<K, V> {
return ((v = get(key)) != null) ? v : defaultValue;
}
+ /**
+ * {@inheritDoc}
+ *
+ * @implSpec The default implementation is equivalent to, for this
+ * {@code map}:
+ * <pre> {@code
+ * for ((Map.Entry<K, V> entry : map.entrySet())
+ * action.accept(entry.getKey(), entry.getValue());
+ * }</pre>
+ *
+ * @implNote The default implementation assumes that
+ * {@code IllegalStateException} thrown by {@code getKey()} or
+ * {@code getValue()} indicates that the entry has been removed and cannot
+ * be processed. Operation continues for subsequent entries.
+ *
+ * @throws NullPointerException {@inheritDoc}
+ * @since 1.8
+ */
+ @Override
+ default void forEach(BiConsumer<? super K, ? super V> action) {
+ Objects.requireNonNull(action);
+ for (Map.Entry<K, V> entry : entrySet()) {
+ K k;
+ V v;
+ try {
+ k = entry.getKey();
+ v = entry.getValue();
+ } catch(IllegalStateException ise) {
+ // this usually means the entry is no longer in the map.
+ continue;
+ }
+ action.accept(k, v);
+ }
+ }
+
/**
* If the specified key is not already associated
* with a value, associate it with the given value.
@@ -82,10 +123,14 @@ public interface ConcurrentMap<K, V> extends Map<K, V> {
* if (!map.containsKey(key))
* return map.put(key, value);
* else
- * return map.get(key);}</pre>
+ * return map.get(key);
+ * }</pre>
*
* except that the action is performed atomically.
*
+ * @implNote This implementation intentionally re-abstracts the
+ * inappropriate default provided in {@code Map}.
+ *
* @param key key with which the specified value is to be associated
* @param value value to be associated with the specified key
* @return the previous value associated with the specified key, or
@@ -102,7 +147,7 @@ public interface ConcurrentMap<K, V> extends Map<K, V> {
* @throws IllegalArgumentException if some property of the specified key
* or value prevents it from being stored in this map
*/
- V putIfAbsent(K key, V value);
+ V putIfAbsent(K key, V value);
/**
* Removes the entry for a key only if currently mapped to a given value.
@@ -112,10 +157,14 @@ public interface ConcurrentMap<K, V> extends Map<K, V> {
* map.remove(key);
* return true;
* } else
- * return false;}</pre>
+ * return false;
+ * }</pre>
*
* except that the action is performed atomically.
*
+ * @implNote This implementation intentionally re-abstracts the
+ * inappropriate default provided in {@code Map}.
+ *
* @param key key with which the specified value is associated
* @param value value expected to be associated with the specified key
* @return {@code true} if the value was removed
@@ -138,10 +187,14 @@ public interface ConcurrentMap<K, V> extends Map<K, V> {
* map.put(key, newValue);
* return true;
* } else
- * return false;}</pre>
+ * return false;
+ * }</pre>
*
* except that the action is performed atomically.
*
+ * @implNote This implementation intentionally re-abstracts the
+ * inappropriate default provided in {@code Map}.
+ *
* @param key key with which the specified value is associated
* @param oldValue value expected to be associated with the specified key
* @param newValue value to be associated with the specified key
@@ -164,10 +217,14 @@ public interface ConcurrentMap<K, V> extends Map<K, V> {
* if (map.containsKey(key)) {
* return map.put(key, value);
* } else
- * return null;}</pre>
+ * return null;
+ * }</pre>
*
* except that the action is performed atomically.
*
+ * @implNote This implementation intentionally re-abstracts the
+ * inappropriate default provided in {@code Map}.
+ *
* @param key key with which the specified value is associated
* @param value value to be associated with the specified key
* @return the previous value associated with the specified key, or
@@ -189,10 +246,30 @@ public interface ConcurrentMap<K, V> extends Map<K, V> {
/**
* {@inheritDoc}
*
- * @implNote This implementation assumes that the ConcurrentMap cannot
- * contain null values and get() returning null unambiguously means the key
- * is absent. Implementations which support null values
- * <strong>must</strong> override this default implementation.
+ * @implSpec
+ * <p>The default implementation is equivalent to, for this {@code map}:
+ * <pre> {@code
+ * for ((Map.Entry<K, V> entry : map.entrySet())
+ * do {
+ * K k = entry.getKey();
+ * V v = entry.getValue();
+ * } while(!replace(k, v, function.apply(k, v)));
+ * }</pre>
+ *
+ * The default implementation may retry these steps when multiple
+ * threads attempt updates including potentially calling the function
+ * repeatedly for a given key.
+ *
+ * <p>This implementation assumes that the ConcurrentMap cannot contain null
+ * values and {@code get()} returning null unambiguously means the key is
+ * absent. Implementations which support null values <strong>must</strong>
+ * override this default implementation.
+ *
+ * @throws UnsupportedOperationException {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
+ * @throws ClassCastException {@inheritDoc}
+ * @throws IllegalArgumentException {@inheritDoc}
+ * @since 1.8
*/
@Override
default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
@@ -200,11 +277,243 @@ public interface ConcurrentMap<K, V> extends Map<K, V> {
forEach((k,v) -> {
while(!replace(k, v, function.apply(k, v))) {
// v changed or k is gone
- if( (v = get(k)) == null) {
+ if ( (v = get(k)) == null) {
// k is no longer in the map.
break;
}
}
});
}
+
+ /**
+ * {@inheritDoc}
+ *
+ * @implSpec
+ * The default implementation is equivalent to the following steps for this
+ * {@code map}, then returning the current value or {@code null} if now
+ * absent:
+ *
+ * <pre> {@code
+ * if (map.get(key) == null) {
+ * V newValue = mappingFunction.apply(key);
+ * if (newValue != null)
+ * return map.putIfAbsent(key, newValue);
+ * }
+ * }</pre>
+ *
+ * The default implementation may retry these steps when multiple
+ * threads attempt updates including potentially calling the mapping
+ * function multiple times.
+ *
+ * <p>This implementation assumes that the ConcurrentMap cannot contain null
+ * values and {@code get()} returning null unambiguously means the key is
+ * absent. Implementations which support null values <strong>must</strong>
+ * override this default implementation.
+ *
+ * @throws UnsupportedOperationException {@inheritDoc}
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
+ * @since 1.8
+ */
+ @Override
+ default V computeIfAbsent(K key,
+ Function<? super K, ? extends V> mappingFunction) {
+ Objects.requireNonNull(mappingFunction);
+ V v, newValue;
+ return ((v = get(key)) == null &&
+ (newValue = mappingFunction.apply(key)) != null &&
+ (v = putIfAbsent(key, newValue)) == null) ? newValue : v;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @implSpec
+ * The default implementation is equivalent to performing the following
+ * steps for this {@code map}, then returning the current value or
+ * {@code null} if now absent. :
+ *
+ * <pre> {@code
+ * if (map.get(key) != null) {
+ * V oldValue = map.get(key);
+ * V newValue = remappingFunction.apply(key, oldValue);
+ * if (newValue != null)
+ * map.replace(key, oldValue, newValue);
+ * else
+ * map.remove(key, oldValue);
+ * }
+ * }</pre>
+ *
+ * The default implementation may retry these steps when multiple threads
+ * attempt updates including potentially calling the remapping function
+ * multiple times.
+ *
+ * <p>This implementation assumes that the ConcurrentMap cannot contain null
+ * values and {@code get()} returning null unambiguously means the key is
+ * absent. Implementations which support null values <strong>must</strong>
+ * override this default implementation.
+ *
+ * @throws UnsupportedOperationException {@inheritDoc}
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
+ * @since 1.8
+ */
+ @Override
+ default V computeIfPresent(K key,
+ BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+ Objects.requireNonNull(remappingFunction);
+ V oldValue;
+ while((oldValue = get(key)) != null) {
+ V newValue = remappingFunction.apply(key, oldValue);
+ if (newValue != null) {
+ if (replace(key, oldValue, newValue))
+ return newValue;
+ } else if (remove(key, oldValue))
+ return null;
+ }
+ return oldValue;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @implSpec
+ * The default implementation is equivalent to performing the following
+ * steps for this {@code map}, then returning the current value or
+ * {@code null} if absent:
+ *
+ * <pre> {@code
+ * V oldValue = map.get(key);
+ * V newValue = remappingFunction.apply(key, oldValue);
+ * if (oldValue != null ) {
+ * if (newValue != null)
+ * map.replace(key, oldValue, newValue);
+ * else
+ * map.remove(key, oldValue);
+ * } else {
+ * if (newValue != null)
+ * map.putIfAbsent(key, newValue);
+ * else
+ * return null;
+ * }
+ * }</pre>
+ *
+ * The default implementation may retry these steps when multiple
+ * threads attempt updates including potentially calling the remapping
+ * function multiple times.
+ *
+ * <p>This implementation assumes that the ConcurrentMap cannot contain null
+ * values and {@code get()} returning null unambiguously means the key is
+ * absent. Implementations which support null values <strong>must</strong>
+ * override this default implementation.
+ *
+ * @throws UnsupportedOperationException {@inheritDoc}
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
+ * @since 1.8
+ */
+ @Override
+ default V compute(K key,
+ BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+ Objects.requireNonNull(remappingFunction);
+ V oldValue = get(key);
+ for(;;) {
+ V newValue = remappingFunction.apply(key, oldValue);
+ if (newValue == null) {
+ // delete mapping
+ if (oldValue != null || containsKey(key)) {
+ // something to remove
+ if (remove(key, oldValue)) {
+ // removed the old value as expected
+ return null;
+ }
+
+ // some other value replaced old value. try again.
+ oldValue = get(key);
+ } else {
+ // nothing to do. Leave things as they were.
+ return null;
+ }
+ } else {
+ // add or replace old mapping
+ if (oldValue != null) {
+ // replace
+ if (replace(key, oldValue, newValue)) {
+ // replaced as expected.
+ return newValue;
+ }
+
+ // some other value replaced old value. try again.
+ oldValue = get(key);
+ } else {
+ // add (replace if oldValue was null)
+ if ((oldValue = putIfAbsent(key, newValue)) == null) {
+ // replaced
+ return newValue;
+ }
+
+ // some other value replaced old value. try again.
+ }
+ }
+ }
+ }
+
+
+ /**
+ * {@inheritDoc}
+ *
+ * @implSpec
+ * The default implementation is equivalent to performing the
+ * following steps for this {@code map}, then returning the
+ * current value or {@code null} if absent:
+ *
+ * <pre> {@code
+ * V oldValue = map.get(key);
+ * V newValue = (oldValue == null) ? value :
+ * remappingFunction.apply(oldValue, value);
+ * if (newValue == null)
+ * map.remove(key);
+ * else if (oldValue == null)
+ * map.remove(key);
+ * else
+ * map.put(key, newValue);
+ * }</pre>
+ *
+ * <p>The default implementation may retry these steps when multiple
+ * threads attempt updates including potentially calling the remapping
+ * function multiple times.
+ *
+ * <p>This implementation assumes that the ConcurrentMap cannot contain null
+ * values and {@code get()} returning null unambiguously means the key is
+ * absent. Implementations which support null values <strong>must</strong>
+ * override this default implementation.
+ *
+ * @throws UnsupportedOperationException {@inheritDoc}
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
+ * @since 1.8
+ */
+ @Override
+ default V merge(K key, V value,
+ BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+ Objects.requireNonNull(remappingFunction);
+ Objects.requireNonNull(value);
+ V oldValue = get(key);
+ for (;;) {
+ if (oldValue != null) {
+ V newValue = remappingFunction.apply(oldValue, value);
+ if (newValue != null) {
+ if (replace(key, oldValue, newValue))
+ return newValue;
+ } else if (remove(key, oldValue)) {
+ return null;
+ }
+ oldValue = get(key);
+ } else {
+ if ((oldValue = putIfAbsent(key, value)) == null) {
+ return value;
+ }
+ }
+ }
+ }
}
diff --git a/src/share/classes/java/util/concurrent/Future.java b/src/share/classes/java/util/concurrent/Future.java
index 5c5578e03a..1011972167 100644
--- a/src/share/classes/java/util/concurrent/Future.java
+++ b/src/share/classes/java/util/concurrent/Future.java
@@ -52,8 +52,8 @@ package java.util.concurrent;
*
* <p>
* <b>Sample Usage</b> (Note that the following classes are all
- * made-up.) <p>
- * <pre> {@code
+ * made-up.)
+ * <pre> {@code
* interface ArchiveSearcher { String search(String target); }
* class App {
* ExecutorService executor = ...
diff --git a/src/share/classes/java/util/concurrent/atomic/DoubleAccumulator.java b/src/share/classes/java/util/concurrent/atomic/DoubleAccumulator.java
index 841f6477d4..929818d9cd 100644
--- a/src/share/classes/java/util/concurrent/atomic/DoubleAccumulator.java
+++ b/src/share/classes/java/util/concurrent/atomic/DoubleAccumulator.java
@@ -224,18 +224,71 @@ public class DoubleAccumulator extends Striped64 implements Serializable {
return (float)get();
}
- private void writeObject(java.io.ObjectOutputStream s)
- throws java.io.IOException {
- s.defaultWriteObject();
- s.writeDouble(get());
+ /**
+ * Serialization proxy, used to avoid reference to the non-public
+ * Striped64 superclass in serialized forms.
+ * @serial include
+ */
+ private static class SerializationProxy implements Serializable {
+ private static final long serialVersionUID = 7249069246863182397L;
+
+ /**
+ * The current value returned by get().
+ * @serial
+ */
+ private final double value;
+ /**
+ * The function used for updates.
+ * @serial
+ */
+ private final DoubleBinaryOperator function;
+ /**
+ * The identity value
+ * @serial
+ */
+ private final long identity;
+
+ SerializationProxy(DoubleAccumulator a) {
+ function = a.function;
+ identity = a.identity;
+ value = a.get();
+ }
+
+ /**
+ * Returns a {@code DoubleAccumulator} object with initial state
+ * held by this proxy.
+ *
+ * @return a {@code DoubleAccumulator} object with initial state
+ * held by this proxy.
+ */
+ private Object readResolve() {
+ double d = Double.longBitsToDouble(identity);
+ DoubleAccumulator a = new DoubleAccumulator(function, d);
+ a.base = Double.doubleToRawLongBits(value);
+ return a;
+ }
}
+ /**
+ * Returns a
+ * <a href="../../../../serialized-form.html#java.util.concurrent.atomic.DoubleAccumulator.SerializationProxy">
+ * SerializationProxy</a>
+ * representing the state of this instance.
+ *
+ * @return a {@link SerializationProxy}
+ * representing the state of this instance
+ */
+ private Object writeReplace() {
+ return new SerializationProxy(this);
+ }
+
+ /**
+ * @param s the stream
+ * @throws java.io.InvalidObjectException always
+ */
private void readObject(java.io.ObjectInputStream s)
- throws java.io.IOException, ClassNotFoundException {
- s.defaultReadObject();
- cellsBusy = 0;
- cells = null;
- base = Double.doubleToRawLongBits(s.readDouble());
+ throws java.io.InvalidObjectException {
+ throw new java.io.InvalidObjectException("Proxy required");
}
}
diff --git a/src/share/classes/java/util/concurrent/atomic/DoubleAdder.java b/src/share/classes/java/util/concurrent/atomic/DoubleAdder.java
index 2db7ca89c5..f548d219ec 100644
--- a/src/share/classes/java/util/concurrent/atomic/DoubleAdder.java
+++ b/src/share/classes/java/util/concurrent/atomic/DoubleAdder.java
@@ -210,18 +210,58 @@ public class DoubleAdder extends Striped64 implements Serializable {
return (float)sum();
}
- private void writeObject(java.io.ObjectOutputStream s)
- throws java.io.IOException {
- s.defaultWriteObject();
- s.writeDouble(sum());
+ /**
+ * Serialization proxy, used to avoid reference to the non-public
+ * Striped64 superclass in serialized forms.
+ * @serial include
+ */
+ private static class SerializationProxy implements Serializable {
+ private static final long serialVersionUID = 7249069246863182397L;
+
+ /**
+ * The current value returned by sum().
+ * @serial
+ */
+ private final double value;
+
+ SerializationProxy(DoubleAdder a) {
+ value = a.sum();
+ }
+
+ /**
+ * Returns a {@code DoubleAdder} object with initial state
+ * held by this proxy.
+ *
+ * @return a {@code DoubleAdder} object with initial state
+ * held by this proxy.
+ */
+ private Object readResolve() {
+ DoubleAdder a = new DoubleAdder();
+ a.base = Double.doubleToRawLongBits(value);
+ return a;
+ }
}
+ /**
+ * Returns a
+ * <a href="../../../../serialized-form.html#java.util.concurrent.atomic.DoubleAdder.SerializationProxy">
+ * SerializationProxy</a>
+ * representing the state of this instance.
+ *
+ * @return a {@link SerializationProxy}
+ * representing the state of this instance
+ */
+ private Object writeReplace() {
+ return new SerializationProxy(this);
+ }
+
+ /**
+ * @param s the stream
+ * @throws java.io.InvalidObjectException always
+ */
private void readObject(java.io.ObjectInputStream s)
- throws java.io.IOException, ClassNotFoundException {
- s.defaultReadObject();
- cellsBusy = 0;
- cells = null;
- base = Double.doubleToRawLongBits(s.readDouble());
+ throws java.io.InvalidObjectException {
+ throw new java.io.InvalidObjectException("Proxy required");
}
}
diff --git a/src/share/classes/java/util/concurrent/atomic/LongAccumulator.java b/src/share/classes/java/util/concurrent/atomic/LongAccumulator.java
index 1289e6b52c..435aa1b90e 100644
--- a/src/share/classes/java/util/concurrent/atomic/LongAccumulator.java
+++ b/src/share/classes/java/util/concurrent/atomic/LongAccumulator.java
@@ -221,18 +221,70 @@ public class LongAccumulator extends Striped64 implements Serializable {
return (double)get();
}
- private void writeObject(java.io.ObjectOutputStream s)
- throws java.io.IOException {
- s.defaultWriteObject();
- s.writeLong(get());
+ /**
+ * Serialization proxy, used to avoid reference to the non-public
+ * Striped64 superclass in serialized forms.
+ * @serial include
+ */
+ private static class SerializationProxy implements Serializable {
+ private static final long serialVersionUID = 7249069246863182397L;
+
+ /**
+ * The current value returned by get().
+ * @serial
+ */
+ private final long value;
+ /**
+ * The function used for updates.
+ * @serial
+ */
+ private final LongBinaryOperator function;
+ /**
+ * The identity value
+ * @serial
+ */
+ private final long identity;
+
+ SerializationProxy(LongAccumulator a) {
+ function = a.function;
+ identity = a.identity;
+ value = a.get();
+ }
+
+ /**
+ * Returns a {@code LongAccumulator} object with initial state
+ * held by this proxy.
+ *
+ * @return a {@code LongAccumulator} object with initial state
+ * held by this proxy.
+ */
+ private Object readResolve() {
+ LongAccumulator a = new LongAccumulator(function, identity);
+ a.base = value;
+ return a;
+ }
}
+ /**
+ * Returns a
+ * <a href="../../../../serialized-form.html#java.util.concurrent.atomic.LongAccumulator.SerializationProxy">
+ * SerializationProxy</a>
+ * representing the state of this instance.
+ *
+ * @return a {@link SerializationProxy}
+ * representing the state of this instance
+ */
+ private Object writeReplace() {
+ return new SerializationProxy(this);
+ }
+
+ /**
+ * @param s the stream
+ * @throws java.io.InvalidObjectException always
+ */
private void readObject(java.io.ObjectInputStream s)
- throws java.io.IOException, ClassNotFoundException {
- s.defaultReadObject();
- cellsBusy = 0;
- cells = null;
- base = s.readLong();
+ throws java.io.InvalidObjectException {
+ throw new java.io.InvalidObjectException("Proxy required");
}
}
diff --git a/src/share/classes/java/util/concurrent/atomic/LongAdder.java b/src/share/classes/java/util/concurrent/atomic/LongAdder.java
index 70c5bed4cc..e7415dea82 100644
--- a/src/share/classes/java/util/concurrent/atomic/LongAdder.java
+++ b/src/share/classes/java/util/concurrent/atomic/LongAdder.java
@@ -211,18 +211,58 @@ public class LongAdder extends Striped64 implements Serializable {
return (double)sum();
}
- private void writeObject(java.io.ObjectOutputStream s)
- throws java.io.IOException {
- s.defaultWriteObject();
- s.writeLong(sum());
+ /**
+ * Serialization proxy, used to avoid reference to the non-public
+ * Striped64 superclass in serialized forms.
+ * @serial include
+ */
+ private static class SerializationProxy implements Serializable {
+ private static final long serialVersionUID = 7249069246863182397L;
+
+ /**
+ * The current value returned by sum().
+ * @serial
+ */
+ private final long value;
+
+ SerializationProxy(LongAdder a) {
+ value = a.sum();
+ }
+
+ /**
+ * Return a {@code LongAdder} object with initial state
+ * held by this proxy.
+ *
+ * @return a {@code LongAdder} object with initial state
+ * held by this proxy.
+ */
+ private Object readResolve() {
+ LongAdder a = new LongAdder();
+ a.base = value;
+ return a;
+ }
}
+ /**
+ * Returns a
+ * <a href="../../../../serialized-form.html#java.util.concurrent.atomic.LongAdder.SerializationProxy">
+ * SerializationProxy</a>
+ * representing the state of this instance.
+ *
+ * @return a {@link SerializationProxy}
+ * representing the state of this instance
+ */
+ private Object writeReplace() {
+ return new SerializationProxy(this);
+ }
+
+ /**
+ * @param s the stream
+ * @throws java.io.InvalidObjectException always
+ */
private void readObject(java.io.ObjectInputStream s)
- throws java.io.IOException, ClassNotFoundException {
- s.defaultReadObject();
- cellsBusy = 0;
- cells = null;
- base = s.readLong();
+ throws java.io.InvalidObjectException {
+ throw new java.io.InvalidObjectException("Proxy required");
}
}
diff --git a/src/share/classes/java/util/concurrent/locks/ReentrantReadWriteLock.java b/src/share/classes/java/util/concurrent/locks/ReentrantReadWriteLock.java
index 519477e524..dc811c2146 100644
--- a/src/share/classes/java/util/concurrent/locks/ReentrantReadWriteLock.java
+++ b/src/share/classes/java/util/concurrent/locks/ReentrantReadWriteLock.java
@@ -56,7 +56,6 @@ import java.util.Collection;
* constraints. A nonfair lock that is continuously contended may
* indefinitely postpone one or more reader or writer threads, but
* will normally have higher throughput than a fair lock.
- * <p>
*
* <dt><b><i>Fair mode</i></b>
* <dd>When constructed as fair, threads contend for entry using an