8134853: Bulk integration of java.util.concurrent classes
8080939: ForkJoinPool and Phaser deadlock
8044616: Clients of Unsafe.compareAndSwapLong need to beware of using direct stores to the same field
8071638: [JAVADOC] Buggy example in javadoc for afterExecute to access a submitted job's Throwable
8043743: Data missed in java.util.concurrent.LinkedTransferQueue
8054446: Repeated offer and remove on ConcurrentLinkedQueue lead to an OutOfMemoryError
8031374: TEST_BUG: java/util/concurrent/ConcurrentQueues/OfferRemoveLoops.java fails Intermittently
8034208: Cleanup to test/java/util/concurrent/BlockingQueue/Interrupt.java
8035661: Test fix java/util/concurrent/ConcurrentQueues/OfferRemoveLoops.java from jsr166 CVS
8062841: ConcurrentHashMap.computeIfAbsent stuck in an endless loop
8073208: javadoc typo in java.util.concurrent.Executor
8073704: FutureTask.isDone returns true when task has not yet completed
8037093: java/util/concurrent/locks/Lock/TimedAcquireLeak.java fails intermittently
8022642: ScheduledThreadPoolExecutor with zero corePoolSize create endlessly threads
8065320: Busy loop in ThreadPoolExecutor.getTask for ScheduledThreadPoolExecutor
8129861: High processor load for ScheduledThreadPoolExecutor with 0 core threads
8051859: ScheduledExecutorService.scheduleWithFixedDelay fails with max delay
7146994: example afterExecute for ScheduledThreadPoolExecutor hangs
Reviewed-by: martin, psandoz, chegar
--- a/jdk/src/java.base/share/classes/java/util/AbstractQueue.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/AbstractQueue.java Tue Oct 13 16:45:35 2015 -0700
@@ -38,16 +38,16 @@
/**
* This class provides skeletal implementations of some {@link Queue}
* operations. The implementations in this class are appropriate when
- * the base implementation does <em>not</em> allow <tt>null</tt>
+ * the base implementation does <em>not</em> allow {@code null}
* elements. Methods {@link #add add}, {@link #remove remove}, and
* {@link #element element} are based on {@link #offer offer}, {@link
* #poll poll}, and {@link #peek peek}, respectively, but throw
- * exceptions instead of indicating failure via <tt>false</tt> or
- * <tt>null</tt> returns.
+ * exceptions instead of indicating failure via {@code false} or
+ * {@code null} returns.
*
- * <p>A <tt>Queue</tt> implementation that extends this class must
+ * <p>A {@code Queue} implementation that extends this class must
* minimally define a method {@link Queue#offer} which does not permit
- * insertion of <tt>null</tt> elements, along with methods {@link
+ * insertion of {@code null} elements, along with methods {@link
* Queue#peek}, {@link Queue#poll}, {@link Collection#size}, and
* {@link Collection#iterator}. Typically, additional methods will be
* overridden as well. If these requirements cannot be met, consider
@@ -59,7 +59,7 @@
*
* @since 1.5
* @author Doug Lea
- * @param <E> the type of elements held in this collection
+ * @param <E> the type of elements held in this queue
*/
public abstract class AbstractQueue<E>
extends AbstractCollection<E>
@@ -74,14 +74,14 @@
/**
* Inserts the specified element into this queue if it is possible to do so
* immediately without violating capacity restrictions, returning
- * <tt>true</tt> upon success and throwing an <tt>IllegalStateException</tt>
+ * {@code true} upon success and throwing an {@code IllegalStateException}
* if no space is currently available.
*
- * <p>This implementation returns <tt>true</tt> if <tt>offer</tt> succeeds,
- * else throws an <tt>IllegalStateException</tt>.
+ * <p>This implementation returns {@code true} if {@code offer} succeeds,
+ * else throws an {@code IllegalStateException}.
*
* @param e the element to add
- * @return <tt>true</tt> (as specified by {@link Collection#add})
+ * @return {@code true} (as specified by {@link Collection#add})
* @throws IllegalStateException if the element cannot be added at this
* time due to capacity restrictions
* @throws ClassCastException if the class of the specified element
@@ -103,7 +103,7 @@
* from {@link #poll poll} only in that it throws an exception if this
* queue is empty.
*
- * <p>This implementation returns the result of <tt>poll</tt>
+ * <p>This implementation returns the result of {@code poll}
* unless the queue is empty.
*
* @return the head of this queue
@@ -122,7 +122,7 @@
* differs from {@link #peek peek} only in that it throws an exception if
* this queue is empty.
*
- * <p>This implementation returns the result of <tt>peek</tt>
+ * <p>This implementation returns the result of {@code peek}
* unless the queue is empty.
*
* @return the head of this queue
@@ -141,7 +141,7 @@
* The queue will be empty after this call returns.
*
* <p>This implementation repeatedly invokes {@link #poll poll} until it
- * returns <tt>null</tt>.
+ * returns {@code null}.
*/
public void clear() {
while (poll() != null)
@@ -151,7 +151,7 @@
/**
* Adds all of the elements in the specified collection to this
* queue. Attempts to addAll of a queue to itself result in
- * <tt>IllegalArgumentException</tt>. Further, the behavior of
+ * {@code IllegalArgumentException}. Further, the behavior of
* this operation is undefined if the specified collection is
* modified while the operation is in progress.
*
@@ -159,12 +159,12 @@
* and adds each element returned by the iterator to this
* queue, in turn. A runtime exception encountered while
* trying to add an element (including, in particular, a
- * <tt>null</tt> element) may result in only some of the elements
+ * {@code null} element) may result in only some of the elements
* having been successfully added when the associated exception is
* thrown.
*
* @param c collection containing elements to be added to this queue
- * @return <tt>true</tt> if this queue changed as a result of the call
+ * @return {@code true} if this queue changed as a result of the call
* @throws ClassCastException if the class of an element of the specified
* collection prevents it from being added to this queue
* @throws NullPointerException if the specified collection contains a
--- a/jdk/src/java.base/share/classes/java/util/ArrayDeque.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/ArrayDeque.java Tue Oct 13 16:45:35 2015 -0700
@@ -47,16 +47,18 @@
* when used as a queue.
*
* <p>Most {@code ArrayDeque} operations run in amortized constant time.
- * Exceptions include {@link #remove(Object) remove}, {@link
- * #removeFirstOccurrence removeFirstOccurrence}, {@link #removeLastOccurrence
- * removeLastOccurrence}, {@link #contains contains}, {@link #iterator
- * iterator.remove()}, and the bulk operations, all of which run in linear
- * time.
+ * Exceptions include
+ * {@link #remove(Object) remove},
+ * {@link #removeFirstOccurrence removeFirstOccurrence},
+ * {@link #removeLastOccurrence removeLastOccurrence},
+ * {@link #contains contains},
+ * {@link #iterator iterator.remove()},
+ * and the bulk operations, all of which run in linear time.
*
- * <p>The iterators returned by this class's {@code iterator} method are
- * <i>fail-fast</i>: If the deque is modified at any time after the iterator
- * is created, in any way except through the iterator's own {@code remove}
- * method, the iterator will generally throw a {@link
+ * <p>The iterators returned by this class's {@link #iterator() iterator}
+ * method are <em>fail-fast</em>: If the deque is modified at any time after
+ * the iterator is created, in any way except through the iterator's own
+ * {@code remove} method, the iterator will generally throw a {@link
* 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
@@ -80,7 +82,7 @@
*
* @author Josh Bloch and Doug Lea
* @since 1.6
- * @param <E> the type of elements held in this collection
+ * @param <E> the type of elements held in this deque
*/
public class ArrayDeque<E> extends AbstractCollection<E>
implements Deque<E>, Cloneable, Serializable
@@ -136,8 +138,8 @@
initialCapacity |= (initialCapacity >>> 16);
initialCapacity++;
- if (initialCapacity < 0) // Too many elements, must back off
- initialCapacity >>>= 1;// Good luck allocating 2 ^ 30 elements
+ if (initialCapacity < 0) // Too many elements, must back off
+ initialCapacity >>>= 1; // Good luck allocating 2^30 elements
}
elements = new Object[initialCapacity];
}
@@ -163,24 +165,6 @@
}
/**
- * Copies the elements from our element array into the specified array,
- * in order (from first to last element in the deque). It is assumed
- * that the array is large enough to hold all elements in the deque.
- *
- * @return its argument
- */
- private <T> T[] copyElements(T[] a) {
- if (head < tail) {
- System.arraycopy(elements, head, a, 0, size());
- } else if (head > tail) {
- int headPortionLen = elements.length - head;
- System.arraycopy(elements, head, a, 0, headPortionLen);
- System.arraycopy(elements, 0, a, headPortionLen, tail);
- }
- return a;
- }
-
- /**
* Constructs an empty array deque with an initial capacity
* sufficient to hold 16 elements.
*/
@@ -292,25 +276,27 @@
}
public E pollFirst() {
- int h = head;
+ final Object[] elements = this.elements;
+ final int h = head;
@SuppressWarnings("unchecked")
E result = (E) elements[h];
// Element is null if deque empty
- if (result == null)
- return null;
- elements[h] = null; // Must null out slot
- head = (h + 1) & (elements.length - 1);
+ if (result != null) {
+ elements[h] = null; // Must null out slot
+ head = (h + 1) & (elements.length - 1);
+ }
return result;
}
public E pollLast() {
- int t = (tail - 1) & (elements.length - 1);
+ final Object[] elements = this.elements;
+ final int t = (tail - 1) & (elements.length - 1);
@SuppressWarnings("unchecked")
E result = (E) elements[t];
- if (result == null)
- return null;
- elements[t] = null;
- tail = t;
+ if (result != null) {
+ elements[t] = null;
+ tail = t;
+ }
return result;
}
@@ -360,17 +346,15 @@
* @return {@code true} if the deque contained the specified element
*/
public boolean removeFirstOccurrence(Object o) {
- if (o == null)
- return false;
- int mask = elements.length - 1;
- int i = head;
- Object x;
- while ( (x = elements[i]) != null) {
- if (o.equals(x)) {
- delete(i);
- return true;
+ if (o != null) {
+ int mask = elements.length - 1;
+ int i = head;
+ for (Object x; (x = elements[i]) != null; i = (i + 1) & mask) {
+ if (o.equals(x)) {
+ delete(i);
+ return true;
+ }
}
- i = (i + 1) & mask;
}
return false;
}
@@ -388,17 +372,15 @@
* @return {@code true} if the deque contained the specified element
*/
public boolean removeLastOccurrence(Object o) {
- if (o == null)
- return false;
- int mask = elements.length - 1;
- int i = (tail - 1) & mask;
- Object x;
- while ( (x = elements[i]) != null) {
- if (o.equals(x)) {
- delete(i);
- return true;
+ if (o != null) {
+ int mask = elements.length - 1;
+ int i = (tail - 1) & mask;
+ for (Object x; (x = elements[i]) != null; i = (i - 1) & mask) {
+ if (o.equals(x)) {
+ delete(i);
+ return true;
+ }
}
- i = (i - 1) & mask;
}
return false;
}
@@ -535,7 +517,7 @@
*
* @return true if elements moved backwards
*/
- private boolean delete(int i) {
+ boolean delete(int i) {
checkInvariants();
final Object[] elements = this.elements;
final int mask = elements.length - 1;
@@ -671,12 +653,12 @@
}
}
+ /**
+ * This class is nearly a mirror-image of DeqIterator, using tail
+ * instead of head for initial cursor, and head instead of tail
+ * for fence.
+ */
private class DescendingIterator implements Iterator<E> {
- /*
- * This class is nearly a mirror-image of DeqIterator, using
- * tail instead of head for initial cursor, and head instead of
- * tail for fence.
- */
private int cursor = tail;
private int fence = head;
private int lastRet = -1;
@@ -717,15 +699,13 @@
* @return {@code true} if this deque contains the specified element
*/
public boolean contains(Object o) {
- if (o == null)
- return false;
- int mask = elements.length - 1;
- int i = head;
- Object x;
- while ( (x = elements[i]) != null) {
- if (o.equals(x))
- return true;
- i = (i + 1) & mask;
+ if (o != null) {
+ int mask = elements.length - 1;
+ int i = head;
+ for (Object x; (x = elements[i]) != null; i = (i + 1) & mask) {
+ if (o.equals(x))
+ return true;
+ }
}
return false;
}
@@ -779,7 +759,14 @@
* @return an array containing all of the elements in this deque
*/
public Object[] toArray() {
- return copyElements(new Object[size()]);
+ final int head = this.head;
+ final int tail = this.tail;
+ boolean wrap = (tail < head);
+ int end = wrap ? tail + elements.length : tail;
+ Object[] a = Arrays.copyOfRange(elements, head, end);
+ if (wrap)
+ System.arraycopy(elements, 0, a, elements.length - head, tail);
+ return a;
}
/**
@@ -804,7 +791,7 @@
* The following code can be used to dump the deque into a newly
* allocated array of {@code String}:
*
- * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+ * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
*
* Note that {@code toArray(new Object[0])} is identical in function to
* {@code toArray()}.
@@ -820,13 +807,22 @@
*/
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
- int size = size();
- if (a.length < size)
- a = (T[])java.lang.reflect.Array.newInstance(
- a.getClass().getComponentType(), size);
- copyElements(a);
- if (a.length > size)
- a[size] = null;
+ final int head = this.head;
+ final int tail = this.tail;
+ boolean wrap = (tail < head);
+ int size = (tail - head) + (wrap ? elements.length : 0);
+ int firstLeg = size - (wrap ? tail : 0);
+ int len = a.length;
+ if (size > len) {
+ a = (T[]) Arrays.copyOfRange(elements, head, head + size,
+ a.getClass());
+ } else {
+ System.arraycopy(elements, head, a, 0, firstLeg);
+ if (size < len)
+ a[size] = null;
+ }
+ if (wrap)
+ System.arraycopy(elements, 0, a, firstLeg, tail);
return a;
}
@@ -853,6 +849,8 @@
/**
* Saves this deque to a stream (that is, serializes it).
*
+ * @param s the stream
+ * @throws java.io.IOException if an I/O error occurs
* @serialData The current size ({@code int}) of the deque,
* followed by all of its elements (each an object reference) in
* first-to-last order.
@@ -872,6 +870,10 @@
/**
* Reconstitutes this deque from a stream (that is, deserializes it).
+ * @param s the stream
+ * @throws ClassNotFoundException if the class of a serialized object
+ * could not be found
+ * @throws java.io.IOException if an I/O error occurs
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
@@ -910,7 +912,7 @@
private int fence; // -1 until first use
private int index; // current index, modified on traverse/split
- /** Creates new spliterator covering the given array and range */
+ /** Creates new spliterator covering the given array and range. */
DeqSpliterator(ArrayDeque<E> deq, int origin, int fence) {
this.deq = deq;
this.index = origin;
@@ -932,7 +934,7 @@
if (h > t)
t += n;
int m = ((h + t) >>> 1) & (n - 1);
- return new DeqSpliterator<>(deq, h, index = m);
+ return new DeqSpliterator<E>(deq, h, index = m);
}
return null;
}
@@ -957,7 +959,7 @@
throw new NullPointerException();
Object[] a = deq.elements;
int m = a.length - 1, f = getFence(), i = index;
- if (i != fence) {
+ if (i != f) {
@SuppressWarnings("unchecked") E e = (E)a[i];
index = (i + 1) & m;
if (e == null)
--- a/jdk/src/java.base/share/classes/java/util/ArrayPrefixHelpers.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/ArrayPrefixHelpers.java Tue Oct 13 16:45:35 2015 -0700
@@ -1,5 +1,4 @@
/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -22,20 +21,26 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
-package java.util;
/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
-import java.util.concurrent.ForkJoinPool;
+package java.util;
+
import java.util.concurrent.CountedCompleter;
+import java.util.concurrent.ForkJoinPool;
import java.util.function.BinaryOperator;
+import java.util.function.DoubleBinaryOperator;
import java.util.function.IntBinaryOperator;
import java.util.function.LongBinaryOperator;
-import java.util.function.DoubleBinaryOperator;
/**
* ForkJoin tasks to perform Arrays.parallelPrefix operations.
@@ -44,7 +49,7 @@
* @since 1.8
*/
class ArrayPrefixHelpers {
- private ArrayPrefixHelpers() {}; // non-instantiable
+ private ArrayPrefixHelpers() {} // non-instantiable
/*
* Parallel prefix (aka cumulate, scan) task classes
@@ -113,8 +118,8 @@
this.lo = this.origin = lo; this.hi = this.fence = hi;
int p;
this.threshold =
- (p = (hi - lo) / (ForkJoinPool.getCommonPoolParallelism() << 3))
- <= MIN_PARTITION ? MIN_PARTITION : p;
+ (p = (hi - lo) / (ForkJoinPool.getCommonPoolParallelism() << 3))
+ <= MIN_PARTITION ? MIN_PARTITION : p;
}
/** Subtask constructor */
@@ -141,9 +146,9 @@
if (lt == null) { // first pass
int mid = (l + h) >>> 1;
f = rt = t.right =
- new CumulateTask<T>(t, fn, a, org, fnc, th, mid, h);
- t = lt = t.left =
- new CumulateTask<T>(t, fn, a, org, fnc, th, l, mid);
+ new CumulateTask<T>(t, fn, a, org, fnc, th, mid, h);
+ t = lt = t.left =
+ new CumulateTask<T>(t, fn, a, org, fnc, th, l, mid);
}
else { // possibly refork
T pin = t.in;
@@ -183,7 +188,7 @@
for (int b;;) {
if (((b = t.getPendingCount()) & FINISHED) != 0)
break outer; // already done
- state = ((b & CUMULATE) != 0? FINISHED :
+ state = ((b & CUMULATE) != 0 ? FINISHED :
(l > org) ? SUMMED : (SUMMED|FINISHED));
if (t.compareAndSetPendingCount(b, b|state))
break;
@@ -265,8 +270,8 @@
this.lo = this.origin = lo; this.hi = this.fence = hi;
int p;
this.threshold =
- (p = (hi - lo) / (ForkJoinPool.getCommonPoolParallelism() << 3))
- <= MIN_PARTITION ? MIN_PARTITION : p;
+ (p = (hi - lo) / (ForkJoinPool.getCommonPoolParallelism() << 3))
+ <= MIN_PARTITION ? MIN_PARTITION : p;
}
/** Subtask constructor */
@@ -293,9 +298,9 @@
if (lt == null) { // first pass
int mid = (l + h) >>> 1;
f = rt = t.right =
- new LongCumulateTask(t, fn, a, org, fnc, th, mid, h);
- t = lt = t.left =
- new LongCumulateTask(t, fn, a, org, fnc, th, l, mid);
+ new LongCumulateTask(t, fn, a, org, fnc, th, mid, h);
+ t = lt = t.left =
+ new LongCumulateTask(t, fn, a, org, fnc, th, l, mid);
}
else { // possibly refork
long pin = t.in;
@@ -335,7 +340,7 @@
for (int b;;) {
if (((b = t.getPendingCount()) & FINISHED) != 0)
break outer; // already done
- state = ((b & CUMULATE) != 0? FINISHED :
+ state = ((b & CUMULATE) != 0 ? FINISHED :
(l > org) ? SUMMED : (SUMMED|FINISHED));
if (t.compareAndSetPendingCount(b, b|state))
break;
@@ -415,8 +420,8 @@
this.lo = this.origin = lo; this.hi = this.fence = hi;
int p;
this.threshold =
- (p = (hi - lo) / (ForkJoinPool.getCommonPoolParallelism() << 3))
- <= MIN_PARTITION ? MIN_PARTITION : p;
+ (p = (hi - lo) / (ForkJoinPool.getCommonPoolParallelism() << 3))
+ <= MIN_PARTITION ? MIN_PARTITION : p;
}
/** Subtask constructor */
@@ -443,9 +448,9 @@
if (lt == null) { // first pass
int mid = (l + h) >>> 1;
f = rt = t.right =
- new DoubleCumulateTask(t, fn, a, org, fnc, th, mid, h);
- t = lt = t.left =
- new DoubleCumulateTask(t, fn, a, org, fnc, th, l, mid);
+ new DoubleCumulateTask(t, fn, a, org, fnc, th, mid, h);
+ t = lt = t.left =
+ new DoubleCumulateTask(t, fn, a, org, fnc, th, l, mid);
}
else { // possibly refork
double pin = t.in;
@@ -485,7 +490,7 @@
for (int b;;) {
if (((b = t.getPendingCount()) & FINISHED) != 0)
break outer; // already done
- state = ((b & CUMULATE) != 0? FINISHED :
+ state = ((b & CUMULATE) != 0 ? FINISHED :
(l > org) ? SUMMED : (SUMMED|FINISHED));
if (t.compareAndSetPendingCount(b, b|state))
break;
@@ -565,8 +570,8 @@
this.lo = this.origin = lo; this.hi = this.fence = hi;
int p;
this.threshold =
- (p = (hi - lo) / (ForkJoinPool.getCommonPoolParallelism() << 3))
- <= MIN_PARTITION ? MIN_PARTITION : p;
+ (p = (hi - lo) / (ForkJoinPool.getCommonPoolParallelism() << 3))
+ <= MIN_PARTITION ? MIN_PARTITION : p;
}
/** Subtask constructor */
@@ -593,9 +598,9 @@
if (lt == null) { // first pass
int mid = (l + h) >>> 1;
f = rt = t.right =
- new IntCumulateTask(t, fn, a, org, fnc, th, mid, h);
- t = lt = t.left =
- new IntCumulateTask(t, fn, a, org, fnc, th, l, mid);
+ new IntCumulateTask(t, fn, a, org, fnc, th, mid, h);
+ t = lt = t.left =
+ new IntCumulateTask(t, fn, a, org, fnc, th, l, mid);
}
else { // possibly refork
int pin = t.in;
@@ -635,7 +640,7 @@
for (int b;;) {
if (((b = t.getPendingCount()) & FINISHED) != 0)
break outer; // already done
- state = ((b & CUMULATE) != 0? FINISHED :
+ state = ((b & CUMULATE) != 0 ? FINISHED :
(l > org) ? SUMMED : (SUMMED|FINISHED));
if (t.compareAndSetPendingCount(b, b|state))
break;
--- a/jdk/src/java.base/share/classes/java/util/Deque.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/Deque.java Tue Oct 13 16:45:35 2015 -0700
@@ -188,7 +188,7 @@
* @author Doug Lea
* @author Josh Bloch
* @since 1.6
- * @param <E> the type of elements held in this collection
+ * @param <E> the type of elements held in this deque
*/
public interface Deque<E> extends Queue<E> {
/**
@@ -344,8 +344,7 @@
* Removes the first occurrence of the specified element from this deque.
* If the deque does not contain the element, it is unchanged.
* More formally, removes the first element {@code e} such that
- * <tt>(o==null ? e==null : o.equals(e))</tt>
- * (if such an element exists).
+ * {@code Objects.equals(o, e)} (if such an element exists).
* Returns {@code true} if this deque contained the specified element
* (or equivalently, if this deque changed as a result of the call).
*
@@ -353,10 +352,10 @@
* @return {@code true} if an element was removed as a result of this call
* @throws ClassCastException if the class of the specified element
* is incompatible with this deque
- * (<a href="Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified element is null and this
* deque does not permit null elements
- * (<a href="Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
*/
boolean removeFirstOccurrence(Object o);
@@ -364,8 +363,7 @@
* Removes the last occurrence of the specified element from this deque.
* If the deque does not contain the element, it is unchanged.
* More formally, removes the last element {@code e} such that
- * <tt>(o==null ? e==null : o.equals(e))</tt>
- * (if such an element exists).
+ * {@code Objects.equals(o, e)} (if such an element exists).
* Returns {@code true} if this deque contained the specified element
* (or equivalently, if this deque changed as a result of the call).
*
@@ -373,10 +371,10 @@
* @return {@code true} if an element was removed as a result of this call
* @throws ClassCastException if the class of the specified element
* is incompatible with this deque
- * (<a href="Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified element is null and this
* deque does not permit null elements
- * (<a href="Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
*/
boolean removeLastOccurrence(Object o);
@@ -521,8 +519,7 @@
* Removes the first occurrence of the specified element from this deque.
* If the deque does not contain the element, it is unchanged.
* More formally, removes the first element {@code e} such that
- * <tt>(o==null ? e==null : o.equals(e))</tt>
- * (if such an element exists).
+ * {@code Objects.equals(o, e)} (if such an element exists).
* Returns {@code true} if this deque contained the specified element
* (or equivalently, if this deque changed as a result of the call).
*
@@ -532,27 +529,26 @@
* @return {@code true} if an element was removed as a result of this call
* @throws ClassCastException if the class of the specified element
* is incompatible with this deque
- * (<a href="Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified element is null and this
* deque does not permit null elements
- * (<a href="Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
*/
boolean remove(Object o);
/**
* Returns {@code true} if this deque contains the specified element.
* More formally, returns {@code true} if and only if this deque contains
- * at least one element {@code e} such that
- * <tt>(o==null ? e==null : o.equals(e))</tt>.
+ * at least one element {@code e} such that {@code Objects.equals(o, e)}.
*
* @param o element whose presence in this deque is to be tested
* @return {@code true} if this deque contains the specified element
- * @throws ClassCastException if the type of the specified element
+ * @throws ClassCastException if the class of the specified element
* is incompatible with this deque
- * (<a href="Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified element is null and this
* deque does not permit null elements
- * (<a href="Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
*/
boolean contains(Object o);
@@ -561,7 +557,7 @@
*
* @return the number of elements in this deque
*/
- public int size();
+ int size();
/**
* Returns an iterator over the elements in this deque in proper sequence.
--- a/jdk/src/java.base/share/classes/java/util/NavigableMap.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/NavigableMap.java Tue Oct 13 16:45:35 2015 -0700
@@ -38,30 +38,32 @@
/**
* A {@link SortedMap} extended with navigation methods returning the
* closest matches for given search targets. Methods
- * {@code lowerEntry}, {@code floorEntry}, {@code ceilingEntry},
- * and {@code higherEntry} return {@code Map.Entry} objects
+ * {@link #lowerEntry}, {@link #floorEntry}, {@link #ceilingEntry},
+ * and {@link #higherEntry} return {@code Map.Entry} objects
* associated with keys respectively less than, less than or equal,
* greater than or equal, and greater than a given key, returning
* {@code null} if there is no such key. Similarly, methods
- * {@code lowerKey}, {@code floorKey}, {@code ceilingKey}, and
- * {@code higherKey} return only the associated keys. All of these
+ * {@link #lowerKey}, {@link #floorKey}, {@link #ceilingKey}, and
+ * {@link #higherKey} return only the associated keys. All of these
* methods are designed for locating, not traversing entries.
*
* <p>A {@code NavigableMap} may be accessed and traversed in either
- * ascending or descending key order. The {@code descendingMap}
+ * ascending or descending key order. The {@link #descendingMap}
* method returns a view of the map with the senses of all relational
* and directional methods inverted. The performance of ascending
* operations and views is likely to be faster than that of descending
- * ones. Methods {@code subMap}, {@code headMap},
- * and {@code tailMap} differ from the like-named {@code
- * SortedMap} methods in accepting additional arguments describing
- * whether lower and upper bounds are inclusive versus exclusive.
- * Submaps of any {@code NavigableMap} must implement the {@code
- * NavigableMap} interface.
+ * ones. Methods
+ * {@link #subMap(Object, boolean, Object, boolean) subMap(K, boolean, K, boolean)},
+ * {@link #headMap(Object, boolean) headMap(K, boolean)}, and
+ * {@link #tailMap(Object, boolean) tailMap(K, boolean)}
+ * differ from the like-named {@code SortedMap} methods in accepting
+ * additional arguments describing whether lower and upper bounds are
+ * inclusive versus exclusive. Submaps of any {@code NavigableMap}
+ * must implement the {@code NavigableMap} interface.
*
- * <p>This interface additionally defines methods {@code firstEntry},
- * {@code pollFirstEntry}, {@code lastEntry}, and
- * {@code pollLastEntry} that return and/or remove the least and
+ * <p>This interface additionally defines methods {@link #firstEntry},
+ * {@link #pollFirstEntry}, {@link #lastEntry}, and
+ * {@link #pollLastEntry} that return and/or remove the least and
* greatest mappings, if any exist, else returning {@code null}.
*
* <p>Implementations of entry-returning methods are expected to
@@ -80,7 +82,7 @@
* implement {@code NavigableMap}, but extensions and implementations
* of this interface are encouraged to override these methods to return
* {@code NavigableMap}. Similarly,
- * {@link #keySet()} can be overriden to return {@code NavigableSet}.
+ * {@link #keySet()} can be overridden to return {@link NavigableSet}.
*
* <p>This interface is a member of the
* <a href="{@docRoot}/../technotes/guides/collections/index.html">
@@ -254,7 +256,7 @@
* operation), the results of the iteration are undefined.
*
* <p>The returned map has an ordering equivalent to
- * <tt>{@link Collections#reverseOrder(Comparator) Collections.reverseOrder}(comparator())</tt>.
+ * {@link Collections#reverseOrder(Comparator) Collections.reverseOrder}{@code (comparator())}.
* The expression {@code m.descendingMap().descendingMap()} returns a
* view of {@code m} essentially equivalent to {@code m}.
*
--- a/jdk/src/java.base/share/classes/java/util/NavigableSet.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/NavigableSet.java Tue Oct 13 16:45:35 2015 -0700
@@ -37,26 +37,30 @@
/**
* A {@link SortedSet} extended with navigation methods reporting
- * closest matches for given search targets. Methods {@code lower},
- * {@code floor}, {@code ceiling}, and {@code higher} return elements
+ * closest matches for given search targets. Methods {@link #lower},
+ * {@link #floor}, {@link #ceiling}, and {@link #higher} return elements
* respectively less than, less than or equal, greater than or equal,
* and greater than a given element, returning {@code null} if there
- * is no such element. A {@code NavigableSet} may be accessed and
- * traversed in either ascending or descending order. The {@code
- * descendingSet} method returns a view of the set with the senses of
- * all relational and directional methods inverted. The performance of
- * ascending operations and views is likely to be faster than that of
- * descending ones. This interface additionally defines methods
- * {@code pollFirst} and {@code pollLast} that return and remove the
- * lowest and highest element, if one exists, else returning {@code
- * null}. Methods {@code subSet}, {@code headSet},
- * and {@code tailSet} differ from the like-named {@code
- * SortedSet} methods in accepting additional arguments describing
- * whether lower and upper bounds are inclusive versus exclusive.
- * Subsets of any {@code NavigableSet} must implement the {@code
- * NavigableSet} interface.
+ * is no such element.
*
- * <p> The return values of navigation methods may be ambiguous in
+ * <p>A {@code NavigableSet} may be accessed and traversed in either
+ * ascending or descending order. The {@link #descendingSet} method
+ * returns a view of the set with the senses of all relational and
+ * directional methods inverted. The performance of ascending
+ * operations and views is likely to be faster than that of descending
+ * ones. This interface additionally defines methods {@link
+ * #pollFirst} and {@link #pollLast} that return and remove the lowest
+ * and highest element, if one exists, else returning {@code null}.
+ * Methods
+ * {@link #subSet(Object, boolean, Object, boolean) subSet(E, boolean, E, boolean)},
+ * {@link #headSet(Object, boolean) headSet(E, boolean)}, and
+ * {@link #tailSet(Object, boolean) tailSet(E, boolean)}
+ * differ from the like-named {@code SortedSet} methods in accepting
+ * additional arguments describing whether lower and upper bounds are
+ * inclusive versus exclusive. Subsets of any {@code NavigableSet}
+ * must implement the {@code NavigableSet} interface.
+ *
+ * <p>The return values of navigation methods may be ambiguous in
* implementations that permit {@code null} elements. However, even
* in this case the result can be disambiguated by checking
* {@code contains(null)}. To avoid such issues, implementations of
@@ -172,7 +176,7 @@
* the iteration are undefined.
*
* <p>The returned set has an ordering equivalent to
- * <tt>{@link Collections#reverseOrder(Comparator) Collections.reverseOrder}(comparator())</tt>.
+ * {@link Collections#reverseOrder(Comparator) Collections.reverseOrder}{@code (comparator())}.
* The expression {@code s.descendingSet().descendingSet()} returns a
* view of {@code s} essentially equivalent to {@code s}.
*
--- a/jdk/src/java.base/share/classes/java/util/PriorityQueue.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/PriorityQueue.java Tue Oct 13 16:45:35 2015 -0700
@@ -77,7 +77,7 @@
*
* @since 1.5
* @author Josh Bloch, Doug Lea
- * @param <E> the type of elements held in this collection
+ * @param <E> the type of elements held in this queue
*/
public class PriorityQueue<E> extends AbstractQueue<E>
implements java.io.Serializable {
@@ -99,7 +99,7 @@
/**
* The number of elements in the priority queue.
*/
- private int size = 0;
+ int size;
/**
* The comparator, or null if priority queue uses elements'
@@ -111,7 +111,7 @@
* The number of times this priority queue has been
* <i>structurally modified</i>. See AbstractList for gory details.
*/
- transient int modCount = 0; // non-private to simplify nested class access
+ transient int modCount; // non-private to simplify nested class access
/**
* Creates a {@code PriorityQueue} with the default initial
@@ -448,7 +448,7 @@
* The following code can be used to dump the queue into a newly
* allocated array of {@code String}:
*
- * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+ * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
*
* Note that {@code toArray(new Object[0])} is identical in function to
* {@code toArray()}.
@@ -489,7 +489,7 @@
* Index (into queue array) of element to be returned by
* subsequent call to next.
*/
- private int cursor = 0;
+ private int cursor;
/**
* Index of element returned by most recent call to next,
@@ -509,13 +509,13 @@
* We expect that most iterations, even those involving removals,
* will not need to store elements in this field.
*/
- private ArrayDeque<E> forgetMeNot = null;
+ private ArrayDeque<E> forgetMeNot;
/**
* Element returned by the most recent call to next iff that
* element was drawn from the forgetMeNot list.
*/
- private E lastRetElt = null;
+ private E lastRetElt;
/**
* The modCount value that the iterator believes that the backing
@@ -609,7 +609,7 @@
* avoid missing traversing elements.
*/
@SuppressWarnings("unchecked")
- private E removeAt(int i) {
+ E removeAt(int i) {
// assert i >= 0 && i < size;
modCount++;
int s = --size;
@@ -756,6 +756,7 @@
* emitted (int), followed by all of its elements
* (each an {@code Object}) in the proper order.
* @param s the stream
+ * @throws java.io.IOException if an I/O error occurs
*/
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
@@ -775,6 +776,9 @@
* (that is, deserializes it).
*
* @param s the stream
+ * @throws ClassNotFoundException if the class of a serialized object
+ * could not be found
+ * @throws java.io.IOException if an I/O error occurs
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
@@ -822,9 +826,9 @@
private int fence; // -1 until first use
private int expectedModCount; // initialized when fence set
- /** Creates new spliterator covering the given range */
+ /** Creates new spliterator covering the given range. */
PriorityQueueSpliterator(PriorityQueue<E> pq, int origin, int fence,
- int expectedModCount) {
+ int expectedModCount) {
this.pq = pq;
this.index = origin;
this.fence = fence;
--- a/jdk/src/java.base/share/classes/java/util/Queue.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/Queue.java Tue Oct 13 16:45:35 2015 -0700
@@ -139,7 +139,7 @@
* @see java.util.concurrent.PriorityBlockingQueue
* @since 1.5
* @author Doug Lea
- * @param <E> the type of elements held in this collection
+ * @param <E> the type of elements held in this queue
*/
public interface Queue<E> extends Collection<E> {
/**
--- a/jdk/src/java.base/share/classes/java/util/SplittableRandom.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/SplittableRandom.java Tue Oct 13 16:45:35 2015 -0700
@@ -26,13 +26,13 @@
package java.util;
import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.DoubleConsumer;
import java.util.function.IntConsumer;
import java.util.function.LongConsumer;
-import java.util.function.DoubleConsumer;
-import java.util.stream.StreamSupport;
+import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
-import java.util.stream.DoubleStream;
+import java.util.stream.StreamSupport;
/**
* A generator of uniform pseudorandom values applicable for use in
@@ -52,15 +52,15 @@
* types and ranges, but similar properties are expected to hold, at
* least approximately, for others as well. The <em>period</em>
* (length of any series of generated values before it repeats) is at
- * least 2<sup>64</sup>. </li>
+ * least 2<sup>64</sup>.
*
- * <li> Method {@link #split} constructs and returns a new
+ * <li>Method {@link #split} constructs and returns a new
* SplittableRandom instance that shares no mutable state with the
* current instance. However, with very high probability, the
* values collectively generated by the two objects have the same
* statistical properties as if the same quantity of values were
* generated by a single thread using a single {@code
- * SplittableRandom} object. </li>
+ * SplittableRandom} object.
*
* <li>Instances of SplittableRandom are <em>not</em> thread-safe.
* They are designed to be split, not shared, across threads. For
@@ -71,7 +71,7 @@
*
* <li>This class provides additional methods for generating random
* streams, that employ the above techniques when used in {@code
- * stream.parallel()} mode.</li>
+ * stream.parallel()} mode.
*
* </ul>
*
@@ -240,9 +240,9 @@
}
// IllegalArgumentException messages
- static final String BadBound = "bound must be positive";
- static final String BadRange = "bound must be greater than origin";
- static final String BadSize = "size must be non-negative";
+ static final String BAD_BOUND = "bound must be positive";
+ static final String BAD_RANGE = "bound must be greater than origin";
+ static final String BAD_SIZE = "size must be non-negative";
/*
* Internal versions of nextX methods used by streams, as well as
@@ -416,7 +416,7 @@
*/
public int nextInt(int bound) {
if (bound <= 0)
- throw new IllegalArgumentException(BadBound);
+ throw new IllegalArgumentException(BAD_BOUND);
// Specialize internalNextInt for origin 0
int r = mix32(nextSeed());
int m = bound - 1;
@@ -444,7 +444,7 @@
*/
public int nextInt(int origin, int bound) {
if (origin >= bound)
- throw new IllegalArgumentException(BadRange);
+ throw new IllegalArgumentException(BAD_RANGE);
return internalNextInt(origin, bound);
}
@@ -468,7 +468,7 @@
*/
public long nextLong(long bound) {
if (bound <= 0)
- throw new IllegalArgumentException(BadBound);
+ throw new IllegalArgumentException(BAD_BOUND);
// Specialize internalNextLong for origin 0
long r = mix64(nextSeed());
long m = bound - 1;
@@ -496,7 +496,7 @@
*/
public long nextLong(long origin, long bound) {
if (origin >= bound)
- throw new IllegalArgumentException(BadRange);
+ throw new IllegalArgumentException(BAD_RANGE);
return internalNextLong(origin, bound);
}
@@ -522,7 +522,7 @@
*/
public double nextDouble(double bound) {
if (!(bound > 0.0))
- throw new IllegalArgumentException(BadBound);
+ throw new IllegalArgumentException(BAD_BOUND);
double result = (mix64(nextSeed()) >>> 11) * DOUBLE_UNIT * bound;
return (result < bound) ? result : // correct for rounding
Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1);
@@ -541,7 +541,7 @@
*/
public double nextDouble(double origin, double bound) {
if (!(origin < bound))
- throw new IllegalArgumentException(BadRange);
+ throw new IllegalArgumentException(BAD_RANGE);
return internalNextDouble(origin, bound);
}
@@ -569,7 +569,7 @@
*/
public IntStream ints(long streamSize) {
if (streamSize < 0L)
- throw new IllegalArgumentException(BadSize);
+ throw new IllegalArgumentException(BAD_SIZE);
return StreamSupport.intStream
(new RandomIntsSpliterator
(this, 0L, streamSize, Integer.MAX_VALUE, 0),
@@ -610,9 +610,9 @@
public IntStream ints(long streamSize, int randomNumberOrigin,
int randomNumberBound) {
if (streamSize < 0L)
- throw new IllegalArgumentException(BadSize);
+ throw new IllegalArgumentException(BAD_SIZE);
if (randomNumberOrigin >= randomNumberBound)
- throw new IllegalArgumentException(BadRange);
+ throw new IllegalArgumentException(BAD_RANGE);
return StreamSupport.intStream
(new RandomIntsSpliterator
(this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
@@ -636,7 +636,7 @@
*/
public IntStream ints(int randomNumberOrigin, int randomNumberBound) {
if (randomNumberOrigin >= randomNumberBound)
- throw new IllegalArgumentException(BadRange);
+ throw new IllegalArgumentException(BAD_RANGE);
return StreamSupport.intStream
(new RandomIntsSpliterator
(this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
@@ -655,7 +655,7 @@
*/
public LongStream longs(long streamSize) {
if (streamSize < 0L)
- throw new IllegalArgumentException(BadSize);
+ throw new IllegalArgumentException(BAD_SIZE);
return StreamSupport.longStream
(new RandomLongsSpliterator
(this, 0L, streamSize, Long.MAX_VALUE, 0L),
@@ -696,9 +696,9 @@
public LongStream longs(long streamSize, long randomNumberOrigin,
long randomNumberBound) {
if (streamSize < 0L)
- throw new IllegalArgumentException(BadSize);
+ throw new IllegalArgumentException(BAD_SIZE);
if (randomNumberOrigin >= randomNumberBound)
- throw new IllegalArgumentException(BadRange);
+ throw new IllegalArgumentException(BAD_RANGE);
return StreamSupport.longStream
(new RandomLongsSpliterator
(this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
@@ -722,7 +722,7 @@
*/
public LongStream longs(long randomNumberOrigin, long randomNumberBound) {
if (randomNumberOrigin >= randomNumberBound)
- throw new IllegalArgumentException(BadRange);
+ throw new IllegalArgumentException(BAD_RANGE);
return StreamSupport.longStream
(new RandomLongsSpliterator
(this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
@@ -741,7 +741,7 @@
*/
public DoubleStream doubles(long streamSize) {
if (streamSize < 0L)
- throw new IllegalArgumentException(BadSize);
+ throw new IllegalArgumentException(BAD_SIZE);
return StreamSupport.doubleStream
(new RandomDoublesSpliterator
(this, 0L, streamSize, Double.MAX_VALUE, 0.0),
@@ -784,9 +784,9 @@
public DoubleStream doubles(long streamSize, double randomNumberOrigin,
double randomNumberBound) {
if (streamSize < 0L)
- throw new IllegalArgumentException(BadSize);
+ throw new IllegalArgumentException(BAD_SIZE);
if (!(randomNumberOrigin < randomNumberBound))
- throw new IllegalArgumentException(BadRange);
+ throw new IllegalArgumentException(BAD_RANGE);
return StreamSupport.doubleStream
(new RandomDoublesSpliterator
(this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
@@ -810,7 +810,7 @@
*/
public DoubleStream doubles(double randomNumberOrigin, double randomNumberBound) {
if (!(randomNumberOrigin < randomNumberBound))
- throw new IllegalArgumentException(BadRange);
+ throw new IllegalArgumentException(BAD_RANGE);
return StreamSupport.doubleStream
(new RandomDoublesSpliterator
(this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
@@ -825,7 +825,8 @@
* approach. The long and double versions of this class are
* identical except for types.
*/
- static final class RandomIntsSpliterator implements Spliterator.OfInt {
+ private static final class RandomIntsSpliterator
+ implements Spliterator.OfInt {
final SplittableRandom rng;
long index;
final long fence;
@@ -880,7 +881,8 @@
/**
* Spliterator for long streams.
*/
- static final class RandomLongsSpliterator implements Spliterator.OfLong {
+ private static final class RandomLongsSpliterator
+ implements Spliterator.OfLong {
final SplittableRandom rng;
long index;
final long fence;
@@ -936,7 +938,8 @@
/**
* Spliterator for double streams.
*/
- static final class RandomDoublesSpliterator implements Spliterator.OfDouble {
+ private static final class RandomDoublesSpliterator
+ implements Spliterator.OfDouble {
final SplittableRandom rng;
long index;
final long fence;
--- a/jdk/src/java.base/share/classes/java/util/concurrent/AbstractExecutorService.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/AbstractExecutorService.java Tue Oct 13 16:45:35 2015 -0700
@@ -34,7 +34,13 @@
*/
package java.util.concurrent;
-import java.util.*;
+
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
/**
* Provides default implementations of {@link ExecutorService}
@@ -51,7 +57,7 @@
* <p><b>Extension example</b>. Here is a sketch of a class
* that customizes {@link ThreadPoolExecutor} to use
* a {@code CustomTask} class instead of the default {@code FutureTask}:
- * <pre> {@code
+ * <pre> {@code
* public class CustomThreadPoolExecutor extends ThreadPoolExecutor {
*
* static class CustomTask<V> implements RunnableFuture<V> {...}
@@ -146,7 +152,7 @@
int ntasks = tasks.size();
if (ntasks == 0)
throw new IllegalArgumentException();
- ArrayList<Future<T>> futures = new ArrayList<Future<T>>(ntasks);
+ ArrayList<Future<T>> futures = new ArrayList<>(ntasks);
ExecutorCompletionService<T> ecs =
new ExecutorCompletionService<T>(this);
@@ -179,7 +185,7 @@
else if (active == 0)
break;
else if (timed) {
- f = ecs.poll(nanos, TimeUnit.NANOSECONDS);
+ f = ecs.poll(nanos, NANOSECONDS);
if (f == null)
throw new TimeoutException();
nanos = deadline - System.nanoTime();
@@ -204,8 +210,7 @@
throw ee;
} finally {
- for (int i = 0, size = futures.size(); i < size; i++)
- futures.get(i).cancel(true);
+ cancelAll(futures);
}
}
@@ -229,8 +234,7 @@
throws InterruptedException {
if (tasks == null)
throw new NullPointerException();
- ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
- boolean done = false;
+ ArrayList<Future<T>> futures = new ArrayList<>(tasks.size());
try {
for (Callable<T> t : tasks) {
RunnableFuture<T> f = newTaskFor(t);
@@ -240,19 +244,15 @@
for (int i = 0, size = futures.size(); i < size; i++) {
Future<T> f = futures.get(i);
if (!f.isDone()) {
- try {
- f.get();
- } catch (CancellationException ignore) {
- } catch (ExecutionException ignore) {
- }
+ try { f.get(); }
+ catch (CancellationException ignore) {}
+ catch (ExecutionException ignore) {}
}
}
- done = true;
return futures;
- } finally {
- if (!done)
- for (int i = 0, size = futures.size(); i < size; i++)
- futures.get(i).cancel(true);
+ } catch (Throwable t) {
+ cancelAll(futures);
+ throw t;
}
}
@@ -261,47 +261,52 @@
throws InterruptedException {
if (tasks == null)
throw new NullPointerException();
- long nanos = unit.toNanos(timeout);
- ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
- boolean done = false;
- try {
+ final long nanos = unit.toNanos(timeout);
+ final long deadline = System.nanoTime() + nanos;
+ ArrayList<Future<T>> futures = new ArrayList<>(tasks.size());
+ int j = 0;
+ timedOut: try {
for (Callable<T> t : tasks)
futures.add(newTaskFor(t));
- final long deadline = System.nanoTime() + nanos;
final int size = futures.size();
// Interleave time checks and calls to execute in case
// executor doesn't have any/much parallelism.
for (int i = 0; i < size; i++) {
+ if (((i == 0) ? nanos : deadline - System.nanoTime()) <= 0L)
+ break timedOut;
execute((Runnable)futures.get(i));
- nanos = deadline - System.nanoTime();
- if (nanos <= 0L)
- return futures;
}
- for (int i = 0; i < size; i++) {
- Future<T> f = futures.get(i);
+ for (; j < size; j++) {
+ Future<T> f = futures.get(j);
if (!f.isDone()) {
- if (nanos <= 0L)
- return futures;
- try {
- f.get(nanos, TimeUnit.NANOSECONDS);
- } catch (CancellationException ignore) {
- } catch (ExecutionException ignore) {
- } catch (TimeoutException toe) {
- return futures;
+ try { f.get(deadline - System.nanoTime(), NANOSECONDS); }
+ catch (CancellationException ignore) {}
+ catch (ExecutionException ignore) {}
+ catch (TimeoutException timedOut) {
+ break timedOut;
}
- nanos = deadline - System.nanoTime();
}
}
- done = true;
return futures;
- } finally {
- if (!done)
- for (int i = 0, size = futures.size(); i < size; i++)
- futures.get(i).cancel(true);
+ } catch (Throwable t) {
+ cancelAll(futures);
+ throw t;
}
+ // Timed out before all the tasks could be completed; cancel remaining
+ cancelAll(futures, j);
+ return futures;
}
+ private static <T> void cancelAll(ArrayList<Future<T>> futures) {
+ cancelAll(futures, 0);
+ }
+
+ /** Cancels all futures with index at least j. */
+ private static <T> void cancelAll(ArrayList<Future<T>> futures, int j) {
+ for (int size = futures.size(); j < size; j++)
+ futures.get(j).cancel(true);
+ }
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ArrayBlockingQueue.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ArrayBlockingQueue.java Tue Oct 13 16:45:35 2015 -0700
@@ -34,15 +34,18 @@
*/
package java.util.concurrent;
-import java.util.concurrent.locks.Condition;
-import java.util.concurrent.locks.ReentrantLock;
+
+import java.lang.ref.WeakReference;
import java.util.AbstractQueue;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
-import java.lang.ref.WeakReference;
+import java.util.Objects;
+import java.util.Spliterator;
import java.util.Spliterators;
-import java.util.Spliterator;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
/**
* A bounded {@linkplain BlockingQueue blocking queue} backed by an
@@ -77,7 +80,7 @@
*
* @since 1.5
* @author Doug Lea
- * @param <E> the type of elements held in this collection
+ * @param <E> the type of elements held in this queue
*/
public class ArrayBlockingQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable {
@@ -121,12 +124,12 @@
* are known not to be any. Allows queue operations to update
* iterator state.
*/
- transient Itrs itrs = null;
+ transient Itrs itrs;
// Internal helper methods
/**
- * Circularly decrement i.
+ * Circularly decrements array index i.
*/
final int dec(int i) {
return ((i == 0) ? items.length : i) - 1;
@@ -141,16 +144,6 @@
}
/**
- * Throws NullPointerException if argument is null.
- *
- * @param v the element
- */
- private static void checkNotNull(Object v) {
- if (v == null)
- throw new NullPointerException();
- }
-
- /**
* Inserts element at current put position, advances, and signals.
* Call only when holding lock.
*/
@@ -159,8 +152,7 @@
// assert items[putIndex] == null;
final Object[] items = this.items;
items[putIndex] = x;
- if (++putIndex == items.length)
- putIndex = 0;
+ if (++putIndex == items.length) putIndex = 0;
count++;
notEmpty.signal();
}
@@ -176,8 +168,7 @@
@SuppressWarnings("unchecked")
E x = (E) items[takeIndex];
items[takeIndex] = null;
- if (++takeIndex == items.length)
- takeIndex = 0;
+ if (++takeIndex == items.length) takeIndex = 0;
count--;
if (itrs != null)
itrs.elementDequeued();
@@ -198,8 +189,7 @@
if (removeIndex == takeIndex) {
// removing front item; just advance
items[takeIndex] = null;
- if (++takeIndex == items.length)
- takeIndex = 0;
+ if (++takeIndex == items.length) takeIndex = 0;
count--;
if (itrs != null)
itrs.elementDequeued();
@@ -207,19 +197,15 @@
// an "interior" remove
// slide over all others up through putIndex.
- final int putIndex = this.putIndex;
- for (int i = removeIndex;;) {
- int next = i + 1;
- if (next == items.length)
- next = 0;
- if (next != putIndex) {
- items[i] = items[next];
- i = next;
- } else {
- items[i] = null;
- this.putIndex = i;
+ for (int i = removeIndex, putIndex = this.putIndex;;) {
+ int pred = i;
+ if (++i == items.length) i = 0;
+ if (i == putIndex) {
+ items[pred] = null;
+ this.putIndex = pred;
break;
}
+ items[pred] = items[i];
}
count--;
if (itrs != null)
@@ -283,10 +269,8 @@
try {
int i = 0;
try {
- for (E e : c) {
- checkNotNull(e);
- items[i++] = e;
- }
+ for (E e : c)
+ items[i++] = Objects.requireNonNull(e);
} catch (ArrayIndexOutOfBoundsException ex) {
throw new IllegalArgumentException();
}
@@ -322,7 +306,7 @@
* @throws NullPointerException if the specified element is null
*/
public boolean offer(E e) {
- checkNotNull(e);
+ Objects.requireNonNull(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
@@ -345,7 +329,7 @@
* @throws NullPointerException {@inheritDoc}
*/
public void put(E e) throws InterruptedException {
- checkNotNull(e);
+ Objects.requireNonNull(e);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
@@ -368,13 +352,13 @@
public boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException {
- checkNotNull(e);
+ Objects.requireNonNull(e);
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length) {
- if (nanos <= 0)
+ if (nanos <= 0L)
return false;
nanos = notFull.awaitNanos(nanos);
}
@@ -413,7 +397,7 @@
lock.lockInterruptibly();
try {
while (count == 0) {
- if (nanos <= 0)
+ if (nanos <= 0L)
return null;
nanos = notEmpty.awaitNanos(nanos);
}
@@ -492,11 +476,11 @@
*/
public boolean remove(Object o) {
if (o == null) return false;
- final Object[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count > 0) {
+ final Object[] items = this.items;
final int putIndex = this.putIndex;
int i = takeIndex;
do {
@@ -504,8 +488,7 @@
removeAt(i);
return true;
}
- if (++i == items.length)
- i = 0;
+ if (++i == items.length) i = 0;
} while (i != putIndex);
}
return false;
@@ -524,18 +507,17 @@
*/
public boolean contains(Object o) {
if (o == null) return false;
- final Object[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count > 0) {
+ final Object[] items = this.items;
final int putIndex = this.putIndex;
int i = takeIndex;
do {
if (o.equals(items[i]))
return true;
- if (++i == items.length)
- i = 0;
+ if (++i == items.length) i = 0;
} while (i != putIndex);
}
return false;
@@ -558,23 +540,18 @@
* @return an array containing all of the elements in this queue
*/
public Object[] toArray() {
- Object[] a;
final ReentrantLock lock = this.lock;
lock.lock();
try {
- final int count = this.count;
- a = new Object[count];
- int n = items.length - takeIndex;
- if (count <= n)
- System.arraycopy(items, takeIndex, a, 0, count);
- else {
- System.arraycopy(items, takeIndex, a, 0, n);
- System.arraycopy(items, 0, a, n, count - n);
- }
+ final Object[] items = this.items;
+ final int end = takeIndex + count;
+ final Object[] a = Arrays.copyOfRange(items, takeIndex, end);
+ if (end != putIndex)
+ System.arraycopy(items, 0, a, items.length - takeIndex, putIndex);
+ return a;
} finally {
lock.unlock();
}
- return a;
}
/**
@@ -598,7 +575,7 @@
* The following code can be used to dump the queue into a newly
* allocated array of {@code String}:
*
- * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+ * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
*
* Note that {@code toArray(new Object[0])} is identical in function to
* {@code toArray()}.
@@ -614,53 +591,30 @@
*/
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
- final Object[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock();
try {
+ final Object[] items = this.items;
final int count = this.count;
- final int len = a.length;
- if (len < count)
- a = (T[])java.lang.reflect.Array.newInstance(
- a.getClass().getComponentType(), count);
- int n = items.length - takeIndex;
- if (count <= n)
- System.arraycopy(items, takeIndex, a, 0, count);
- else {
- System.arraycopy(items, takeIndex, a, 0, n);
- System.arraycopy(items, 0, a, n, count - n);
+ final int firstLeg = Math.min(items.length - takeIndex, count);
+ if (a.length < count) {
+ a = (T[]) Arrays.copyOfRange(items, takeIndex, takeIndex + count,
+ a.getClass());
+ } else {
+ System.arraycopy(items, takeIndex, a, 0, firstLeg);
+ if (a.length > count)
+ a[count] = null;
}
- if (len > count)
- a[count] = null;
+ if (firstLeg < count)
+ System.arraycopy(items, 0, a, firstLeg, putIndex);
+ return a;
} finally {
lock.unlock();
}
- return a;
}
public String toString() {
- final ReentrantLock lock = this.lock;
- lock.lock();
- try {
- int k = count;
- if (k == 0)
- return "[]";
-
- final Object[] items = this.items;
- StringBuilder sb = new StringBuilder();
- sb.append('[');
- for (int i = takeIndex; ; ) {
- Object e = items[i];
- sb.append(e == this ? "(this Collection)" : e);
- if (--k == 0)
- return sb.append(']').toString();
- sb.append(',').append(' ');
- if (++i == items.length)
- i = 0;
- }
- } finally {
- lock.unlock();
- }
+ return Helpers.collectionToString(this);
}
/**
@@ -668,18 +622,17 @@
* The queue will be empty after this call returns.
*/
public void clear() {
- final Object[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock();
try {
int k = count;
if (k > 0) {
+ final Object[] items = this.items;
final int putIndex = this.putIndex;
int i = takeIndex;
do {
items[i] = null;
- if (++i == items.length)
- i = 0;
+ if (++i == items.length) i = 0;
} while (i != putIndex);
takeIndex = putIndex;
count = 0;
@@ -710,7 +663,7 @@
* @throws IllegalArgumentException {@inheritDoc}
*/
public int drainTo(Collection<? super E> c, int maxElements) {
- checkNotNull(c);
+ Objects.requireNonNull(c);
if (c == this)
throw new IllegalArgumentException();
if (maxElements <= 0)
@@ -728,8 +681,7 @@
E x = (E) items[take];
c.add(x);
items[take] = null;
- if (++take == items.length)
- take = 0;
+ if (++take == items.length) take = 0;
i++;
}
return n;
@@ -832,13 +784,13 @@
}
/** Incremented whenever takeIndex wraps around to 0 */
- int cycles = 0;
+ int cycles;
/** Linked list of weak iterator references */
private Node head;
/** Used to expunge stale iterators */
- private Node sweeper = null;
+ private Node sweeper;
private static final int SHORT_SWEEP_PROBES = 4;
private static final int LONG_SWEEP_PROBES = 16;
@@ -1095,10 +1047,8 @@
private int incCursor(int index) {
// assert lock.getHoldCount() == 1;
- if (++index == items.length)
- index = 0;
- if (index == putIndex)
- index = NONE;
+ if (++index == items.length) index = 0;
+ if (index == putIndex) index = NONE;
return index;
}
@@ -1314,17 +1264,18 @@
if (isDetached())
return true;
- final int cycles = itrs.cycles;
final int takeIndex = ArrayBlockingQueue.this.takeIndex;
- final int prevCycles = this.prevCycles;
final int prevTakeIndex = this.prevTakeIndex;
final int len = items.length;
- int cycleDiff = cycles - prevCycles;
- if (removedIndex < takeIndex)
- cycleDiff++;
+ // distance from prevTakeIndex to removedIndex
final int removedDistance =
- (cycleDiff * len) + (removedIndex - prevTakeIndex);
- // assert removedDistance >= 0;
+ len * (itrs.cycles - this.prevCycles
+ + ((removedIndex < takeIndex) ? 1 : 0))
+ + (removedIndex - prevTakeIndex);
+ // assert itrs.cycles - this.prevCycles >= 0;
+ // assert itrs.cycles - this.prevCycles <= 1;
+ // assert removedDistance > 0;
+ // assert removedIndex != takeIndex;
int cursor = this.cursor;
if (cursor >= 0) {
int x = distance(cursor, prevTakeIndex, len);
@@ -1353,7 +1304,7 @@
else if (x > removedDistance)
this.nextIndex = nextIndex = dec(nextIndex);
}
- else if (cursor < 0 && nextIndex < 0 && lastRet < 0) {
+ if (cursor < 0 && nextIndex < 0 && lastRet < 0) {
this.prevTakeIndex = DETACHED;
return true;
}
@@ -1410,8 +1361,9 @@
*/
public Spliterator<E> spliterator() {
return Spliterators.spliterator
- (this, Spliterator.ORDERED | Spliterator.NONNULL |
- Spliterator.CONCURRENT);
+ (this, (Spliterator.ORDERED |
+ Spliterator.NONNULL |
+ Spliterator.CONCURRENT));
}
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/BlockingDeque.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/BlockingDeque.java Tue Oct 13 16:45:35 2015 -0700
@@ -34,7 +34,10 @@
*/
package java.util.concurrent;
-import java.util.*;
+
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
/**
* A {@link Deque} that additionally supports blocking operations that wait
@@ -195,7 +198,7 @@
*
* @since 1.6
* @author Doug Lea
- * @param <E> the type of elements held in this collection
+ * @param <E> the type of elements held in this deque
*/
public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> {
/*
@@ -401,9 +404,9 @@
* @return {@code true} if an element was removed as a result of this call
* @throws ClassCastException if the class of the specified element
* is incompatible with this deque
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified element is null
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
*/
boolean removeFirstOccurrence(Object o);
@@ -419,9 +422,9 @@
* @return {@code true} if an element was removed as a result of this call
* @throws ClassCastException if the class of the specified element
* is incompatible with this deque
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified element is null
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
*/
boolean removeLastOccurrence(Object o);
@@ -596,9 +599,9 @@
* @return {@code true} if this deque changed as a result of the call
* @throws ClassCastException if the class of the specified element
* is incompatible with this deque
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified element is null
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
*/
boolean remove(Object o);
@@ -611,18 +614,18 @@
* @return {@code true} if this deque contains the specified element
* @throws ClassCastException if the class of the specified element
* is incompatible with this deque
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified element is null
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
*/
- public boolean contains(Object o);
+ boolean contains(Object o);
/**
* Returns the number of elements in this deque.
*
* @return the number of elements in this deque
*/
- public int size();
+ int size();
/**
* Returns an iterator over the elements in this deque in proper sequence.
--- a/jdk/src/java.base/share/classes/java/util/concurrent/BlockingQueue.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/BlockingQueue.java Tue Oct 13 16:45:35 2015 -0700
@@ -127,7 +127,7 @@
* Usage example, based on a typical producer-consumer scenario.
* Note that a {@code BlockingQueue} can safely be used with multiple
* producers and multiple consumers.
- * <pre> {@code
+ * <pre> {@code
* class Producer implements Runnable {
* private final BlockingQueue queue;
* Producer(BlockingQueue q) { queue = q; }
@@ -175,7 +175,7 @@
*
* @since 1.5
* @author Doug Lea
- * @param <E> the type of elements held in this collection
+ * @param <E> the type of elements held in this queue
*/
public interface BlockingQueue<E> extends Queue<E> {
/**
@@ -303,9 +303,9 @@
* @return {@code true} if this queue changed as a result of the call
* @throws ClassCastException if the class of the specified element
* is incompatible with this queue
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified element is null
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
*/
boolean remove(Object o);
@@ -318,11 +318,11 @@
* @return {@code true} if this queue contains the specified element
* @throws ClassCastException if the class of the specified element
* is incompatible with this queue
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified element is null
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
*/
- public boolean contains(Object o);
+ boolean contains(Object o);
/**
* Removes all available elements from this queue and adds them
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java Tue Oct 13 16:45:35 2015 -0700
@@ -42,7 +42,6 @@
import java.util.AbstractMap;
import java.util.Arrays;
import java.util.Collection;
-import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
@@ -51,14 +50,11 @@
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.Spliterator;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
-import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.DoubleBinaryOperator;
import java.util.function.Function;
@@ -154,43 +150,43 @@
* being concurrently updated by other threads; for example, when
* computing a snapshot summary of the values in a shared registry.
* There are three kinds of operation, each with four forms, accepting
- * functions with Keys, Values, Entries, and (Key, Value) arguments
- * and/or return values. Because the elements of a ConcurrentHashMap
- * are not ordered in any particular way, and may be processed in
- * different orders in different parallel executions, the correctness
- * of supplied functions should not depend on any ordering, or on any
- * other objects or values that may transiently change while
- * computation is in progress; and except for forEach actions, should
- * ideally be side-effect-free. Bulk operations on {@link java.util.Map.Entry}
- * objects do not support method {@code setValue}.
+ * functions with keys, values, entries, and (key, value) pairs as
+ * arguments and/or return values. Because the elements of a
+ * ConcurrentHashMap are not ordered in any particular way, and may be
+ * processed in different orders in different parallel executions, the
+ * correctness of supplied functions should not depend on any
+ * ordering, or on any other objects or values that may transiently
+ * change while computation is in progress; and except for forEach
+ * actions, should ideally be side-effect-free. Bulk operations on
+ * {@link java.util.Map.Entry} objects do not support method {@code
+ * setValue}.
*
* <ul>
- * <li> forEach: Perform a given action on each element.
+ * <li>forEach: Performs a given action on each element.
* A variant form applies a given transformation on each element
- * before performing the action.</li>
+ * before performing the action.
*
- * <li> search: Return the first available non-null result of
+ * <li>search: Returns the first available non-null result of
* applying a given function on each element; skipping further
- * search when a result is found.</li>
+ * search when a result is found.
*
- * <li> reduce: Accumulate each element. The supplied reduction
+ * <li>reduce: Accumulates each element. The supplied reduction
* function cannot rely on ordering (more formally, it should be
* both associative and commutative). There are five variants:
*
* <ul>
*
- * <li> Plain reductions. (There is not a form of this method for
+ * <li>Plain reductions. (There is not a form of this method for
* (key, value) function arguments since there is no corresponding
- * return type.)</li>
+ * return type.)
*
- * <li> Mapped reductions that accumulate the results of a given
- * function applied to each element.</li>
+ * <li>Mapped reductions that accumulate the results of a given
+ * function applied to each element.
*
- * <li> Reductions to scalar doubles, longs, and ints, using a
- * given basis value.</li>
+ * <li>Reductions to scalar doubles, longs, and ints, using a
+ * given basis value.
*
* </ul>
- * </li>
* </ul>
*
* <p>These bulk operations accept a {@code parallelismThreshold}
@@ -576,7 +572,7 @@
* The number of bits used for generation stamp in sizeCtl.
* Must be at least 6 for 32bit arrays.
*/
- private static int RESIZE_STAMP_BITS = 16;
+ private static final int RESIZE_STAMP_BITS = 16;
/**
* The maximum number of threads that can help resize.
@@ -604,7 +600,7 @@
private static final ObjectStreamField[] serialPersistentFields = {
new ObjectStreamField("segments", Segment[].class),
new ObjectStreamField("segmentMask", Integer.TYPE),
- new ObjectStreamField("segmentShift", Integer.TYPE)
+ new ObjectStreamField("segmentShift", Integer.TYPE),
};
/* ---------------- Nodes -------------- */
@@ -630,10 +626,12 @@
this.next = next;
}
- public final K getKey() { return key; }
- public final V getValue() { return val; }
- public final int hashCode() { return key.hashCode() ^ val.hashCode(); }
- public final String toString(){ return key + "=" + val; }
+ public final K getKey() { return key; }
+ public final V getValue() { return val; }
+ public final int hashCode() { return key.hashCode() ^ val.hashCode(); }
+ public final String toString() {
+ return Helpers.mapEntryToString(key, val);
+ }
public final V setValue(V value) {
throw new UnsupportedOperationException();
}
@@ -1057,6 +1055,8 @@
p.val = value;
}
}
+ else if (f instanceof ReservationNode)
+ throw new IllegalStateException("Recursive update");
}
}
if (binCount != 0) {
@@ -1159,6 +1159,8 @@
}
}
}
+ else if (f instanceof ReservationNode)
+ throw new IllegalStateException("Recursive update");
}
}
if (validated) {
@@ -1366,7 +1368,7 @@
/**
* Stripped-down version of helper class used in previous version,
- * declared for the sake of serialization compatibility
+ * declared for the sake of serialization compatibility.
*/
static class Segment<K,V> extends ReentrantLock implements Serializable {
private static final long serialVersionUID = 2249069246763182397L;
@@ -1401,9 +1403,10 @@
new Segment<?,?>[DEFAULT_CONCURRENCY_LEVEL];
for (int i = 0; i < segments.length; ++i)
segments[i] = new Segment<K,V>(LOAD_FACTOR);
- s.putFields().put("segments", segments);
- s.putFields().put("segmentShift", segmentShift);
- s.putFields().put("segmentMask", segmentMask);
+ java.io.ObjectOutputStream.PutField streamFields = s.putFields();
+ streamFields.put("segments", segments);
+ streamFields.put("segmentShift", segmentShift);
+ streamFields.put("segmentMask", segmentMask);
s.writeFields();
Node<K,V>[] t;
@@ -1620,9 +1623,9 @@
}
/**
- * Helper method for EntrySet.removeIf
+ * Helper method for EntrySetView.removeIf.
*/
- boolean removeEntryIf(Predicate<? super Entry<K, V>> function) {
+ boolean removeEntryIf(Predicate<? super Entry<K,V>> function) {
if (function == null) throw new NullPointerException();
Node<K,V>[] t;
boolean removed = false;
@@ -1640,9 +1643,9 @@
}
/**
- * Helper method for Values.removeIf
+ * Helper method for ValuesView.removeIf.
*/
- boolean removeValueIf(Predicate<? super V> function) {
+ boolean removeValueIf(Predicate<? super V> function) {
if (function == null) throw new NullPointerException();
Node<K,V>[] t;
boolean removed = false;
@@ -1716,7 +1719,7 @@
if (fh >= 0) {
binCount = 1;
for (Node<K,V> e = f;; ++binCount) {
- K ek; V ev;
+ K ek;
if (e.hash == h &&
((ek = e.key) == key ||
(ek != null && key.equals(ek)))) {
@@ -1726,6 +1729,8 @@
Node<K,V> pred = e;
if ((e = e.next) == null) {
if ((val = mappingFunction.apply(key)) != null) {
+ if (pred.next != null)
+ throw new IllegalStateException("Recursive update");
added = true;
pred.next = new Node<K,V>(h, key, val, null);
}
@@ -1745,6 +1750,8 @@
t.putTreeVal(h, key, val);
}
}
+ else if (f instanceof ReservationNode)
+ throw new IllegalStateException("Recursive update");
}
}
if (binCount != 0) {
@@ -1840,6 +1847,8 @@
}
}
}
+ else if (f instanceof ReservationNode)
+ throw new IllegalStateException("Recursive update");
}
}
if (binCount != 0)
@@ -1931,6 +1940,8 @@
if ((e = e.next) == null) {
val = remappingFunction.apply(key, null);
if (val != null) {
+ if (pred.next != null)
+ throw new IllegalStateException("Recursive update");
delta = 1;
pred.next =
new Node<K,V>(h, key, val, null);
@@ -1963,6 +1974,8 @@
setTabAt(tab, i, untreeify(t.first));
}
}
+ else if (f instanceof ReservationNode)
+ throw new IllegalStateException("Recursive update");
}
}
if (binCount != 0) {
@@ -2072,6 +2085,8 @@
setTabAt(tab, i, untreeify(t.first));
}
}
+ else if (f instanceof ReservationNode)
+ throw new IllegalStateException("Recursive update");
}
}
if (binCount != 0) {
@@ -2089,12 +2104,13 @@
// Hashtable legacy methods
/**
- * Legacy method testing if some key maps into the specified value
- * in this table. This method is identical in functionality to
+ * Tests if some key maps into the specified value in this table.
+ *
+ * <p>Note that this method is identical in functionality to
* {@link #containsValue(Object)}, and exists solely to ensure
* full compatibility with class {@link java.util.Hashtable},
* which supported this method prior to introduction of the
- * Java Collections framework.
+ * Java Collections Framework.
*
* @param value a value to search for
* @return {@code true} if and only if some key maps to the
@@ -2235,7 +2251,7 @@
}
/**
- * A place-holder node used in computeIfAbsent and compute
+ * A place-holder node used in computeIfAbsent and compute.
*/
static final class ReservationNode<K,V> extends Node<K,V> {
ReservationNode() {
@@ -2384,17 +2400,8 @@
break;
else if (tab == table) {
int rs = resizeStamp(n);
- if (sc < 0) {
- Node<K,V>[] nt;
- if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
- sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||
- transferIndex <= 0)
- break;
- if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1))
- transfer(tab, nt);
- }
- else if (U.compareAndSwapInt(this, SIZECTL, sc,
- (rs << RESIZE_STAMP_SHIFT) + 2))
+ if (U.compareAndSwapInt(this, SIZECTL, sc,
+ (rs << RESIZE_STAMP_SHIFT) + 2))
transfer(tab, null);
}
}
@@ -2649,7 +2656,7 @@
* too small, in which case resizes instead.
*/
private final void treeifyBin(Node<K,V>[] tab, int index) {
- Node<K,V> b; int n, sc;
+ Node<K,V> b; int n;
if (tab != null) {
if ((n = tab.length) < MIN_TREEIFY_CAPACITY)
tryPresize(n << 1);
@@ -2693,7 +2700,7 @@
/* ---------------- TreeNodes -------------- */
/**
- * Nodes for use in TreeBins
+ * Nodes for use in TreeBins.
*/
static final class TreeNode<K,V> extends Node<K,V> {
TreeNode<K,V> parent; // red-black tree links
@@ -2719,7 +2726,7 @@
final TreeNode<K,V> findTreeNode(int h, Object k, Class<?> kc) {
if (k != null) {
TreeNode<K,V> p = this;
- do {
+ do {
int ph, dir; K pk; TreeNode<K,V> q;
TreeNode<K,V> pl = p.left, pr = p.right;
if ((ph = p.hash) > h)
@@ -2812,7 +2819,7 @@
(kc = comparableClassFor(k)) == null) ||
(dir = compareComparables(kc, k, pk)) == 0)
dir = tieBreakOrder(k, pk);
- TreeNode<K,V> xp = p;
+ TreeNode<K,V> xp = p;
if ((p = (dir <= 0) ? p.left : p.right) == null) {
x.parent = xp;
if (dir <= 0)
@@ -3165,7 +3172,7 @@
static <K,V> TreeNode<K,V> balanceDeletion(TreeNode<K,V> root,
TreeNode<K,V> x) {
- for (TreeNode<K,V> xp, xpl, xpr;;) {
+ for (TreeNode<K,V> xp, xpl, xpr;;) {
if (x == null || x == root)
return root;
else if ((xp = x.parent) == null) {
@@ -3256,7 +3263,7 @@
}
/**
- * Recursive invariant check
+ * Checks invariants recursively for the tree of Nodes rooted at t.
*/
static <K,V> boolean checkInvariants(TreeNode<K,V> t) {
TreeNode<K,V> tp = t.parent, tl = t.left, tr = t.right,
@@ -3280,15 +3287,13 @@
return true;
}
- private static final sun.misc.Unsafe U;
+ private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
private static final long LOCKSTATE;
static {
try {
- U = sun.misc.Unsafe.getUnsafe();
- Class<?> k = TreeBin.class;
LOCKSTATE = U.objectFieldOffset
- (k.getDeclaredField("lockState"));
- } catch (Exception e) {
+ (TreeBin.class.getDeclaredField("lockState"));
+ } catch (ReflectiveOperationException e) {
throw new Error(e);
}
}
@@ -3503,7 +3508,7 @@
}
/**
- * Exported Entry for EntryIterator
+ * Exported Entry for EntryIterator.
*/
static final class MapEntry<K,V> implements Map.Entry<K,V> {
final K key; // non-null
@@ -3517,7 +3522,9 @@
public K getKey() { return key; }
public V getValue() { return val; }
public int hashCode() { return key.hashCode() ^ val.hashCode(); }
- public String toString() { return key + "=" + val; }
+ public String toString() {
+ return Helpers.mapEntryToString(key, val);
+ }
public boolean equals(Object o) {
Object k, v; Map.Entry<?,?> e;
@@ -3554,7 +3561,7 @@
this.est = est;
}
- public Spliterator<K> trySplit() {
+ public KeySpliterator<K,V> trySplit() {
int i, f, h;
return (h = ((i = baseIndex) + (f = baseLimit)) >>> 1) <= i ? null :
new KeySpliterator<K,V>(tab, baseSize, baseLimit = h,
@@ -3593,7 +3600,7 @@
this.est = est;
}
- public Spliterator<V> trySplit() {
+ public ValueSpliterator<K,V> trySplit() {
int i, f, h;
return (h = ((i = baseIndex) + (f = baseLimit)) >>> 1) <= i ? null :
new ValueSpliterator<K,V>(tab, baseSize, baseLimit = h,
@@ -3633,7 +3640,7 @@
this.est = est;
}
- public Spliterator<Map.Entry<K,V>> trySplit() {
+ public EntrySpliterator<K,V> trySplit() {
int i, f, h;
return (h = ((i = baseIndex) + (f = baseLimit)) >>> 1) <= i ? null :
new EntrySpliterator<K,V>(tab, baseSize, baseLimit = h,
@@ -4445,19 +4452,19 @@
public abstract boolean contains(Object o);
public abstract boolean remove(Object o);
- private static final String oomeMsg = "Required array size too large";
+ private static final String OOME_MSG = "Required array size too large";
public final Object[] toArray() {
long sz = map.mappingCount();
if (sz > MAX_ARRAY_SIZE)
- throw new OutOfMemoryError(oomeMsg);
+ throw new OutOfMemoryError(OOME_MSG);
int n = (int)sz;
Object[] r = new Object[n];
int i = 0;
for (E e : this) {
if (i == n) {
if (n >= MAX_ARRAY_SIZE)
- throw new OutOfMemoryError(oomeMsg);
+ throw new OutOfMemoryError(OOME_MSG);
if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1)
n = MAX_ARRAY_SIZE;
else
@@ -4473,7 +4480,7 @@
public final <T> T[] toArray(T[] a) {
long sz = map.mappingCount();
if (sz > MAX_ARRAY_SIZE)
- throw new OutOfMemoryError(oomeMsg);
+ throw new OutOfMemoryError(OOME_MSG);
int m = (int)sz;
T[] r = (a.length >= m) ? a :
(T[])java.lang.reflect.Array
@@ -4483,7 +4490,7 @@
for (E e : this) {
if (i == n) {
if (n >= MAX_ARRAY_SIZE)
- throw new OutOfMemoryError(oomeMsg);
+ throw new OutOfMemoryError(OOME_MSG);
if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1)
n = MAX_ARRAY_SIZE;
else
@@ -4803,7 +4810,7 @@
return added;
}
- public boolean removeIf(Predicate<? super Entry<K, V>> filter) {
+ public boolean removeIf(Predicate<? super Entry<K,V>> filter) {
return map.removeEntryIf(filter);
}
@@ -4878,7 +4885,7 @@
}
/**
- * Same as Traverser version
+ * Same as Traverser version.
*/
final Node<K,V> advance() {
Node<K,V> e;
@@ -6323,38 +6330,40 @@
}
// Unsafe mechanics
- private static final sun.misc.Unsafe U;
+ private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
private static final long SIZECTL;
private static final long TRANSFERINDEX;
private static final long BASECOUNT;
private static final long CELLSBUSY;
private static final long CELLVALUE;
- private static final long ABASE;
+ private static final int ABASE;
private static final int ASHIFT;
static {
try {
- U = sun.misc.Unsafe.getUnsafe();
- Class<?> k = ConcurrentHashMap.class;
SIZECTL = U.objectFieldOffset
- (k.getDeclaredField("sizeCtl"));
+ (ConcurrentHashMap.class.getDeclaredField("sizeCtl"));
TRANSFERINDEX = U.objectFieldOffset
- (k.getDeclaredField("transferIndex"));
+ (ConcurrentHashMap.class.getDeclaredField("transferIndex"));
BASECOUNT = U.objectFieldOffset
- (k.getDeclaredField("baseCount"));
+ (ConcurrentHashMap.class.getDeclaredField("baseCount"));
CELLSBUSY = U.objectFieldOffset
- (k.getDeclaredField("cellsBusy"));
- Class<?> ck = CounterCell.class;
+ (ConcurrentHashMap.class.getDeclaredField("cellsBusy"));
+
CELLVALUE = U.objectFieldOffset
- (ck.getDeclaredField("value"));
- Class<?> ak = Node[].class;
- ABASE = U.arrayBaseOffset(ak);
- int scale = U.arrayIndexScale(ak);
+ (CounterCell.class.getDeclaredField("value"));
+
+ ABASE = U.arrayBaseOffset(Node[].class);
+ int scale = U.arrayIndexScale(Node[].class);
if ((scale & (scale - 1)) != 0)
- throw new Error("data type scale not a power of two");
+ throw new Error("array index scale not a power of two");
ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
- } catch (Exception e) {
+ } catch (ReflectiveOperationException e) {
throw new Error(e);
}
+
+ // Reduce the risk of rare disastrous classloading in first call to
+ // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+ Class<?> ensureLoaded = LockSupport.class;
}
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java Tue Oct 13 16:45:35 2015 -0700
@@ -36,11 +36,12 @@
package java.util.concurrent;
import java.util.AbstractCollection;
-import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Deque;
import java.util.Iterator;
import java.util.NoSuchElementException;
+import java.util.Objects;
import java.util.Queue;
import java.util.Spliterator;
import java.util.Spliterators;
@@ -87,7 +88,7 @@
* @since 1.7
* @author Doug Lea
* @author Martin Buchholz
- * @param <E> the type of elements held in this collection
+ * @param <E> the type of elements held in this deque
*/
public class ConcurrentLinkedDeque<E>
extends AbstractCollection<E>
@@ -300,47 +301,45 @@
* only be seen after publication via casNext or casPrev.
*/
Node(E item) {
- UNSAFE.putObject(this, itemOffset, item);
+ U.putObject(this, ITEM, item);
}
boolean casItem(E cmp, E val) {
- return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);
+ return U.compareAndSwapObject(this, ITEM, cmp, val);
}
void lazySetNext(Node<E> val) {
- UNSAFE.putOrderedObject(this, nextOffset, val);
+ U.putOrderedObject(this, NEXT, val);
}
boolean casNext(Node<E> cmp, Node<E> val) {
- return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
+ return U.compareAndSwapObject(this, NEXT, cmp, val);
}
void lazySetPrev(Node<E> val) {
- UNSAFE.putOrderedObject(this, prevOffset, val);
+ U.putOrderedObject(this, PREV, val);
}
boolean casPrev(Node<E> cmp, Node<E> val) {
- return UNSAFE.compareAndSwapObject(this, prevOffset, cmp, val);
+ return U.compareAndSwapObject(this, PREV, cmp, val);
}
// Unsafe mechanics
- private static final sun.misc.Unsafe UNSAFE;
- private static final long prevOffset;
- private static final long itemOffset;
- private static final long nextOffset;
+ private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+ private static final long PREV;
+ private static final long ITEM;
+ private static final long NEXT;
static {
try {
- UNSAFE = sun.misc.Unsafe.getUnsafe();
- Class<?> k = Node.class;
- prevOffset = UNSAFE.objectFieldOffset
- (k.getDeclaredField("prev"));
- itemOffset = UNSAFE.objectFieldOffset
- (k.getDeclaredField("item"));
- nextOffset = UNSAFE.objectFieldOffset
- (k.getDeclaredField("next"));
- } catch (Exception e) {
+ PREV = U.objectFieldOffset
+ (Node.class.getDeclaredField("prev"));
+ ITEM = U.objectFieldOffset
+ (Node.class.getDeclaredField("item"));
+ NEXT = U.objectFieldOffset
+ (Node.class.getDeclaredField("next"));
+ } catch (ReflectiveOperationException e) {
throw new Error(e);
}
}
@@ -350,8 +349,7 @@
* Links e as first element.
*/
private void linkFirst(E e) {
- checkNotNull(e);
- final Node<E> newNode = new Node<E>(e);
+ final Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
restartFromHead:
for (;;)
@@ -383,8 +381,7 @@
* Links e as last element.
*/
private void linkLast(E e) {
- checkNotNull(e);
- final Node<E> newNode = new Node<E>(e);
+ final Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
restartFromTail:
for (;;)
@@ -789,16 +786,6 @@
// Minor convenience utilities
/**
- * Throws NullPointerException if argument is null.
- *
- * @param v the element
- */
- private static void checkNotNull(Object v) {
- if (v == null)
- throw new NullPointerException();
- }
-
- /**
* Returns element unless it is null, in which case throws
* NoSuchElementException.
*
@@ -812,22 +799,6 @@
}
/**
- * Creates an array list and fills it with elements of this list.
- * Used by toArray.
- *
- * @return the array list
- */
- private ArrayList<E> toArrayList() {
- ArrayList<E> list = new ArrayList<E>();
- for (Node<E> p = first(); p != null; p = succ(p)) {
- E item = p.item;
- if (item != null)
- list.add(item);
- }
- return list;
- }
-
- /**
* Constructs an empty deque.
*/
public ConcurrentLinkedDeque() {
@@ -847,8 +818,7 @@
// Copy c into a private chain of Nodes
Node<E> h = null, t = null;
for (E e : c) {
- checkNotNull(e);
- Node<E> newNode = new Node<E>(e);
+ Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
if (h == null)
h = t = newNode;
else {
@@ -1046,16 +1016,19 @@
public void push(E e) { addFirst(e); }
/**
- * Removes the first element {@code e} such that
- * {@code o.equals(e)}, if such an element exists in this deque.
+ * Removes the first occurrence of the specified element from this deque.
* If the deque does not contain the element, it is unchanged.
+ * More formally, removes the first element {@code e} such that
+ * {@code o.equals(e)} (if such an element exists).
+ * Returns {@code true} if this deque contained the specified element
+ * (or equivalently, if this deque changed as a result of the call).
*
* @param o element to be removed from this deque, if present
* @return {@code true} if the deque contained the specified element
* @throws NullPointerException if the specified element is null
*/
public boolean removeFirstOccurrence(Object o) {
- checkNotNull(o);
+ Objects.requireNonNull(o);
for (Node<E> p = first(); p != null; p = succ(p)) {
E item = p.item;
if (item != null && o.equals(item) && p.casItem(item, null)) {
@@ -1067,16 +1040,19 @@
}
/**
- * Removes the last element {@code e} such that
- * {@code o.equals(e)}, if such an element exists in this deque.
+ * Removes the last occurrence of the specified element from this deque.
* If the deque does not contain the element, it is unchanged.
+ * More formally, removes the last element {@code e} such that
+ * {@code o.equals(e)} (if such an element exists).
+ * Returns {@code true} if this deque contained the specified element
+ * (or equivalently, if this deque changed as a result of the call).
*
* @param o element to be removed from this deque, if present
* @return {@code true} if the deque contained the specified element
* @throws NullPointerException if the specified element is null
*/
public boolean removeLastOccurrence(Object o) {
- checkNotNull(o);
+ Objects.requireNonNull(o);
for (Node<E> p = last(); p != null; p = pred(p)) {
E item = p.item;
if (item != null && o.equals(item) && p.casItem(item, null)) {
@@ -1088,18 +1064,20 @@
}
/**
- * Returns {@code true} if this deque contains at least one
- * element {@code e} such that {@code o.equals(e)}.
+ * Returns {@code true} if this deque contains the specified element.
+ * More formally, returns {@code true} if and only if this deque contains
+ * at least one element {@code e} such that {@code o.equals(e)}.
*
* @param o element whose presence in this deque is to be tested
* @return {@code true} if this deque contains the specified element
*/
public boolean contains(Object o) {
- if (o == null) return false;
- for (Node<E> p = first(); p != null; p = succ(p)) {
- E item = p.item;
- if (item != null && o.equals(item))
- return true;
+ if (o != null) {
+ for (Node<E> p = first(); p != null; p = succ(p)) {
+ E item = p.item;
+ if (item != null && o.equals(item))
+ return true;
+ }
}
return false;
}
@@ -1130,19 +1108,28 @@
* @return the number of elements in this deque
*/
public int size() {
- int count = 0;
- for (Node<E> p = first(); p != null; p = succ(p))
- if (p.item != null)
- // Collection.size() spec says to max out
- if (++count == Integer.MAX_VALUE)
- break;
- return count;
+ restartFromHead: for (;;) {
+ int count = 0;
+ for (Node<E> p = first(); p != null;) {
+ if (p.item != null)
+ if (++count == Integer.MAX_VALUE)
+ break; // @see Collection.size()
+ if (p == (p = p.next))
+ continue restartFromHead;
+ }
+ return count;
+ }
}
/**
- * Removes the first element {@code e} such that
- * {@code o.equals(e)}, if such an element exists in this deque.
+ * Removes the first occurrence of the specified element from this deque.
* If the deque does not contain the element, it is unchanged.
+ * More formally, removes the first element {@code e} such that
+ * {@code o.equals(e)} (if such an element exists).
+ * Returns {@code true} if this deque contained the specified element
+ * (or equivalently, if this deque changed as a result of the call).
+ *
+ * <p>This method is equivalent to {@link #removeFirstOccurrence(Object)}.
*
* @param o element to be removed from this deque, if present
* @return {@code true} if the deque contained the specified element
@@ -1172,8 +1159,7 @@
// Copy c into a private chain of Nodes
Node<E> beginningOfTheEnd = null, last = null;
for (E e : c) {
- checkNotNull(e);
- Node<E> newNode = new Node<E>(e);
+ Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
if (beginningOfTheEnd == null)
beginningOfTheEnd = last = newNode;
else {
@@ -1224,6 +1210,62 @@
;
}
+ public String toString() {
+ String[] a = null;
+ restartFromHead: for (;;) {
+ int charLength = 0;
+ int size = 0;
+ for (Node<E> p = first(); p != null;) {
+ E item = p.item;
+ if (item != null) {
+ if (a == null)
+ a = new String[4];
+ else if (size == a.length)
+ a = Arrays.copyOf(a, 2 * size);
+ String s = item.toString();
+ a[size++] = s;
+ charLength += s.length();
+ }
+ if (p == (p = p.next))
+ continue restartFromHead;
+ }
+
+ if (size == 0)
+ return "[]";
+
+ return Helpers.toString(a, size, charLength);
+ }
+ }
+
+ private Object[] toArrayInternal(Object[] a) {
+ Object[] x = a;
+ restartFromHead: for (;;) {
+ int size = 0;
+ for (Node<E> p = first(); p != null;) {
+ E item = p.item;
+ if (item != null) {
+ if (x == null)
+ x = new Object[4];
+ else if (size == x.length)
+ x = Arrays.copyOf(x, 2 * (size + 4));
+ x[size++] = item;
+ }
+ if (p == (p = p.next))
+ continue restartFromHead;
+ }
+ if (x == null)
+ return new Object[0];
+ else if (a != null && size <= a.length) {
+ if (a != x)
+ System.arraycopy(x, 0, a, 0, size);
+ if (size < a.length)
+ a[size] = null;
+ return a;
+ }
+ return (size == x.length) ? x : Arrays.copyOf(x, size);
+ }
+ }
+
/**
* Returns an array containing all of the elements in this deque, in
* proper sequence (from first to last element).
@@ -1238,7 +1280,7 @@
* @return an array containing all of the elements in this deque
*/
public Object[] toArray() {
- return toArrayList().toArray();
+ return toArrayInternal(null);
}
/**
@@ -1264,7 +1306,7 @@
* The following code can be used to dump the deque into a newly
* allocated array of {@code String}:
*
- * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+ * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
*
* Note that {@code toArray(new Object[0])} is identical in function to
* {@code toArray()}.
@@ -1278,8 +1320,10 @@
* this deque
* @throws NullPointerException if the specified array is null
*/
+ @SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
- return toArrayList().toArray(a);
+ if (a == null) throw new NullPointerException();
+ return (T[]) toArrayInternal(a);
}
/**
@@ -1346,7 +1390,7 @@
Node<E> p = (nextNode == null) ? startNode() : nextNode(nextNode);
for (;; p = nextNode(p)) {
if (p == null) {
- // p might be active end or TERMINATOR node; both are OK
+ // might be at active end or TERMINATOR node; both are OK
nextNode = null;
nextItem = null;
break;
@@ -1426,8 +1470,9 @@
if (i > 0) {
batch = i;
return Spliterators.spliterator
- (a, 0, i, Spliterator.ORDERED | Spliterator.NONNULL |
- Spliterator.CONCURRENT);
+ (a, 0, i, (Spliterator.ORDERED |
+ Spliterator.NONNULL |
+ Spliterator.CONCURRENT));
}
}
}
@@ -1539,8 +1584,7 @@
// Read in elements until trailing null sentinel found
Node<E> h = null, t = null;
- Object item;
- while ((item = s.readObject()) != null) {
+ for (Object item; (item = s.readObject()) != null; ) {
@SuppressWarnings("unchecked")
Node<E> newNode = new Node<E>((E) item);
if (h == null)
@@ -1555,31 +1599,29 @@
}
private boolean casHead(Node<E> cmp, Node<E> val) {
- return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val);
+ return U.compareAndSwapObject(this, HEAD, cmp, val);
}
private boolean casTail(Node<E> cmp, Node<E> val) {
- return UNSAFE.compareAndSwapObject(this, tailOffset, cmp, val);
+ return U.compareAndSwapObject(this, TAIL, cmp, val);
}
// Unsafe mechanics
- private static final sun.misc.Unsafe UNSAFE;
- private static final long headOffset;
- private static final long tailOffset;
+ private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+ private static final long HEAD;
+ private static final long TAIL;
static {
PREV_TERMINATOR = new Node<Object>();
PREV_TERMINATOR.next = PREV_TERMINATOR;
NEXT_TERMINATOR = new Node<Object>();
NEXT_TERMINATOR.prev = NEXT_TERMINATOR;
try {
- UNSAFE = sun.misc.Unsafe.getUnsafe();
- Class<?> k = ConcurrentLinkedDeque.class;
- headOffset = UNSAFE.objectFieldOffset
- (k.getDeclaredField("head"));
- tailOffset = UNSAFE.objectFieldOffset
- (k.getDeclaredField("tail"));
- } catch (Exception e) {
+ HEAD = U.objectFieldOffset
+ (ConcurrentLinkedDeque.class.getDeclaredField("head"));
+ TAIL = U.objectFieldOffset
+ (ConcurrentLinkedDeque.class.getDeclaredField("tail"));
+ } catch (ReflectiveOperationException e) {
throw new Error(e);
}
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java Tue Oct 13 16:45:35 2015 -0700
@@ -36,10 +36,11 @@
package java.util.concurrent;
import java.util.AbstractQueue;
-import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
+import java.util.Objects;
import java.util.Queue;
import java.util.Spliterator;
import java.util.Spliterators;
@@ -60,9 +61,9 @@
* does not permit the use of {@code null} elements.
*
* <p>This implementation employs an efficient <em>non-blocking</em>
- * algorithm based on one described in <a
- * href="http://www.cs.rochester.edu/u/michael/PODC96.html"> Simple,
- * Fast, and Practical Non-Blocking and Blocking Concurrent Queue
+ * algorithm based on one described in
+ * <a href="http://www.cs.rochester.edu/~scott/papers/1996_PODC_queues.pdf">
+ * Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue
* Algorithms</a> by Maged M. Michael and Michael L. Scott.
*
* <p>Iterators are <i>weakly consistent</i>, returning elements
@@ -100,7 +101,7 @@
*
* @since 1.5
* @author Doug Lea
- * @param <E> the type of elements held in this collection
+ * @param <E> the type of elements held in this queue
*/
public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
implements Queue<E>, java.io.Serializable {
@@ -180,45 +181,28 @@
private static class Node<E> {
volatile E item;
volatile Node<E> next;
-
- /**
- * Constructs a new node. Uses relaxed write because item can
- * only be seen after publication via casNext.
- */
- Node(E item) {
- UNSAFE.putObject(this, itemOffset, item);
- }
-
- boolean casItem(E cmp, E val) {
- return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);
- }
-
- void lazySetNext(Node<E> val) {
- UNSAFE.putOrderedObject(this, nextOffset, val);
- }
+ }
- boolean casNext(Node<E> cmp, Node<E> val) {
- return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
- }
-
- // Unsafe mechanics
-
- private static final sun.misc.Unsafe UNSAFE;
- private static final long itemOffset;
- private static final long nextOffset;
+ /**
+ * Returns a new node holding item. Uses relaxed write because item
+ * can only be seen after piggy-backing publication via casNext.
+ */
+ static <E> Node<E> newNode(E item) {
+ Node<E> node = new Node<E>();
+ U.putObject(node, ITEM, item);
+ return node;
+ }
- static {
- try {
- UNSAFE = sun.misc.Unsafe.getUnsafe();
- Class<?> k = Node.class;
- itemOffset = UNSAFE.objectFieldOffset
- (k.getDeclaredField("item"));
- nextOffset = UNSAFE.objectFieldOffset
- (k.getDeclaredField("next"));
- } catch (Exception e) {
- throw new Error(e);
- }
- }
+ static <E> boolean casItem(Node<E> node, E cmp, E val) {
+ return U.compareAndSwapObject(node, ITEM, cmp, val);
+ }
+
+ static <E> void lazySetNext(Node<E> node, Node<E> val) {
+ U.putOrderedObject(node, NEXT, val);
+ }
+
+ static <E> boolean casNext(Node<E> node, Node<E> cmp, Node<E> val) {
+ return U.compareAndSwapObject(node, NEXT, cmp, val);
}
/**
@@ -233,7 +217,7 @@
* - it is permitted for tail to lag behind head, that is, for tail
* to not be reachable from head!
*/
- private transient volatile Node<E> head;
+ transient volatile Node<E> head;
/**
* A node from which the last node on list (that is, the unique
@@ -253,7 +237,7 @@
* Creates a {@code ConcurrentLinkedQueue} that is initially empty.
*/
public ConcurrentLinkedQueue() {
- head = tail = new Node<E>(null);
+ head = tail = newNode(null);
}
/**
@@ -268,17 +252,16 @@
public ConcurrentLinkedQueue(Collection<? extends E> c) {
Node<E> h = null, t = null;
for (E e : c) {
- checkNotNull(e);
- Node<E> newNode = new Node<E>(e);
+ Node<E> newNode = newNode(Objects.requireNonNull(e));
if (h == null)
h = t = newNode;
else {
- t.lazySetNext(newNode);
+ lazySetNext(t, newNode);
t = newNode;
}
}
if (h == null)
- h = t = new Node<E>(null);
+ h = t = newNode(null);
head = h;
tail = t;
}
@@ -302,8 +285,9 @@
* as sentinel for succ(), below.
*/
final void updateHead(Node<E> h, Node<E> p) {
+ // assert h != null && p != null && (h == p || h.item == null);
if (h != p && casHead(h, p))
- h.lazySetNext(h);
+ lazySetNext(h, h);
}
/**
@@ -324,14 +308,13 @@
* @throws NullPointerException if the specified element is null
*/
public boolean offer(E e) {
- checkNotNull(e);
- final Node<E> newNode = new Node<E>(e);
+ final Node<E> newNode = newNode(Objects.requireNonNull(e));
for (Node<E> t = tail, p = t;;) {
Node<E> q = p.next;
if (q == null) {
// p is last node
- if (p.casNext(null, newNode)) {
+ if (casNext(p, null, newNode)) {
// Successful CAS is the linearization point
// for e to become an element of this queue,
// and for newNode to become "live".
@@ -359,7 +342,7 @@
for (Node<E> h = head, p = h, q;;) {
E item = p.item;
- if (item != null && p.casItem(item, null)) {
+ if (item != null && casItem(p, item, null)) {
// Successful CAS is the linearization point
// for item to be removed from this queue.
if (p != h) // hop two nodes at a time
@@ -446,13 +429,17 @@
* @return the number of elements in this queue
*/
public int size() {
- int count = 0;
- for (Node<E> p = first(); p != null; p = succ(p))
- if (p.item != null)
- // Collection.size() spec says to max out
- if (++count == Integer.MAX_VALUE)
- break;
- return count;
+ restartFromHead: for (;;) {
+ int count = 0;
+ for (Node<E> p = first(); p != null;) {
+ if (p.item != null)
+ if (++count == Integer.MAX_VALUE)
+ break; // @see Collection.size()
+ if (p == (p = p.next))
+ continue restartFromHead;
+ }
+ return count;
+ }
}
/**
@@ -464,11 +451,12 @@
* @return {@code true} if this queue contains the specified element
*/
public boolean contains(Object o) {
- if (o == null) return false;
- for (Node<E> p = first(); p != null; p = succ(p)) {
- E item = p.item;
- if (item != null && o.equals(item))
- return true;
+ if (o != null) {
+ for (Node<E> p = first(); p != null; p = succ(p)) {
+ E item = p.item;
+ if (item != null && o.equals(item))
+ return true;
+ }
}
return false;
}
@@ -485,19 +473,25 @@
* @return {@code true} if this queue changed as a result of the call
*/
public boolean remove(Object o) {
- if (o == null) return false;
- Node<E> pred = null;
- for (Node<E> p = first(); p != null; p = succ(p)) {
- E item = p.item;
- if (item != null &&
- o.equals(item) &&
- p.casItem(item, null)) {
- Node<E> next = succ(p);
- if (pred != null && next != null)
- pred.casNext(p, next);
- return true;
+ if (o != null) {
+ Node<E> next, pred = null;
+ for (Node<E> p = first(); p != null; pred = p, p = next) {
+ boolean removed = false;
+ E item = p.item;
+ if (item != null) {
+ if (!o.equals(item)) {
+ next = succ(p);
+ continue;
+ }
+ removed = casItem(p, item, null);
+ }
+
+ next = succ(p);
+ if (pred != null && next != null) // unlink
+ casNext(pred, p, next);
+ if (removed)
+ return true;
}
- pred = p;
}
return false;
}
@@ -522,12 +516,11 @@
// Copy c into a private chain of Nodes
Node<E> beginningOfTheEnd = null, last = null;
for (E e : c) {
- checkNotNull(e);
- Node<E> newNode = new Node<E>(e);
+ Node<E> newNode = newNode(Objects.requireNonNull(e));
if (beginningOfTheEnd == null)
beginningOfTheEnd = last = newNode;
else {
- last.lazySetNext(newNode);
+ lazySetNext(last, newNode);
last = newNode;
}
}
@@ -539,7 +532,7 @@
Node<E> q = p.next;
if (q == null) {
// p is last node
- if (p.casNext(null, beginningOfTheEnd)) {
+ if (casNext(p, null, beginningOfTheEnd)) {
// Successful CAS is the linearization point
// for all elements to be added to this queue.
if (!casTail(t, last)) {
@@ -565,6 +558,62 @@
}
}
+ public String toString() {
+ String[] a = null;
+ restartFromHead: for (;;) {
+ int charLength = 0;
+ int size = 0;
+ for (Node<E> p = first(); p != null;) {
+ E item = p.item;
+ if (item != null) {
+ if (a == null)
+ a = new String[4];
+ else if (size == a.length)
+ a = Arrays.copyOf(a, 2 * size);
+ String s = item.toString();
+ a[size++] = s;
+ charLength += s.length();
+ }
+ if (p == (p = p.next))
+ continue restartFromHead;
+ }
+
+ if (size == 0)
+ return "[]";
+
+ return Helpers.toString(a, size, charLength);
+ }
+ }
+
+ private Object[] toArrayInternal(Object[] a) {
+ Object[] x = a;
+ restartFromHead: for (;;) {
+ int size = 0;
+ for (Node<E> p = first(); p != null;) {
+ E item = p.item;
+ if (item != null) {
+ if (x == null)
+ x = new Object[4];
+ else if (size == x.length)
+ x = Arrays.copyOf(x, 2 * (size + 4));
+ x[size++] = item;
+ }
+ if (p == (p = p.next))
+ continue restartFromHead;
+ }
+ if (x == null)
+ return new Object[0];
+ else if (a != null && size <= a.length) {
+ if (a != x)
+ System.arraycopy(x, 0, a, 0, size);
+ if (size < a.length)
+ a[size] = null;
+ return a;
+ }
+ return (size == x.length) ? x : Arrays.copyOf(x, size);
+ }
+ }
+
/**
* Returns an array containing all of the elements in this queue, in
* proper sequence.
@@ -579,14 +628,7 @@
* @return an array containing all of the elements in this queue
*/
public Object[] toArray() {
- // Use ArrayList to deal with resizing.
- ArrayList<E> al = new ArrayList<E>();
- for (Node<E> p = first(); p != null; p = succ(p)) {
- E item = p.item;
- if (item != null)
- al.add(item);
- }
- return al.toArray();
+ return toArrayInternal(null);
}
/**
@@ -610,7 +652,7 @@
* The following code can be used to dump the queue into a newly
* allocated array of {@code String}:
*
- * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+ * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
*
* Note that {@code toArray(new Object[0])} is identical in function to
* {@code toArray()}.
@@ -626,28 +668,8 @@
*/
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
- // try to use sent-in array
- int k = 0;
- Node<E> p;
- for (p = first(); p != null && k < a.length; p = succ(p)) {
- E item = p.item;
- if (item != null)
- a[k++] = (T)item;
- }
- if (p == null) {
- if (k < a.length)
- a[k] = null;
- return a;
- }
-
- // If won't fit, use ArrayList version
- ArrayList<E> al = new ArrayList<E>();
- for (Node<E> q = first(); q != null; q = succ(q)) {
- E item = q.item;
- if (item != null)
- al.add(item);
- }
- return al.toArray(a);
+ if (a == null) throw new NullPointerException();
+ return (T[]) toArrayInternal(a);
}
/**
@@ -683,54 +705,47 @@
private Node<E> lastRet;
Itr() {
- advance();
- }
-
- /**
- * Moves to next valid node and returns item to return for
- * next(), or null if no such.
- */
- private E advance() {
- lastRet = nextNode;
- E x = nextItem;
-
- Node<E> pred, p;
- if (nextNode == null) {
- p = first();
- pred = null;
- } else {
- pred = nextNode;
- p = succ(nextNode);
- }
-
- for (;;) {
- if (p == null) {
- nextNode = null;
- nextItem = null;
- return x;
+ restartFromHead: for (;;) {
+ Node<E> h, p, q;
+ for (p = h = head;; p = q) {
+ E item;
+ if ((item = p.item) != null) {
+ nextNode = p;
+ nextItem = item;
+ break;
+ }
+ else if ((q = p.next) == null)
+ break;
+ else if (p == q)
+ continue restartFromHead;
}
- E item = p.item;
- if (item != null) {
- nextNode = p;
- nextItem = item;
- return x;
- } else {
- // skip over nulls
- Node<E> next = succ(p);
- if (pred != null && next != null)
- pred.casNext(p, next);
- p = next;
- }
+ updateHead(h, p);
+ return;
}
}
public boolean hasNext() {
- return nextNode != null;
+ return nextItem != null;
}
public E next() {
- if (nextNode == null) throw new NoSuchElementException();
- return advance();
+ final Node<E> pred = nextNode;
+ if (pred == null) throw new NoSuchElementException();
+ // assert nextItem != null;
+ lastRet = pred;
+ E item = null;
+
+ for (Node<E> p = succ(pred), q;; p = q) {
+ if (p == null || (item = p.item) != null) {
+ nextNode = p;
+ E x = nextItem;
+ nextItem = item;
+ return x;
+ }
+ // unlink deleted nodes
+ if ((q = succ(p)) != null)
+ casNext(pred, p, q);
+ }
}
public void remove() {
@@ -780,19 +795,18 @@
// Read in elements until trailing null sentinel found
Node<E> h = null, t = null;
- Object item;
- while ((item = s.readObject()) != null) {
+ for (Object item; (item = s.readObject()) != null; ) {
@SuppressWarnings("unchecked")
- Node<E> newNode = new Node<E>((E) item);
+ Node<E> newNode = newNode((E) item);
if (h == null)
h = t = newNode;
else {
- t.lazySetNext(newNode);
+ lazySetNext(t, newNode);
t = newNode;
}
}
if (h == null)
- h = t = new Node<E>(null);
+ h = t = newNode(null);
head = h;
tail = t;
}
@@ -829,8 +843,9 @@
if (i > 0) {
batch = i;
return Spliterators.spliterator
- (a, 0, i, Spliterator.ORDERED | Spliterator.NONNULL |
- Spliterator.CONCURRENT);
+ (a, 0, i, (Spliterator.ORDERED |
+ Spliterator.NONNULL |
+ Spliterator.CONCURRENT));
}
}
return null;
@@ -904,38 +919,32 @@
return new CLQSpliterator<E>(this);
}
- /**
- * Throws NullPointerException if argument is null.
- *
- * @param v the element
- */
- private static void checkNotNull(Object v) {
- if (v == null)
- throw new NullPointerException();
- }
-
private boolean casTail(Node<E> cmp, Node<E> val) {
- return UNSAFE.compareAndSwapObject(this, tailOffset, cmp, val);
+ return U.compareAndSwapObject(this, TAIL, cmp, val);
}
private boolean casHead(Node<E> cmp, Node<E> val) {
- return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val);
+ return U.compareAndSwapObject(this, HEAD, cmp, val);
}
// Unsafe mechanics
- private static final sun.misc.Unsafe UNSAFE;
- private static final long headOffset;
- private static final long tailOffset;
+ private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+ private static final long HEAD;
+ private static final long TAIL;
+ private static final long ITEM;
+ private static final long NEXT;
static {
try {
- UNSAFE = sun.misc.Unsafe.getUnsafe();
- Class<?> k = ConcurrentLinkedQueue.class;
- headOffset = UNSAFE.objectFieldOffset
- (k.getDeclaredField("head"));
- tailOffset = UNSAFE.objectFieldOffset
- (k.getDeclaredField("tail"));
- } catch (Exception e) {
+ HEAD = U.objectFieldOffset
+ (ConcurrentLinkedQueue.class.getDeclaredField("head"));
+ TAIL = U.objectFieldOffset
+ (ConcurrentLinkedQueue.class.getDeclaredField("tail"));
+ ITEM = U.objectFieldOffset
+ (Node.class.getDeclaredField("item"));
+ NEXT = U.objectFieldOffset
+ (Node.class.getDeclaredField("next"));
+ } catch (ReflectiveOperationException e) {
throw new Error(e);
}
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentMap.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentMap.java Tue Oct 13 16:45:35 2015 -0700
@@ -89,7 +89,7 @@
return ((v = get(key)) != null) ? v : defaultValue;
}
- /**
+ /**
* {@inheritDoc}
*
* @implSpec The default implementation is equivalent to, for this
@@ -181,10 +181,10 @@
* is not supported by this map
* @throws ClassCastException if the key or value is of an inappropriate
* type for this map
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified key or value is null,
* and this map does not permit null keys or values
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
*/
boolean remove(Object key, Object value);
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentNavigableMap.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentNavigableMap.java Tue Oct 13 16:45:35 2015 -0700
@@ -34,7 +34,9 @@
*/
package java.util.concurrent;
-import java.util.*;
+
+import java.util.NavigableMap;
+import java.util.NavigableSet;
/**
* A {@link ConcurrentMap} supporting {@link NavigableMap} operations,
@@ -101,7 +103,7 @@
* reflected in the descending map, and vice-versa.
*
* <p>The returned map has an ordering equivalent to
- * {@link Collections#reverseOrder(Comparator) Collections.reverseOrder}{@code (comparator())}.
+ * {@link java.util.Collections#reverseOrder(Comparator) Collections.reverseOrder}{@code (comparator())}.
* The expression {@code m.descendingMap().descendingMap()} returns a
* view of {@code m} essentially equivalent to {@code m}.
*
@@ -125,7 +127,7 @@
*
* @return a navigable set view of the keys in this map
*/
- public NavigableSet<K> navigableKeySet();
+ NavigableSet<K> navigableKeySet();
/**
* Returns a {@link NavigableSet} view of the keys contained in this map.
@@ -163,5 +165,5 @@
*
* @return a reverse order navigable set view of the keys in this map
*/
- public NavigableSet<K> descendingKeySet();
+ NavigableSet<K> descendingKeySet();
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java Tue Oct 13 16:45:35 2015 -0700
@@ -34,6 +34,7 @@
*/
package java.util.concurrent;
+
import java.io.Serializable;
import java.util.AbstractCollection;
import java.util.AbstractMap;
@@ -50,13 +51,10 @@
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.SortedMap;
-import java.util.SortedSet;
import java.util.Spliterator;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.ConcurrentNavigableMap;
+import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
-import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Predicate;
@@ -359,9 +357,9 @@
private static final long serialVersionUID = -8627078645895051609L;
/**
- * Special value used to identify base-level header
+ * Special value used to identify base-level header.
*/
- private static final Object BASE_HEADER = new Object();
+ static final Object BASE_HEADER = new Object();
/**
* The topmost head index of the skiplist.
@@ -377,11 +375,11 @@
final Comparator<? super K> comparator;
/** Lazily initialized key set */
- private transient KeySet<K> keySet;
+ private transient KeySet<K,V> keySet;
/** Lazily initialized entry set */
private transient EntrySet<K,V> entrySet;
/** Lazily initialized values collection */
- private transient Values<V> values;
+ private transient Values<K,V> values;
/** Lazily initialized descending key set */
private transient ConcurrentNavigableMap<K,V> descendingMap;
@@ -400,10 +398,10 @@
}
/**
- * compareAndSet head node
+ * compareAndSet head node.
*/
private boolean casHead(HeadIndex<K,V> cmp, HeadIndex<K,V> val) {
- return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val);
+ return U.compareAndSwapObject(this, HEAD, cmp, val);
}
/* ---------------- Nodes -------------- */
@@ -443,17 +441,17 @@
}
/**
- * compareAndSet value field
+ * compareAndSet value field.
*/
boolean casValue(Object cmp, Object val) {
- return UNSAFE.compareAndSwapObject(this, valueOffset, cmp, val);
+ return U.compareAndSwapObject(this, VALUE, cmp, val);
}
/**
- * compareAndSet next field
+ * compareAndSet next field.
*/
boolean casNext(Node<K,V> cmp, Node<K,V> val) {
- return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
+ return U.compareAndSwapObject(this, NEXT, cmp, val);
}
/**
@@ -534,21 +532,19 @@
return new AbstractMap.SimpleImmutableEntry<K,V>(key, vv);
}
- // UNSAFE mechanics
+ // Unsafe mechanics
- private static final sun.misc.Unsafe UNSAFE;
- private static final long valueOffset;
- private static final long nextOffset;
+ private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+ private static final long VALUE;
+ private static final long NEXT;
static {
try {
- UNSAFE = sun.misc.Unsafe.getUnsafe();
- Class<?> k = Node.class;
- valueOffset = UNSAFE.objectFieldOffset
- (k.getDeclaredField("value"));
- nextOffset = UNSAFE.objectFieldOffset
- (k.getDeclaredField("next"));
- } catch (Exception e) {
+ VALUE = U.objectFieldOffset
+ (Node.class.getDeclaredField("value"));
+ NEXT = U.objectFieldOffset
+ (Node.class.getDeclaredField("next"));
+ } catch (ReflectiveOperationException e) {
throw new Error(e);
}
}
@@ -578,10 +574,10 @@
}
/**
- * compareAndSet right field
+ * compareAndSet right field.
*/
final boolean casRight(Index<K,V> cmp, Index<K,V> val) {
- return UNSAFE.compareAndSwapObject(this, rightOffset, cmp, val);
+ return U.compareAndSwapObject(this, RIGHT, cmp, val);
}
/**
@@ -618,15 +614,13 @@
}
// Unsafe mechanics
- private static final sun.misc.Unsafe UNSAFE;
- private static final long rightOffset;
+ private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+ private static final long RIGHT;
static {
try {
- UNSAFE = sun.misc.Unsafe.getUnsafe();
- Class<?> k = Index.class;
- rightOffset = UNSAFE.objectFieldOffset
- (k.getDeclaredField("right"));
- } catch (Exception e) {
+ RIGHT = U.objectFieldOffset
+ (Index.class.getDeclaredField("right"));
+ } catch (ReflectiveOperationException e) {
throw new Error(e);
}
}
@@ -730,10 +724,10 @@
*
* The traversal loops in doPut, doRemove, and findNear all
* include the same three kinds of checks. And specialized
- * versions appear in findFirst, and findLast and their
- * variants. They can't easily share code because each uses the
- * reads of fields held in locals occurring in the orders they
- * were performed.
+ * versions appear in findFirst, and findLast and their variants.
+ * They can't easily share code because each uses the reads of
+ * fields held in locals occurring in the orders they were
+ * performed.
*
* @param key the key
* @return node holding key, or null if no such
@@ -1364,7 +1358,7 @@
// Track the current rightmost node at each level. Uses an
// ArrayList to avoid committing to initial or maximum level.
- ArrayList<Index<K,V>> preds = new ArrayList<Index<K,V>>();
+ ArrayList<Index<K,V>> preds = new ArrayList<>();
// initialize
for (int i = 0; i <= h.level; ++i)
@@ -1461,12 +1455,12 @@
* distinct because readObject calls can't be nicely adapted
* as the kind of iterator needed by buildFromSorted. (They
* can be, but doing so requires type cheats and/or creation
- * of adaptor classes.) It is simpler to just adapt the code.
+ * of adapter classes.) It is simpler to just adapt the code.
*/
HeadIndex<K,V> h = head;
Node<K,V> basepred = h.node;
- ArrayList<Index<K,V>> preds = new ArrayList<Index<K,V>>();
+ ArrayList<Index<K,V>> preds = new ArrayList<>();
for (int i = 0; i <= h.level; ++i)
preds.add(null);
Index<K,V> q = h;
@@ -1833,13 +1827,13 @@
* @return a navigable set view of the keys in this map
*/
public NavigableSet<K> keySet() {
- KeySet<K> ks = keySet;
- return (ks != null) ? ks : (keySet = new KeySet<K>(this));
+ KeySet<K,V> ks = keySet;
+ return (ks != null) ? ks : (keySet = new KeySet<>(this));
}
public NavigableSet<K> navigableKeySet() {
- KeySet<K> ks = keySet;
- return (ks != null) ? ks : (keySet = new KeySet<K>(this));
+ KeySet<K,V> ks = keySet;
+ return (ks != null) ? ks : (keySet = new KeySet<>(this));
}
/**
@@ -1862,8 +1856,8 @@
* <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
*/
public Collection<V> values() {
- Values<V> vs = values;
- return (vs != null) ? vs : (values = new Values<V>(this));
+ Values<K,V> vs = values;
+ return (vs != null) ? vs : (values = new Values<>(this));
}
/**
@@ -2346,20 +2340,6 @@
}
}
- // Factory methods for iterators needed by ConcurrentSkipListSet etc
-
- Iterator<K> keyIterator() {
- return new KeyIterator();
- }
-
- Iterator<V> valueIterator() {
- return new ValueIterator();
- }
-
- Iterator<Map.Entry<K,V>> entryIterator() {
- return new EntryIterator();
- }
-
/* ---------------- View Classes -------------- */
/*
@@ -2376,36 +2356,34 @@
return list;
}
- static final class KeySet<E>
- extends AbstractSet<E> implements NavigableSet<E> {
- final ConcurrentNavigableMap<E,?> m;
- KeySet(ConcurrentNavigableMap<E,?> map) { m = map; }
+ static final class KeySet<K,V>
+ extends AbstractSet<K> implements NavigableSet<K> {
+ final ConcurrentNavigableMap<K,V> m;
+ KeySet(ConcurrentNavigableMap<K,V> map) { m = map; }
public int size() { return m.size(); }
public boolean isEmpty() { return m.isEmpty(); }
public boolean contains(Object o) { return m.containsKey(o); }
public boolean remove(Object o) { return m.remove(o) != null; }
public void clear() { m.clear(); }
- public E lower(E e) { return m.lowerKey(e); }
- public E floor(E e) { return m.floorKey(e); }
- public E ceiling(E e) { return m.ceilingKey(e); }
- public E higher(E e) { return m.higherKey(e); }
- public Comparator<? super E> comparator() { return m.comparator(); }
- public E first() { return m.firstKey(); }
- public E last() { return m.lastKey(); }
- public E pollFirst() {
- Map.Entry<E,?> e = m.pollFirstEntry();
+ public K lower(K e) { return m.lowerKey(e); }
+ public K floor(K e) { return m.floorKey(e); }
+ public K ceiling(K e) { return m.ceilingKey(e); }
+ public K higher(K e) { return m.higherKey(e); }
+ public Comparator<? super K> comparator() { return m.comparator(); }
+ public K first() { return m.firstKey(); }
+ public K last() { return m.lastKey(); }
+ public K pollFirst() {
+ Map.Entry<K,V> e = m.pollFirstEntry();
return (e == null) ? null : e.getKey();
}
- public E pollLast() {
- Map.Entry<E,?> e = m.pollLastEntry();
+ public K pollLast() {
+ Map.Entry<K,V> e = m.pollLastEntry();
return (e == null) ? null : e.getKey();
}
- @SuppressWarnings("unchecked")
- public Iterator<E> iterator() {
- if (m instanceof ConcurrentSkipListMap)
- return ((ConcurrentSkipListMap<E,Object>)m).keyIterator();
- else
- return ((ConcurrentSkipListMap.SubMap<E,Object>)m).keyIterator();
+ public Iterator<K> iterator() {
+ return (m instanceof ConcurrentSkipListMap)
+ ? ((ConcurrentSkipListMap<K,V>)m).new KeyIterator()
+ : ((SubMap<K,V>)m).new SubMapKeyIterator();
}
public boolean equals(Object o) {
if (o == this)
@@ -2423,87 +2401,76 @@
}
public Object[] toArray() { return toList(this).toArray(); }
public <T> T[] toArray(T[] a) { return toList(this).toArray(a); }
- public Iterator<E> descendingIterator() {
+ public Iterator<K> descendingIterator() {
return descendingSet().iterator();
}
- public NavigableSet<E> subSet(E fromElement,
+ public NavigableSet<K> subSet(K fromElement,
boolean fromInclusive,
- E toElement,
+ K toElement,
boolean toInclusive) {
- return new KeySet<E>(m.subMap(fromElement, fromInclusive,
- toElement, toInclusive));
+ return new KeySet<>(m.subMap(fromElement, fromInclusive,
+ toElement, toInclusive));
}
- public NavigableSet<E> headSet(E toElement, boolean inclusive) {
- return new KeySet<E>(m.headMap(toElement, inclusive));
+ public NavigableSet<K> headSet(K toElement, boolean inclusive) {
+ return new KeySet<>(m.headMap(toElement, inclusive));
}
- public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
- return new KeySet<E>(m.tailMap(fromElement, inclusive));
+ public NavigableSet<K> tailSet(K fromElement, boolean inclusive) {
+ return new KeySet<>(m.tailMap(fromElement, inclusive));
}
- public NavigableSet<E> subSet(E fromElement, E toElement) {
+ public NavigableSet<K> subSet(K fromElement, K toElement) {
return subSet(fromElement, true, toElement, false);
}
- public NavigableSet<E> headSet(E toElement) {
+ public NavigableSet<K> headSet(K toElement) {
return headSet(toElement, false);
}
- public NavigableSet<E> tailSet(E fromElement) {
+ public NavigableSet<K> tailSet(K fromElement) {
return tailSet(fromElement, true);
}
- public NavigableSet<E> descendingSet() {
- return new KeySet<E>(m.descendingMap());
+ public NavigableSet<K> descendingSet() {
+ return new KeySet<>(m.descendingMap());
}
- @SuppressWarnings("unchecked")
- public Spliterator<E> spliterator() {
- if (m instanceof ConcurrentSkipListMap)
- return ((ConcurrentSkipListMap<E,?>)m).keySpliterator();
- else
- return (Spliterator<E>)((SubMap<E,?>)m).keyIterator();
+
+ public Spliterator<K> spliterator() {
+ return (m instanceof ConcurrentSkipListMap)
+ ? ((ConcurrentSkipListMap<K,V>)m).keySpliterator()
+ : ((SubMap<K,V>)m).new SubMapKeyIterator();
}
}
- static final class Values<E> extends AbstractCollection<E> {
- final ConcurrentNavigableMap<?, E> m;
- Values(ConcurrentNavigableMap<?, E> map) {
+ static final class Values<K,V> extends AbstractCollection<V> {
+ final ConcurrentNavigableMap<K,V> m;
+ Values(ConcurrentNavigableMap<K,V> map) {
m = map;
}
- @SuppressWarnings("unchecked")
- public Iterator<E> iterator() {
- if (m instanceof ConcurrentSkipListMap)
- return ((ConcurrentSkipListMap<?,E>)m).valueIterator();
- else
- return ((SubMap<?,E>)m).valueIterator();
- }
- public boolean isEmpty() {
- return m.isEmpty();
+ public Iterator<V> iterator() {
+ return (m instanceof ConcurrentSkipListMap)
+ ? ((ConcurrentSkipListMap<K,V>)m).new ValueIterator()
+ : ((SubMap<K,V>)m).new SubMapValueIterator();
}
- public int size() {
- return m.size();
- }
- public boolean contains(Object o) {
- return m.containsValue(o);
- }
- public void clear() {
- m.clear();
- }
+ public int size() { return m.size(); }
+ public boolean isEmpty() { return m.isEmpty(); }
+ public boolean contains(Object o) { return m.containsValue(o); }
+ public void clear() { m.clear(); }
public Object[] toArray() { return toList(this).toArray(); }
public <T> T[] toArray(T[] a) { return toList(this).toArray(a); }
- @SuppressWarnings("unchecked")
- public Spliterator<E> spliterator() {
- if (m instanceof ConcurrentSkipListMap)
- return ((ConcurrentSkipListMap<?,E>)m).valueSpliterator();
- else
- return (Spliterator<E>)((SubMap<?,E>)m).valueIterator();
+
+ public Spliterator<V> spliterator() {
+ return (m instanceof ConcurrentSkipListMap)
+ ? ((ConcurrentSkipListMap<K,V>)m).valueSpliterator()
+ : ((SubMap<K,V>)m).new SubMapValueIterator();
}
- public boolean removeIf(Predicate<? super E> filter) {
+
+ public boolean removeIf(Predicate<? super V> filter) {
if (filter == null) throw new NullPointerException();
if (m instanceof ConcurrentSkipListMap)
- return ((ConcurrentSkipListMap<?,E>)m).removeValueIf(filter);
+ return ((ConcurrentSkipListMap<K,V>)m).removeValueIf(filter);
// else use iterator
- @SuppressWarnings("unchecked") Iterator<Map.Entry<Object,E>> it =
- ((SubMap<Object,E>)m).entryIterator();
+ Iterator<Map.Entry<K,V>> it =
+ ((SubMap<K,V>)m).new SubMapEntryIterator();
boolean removed = false;
while (it.hasNext()) {
- Map.Entry<Object,E> e = it.next();
- E v = e.getValue();
+ Map.Entry<K,V> e = it.next();
+ V v = e.getValue();
if (filter.test(v) && m.remove(e.getKey(), v))
removed = true;
}
@@ -2511,24 +2478,22 @@
}
}
- static final class EntrySet<K1,V1> extends AbstractSet<Map.Entry<K1,V1>> {
- final ConcurrentNavigableMap<K1, V1> m;
- EntrySet(ConcurrentNavigableMap<K1, V1> map) {
+ static final class EntrySet<K,V> extends AbstractSet<Map.Entry<K,V>> {
+ final ConcurrentNavigableMap<K,V> m;
+ EntrySet(ConcurrentNavigableMap<K,V> map) {
m = map;
}
- @SuppressWarnings("unchecked")
- public Iterator<Map.Entry<K1,V1>> iterator() {
- if (m instanceof ConcurrentSkipListMap)
- return ((ConcurrentSkipListMap<K1,V1>)m).entryIterator();
- else
- return ((SubMap<K1,V1>)m).entryIterator();
+ public Iterator<Map.Entry<K,V>> iterator() {
+ return (m instanceof ConcurrentSkipListMap)
+ ? ((ConcurrentSkipListMap<K,V>)m).new EntryIterator()
+ : ((SubMap<K,V>)m).new SubMapEntryIterator();
}
public boolean contains(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
- V1 v = m.get(e.getKey());
+ V v = m.get(e.getKey());
return v != null && v.equals(e.getValue());
}
public boolean remove(Object o) {
@@ -2563,23 +2528,22 @@
}
public Object[] toArray() { return toList(this).toArray(); }
public <T> T[] toArray(T[] a) { return toList(this).toArray(a); }
- @SuppressWarnings("unchecked")
- public Spliterator<Map.Entry<K1,V1>> spliterator() {
- if (m instanceof ConcurrentSkipListMap)
- return ((ConcurrentSkipListMap<K1,V1>)m).entrySpliterator();
- else
- return (Spliterator<Map.Entry<K1,V1>>)
- ((SubMap<K1,V1>)m).entryIterator();
+
+ public Spliterator<Map.Entry<K,V>> spliterator() {
+ return (m instanceof ConcurrentSkipListMap)
+ ? ((ConcurrentSkipListMap<K,V>)m).entrySpliterator()
+ : ((SubMap<K,V>)m).new SubMapEntryIterator();
}
- public boolean removeIf(Predicate<? super Entry<K1, V1>> filter) {
+ public boolean removeIf(Predicate<? super Entry<K,V>> filter) {
if (filter == null) throw new NullPointerException();
if (m instanceof ConcurrentSkipListMap)
- return ((ConcurrentSkipListMap<K1,V1>)m).removeEntryIf(filter);
+ return ((ConcurrentSkipListMap<K,V>)m).removeEntryIf(filter);
// else use iterator
- Iterator<Map.Entry<K1,V1>> it = ((SubMap<K1,V1>)m).entryIterator();
+ Iterator<Map.Entry<K,V>> it =
+ ((SubMap<K,V>)m).new SubMapEntryIterator();
boolean removed = false;
while (it.hasNext()) {
- Map.Entry<K1,V1> e = it.next();
+ Map.Entry<K,V> e = it.next();
if (filter.test(e) && m.remove(e.getKey(), e.getValue()))
removed = true;
}
@@ -2589,13 +2553,13 @@
/**
* Submaps returned by {@link ConcurrentSkipListMap} submap operations
- * represent a subrange of mappings of their underlying
- * maps. Instances of this class support all methods of their
- * underlying maps, differing in that mappings outside their range are
- * ignored, and attempts to add mappings outside their ranges result
- * in {@link IllegalArgumentException}. Instances of this class are
- * constructed only using the {@code subMap}, {@code headMap}, and
- * {@code tailMap} methods of their underlying maps.
+ * represent a subrange of mappings of their underlying maps.
+ * Instances of this class support all methods of their underlying
+ * maps, differing in that mappings outside their range are ignored,
+ * and attempts to add mappings outside their ranges result in {@link
+ * IllegalArgumentException}. Instances of this class are constructed
+ * only using the {@code subMap}, {@code headMap}, and {@code tailMap}
+ * methods of their underlying maps.
*
* @serial include
*/
@@ -2604,7 +2568,7 @@
private static final long serialVersionUID = -7647078645895051609L;
/** Underlying map */
- private final ConcurrentSkipListMap<K,V> m;
+ final ConcurrentSkipListMap<K,V> m;
/** lower bound key, or null if from start */
private final K lo;
/** upper bound key, or null if to end */
@@ -2614,10 +2578,10 @@
/** inclusion flag for hi */
private final boolean hiInclusive;
/** direction */
- private final boolean isDescending;
+ final boolean isDescending;
// Lazily initialized view holders
- private transient KeySet<K> keySetView;
+ private transient KeySet<K,V> keySetView;
private transient Set<Map.Entry<K,V>> entrySetView;
private transient Collection<V> valuesView;
@@ -2790,7 +2754,7 @@
}
/**
- * Submap version of ConcurrentSkipListMap.getNearEntry
+ * Submap version of ConcurrentSkipListMap.getNearEntry.
*/
Map.Entry<K,V> getNearEntry(K key, int rel) {
Comparator<? super K> cmp = m.comparator;
@@ -3085,18 +3049,18 @@
/* ---------------- Submap Views -------------- */
public NavigableSet<K> keySet() {
- KeySet<K> ks = keySetView;
- return (ks != null) ? ks : (keySetView = new KeySet<K>(this));
+ KeySet<K,V> ks = keySetView;
+ return (ks != null) ? ks : (keySetView = new KeySet<>(this));
}
public NavigableSet<K> navigableKeySet() {
- KeySet<K> ks = keySetView;
- return (ks != null) ? ks : (keySetView = new KeySet<K>(this));
+ KeySet<K,V> ks = keySetView;
+ return (ks != null) ? ks : (keySetView = new KeySet<>(this));
}
public Collection<V> values() {
Collection<V> vs = valuesView;
- return (vs != null) ? vs : (valuesView = new Values<V>(this));
+ return (vs != null) ? vs : (valuesView = new Values<>(this));
}
public Set<Map.Entry<K,V>> entrySet() {
@@ -3108,21 +3072,9 @@
return descendingMap().navigableKeySet();
}
- Iterator<K> keyIterator() {
- return new SubMapKeyIterator();
- }
-
- Iterator<V> valueIterator() {
- return new SubMapValueIterator();
- }
-
- Iterator<Map.Entry<K,V>> entryIterator() {
- return new SubMapEntryIterator();
- }
-
/**
* Variant of main Iter class to traverse through submaps.
- * Also serves as back-up Spliterator for views
+ * Also serves as back-up Spliterator for views.
*/
abstract class SubMapIter<T> implements Iterator<T>, Spliterator<T> {
/** the last node returned by next() */
@@ -3298,9 +3250,9 @@
}
/**
- * Helper method for EntrySet.removeIf
+ * Helper method for EntrySet.removeIf.
*/
- boolean removeEntryIf(Predicate<? super Entry<K, V>> function) {
+ boolean removeEntryIf(Predicate<? super Entry<K,V>> function) {
if (function == null) throw new NullPointerException();
boolean removed = false;
for (Node<K,V> n = findFirst(); n != null; n = n.next) {
@@ -3316,7 +3268,7 @@
}
/**
- * Helper method for Values.removeIf
+ * Helper method for Values.removeIf.
*/
boolean removeValueIf(Predicate<? super V> function) {
if (function == null) throw new NullPointerException();
@@ -3371,7 +3323,7 @@
super(comparator, row, origin, fence, est);
}
- public Spliterator<K> trySplit() {
+ public KeySpliterator<K,V> trySplit() {
Node<K,V> e; K ek;
Comparator<? super K> cmp = comparator;
K f = fence;
@@ -3459,7 +3411,7 @@
super(comparator, row, origin, fence, est);
}
- public Spliterator<V> trySplit() {
+ public ValueSpliterator<K,V> trySplit() {
Node<K,V> e; K ek;
Comparator<? super K> cmp = comparator;
K f = fence;
@@ -3546,7 +3498,7 @@
super(comparator, row, origin, fence, est);
}
- public Spliterator<Map.Entry<K,V>> trySplit() {
+ public EntrySpliterator<K,V> trySplit() {
Node<K,V> e; K ek;
Comparator<? super K> cmp = comparator;
K f = fence;
@@ -3644,20 +3596,13 @@
}
// Unsafe mechanics
- private static final sun.misc.Unsafe UNSAFE;
- private static final long headOffset;
- private static final long SECONDARY;
+ private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+ private static final long HEAD;
static {
try {
- UNSAFE = sun.misc.Unsafe.getUnsafe();
- Class<?> k = ConcurrentSkipListMap.class;
- headOffset = UNSAFE.objectFieldOffset
- (k.getDeclaredField("head"));
- Class<?> tk = Thread.class;
- SECONDARY = UNSAFE.objectFieldOffset
- (tk.getDeclaredField("threadLocalRandomSecondarySeed"));
-
- } catch (Exception e) {
+ HEAD = U.objectFieldOffset
+ (ConcurrentSkipListMap.class.getDeclaredField("head"));
+ } catch (ReflectiveOperationException e) {
throw new Error(e);
}
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListSet.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListSet.java Tue Oct 13 16:45:35 2015 -0700
@@ -34,6 +34,7 @@
*/
package java.util.concurrent;
+
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Collections;
@@ -323,8 +324,9 @@
*
* @param c collection containing elements to be removed from this set
* @return {@code true} if this set changed as a result of the call
- * @throws ClassCastException if the types of one or more elements in this
- * set are incompatible with the specified collection
+ * @throws ClassCastException if the class of an element of this set
+ * is incompatible with the specified collection
+ * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified collection or any
* of its elements are null
*/
@@ -384,7 +386,6 @@
/* ---------------- SortedSet operations -------------- */
-
public Comparator<? super E> comparator() {
return m.comparator();
}
@@ -498,28 +499,24 @@
* @return a {@code Spliterator} over the elements in this set
* @since 1.8
*/
- @SuppressWarnings("unchecked")
public Spliterator<E> spliterator() {
- if (m instanceof ConcurrentSkipListMap)
- return ((ConcurrentSkipListMap<E,?>)m).keySpliterator();
- else
- return (Spliterator<E>)((ConcurrentSkipListMap.SubMap<E,?>)m).keyIterator();
+ return (m instanceof ConcurrentSkipListMap)
+ ? ((ConcurrentSkipListMap<E,?>)m).keySpliterator()
+ : ((ConcurrentSkipListMap.SubMap<E,?>)m).new SubMapKeyIterator();
}
// Support for resetting map in clone
private void setMap(ConcurrentNavigableMap<E,Object> map) {
- UNSAFE.putObjectVolatile(this, mapOffset, map);
+ U.putObjectVolatile(this, MAP, map);
}
- private static final sun.misc.Unsafe UNSAFE;
- private static final long mapOffset;
+ private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+ private static final long MAP;
static {
try {
- UNSAFE = sun.misc.Unsafe.getUnsafe();
- Class<?> k = ConcurrentSkipListSet.class;
- mapOffset = UNSAFE.objectFieldOffset
- (k.getDeclaredField("m"));
- } catch (Exception e) {
+ MAP = U.objectFieldOffset
+ (ConcurrentSkipListSet.class.getDeclaredField("m"));
+ } catch (ReflectiveOperationException e) {
throw new Error(e);
}
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java Tue Oct 13 16:45:35 2015 -0700
@@ -33,6 +33,7 @@
*/
package java.util.concurrent;
+
import java.util.AbstractList;
import java.util.Arrays;
import java.util.Collection;
@@ -46,7 +47,6 @@
import java.util.RandomAccess;
import java.util.Spliterator;
import java.util.Spliterators;
-import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
@@ -86,14 +86,17 @@
*
* @since 1.5
* @author Doug Lea
- * @param <E> the type of elements held in this collection
+ * @param <E> the type of elements held in this list
*/
public class CopyOnWriteArrayList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
private static final long serialVersionUID = 8673264195747942595L;
- /** The lock protecting all mutators */
- final transient ReentrantLock lock = new ReentrantLock();
+ /**
+ * The lock protecting all mutators. (We have a mild preference
+ * for builtin monitors over ReentrantLock when either will do.)
+ */
+ final transient Object lock = new Object();
/** The array, accessed only via getArray/setArray. */
private transient volatile Object[] array;
@@ -172,13 +175,6 @@
}
/**
- * Tests for equality, coping with nulls.
- */
- private static boolean eq(Object o1, Object o2) {
- return (o1 == null) ? o2 == null : o1.equals(o2);
- }
-
- /**
* static version of indexOf, to allow repeated calls without
* needing to re-acquire array each time.
* @param o element to search for
@@ -224,8 +220,7 @@
/**
* Returns {@code true} if this list contains the specified element.
* More formally, returns {@code true} if and only if this list contains
- * at least one element {@code e} such that
- * <tt>(o==null ? e==null : o.equals(e))</tt>.
+ * at least one element {@code e} such that {@code Objects.equals(o, e)}.
*
* @param o element whose presence in this list is to be tested
* @return {@code true} if this list contains the specified element
@@ -248,7 +243,7 @@
* this list, searching forwards from {@code index}, or returns -1 if
* the element is not found.
* More formally, returns the lowest index {@code i} such that
- * <tt>(i >= index && (e==null ? get(i)==null : e.equals(get(i))))</tt>,
+ * {@code i >= index && Objects.equals(get(i), e)},
* or -1 if there is no such index.
*
* @param e element to search for
@@ -276,7 +271,7 @@
* this list, searching backwards from {@code index}, or returns -1 if
* the element is not found.
* More formally, returns the highest index {@code i} such that
- * <tt>(i <= index && (e==null ? get(i)==null : e.equals(get(i))))</tt>,
+ * {@code i <= index && Objects.equals(get(i), e)},
* or -1 if there is no such index.
*
* @param e element to search for
@@ -353,7 +348,7 @@
* The following code can be used to dump the list into a newly
* allocated array of {@code String}:
*
- * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+ * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
*
* Note that {@code toArray(new Object[0])} is identical in function to
* {@code toArray()}.
@@ -368,7 +363,7 @@
* @throws NullPointerException if the specified array is null
*/
@SuppressWarnings("unchecked")
- public <T> T[] toArray(T a[]) {
+ public <T> T[] toArray(T[] a) {
Object[] elements = getArray();
int len = elements.length;
if (a.length < len)
@@ -388,6 +383,10 @@
return (E) a[index];
}
+ static String outOfBounds(int index, int size) {
+ return "Index: " + index + ", Size: " + size;
+ }
+
/**
* {@inheritDoc}
*
@@ -404,9 +403,7 @@
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E set(int index, E element) {
- final ReentrantLock lock = this.lock;
- lock.lock();
- try {
+ synchronized (lock) {
Object[] elements = getArray();
E oldValue = get(elements, index);
@@ -420,8 +417,6 @@
setArray(elements);
}
return oldValue;
- } finally {
- lock.unlock();
}
}
@@ -432,17 +427,13 @@
* @return {@code true} (as specified by {@link Collection#add})
*/
public boolean add(E e) {
- final ReentrantLock lock = this.lock;
- lock.lock();
- try {
+ synchronized (lock) {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
- } finally {
- lock.unlock();
}
}
@@ -454,14 +445,11 @@
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public void add(int index, E element) {
- final ReentrantLock lock = this.lock;
- lock.lock();
- try {
+ synchronized (lock) {
Object[] elements = getArray();
int len = elements.length;
if (index > len || index < 0)
- throw new IndexOutOfBoundsException("Index: "+index+
- ", Size: "+len);
+ throw new IndexOutOfBoundsException(outOfBounds(index, len));
Object[] newElements;
int numMoved = len - index;
if (numMoved == 0)
@@ -474,8 +462,6 @@
}
newElements[index] = element;
setArray(newElements);
- } finally {
- lock.unlock();
}
}
@@ -487,9 +473,7 @@
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E remove(int index) {
- final ReentrantLock lock = this.lock;
- lock.lock();
- try {
+ synchronized (lock) {
Object[] elements = getArray();
int len = elements.length;
E oldValue = get(elements, index);
@@ -504,8 +488,6 @@
setArray(newElements);
}
return oldValue;
- } finally {
- lock.unlock();
}
}
@@ -513,8 +495,7 @@
* Removes the first occurrence of the specified element from this list,
* if it is present. If this list does not contain the element, it is
* unchanged. More formally, removes the element with the lowest index
- * {@code i} such that
- * <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>
+ * {@code i} such that {@code Objects.equals(o, get(i))}
* (if such an element exists). Returns {@code true} if this list
* contained the specified element (or equivalently, if this list
* changed as a result of the call).
@@ -533,15 +514,14 @@
* recent snapshot contains o at the given index.
*/
private boolean remove(Object o, Object[] snapshot, int index) {
- final ReentrantLock lock = this.lock;
- lock.lock();
- try {
+ synchronized (lock) {
Object[] current = getArray();
int len = current.length;
if (snapshot != current) findIndex: {
int prefix = Math.min(index, len);
for (int i = 0; i < prefix; i++) {
- if (current[i] != snapshot[i] && eq(o, current[i])) {
+ if (current[i] != snapshot[i]
+ && Objects.equals(o, current[i])) {
index = i;
break findIndex;
}
@@ -561,8 +541,6 @@
len - index - 1);
setArray(newElements);
return true;
- } finally {
- lock.unlock();
}
}
@@ -579,9 +557,7 @@
* ({@code fromIndex < 0 || toIndex > size() || toIndex < fromIndex})
*/
void removeRange(int fromIndex, int toIndex) {
- final ReentrantLock lock = this.lock;
- lock.lock();
- try {
+ synchronized (lock) {
Object[] elements = getArray();
int len = elements.length;
@@ -598,8 +574,6 @@
fromIndex, numMoved);
setArray(newElements);
}
- } finally {
- lock.unlock();
}
}
@@ -620,16 +594,15 @@
* recent snapshot does not contain e.
*/
private boolean addIfAbsent(E e, Object[] snapshot) {
- final ReentrantLock lock = this.lock;
- lock.lock();
- try {
+ synchronized (lock) {
Object[] current = getArray();
int len = current.length;
if (snapshot != current) {
// Optimize for lost race to another addXXX operation
int common = Math.min(snapshot.length, len);
for (int i = 0; i < common; i++)
- if (current[i] != snapshot[i] && eq(e, current[i]))
+ if (current[i] != snapshot[i]
+ && Objects.equals(e, current[i]))
return false;
if (indexOf(e, current, common, len) >= 0)
return false;
@@ -638,8 +611,6 @@
newElements[len] = e;
setArray(newElements);
return true;
- } finally {
- lock.unlock();
}
}
@@ -672,18 +643,16 @@
* @return {@code true} if this list changed as a result of the call
* @throws ClassCastException if the class of an element of this list
* is incompatible with the specified collection
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/../api/java/util/Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if this list contains a null element and the
* specified collection does not permit null elements
- * (<a href="../Collection.html#optional-restrictions">optional</a>),
+ * (<a href="{@docRoot}/../api/java/util/Collection.html#optional-restrictions">optional</a>),
* or if the specified collection is null
* @see #remove(Object)
*/
public boolean removeAll(Collection<?> c) {
if (c == null) throw new NullPointerException();
- final ReentrantLock lock = this.lock;
- lock.lock();
- try {
+ synchronized (lock) {
Object[] elements = getArray();
int len = elements.length;
if (len != 0) {
@@ -701,8 +670,6 @@
}
}
return false;
- } finally {
- lock.unlock();
}
}
@@ -715,18 +682,16 @@
* @return {@code true} if this list changed as a result of the call
* @throws ClassCastException if the class of an element of this list
* is incompatible with the specified collection
- * (<a href="../Collection.html#optional-restrictions">optional</a>)
+ * (<a href="{@docRoot}/../api/java/util/Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if this list contains a null element and the
* specified collection does not permit null elements
- * (<a href="../Collection.html#optional-restrictions">optional</a>),
+ * (<a href="{@docRoot}/../api/java/util/Collection.html#optional-restrictions">optional</a>),
* or if the specified collection is null
* @see #remove(Object)
*/
public boolean retainAll(Collection<?> c) {
if (c == null) throw new NullPointerException();
- final ReentrantLock lock = this.lock;
- lock.lock();
- try {
+ synchronized (lock) {
Object[] elements = getArray();
int len = elements.length;
if (len != 0) {
@@ -744,8 +709,6 @@
}
}
return false;
- } finally {
- lock.unlock();
}
}
@@ -764,9 +727,7 @@
Object[] cs = c.toArray();
if (cs.length == 0)
return 0;
- final ReentrantLock lock = this.lock;
- lock.lock();
- try {
+ synchronized (lock) {
Object[] elements = getArray();
int len = elements.length;
int added = 0;
@@ -783,8 +744,6 @@
setArray(newElements);
}
return added;
- } finally {
- lock.unlock();
}
}
@@ -793,12 +752,8 @@
* The list will be empty after this call returns.
*/
public void clear() {
- final ReentrantLock lock = this.lock;
- lock.lock();
- try {
+ synchronized (lock) {
setArray(new Object[0]);
- } finally {
- lock.unlock();
}
}
@@ -817,9 +772,7 @@
((CopyOnWriteArrayList<?>)c).getArray() : c.toArray();
if (cs.length == 0)
return false;
- final ReentrantLock lock = this.lock;
- lock.lock();
- try {
+ synchronized (lock) {
Object[] elements = getArray();
int len = elements.length;
if (len == 0 && cs.getClass() == Object[].class)
@@ -830,8 +783,6 @@
setArray(newElements);
}
return true;
- } finally {
- lock.unlock();
}
}
@@ -853,14 +804,11 @@
*/
public boolean addAll(int index, Collection<? extends E> c) {
Object[] cs = c.toArray();
- final ReentrantLock lock = this.lock;
- lock.lock();
- try {
+ synchronized (lock) {
Object[] elements = getArray();
int len = elements.length;
if (index > len || index < 0)
- throw new IndexOutOfBoundsException("Index: "+index+
- ", Size: "+len);
+ throw new IndexOutOfBoundsException(outOfBounds(index, len));
if (cs.length == 0)
return false;
int numMoved = len - index;
@@ -877,52 +825,47 @@
System.arraycopy(cs, 0, newElements, index, cs.length);
setArray(newElements);
return true;
- } finally {
- lock.unlock();
}
}
public void forEach(Consumer<? super E> action) {
if (action == null) throw new NullPointerException();
- Object[] elements = getArray();
- int len = elements.length;
- for (int i = 0; i < len; ++i) {
- @SuppressWarnings("unchecked") E e = (E) elements[i];
+ for (Object x : getArray()) {
+ @SuppressWarnings("unchecked") E e = (E) x;
action.accept(e);
}
}
public boolean removeIf(Predicate<? super E> filter) {
if (filter == null) throw new NullPointerException();
- final ReentrantLock lock = this.lock;
- lock.lock();
- try {
- Object[] elements = getArray();
- int len = elements.length;
- if (len != 0) {
- int newlen = 0;
- Object[] temp = new Object[len];
- for (int i = 0; i < len; ++i) {
- @SuppressWarnings("unchecked") E e = (E) elements[i];
- if (!filter.test(e))
- temp[newlen++] = e;
- }
- if (newlen != len) {
- setArray(Arrays.copyOf(temp, newlen));
+ synchronized (lock) {
+ final Object[] elements = getArray();
+ final int len = elements.length;
+ int i;
+ for (i = 0; i < len; i++) {
+ @SuppressWarnings("unchecked") E e = (E) elements[i];
+ if (filter.test(e)) {
+ int newlen = i;
+ final Object[] newElements = new Object[len - 1];
+ System.arraycopy(elements, 0, newElements, 0, newlen);
+ for (i++; i < len; i++) {
+ @SuppressWarnings("unchecked") E x = (E) elements[i];
+ if (!filter.test(x))
+ newElements[newlen++] = x;
+ }
+ setArray((newlen == len - 1)
+ ? newElements // one match => one copy
+ : Arrays.copyOf(newElements, newlen));
return true;
}
}
- return false;
- } finally {
- lock.unlock();
+ return false; // zero matches => zero copies
}
}
public void replaceAll(UnaryOperator<E> operator) {
if (operator == null) throw new NullPointerException();
- final ReentrantLock lock = this.lock;
- lock.lock();
- try {
+ synchronized (lock) {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len);
@@ -931,22 +874,16 @@
newElements[i] = operator.apply(e);
}
setArray(newElements);
- } finally {
- lock.unlock();
}
}
public void sort(Comparator<? super E> c) {
- final ReentrantLock lock = this.lock;
- lock.lock();
- try {
+ synchronized (lock) {
Object[] elements = getArray();
Object[] newElements = Arrays.copyOf(elements, elements.length);
@SuppressWarnings("unchecked") E[] es = (E[])newElements;
Arrays.sort(es, c);
setArray(newElements);
- } finally {
- lock.unlock();
}
}
@@ -1022,7 +959,7 @@
* be the same if they have the same length and corresponding
* elements at the same position in the sequence are <em>equal</em>.
* Two elements {@code e1} and {@code e2} are considered
- * <em>equal</em> if {@code (e1==null ? e2==null : e1.equals(e2))}.
+ * <em>equal</em> if {@code Objects.equals(e1, e2)}.
*
* @param o the object to be compared for equality with this list
* @return {@code true} if the specified object is equal to this list
@@ -1033,12 +970,11 @@
if (!(o instanceof List))
return false;
- List<?> list = (List<?>)(o);
+ List<?> list = (List<?>)o;
Iterator<?> it = list.iterator();
Object[] elements = getArray();
- int len = elements.length;
- for (int i = 0; i < len; ++i)
- if (!it.hasNext() || !eq(elements[i], it.next()))
+ for (int i = 0, len = elements.length; i < len; i++)
+ if (!it.hasNext() || !Objects.equals(elements[i], it.next()))
return false;
if (it.hasNext())
return false;
@@ -1054,12 +990,8 @@
*/
public int hashCode() {
int hashCode = 1;
- Object[] elements = getArray();
- int len = elements.length;
- for (int i = 0; i < len; ++i) {
- Object obj = elements[i];
- hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());
- }
+ for (Object x : getArray())
+ hashCode = 31 * hashCode + (x == null ? 0 : x.hashCode());
return hashCode;
}
@@ -1103,7 +1035,7 @@
Object[] elements = getArray();
int len = elements.length;
if (index < 0 || index > len)
- throw new IndexOutOfBoundsException("Index: "+index);
+ throw new IndexOutOfBoundsException(outOfBounds(index, len));
return new COWIterator<E>(elements, index);
}
@@ -1133,7 +1065,7 @@
/** Index of element to be returned by subsequent call to next. */
private int cursor;
- private COWIterator(Object[] elements, int initialCursor) {
+ COWIterator(Object[] elements, int initialCursor) {
cursor = initialCursor;
snapshot = elements;
}
@@ -1196,13 +1128,12 @@
}
@Override
+ @SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
- Object[] elements = snapshot;
- final int size = elements.length;
+ final int size = snapshot.length;
for (int i = cursor; i < size; i++) {
- @SuppressWarnings("unchecked") E e = (E) elements[i];
- action.accept(e);
+ action.accept((E) snapshot[i]);
}
cursor = size;
}
@@ -1224,16 +1155,12 @@
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public List<E> subList(int fromIndex, int toIndex) {
- final ReentrantLock lock = this.lock;
- lock.lock();
- try {
+ synchronized (lock) {
Object[] elements = getArray();
int len = elements.length;
if (fromIndex < 0 || toIndex > len || fromIndex > toIndex)
throw new IndexOutOfBoundsException();
return new COWSubList<E>(this, fromIndex, toIndex);
- } finally {
- lock.unlock();
}
}
@@ -1264,6 +1191,7 @@
// only call this holding l's lock
COWSubList(CopyOnWriteArrayList<E> list,
int fromIndex, int toIndex) {
+ // assert Thread.holdsLock(list.lock);
l = list;
expectedArray = l.getArray();
offset = fromIndex;
@@ -1272,94 +1200,72 @@
// only call this holding l's lock
private void checkForComodification() {
+ // assert Thread.holdsLock(l.lock);
if (l.getArray() != expectedArray)
throw new ConcurrentModificationException();
}
// only call this holding l's lock
private void rangeCheck(int index) {
+ // assert Thread.holdsLock(l.lock);
if (index < 0 || index >= size)
- throw new IndexOutOfBoundsException("Index: "+index+
- ",Size: "+size);
+ throw new IndexOutOfBoundsException(outOfBounds(index, size));
}
public E set(int index, E element) {
- final ReentrantLock lock = l.lock;
- lock.lock();
- try {
+ synchronized (l.lock) {
rangeCheck(index);
checkForComodification();
E x = l.set(index+offset, element);
expectedArray = l.getArray();
return x;
- } finally {
- lock.unlock();
}
}
public E get(int index) {
- final ReentrantLock lock = l.lock;
- lock.lock();
- try {
+ synchronized (l.lock) {
rangeCheck(index);
checkForComodification();
return l.get(index+offset);
- } finally {
- lock.unlock();
}
}
public int size() {
- final ReentrantLock lock = l.lock;
- lock.lock();
- try {
+ synchronized (l.lock) {
checkForComodification();
return size;
- } finally {
- lock.unlock();
}
}
public void add(int index, E element) {
- final ReentrantLock lock = l.lock;
- lock.lock();
- try {
+ synchronized (l.lock) {
checkForComodification();
if (index < 0 || index > size)
- throw new IndexOutOfBoundsException();
+ throw new IndexOutOfBoundsException
+ (outOfBounds(index, size));
l.add(index+offset, element);
expectedArray = l.getArray();
size++;
- } finally {
- lock.unlock();
}
}
public void clear() {
- final ReentrantLock lock = l.lock;
- lock.lock();
- try {
+ synchronized (l.lock) {
checkForComodification();
l.removeRange(offset, offset+size);
expectedArray = l.getArray();
size = 0;
- } finally {
- lock.unlock();
}
}
public E remove(int index) {
- final ReentrantLock lock = l.lock;
- lock.lock();
- try {
+ synchronized (l.lock) {
rangeCheck(index);
checkForComodification();
E result = l.remove(index+offset);
expectedArray = l.getArray();
size--;
return result;
- } finally {
- lock.unlock();
}
}
@@ -1372,41 +1278,29 @@
}
public Iterator<E> iterator() {
- final ReentrantLock lock = l.lock;
- lock.lock();
- try {
+ synchronized (l.lock) {
checkForComodification();
return new COWSubListIterator<E>(l, 0, offset, size);
- } finally {
- lock.unlock();
}
}
public ListIterator<E> listIterator(int index) {
- final ReentrantLock lock = l.lock;
- lock.lock();
- try {
+ synchronized (l.lock) {
checkForComodification();
if (index < 0 || index > size)
- throw new IndexOutOfBoundsException("Index: "+index+
- ", Size: "+size);
+ throw new IndexOutOfBoundsException
+ (outOfBounds(index, size));
return new COWSubListIterator<E>(l, index, offset, size);
- } finally {
- lock.unlock();
}
}
public List<E> subList(int fromIndex, int toIndex) {
- final ReentrantLock lock = l.lock;
- lock.lock();
- try {
+ synchronized (l.lock) {
checkForComodification();
if (fromIndex < 0 || toIndex > size || fromIndex > toIndex)
throw new IndexOutOfBoundsException();
return new COWSubList<E>(l, fromIndex + offset,
toIndex + offset);
- } finally {
- lock.unlock();
}
}
@@ -1427,9 +1321,7 @@
public void replaceAll(UnaryOperator<E> operator) {
if (operator == null) throw new NullPointerException();
- final ReentrantLock lock = l.lock;
- lock.lock();
- try {
+ synchronized (l.lock) {
int lo = offset;
int hi = offset + size;
Object[] elements = expectedArray;
@@ -1444,15 +1336,11 @@
newElements[i] = operator.apply(e);
}
l.setArray(expectedArray = newElements);
- } finally {
- lock.unlock();
}
}
public void sort(Comparator<? super E> c) {
- final ReentrantLock lock = l.lock;
- lock.lock();
- try {
+ synchronized (l.lock) {
int lo = offset;
int hi = offset + size;
Object[] elements = expectedArray;
@@ -1465,17 +1353,13 @@
@SuppressWarnings("unchecked") E[] es = (E[])newElements;
Arrays.sort(es, lo, hi, c);
l.setArray(expectedArray = newElements);
- } finally {
- lock.unlock();
}
}
public boolean removeAll(Collection<?> c) {
if (c == null) throw new NullPointerException();
boolean removed = false;
- final ReentrantLock lock = l.lock;
- lock.lock();
- try {
+ synchronized (l.lock) {
int n = size;
if (n > 0) {
int lo = offset;
@@ -1504,8 +1388,6 @@
l.setArray(expectedArray = newElements);
}
}
- } finally {
- lock.unlock();
}
return removed;
}
@@ -1513,9 +1395,7 @@
public boolean retainAll(Collection<?> c) {
if (c == null) throw new NullPointerException();
boolean removed = false;
- final ReentrantLock lock = l.lock;
- lock.lock();
- try {
+ synchronized (l.lock) {
int n = size;
if (n > 0) {
int lo = offset;
@@ -1544,8 +1424,6 @@
l.setArray(expectedArray = newElements);
}
}
- } finally {
- lock.unlock();
}
return removed;
}
@@ -1553,9 +1431,7 @@
public boolean removeIf(Predicate<? super E> filter) {
if (filter == null) throw new NullPointerException();
boolean removed = false;
- final ReentrantLock lock = l.lock;
- lock.lock();
- try {
+ synchronized (l.lock) {
int n = size;
if (n > 0) {
int lo = offset;
@@ -1584,8 +1460,6 @@
l.setArray(expectedArray = newElements);
}
}
- } finally {
- lock.unlock();
}
return removed;
}
@@ -1658,29 +1532,26 @@
}
@Override
+ @SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
- int s = size;
- ListIterator<E> i = it;
- while (nextIndex() < s) {
- action.accept(i.next());
+ while (nextIndex() < size) {
+ action.accept(it.next());
}
}
}
// Support for resetting lock while deserializing
private void resetLock() {
- UNSAFE.putObjectVolatile(this, lockOffset, new ReentrantLock());
+ U.putObjectVolatile(this, LOCK, new Object());
}
- private static final sun.misc.Unsafe UNSAFE;
- private static final long lockOffset;
+ private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+ private static final long LOCK;
static {
try {
- UNSAFE = sun.misc.Unsafe.getUnsafe();
- Class<?> k = CopyOnWriteArrayList.class;
- lockOffset = UNSAFE.objectFieldOffset
- (k.getDeclaredField("lock"));
- } catch (Exception e) {
+ LOCK = U.objectFieldOffset
+ (CopyOnWriteArrayList.class.getDeclaredField("lock"));
+ } catch (ReflectiveOperationException e) {
throw new Error(e);
}
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArraySet.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArraySet.java Tue Oct 13 16:45:35 2015 -0700
@@ -34,14 +34,16 @@
*/
package java.util.concurrent;
+
+import java.util.AbstractSet;
import java.util.Collection;
+import java.util.Iterator;
+import java.util.Objects;
import java.util.Set;
-import java.util.AbstractSet;
-import java.util.Iterator;
import java.util.Spliterator;
import java.util.Spliterators;
+import java.util.function.Consumer;
import java.util.function.Predicate;
-import java.util.function.Consumer;
/**
* A {@link java.util.Set} that uses an internal {@link CopyOnWriteArrayList}
@@ -66,12 +68,12 @@
* copy-on-write set to maintain a set of Handler objects that
* perform some action upon state updates.
*
- * <pre> {@code
+ * <pre> {@code
* class Handler { void handle(); ... }
*
* class X {
* private final CopyOnWriteArraySet<Handler> handlers
- * = new CopyOnWriteArraySet<Handler>();
+ * = new CopyOnWriteArraySet<>();
* public void addHandler(Handler h) { handlers.add(h); }
*
* private long internalState;
@@ -91,7 +93,7 @@
* @see CopyOnWriteArrayList
* @since 1.5
* @author Doug Lea
- * @param <E> the type of elements held in this collection
+ * @param <E> the type of elements held in this set
*/
public class CopyOnWriteArraySet<E> extends AbstractSet<E>
implements java.io.Serializable {
@@ -146,8 +148,7 @@
/**
* Returns {@code true} if this set contains the specified element.
* More formally, returns {@code true} if and only if this set
- * contains an element {@code e} such that
- * <tt>(o==null ? e==null : o.equals(e))</tt>.
+ * contains an element {@code e} such that {@code Objects.equals(o, e)}.
*
* @param o element whose presence in this set is to be tested
* @return {@code true} if this set contains the specified element
@@ -203,7 +204,7 @@
* The following code can be used to dump the set into a newly allocated
* array of {@code String}:
*
- * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+ * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
*
* Note that {@code toArray(new Object[0])} is identical in function to
* {@code toArray()}.
@@ -232,11 +233,10 @@
/**
* Removes the specified element from this set if it is present.
* More formally, removes an element {@code e} such that
- * <tt>(o==null ? e==null : o.equals(e))</tt>,
- * if this set contains such an element. Returns {@code true} if
- * this set contained the element (or equivalently, if this set
- * changed as a result of the call). (This set will not contain the
- * element once the call returns.)
+ * {@code Objects.equals(o, e)}, if this set contains such an element.
+ * Returns {@code true} if this set contained the element (or
+ * equivalently, if this set changed as a result of the call).
+ * (This set will not contain the element once the call returns.)
*
* @param o object to be removed from this set, if present
* @return {@code true} if this set contained the specified element
@@ -249,7 +249,7 @@
* Adds the specified element to this set if it is not already present.
* More formally, adds the specified element {@code e} to this set if
* the set contains no element {@code e2} such that
- * <tt>(e==null ? e2==null : e.equals(e2))</tt>.
+ * {@code Objects.equals(e, e2)}.
* If this set already contains the element, the call leaves the set
* unchanged and returns {@code false}.
*
@@ -273,7 +273,44 @@
* @see #contains(Object)
*/
public boolean containsAll(Collection<?> c) {
- return al.containsAll(c);
+ return (c instanceof Set)
+ ? compareSets(al.getArray(), (Set<?>) c) >= 0
+ : al.containsAll(c);
+ }
+
+ /**
+ * Tells whether the objects in snapshot (regarded as a set) are a
+ * superset of the given set.
+ *
+ * @return -1 if snapshot is not a superset, 0 if the two sets
+ * contain precisely the same elements, and 1 if snapshot is a
+ * proper superset of the given set
+ */
+ private static int compareSets(Object[] snapshot, Set<?> set) {
+ // Uses O(n^2) algorithm, that is only appropriate for small
+ // sets, which CopyOnWriteArraySets should be.
+ //
+ // Optimize up to O(n) if the two sets share a long common prefix,
+ // as might happen if one set was created as a copy of the other set.
+
+ final int len = snapshot.length;
+ // Mark matched elements to avoid re-checking
+ final boolean[] matched = new boolean[len];
+
+ // j is the largest int with matched[i] true for { i | 0 <= i < j }
+ int j = 0;
+ outer: for (Object x : set) {
+ for (int i = j; i < len; i++) {
+ if (!matched[i] && Objects.equals(x, snapshot[i])) {
+ matched[i] = true;
+ if (i == j)
+ do { j++; } while (j < len && matched[j]);
+ continue outer;
+ }
+ }
+ return -1;
+ }
+ return (j == len) ? 0 : 1;
}
/**
@@ -302,9 +339,11 @@
* @param c collection containing elements to be removed from this set
* @return {@code true} if this set changed as a result of the call
* @throws ClassCastException if the class of an element of this set
- * is incompatible with the specified collection (optional)
+ * is incompatible with the specified collection
+ * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if this set contains a null element and the
- * specified collection does not permit null elements (optional),
+ * specified collection does not permit null elements
+ * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>),
* or if the specified collection is null
* @see #remove(Object)
*/
@@ -323,9 +362,11 @@
* @param c collection containing elements to be retained in this set
* @return {@code true} if this set changed as a result of the call
* @throws ClassCastException if the class of an element of this set
- * is incompatible with the specified collection (optional)
+ * is incompatible with the specified collection
+ * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if this set contains a null element and the
- * specified collection does not permit null elements (optional),
+ * specified collection does not permit null elements
+ * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>),
* or if the specified collection is null
* @see #remove(Object)
*/
@@ -359,41 +400,15 @@
* number of elements and for every element {@code e1} returned by
* the iterator over the specified set, there is an element
* {@code e2} returned by the iterator over this set such that
- * {@code (e1==null ? e2==null : e1.equals(e2))}.
+ * {@code Objects.equals(e1, e2)}.
*
* @param o object to be compared for equality with this set
* @return {@code true} if the specified object is equal to this set
*/
public boolean equals(Object o) {
- if (o == this)
- return true;
- if (!(o instanceof Set))
- return false;
- Set<?> set = (Set<?>)(o);
- Iterator<?> it = set.iterator();
-
- // Uses O(n^2) algorithm that is only appropriate
- // for small sets, which CopyOnWriteArraySets should be.
-
- // Use a single snapshot of underlying array
- Object[] elements = al.getArray();
- int len = elements.length;
- // Mark matched elements to avoid re-checking
- boolean[] matched = new boolean[len];
- int k = 0;
- outer: while (it.hasNext()) {
- if (++k > len)
- return false;
- Object x = it.next();
- for (int i = 0; i < len; ++i) {
- if (!matched[i] && eq(x, elements[i])) {
- matched[i] = true;
- continue outer;
- }
- }
- return false;
- }
- return k == len;
+ return (o == this)
+ || ((o instanceof Set)
+ && compareSets(al.getArray(), (Set<?>) o) == 0);
}
public boolean removeIf(Predicate<? super E> filter) {
@@ -423,11 +438,4 @@
return Spliterators.spliterator
(al.getArray(), Spliterator.IMMUTABLE | Spliterator.DISTINCT);
}
-
- /**
- * Tests for equality, coping with nulls.
- */
- private static boolean eq(Object o1, Object o2) {
- return (o1 == null) ? o2 == null : o1.equals(o2);
- }
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/CountDownLatch.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/CountDownLatch.java Tue Oct 13 16:45:35 2015 -0700
@@ -34,6 +34,7 @@
*/
package java.util.concurrent;
+
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
/**
@@ -72,7 +73,7 @@
* until all workers have completed.
* </ul>
*
- * <pre> {@code
+ * <pre> {@code
* class Driver { // ...
* void main() throws InterruptedException {
* CountDownLatch startSignal = new CountDownLatch(1);
@@ -113,7 +114,7 @@
* will be able to pass through await. (When threads must repeatedly
* count down in this way, instead use a {@link CyclicBarrier}.)
*
- * <pre> {@code
+ * <pre> {@code
* class Driver2 { // ...
* void main() throws InterruptedException {
* CountDownLatch doneSignal = new CountDownLatch(N);
@@ -179,7 +180,7 @@
int c = getState();
if (c == 0)
return false;
- int nextc = c-1;
+ int nextc = c - 1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/CountedCompleter.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/CountedCompleter.java Tue Oct 13 16:45:35 2015 -0700
@@ -168,7 +168,8 @@
* {@code tryComplete}) the pending count is set to one:
*
* <pre> {@code
- * class ForEach<E> ...
+ * class ForEach<E> ... {
+ * ...
* public void compute() { // version 2
* if (hi - lo >= 2) {
* int mid = (lo + hi) >>> 1;
@@ -182,7 +183,7 @@
* tryComplete();
* }
* }
- * }</pre>
+ * }}</pre>
*
* As a further improvement, notice that the left task need not even exist.
* Instead of creating a new one, we can iterate using the original task,
@@ -191,9 +192,10 @@
* {@code tryComplete()} can be replaced with {@link #propagateCompletion}.
*
* <pre> {@code
- * class ForEach<E> ...
+ * class ForEach<E> ... {
+ * ...
* public void compute() { // version 3
- * int l = lo, h = hi;
+ * int l = lo, h = hi;
* while (h - l >= 2) {
* int mid = (l + h) >>> 1;
* addToPendingCount(1);
@@ -204,7 +206,7 @@
* op.apply(array[l]);
* propagateCompletion();
* }
- * }</pre>
+ * }}</pre>
*
* Additional improvements of such classes might entail precomputing
* pending counts so that they can be established in constructors,
@@ -233,7 +235,7 @@
* }
* public E getRawResult() { return result.get(); }
* public void compute() { // similar to ForEach version 3
- * int l = lo, h = hi;
+ * int l = lo, h = hi;
* while (result.get() == null && h >= l) {
* if (h - l >= 2) {
* int mid = (l + h) >>> 1;
@@ -363,7 +365,7 @@
* this.next = next;
* }
* public void compute() {
- * int l = lo, h = hi;
+ * int l = lo, h = hi;
* while (h - l >= 2) {
* int mid = (l + h) >>> 1;
* addToPendingCount(1);
@@ -374,7 +376,7 @@
* result = mapper.apply(array[l]);
* // process completions by reducing along and advancing subtask links
* for (CountedCompleter<?> c = firstComplete(); c != null; c = c.nextComplete()) {
- * for (MapReducer t = (MapReducer)c, s = t.forks; s != null; s = t.forks = s.next)
+ * for (MapReducer t = (MapReducer)c, s = t.forks; s != null; s = t.forks = s.next)
* t.result = reducer.apply(t.result, s.result);
* }
* }
@@ -402,8 +404,7 @@
* // sample use:
* PacketSender p = new PacketSender();
* new HeaderBuilder(p, ...).fork();
- * new BodyBuilder(p, ...).fork();
- * }</pre>
+ * new BodyBuilder(p, ...).fork();}</pre>
*
* @since 1.8
* @author Doug Lea
@@ -733,7 +734,7 @@
}
/**
- * Returns the result of the computation. By default
+ * Returns the result of the computation. By default,
* returns {@code null}, which is appropriate for {@code Void}
* actions, but in other cases should be overridden, almost
* always to return a field or function of a field that
@@ -753,14 +754,13 @@
protected void setRawResult(T t) { }
// Unsafe mechanics
- private static final sun.misc.Unsafe U;
+ private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
private static final long PENDING;
static {
try {
- U = sun.misc.Unsafe.getUnsafe();
PENDING = U.objectFieldOffset
(CountedCompleter.class.getDeclaredField("pending"));
- } catch (Exception e) {
+ } catch (ReflectiveOperationException e) {
throw new Error(e);
}
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/CyclicBarrier.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/CyclicBarrier.java Tue Oct 13 16:45:35 2015 -0700
@@ -34,6 +34,7 @@
*/
package java.util.concurrent;
+
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
@@ -54,7 +55,7 @@
* <p><b>Sample usage:</b> Here is an example of using a barrier in a
* parallel decomposition design:
*
- * <pre> {@code
+ * <pre> {@code
* class Solver {
* final int N;
* final float[][] data;
@@ -85,7 +86,7 @@
* new Runnable() { public void run() { mergeRows(...); }};
* barrier = new CyclicBarrier(N, barrierAction);
*
- * List<Thread> threads = new ArrayList<Thread>(N);
+ * List<Thread> threads = new ArrayList<>(N);
* for (int i = 0; i < N; i++) {
* Thread thread = new Thread(new Worker(i));
* threads.add(thread);
@@ -111,7 +112,7 @@
* {@link #await} returns the arrival index of that thread at the barrier.
* You can then choose which thread should execute the barrier action, for
* example:
- * <pre> {@code
+ * <pre> {@code
* if (barrier.await() == 0) {
* // log the completion of this iteration
* }}</pre>
@@ -149,7 +150,7 @@
* but no subsequent reset.
*/
private static class Generation {
- boolean broken = false;
+ boolean broken; // initially false
}
/** The lock for guarding barrier entry */
@@ -158,7 +159,7 @@
private final Condition trip = lock.newCondition();
/** The number of parties */
private final int parties;
- /* The command to run when tripped */
+ /** The command to run when tripped */
private final Runnable barrierCommand;
/** The current generation */
private Generation generation = new Generation();
--- a/jdk/src/java.base/share/classes/java/util/concurrent/DelayQueue.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/DelayQueue.java Tue Oct 13 16:45:35 2015 -0700
@@ -34,10 +34,16 @@
*/
package java.util.concurrent;
+
import static java.util.concurrent.TimeUnit.NANOSECONDS;
+
+import java.util.AbstractQueue;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.PriorityQueue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
-import java.util.*;
/**
* An unbounded {@linkplain BlockingQueue blocking queue} of
@@ -65,7 +71,7 @@
*
* @since 1.5
* @author Doug Lea
- * @param <E> the type of elements held in this collection
+ * @param <E> the type of elements held in this queue
*/
public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
implements BlockingQueue<E> {
@@ -89,7 +95,7 @@
* signalled. So waiting threads must be prepared to acquire
* and lose leadership while waiting.
*/
- private Thread leader = null;
+ private Thread leader;
/**
* Condition signalled when a newer element becomes available
@@ -185,10 +191,9 @@
lock.lock();
try {
E first = q.peek();
- if (first == null || first.getDelay(NANOSECONDS) > 0)
- return null;
- else
- return q.poll();
+ return (first == null || first.getDelay(NANOSECONDS) > 0)
+ ? null
+ : q.poll();
} finally {
lock.unlock();
}
@@ -211,7 +216,7 @@
available.await();
else {
long delay = first.getDelay(NANOSECONDS);
- if (delay <= 0)
+ if (delay <= 0L)
return q.poll();
first = null; // don't retain ref while waiting
if (leader != null)
@@ -253,15 +258,15 @@
for (;;) {
E first = q.peek();
if (first == null) {
- if (nanos <= 0)
+ if (nanos <= 0L)
return null;
else
nanos = available.awaitNanos(nanos);
} else {
long delay = first.getDelay(NANOSECONDS);
- if (delay <= 0)
+ if (delay <= 0L)
return q.poll();
- if (nanos <= 0)
+ if (nanos <= 0L)
return null;
first = null; // don't retain ref while waiting
if (nanos < delay || leader != null)
@@ -490,7 +495,7 @@
}
/**
- * Identity-based version for use in Itr.remove
+ * Identity-based version for use in Itr.remove.
*/
void removeEQ(Object o) {
final ReentrantLock lock = this.lock;
--- a/jdk/src/java.base/share/classes/java/util/concurrent/Exchanger.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/Exchanger.java Tue Oct 13 16:45:35 2015 -0700
@@ -35,9 +35,6 @@
*/
package java.util.concurrent;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.concurrent.locks.LockSupport;
/**
* A synchronization point at which threads can pair and swap elements
@@ -53,9 +50,9 @@
* to swap buffers between threads so that the thread filling the
* buffer gets a freshly emptied one when it needs it, handing off the
* filled one to the thread emptying the buffer.
- * <pre> {@code
+ * <pre> {@code
* class FillAndEmpty {
- * Exchanger<DataBuffer> exchanger = new Exchanger<DataBuffer>();
+ * Exchanger<DataBuffer> exchanger = new Exchanger<>();
* DataBuffer initialEmptyBuffer = ... a made-up type
* DataBuffer initialFullBuffer = ...
*
@@ -326,7 +323,7 @@
}
/**
- * Per-thread state
+ * Per-thread state.
*/
private final Participant participant;
@@ -628,37 +625,33 @@
}
// Unsafe mechanics
- private static final sun.misc.Unsafe U;
+ private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
private static final long BOUND;
private static final long SLOT;
private static final long MATCH;
private static final long BLOCKER;
private static final int ABASE;
static {
- int s;
try {
- U = sun.misc.Unsafe.getUnsafe();
- Class<?> ek = Exchanger.class;
- Class<?> nk = Node.class;
- Class<?> ak = Node[].class;
- Class<?> tk = Thread.class;
BOUND = U.objectFieldOffset
- (ek.getDeclaredField("bound"));
+ (Exchanger.class.getDeclaredField("bound"));
SLOT = U.objectFieldOffset
- (ek.getDeclaredField("slot"));
+ (Exchanger.class.getDeclaredField("slot"));
+
MATCH = U.objectFieldOffset
- (nk.getDeclaredField("match"));
+ (Node.class.getDeclaredField("match"));
+
BLOCKER = U.objectFieldOffset
- (tk.getDeclaredField("parkBlocker"));
- s = U.arrayIndexScale(ak);
+ (Thread.class.getDeclaredField("parkBlocker"));
+
+ int scale = U.arrayIndexScale(Node[].class);
+ if ((scale & (scale - 1)) != 0 || scale > (1 << ASHIFT))
+ throw new Error("Unsupported array scale");
// ABASE absorbs padding in front of element 0
- ABASE = U.arrayBaseOffset(ak) + (1 << ASHIFT);
-
- } catch (Exception e) {
+ ABASE = U.arrayBaseOffset(Node[].class) + (1 << ASHIFT);
+ } catch (ReflectiveOperationException e) {
throw new Error(e);
}
- if ((s & (s-1)) != 0 || s > (1 << ASHIFT))
- throw new Error("Unsupported array scale");
}
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/Executor.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/Executor.java Tue Oct 13 16:45:35 2015 -0700
@@ -41,33 +41,31 @@
* mechanics of how each task will be run, including details of thread
* use, scheduling, etc. An {@code Executor} is normally used
* instead of explicitly creating threads. For example, rather than
- * invoking {@code new Thread(new(RunnableTask())).start()} for each
+ * invoking {@code new Thread(new RunnableTask()).start()} for each
* of a set of tasks, you might use:
*
- * <pre>
- * Executor executor = <em>anExecutor</em>;
+ * <pre> {@code
+ * Executor executor = anExecutor();
* executor.execute(new RunnableTask1());
* executor.execute(new RunnableTask2());
- * ...
- * </pre>
+ * ...}</pre>
*
- * However, the {@code Executor} interface does not strictly
- * require that execution be asynchronous. In the simplest case, an
- * executor can run the submitted task immediately in the caller's
- * thread:
+ * However, the {@code Executor} interface does not strictly require
+ * that execution be asynchronous. In the simplest case, an executor
+ * can run the submitted task immediately in the caller's thread:
*
- * <pre> {@code
+ * <pre> {@code
* class DirectExecutor implements Executor {
* public void execute(Runnable r) {
* r.run();
* }
* }}</pre>
*
- * More typically, tasks are executed in some thread other
- * than the caller's thread. The executor below spawns a new thread
- * for each task.
+ * More typically, tasks are executed in some thread other than the
+ * caller's thread. The executor below spawns a new thread for each
+ * task.
*
- * <pre> {@code
+ * <pre> {@code
* class ThreadPerTaskExecutor implements Executor {
* public void execute(Runnable r) {
* new Thread(r).start();
@@ -79,9 +77,9 @@
* serializes the submission of tasks to a second executor,
* illustrating a composite executor.
*
- * <pre> {@code
+ * <pre> {@code
* class SerialExecutor implements Executor {
- * final Queue<Runnable> tasks = new ArrayDeque<Runnable>();
+ * final Queue<Runnable> tasks = new ArrayDeque<>();
* final Executor executor;
* Runnable active;
*
@@ -90,7 +88,7 @@
* }
*
* public synchronized void execute(final Runnable r) {
- * tasks.offer(new Runnable() {
+ * tasks.add(new Runnable() {
* public void run() {
* try {
* r.run();
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ExecutorCompletionService.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ExecutorCompletionService.java Tue Oct 13 16:45:35 2015 -0700
@@ -56,16 +56,16 @@
* void solve(Executor e,
* Collection<Callable<Result>> solvers)
* throws InterruptedException, ExecutionException {
- * CompletionService<Result> ecs
- * = new ExecutorCompletionService<Result>(e);
- * for (Callable<Result> s : solvers)
- * ecs.submit(s);
- * int n = solvers.size();
- * for (int i = 0; i < n; ++i) {
- * Result r = ecs.take().get();
- * if (r != null)
- * use(r);
- * }
+ * CompletionService<Result> ecs
+ * = new ExecutorCompletionService<Result>(e);
+ * for (Callable<Result> s : solvers)
+ * ecs.submit(s);
+ * int n = solvers.size();
+ * for (int i = 0; i < n; ++i) {
+ * Result r = ecs.take().get();
+ * if (r != null)
+ * use(r);
+ * }
* }}</pre>
*
* Suppose instead that you would like to use the first non-null result
@@ -76,32 +76,31 @@
* void solve(Executor e,
* Collection<Callable<Result>> solvers)
* throws InterruptedException {
- * CompletionService<Result> ecs
- * = new ExecutorCompletionService<Result>(e);
- * int n = solvers.size();
- * List<Future<Result>> futures
- * = new ArrayList<Future<Result>>(n);
- * Result result = null;
- * try {
- * for (Callable<Result> s : solvers)
- * futures.add(ecs.submit(s));
- * for (int i = 0; i < n; ++i) {
- * try {
- * Result r = ecs.take().get();
- * if (r != null) {
- * result = r;
- * break;
- * }
- * } catch (ExecutionException ignore) {}
+ * CompletionService<Result> ecs
+ * = new ExecutorCompletionService<Result>(e);
+ * int n = solvers.size();
+ * List<Future<Result>> futures = new ArrayList<>(n);
+ * Result result = null;
+ * try {
+ * for (Callable<Result> s : solvers)
+ * futures.add(ecs.submit(s));
+ * for (int i = 0; i < n; ++i) {
+ * try {
+ * Result r = ecs.take().get();
+ * if (r != null) {
+ * result = r;
+ * break;
* }
+ * } catch (ExecutionException ignore) {}
* }
- * finally {
- * for (Future<Result> f : futures)
- * f.cancel(true);
- * }
+ * }
+ * finally {
+ * for (Future<Result> f : futures)
+ * f.cancel(true);
+ * }
*
- * if (result != null)
- * use(result);
+ * if (result != null)
+ * use(result);
* }}</pre>
*/
public class ExecutorCompletionService<V> implements CompletionService<V> {
@@ -110,15 +109,18 @@
private final BlockingQueue<Future<V>> completionQueue;
/**
- * FutureTask extension to enqueue upon completion
+ * FutureTask extension to enqueue upon completion.
*/
- private class QueueingFuture extends FutureTask<Void> {
- QueueingFuture(RunnableFuture<V> task) {
+ private static class QueueingFuture<V> extends FutureTask<Void> {
+ QueueingFuture(RunnableFuture<V> task,
+ BlockingQueue<Future<V>> completionQueue) {
super(task, null);
this.task = task;
+ this.completionQueue = completionQueue;
}
+ private final Future<V> task;
+ private final BlockingQueue<Future<V>> completionQueue;
protected void done() { completionQueue.add(task); }
- private final Future<V> task;
}
private RunnableFuture<V> newTaskFor(Callable<V> task) {
@@ -178,14 +180,14 @@
public Future<V> submit(Callable<V> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<V> f = newTaskFor(task);
- executor.execute(new QueueingFuture(f));
+ executor.execute(new QueueingFuture<V>(f, completionQueue));
return f;
}
public Future<V> submit(Runnable task, V result) {
if (task == null) throw new NullPointerException();
RunnableFuture<V> f = newTaskFor(task, result);
- executor.execute(new QueueingFuture(f));
+ executor.execute(new QueueingFuture<V>(f, completionQueue));
return f;
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ExecutorService.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ExecutorService.java Tue Oct 13 16:45:35 2015 -0700
@@ -34,8 +34,9 @@
*/
package java.util.concurrent;
+
+import java.util.Collection;
import java.util.List;
-import java.util.Collection;
/**
* An {@link Executor} that provides methods to manage termination and
@@ -71,7 +72,7 @@
* pool service incoming requests. It uses the preconfigured {@link
* Executors#newFixedThreadPool} factory method:
*
- * <pre> {@code
+ * <pre> {@code
* class NetworkService implements Runnable {
* private final ServerSocket serverSocket;
* private final ExecutorService pool;
@@ -105,7 +106,7 @@
* first by calling {@code shutdown} to reject incoming tasks, and then
* calling {@code shutdownNow}, if necessary, to cancel any lingering tasks:
*
- * <pre> {@code
+ * <pre> {@code
* void shutdownAndAwaitTermination(ExecutorService pool) {
* pool.shutdown(); // Disable new tasks from being submitted
* try {
--- a/jdk/src/java.base/share/classes/java/util/concurrent/Executors.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/Executors.java Tue Oct 13 16:45:35 2015 -0700
@@ -34,14 +34,16 @@
*/
package java.util.concurrent;
-import java.util.*;
-import java.util.concurrent.atomic.AtomicInteger;
+
import java.security.AccessControlContext;
+import java.security.AccessControlException;
import java.security.AccessController;
import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
-import java.security.PrivilegedActionException;
-import java.security.AccessControlException;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
import sun.security.util.SecurityConstants;
/**
@@ -51,18 +53,18 @@
* package. This class supports the following kinds of methods:
*
* <ul>
- * <li> Methods that create and return an {@link ExecutorService}
- * set up with commonly useful configuration settings.
- * <li> Methods that create and return a {@link ScheduledExecutorService}
- * set up with commonly useful configuration settings.
- * <li> Methods that create and return a "wrapped" ExecutorService, that
- * disables reconfiguration by making implementation-specific methods
- * inaccessible.
- * <li> Methods that create and return a {@link ThreadFactory}
- * that sets newly created threads to a known state.
- * <li> Methods that create and return a {@link Callable}
- * out of other closure-like forms, so they can be used
- * in execution methods requiring {@code Callable}.
+ * <li>Methods that create and return an {@link ExecutorService}
+ * set up with commonly useful configuration settings.
+ * <li>Methods that create and return a {@link ScheduledExecutorService}
+ * set up with commonly useful configuration settings.
+ * <li>Methods that create and return a "wrapped" ExecutorService, that
+ * disables reconfiguration by making implementation-specific methods
+ * inaccessible.
+ * <li>Methods that create and return a {@link ThreadFactory}
+ * that sets newly created threads to a known state.
+ * <li>Methods that create and return a {@link Callable}
+ * out of other closure-like forms, so they can be used
+ * in execution methods requiring {@code Callable}.
* </ul>
*
* @since 1.5
@@ -114,9 +116,10 @@
}
/**
- * Creates a work-stealing thread pool using all
- * {@link Runtime#availableProcessors available processors}
+ * Creates a work-stealing thread pool using the number of
+ * {@linkplain Runtime#availableProcessors available processors}
* as its target parallelism level.
+ *
* @return the newly created thread pool
* @see #newWorkStealingPool(int)
* @since 1.8
@@ -498,11 +501,11 @@
// Non-public classes supporting the public methods
/**
- * A callable that runs given task and returns given result
+ * A callable that runs given task and returns given result.
*/
- static final class RunnableAdapter<T> implements Callable<T> {
- final Runnable task;
- final T result;
+ private static final class RunnableAdapter<T> implements Callable<T> {
+ private final Runnable task;
+ private final T result;
RunnableAdapter(Runnable task, T result) {
this.task = task;
this.result = result;
@@ -514,11 +517,11 @@
}
/**
- * A callable that runs under established access control settings
+ * A callable that runs under established access control settings.
*/
- static final class PrivilegedCallable<T> implements Callable<T> {
- private final Callable<T> task;
- private final AccessControlContext acc;
+ private static final class PrivilegedCallable<T> implements Callable<T> {
+ final Callable<T> task;
+ final AccessControlContext acc;
PrivilegedCallable(Callable<T> task) {
this.task = task;
@@ -541,12 +544,13 @@
/**
* A callable that runs under established access control settings and
- * current ClassLoader
+ * current ClassLoader.
*/
- static final class PrivilegedCallableUsingCurrentClassLoader<T> implements Callable<T> {
- private final Callable<T> task;
- private final AccessControlContext acc;
- private final ClassLoader ccl;
+ private static final class PrivilegedCallableUsingCurrentClassLoader<T>
+ implements Callable<T> {
+ final Callable<T> task;
+ final AccessControlContext acc;
+ final ClassLoader ccl;
PrivilegedCallableUsingCurrentClassLoader(Callable<T> task) {
SecurityManager sm = System.getSecurityManager();
@@ -591,9 +595,9 @@
}
/**
- * The default thread factory
+ * The default thread factory.
*/
- static class DefaultThreadFactory implements ThreadFactory {
+ private static class DefaultThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
@@ -621,11 +625,11 @@
}
/**
- * Thread factory capturing access control context and class loader
+ * Thread factory capturing access control context and class loader.
*/
- static class PrivilegedThreadFactory extends DefaultThreadFactory {
- private final AccessControlContext acc;
- private final ClassLoader ccl;
+ private static class PrivilegedThreadFactory extends DefaultThreadFactory {
+ final AccessControlContext acc;
+ final ClassLoader ccl;
PrivilegedThreadFactory() {
super();
@@ -662,7 +666,8 @@
* A wrapper class that exposes only the ExecutorService methods
* of an ExecutorService implementation.
*/
- static class DelegatedExecutorService extends AbstractExecutorService {
+ private static class DelegatedExecutorService
+ extends AbstractExecutorService {
private final ExecutorService e;
DelegatedExecutorService(ExecutorService executor) { e = executor; }
public void execute(Runnable command) { e.execute(command); }
@@ -703,8 +708,8 @@
}
}
- static class FinalizableDelegatedExecutorService
- extends DelegatedExecutorService {
+ private static class FinalizableDelegatedExecutorService
+ extends DelegatedExecutorService {
FinalizableDelegatedExecutorService(ExecutorService executor) {
super(executor);
}
@@ -717,7 +722,7 @@
* A wrapper class that exposes only the ScheduledExecutorService
* methods of a ScheduledExecutorService implementation.
*/
- static class DelegatedScheduledExecutorService
+ private static class DelegatedScheduledExecutorService
extends DelegatedExecutorService
implements ScheduledExecutorService {
private final ScheduledExecutorService e;
--- a/jdk/src/java.base/share/classes/java/util/concurrent/Future.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/Future.java Tue Oct 13 16:45:35 2015 -0700
@@ -53,6 +53,7 @@
* <p>
* <b>Sample Usage</b> (Note that the following classes are all
* made-up.)
+ *
* <pre> {@code
* interface ArchiveSearcher { String search(String target); }
* class App {
@@ -75,9 +76,9 @@
* The {@link FutureTask} class is an implementation of {@code Future} that
* implements {@code Runnable}, and so may be executed by an {@code Executor}.
* For example, the above construction with {@code submit} could be replaced by:
- * <pre> {@code
+ * <pre> {@code
* FutureTask<String> future =
- * new FutureTask<String>(new Callable<String>() {
+ * new FutureTask<>(new Callable<String>() {
* public String call() {
* return searcher.search(target);
* }});
--- a/jdk/src/java.base/share/classes/java/util/concurrent/FutureTask.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/FutureTask.java Tue Oct 13 16:45:35 2015 -0700
@@ -34,6 +34,7 @@
*/
package java.util.concurrent;
+
import java.util.concurrent.locks.LockSupport;
/**
@@ -395,7 +396,7 @@
throws InterruptedException {
// The code below is very delicate, to achieve these goals:
// - call nanoTime exactly once for each call to park
- // - if nanos <= 0, return promptly without allocation or nanoTime
+ // - if nanos <= 0L, return promptly without allocation or nanoTime
// - if nanos == Long.MIN_VALUE, don't underflow
// - if nanos == Long.MAX_VALUE, and nanoTime is non-monotonic
// and we suffer a spurious wakeup, we will do no worse than
@@ -404,19 +405,20 @@
WaitNode q = null;
boolean queued = false;
for (;;) {
- if (Thread.interrupted()) {
- removeWaiter(q);
- throw new InterruptedException();
- }
-
int s = state;
if (s > COMPLETING) {
if (q != null)
q.thread = null;
return s;
}
- else if (s == COMPLETING) // cannot time out yet
+ else if (s == COMPLETING)
+ // We may have already promised (via isDone) that we are done
+ // so never return empty-handed or throw InterruptedException
Thread.yield();
+ else if (Thread.interrupted()) {
+ removeWaiter(q);
+ throw new InterruptedException();
+ }
else if (q == null) {
if (timed && nanos <= 0L)
return s;
@@ -440,7 +442,9 @@
}
parkNanos = nanos - elapsed;
}
- LockSupport.parkNanos(this, parkNanos);
+ // nanoTime may be slow; recheck before parking
+ if (state < COMPLETING)
+ LockSupport.parkNanos(this, parkNanos);
}
else
LockSupport.park(this);
@@ -480,20 +484,25 @@
}
// Unsafe mechanics
- private static final sun.misc.Unsafe U;
+ private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
private static final long STATE;
private static final long RUNNER;
private static final long WAITERS;
static {
try {
- U = sun.misc.Unsafe.getUnsafe();
- Class<?> k = FutureTask.class;
- STATE = U.objectFieldOffset(k.getDeclaredField("state"));
- RUNNER = U.objectFieldOffset(k.getDeclaredField("runner"));
- WAITERS = U.objectFieldOffset(k.getDeclaredField("waiters"));
- } catch (Exception e) {
+ STATE = U.objectFieldOffset
+ (FutureTask.class.getDeclaredField("state"));
+ RUNNER = U.objectFieldOffset
+ (FutureTask.class.getDeclaredField("runner"));
+ WAITERS = U.objectFieldOffset
+ (FutureTask.class.getDeclaredField("waiters"));
+ } catch (ReflectiveOperationException e) {
throw new Error(e);
}
+
+ // Reduce the risk of rare disastrous classloading in first call to
+ // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+ Class<?> ensureLoaded = LockSupport.class;
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/Helpers.java Tue Oct 13 16:45:35 2015 -0700
@@ -0,0 +1,118 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Martin Buchholz with assistance from members of JCP
+ * JSR-166 Expert Group and released to the public domain, as
+ * explained at http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.Collection;
+
+/** Shared implementation code for java.util.concurrent. */
+class Helpers {
+ private Helpers() {} // non-instantiable
+
+ /**
+ * An implementation of Collection.toString() suitable for classes
+ * with locks. Instead of holding a lock for the entire duration of
+ * toString(), or acquiring a lock for each call to Iterator.next(),
+ * we hold the lock only during the call to toArray() (less
+ * disruptive to other threads accessing the collection) and follows
+ * the maxim "Never call foreign code while holding a lock".
+ */
+ static String collectionToString(Collection<?> c) {
+ final Object[] a = c.toArray();
+ final int size = a.length;
+ if (size == 0)
+ return "[]";
+ int charLength = 0;
+
+ // Replace every array element with its string representation
+ for (int i = 0; i < size; i++) {
+ Object e = a[i];
+ // Extreme compatibility with AbstractCollection.toString()
+ String s = (e == c) ? "(this Collection)" : objectToString(e);
+ a[i] = s;
+ charLength += s.length();
+ }
+
+ return toString(a, size, charLength);
+ }
+
+ /**
+ * Like Arrays.toString(), but caller guarantees that size > 0,
+ * each element with index 0 <= i < size is a non-null String,
+ * and charLength is the sum of the lengths of the input Strings.
+ */
+ static String toString(Object[] a, int size, int charLength) {
+ // assert a != null;
+ // assert size > 0;
+
+ // Copy each string into a perfectly sized char[]
+ // Length of [ , , , ] == 2 * size
+ final char[] chars = new char[charLength + 2 * size];
+ chars[0] = '[';
+ int j = 1;
+ for (int i = 0; i < size; i++) {
+ if (i > 0) {
+ chars[j++] = ',';
+ chars[j++] = ' ';
+ }
+ String s = (String) a[i];
+ int len = s.length();
+ s.getChars(0, len, chars, j);
+ j += len;
+ }
+ chars[j] = ']';
+ // assert j == chars.length - 1;
+ return new String(chars);
+ }
+
+ /** Optimized form of: key + "=" + val */
+ static String mapEntryToString(Object key, Object val) {
+ final String k, v;
+ final int klen, vlen;
+ final char[] chars =
+ new char[(klen = (k = objectToString(key)).length()) +
+ (vlen = (v = objectToString(val)).length()) + 1];
+ k.getChars(0, klen, chars, 0);
+ chars[klen] = '=';
+ v.getChars(0, vlen, chars, klen + 1);
+ return new String(chars);
+ }
+
+ private static String objectToString(Object x) {
+ // Extreme compatibility with StringBuilder.append(null)
+ String s;
+ return (x == null || (s = x.toString()) == null) ? "null" : s;
+ }
+}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/LinkedBlockingDeque.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/LinkedBlockingDeque.java Tue Oct 13 16:45:35 2015 -0700
@@ -39,10 +39,10 @@
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
+import java.util.Spliterator;
+import java.util.Spliterators;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
-import java.util.Spliterator;
-import java.util.Spliterators;
import java.util.function.Consumer;
/**
@@ -72,7 +72,7 @@
*
* @since 1.6
* @author Doug Lea
- * @param <E> the type of elements held in this collection
+ * @param <E> the type of elements held in this deque
*/
public class LinkedBlockingDeque<E>
extends AbstractQueue<E>
@@ -412,7 +412,7 @@
lock.lockInterruptibly();
try {
while (!linkFirst(node)) {
- if (nanos <= 0)
+ if (nanos <= 0L)
return false;
nanos = notFull.awaitNanos(nanos);
}
@@ -435,7 +435,7 @@
lock.lockInterruptibly();
try {
while (!linkLast(node)) {
- if (nanos <= 0)
+ if (nanos <= 0L)
return false;
nanos = notFull.awaitNanos(nanos);
}
@@ -517,7 +517,7 @@
try {
E x;
while ( (x = unlinkFirst()) == null) {
- if (nanos <= 0)
+ if (nanos <= 0L)
return null;
nanos = notEmpty.awaitNanos(nanos);
}
@@ -535,7 +535,7 @@
try {
E x;
while ( (x = unlinkLast()) == null) {
- if (nanos <= 0)
+ if (nanos <= 0L)
return null;
nanos = notEmpty.awaitNanos(nanos);
}
@@ -924,7 +924,7 @@
* The following code can be used to dump the deque into a newly
* allocated array of {@code String}:
*
- * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+ * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
*
* Note that {@code toArray(new Object[0])} is identical in function to
* {@code toArray()}.
@@ -959,26 +959,7 @@
}
public String toString() {
- final ReentrantLock lock = this.lock;
- lock.lock();
- try {
- Node<E> p = first;
- if (p == null)
- return "[]";
-
- StringBuilder sb = new StringBuilder();
- sb.append('[');
- for (;;) {
- E e = p.item;
- sb.append(e == this ? "(this Collection)" : e);
- p = p.next;
- if (p == null)
- return sb.append(']').toString();
- sb.append(',').append(' ');
- }
- } finally {
- lock.unlock();
- }
+ return Helpers.collectionToString(this);
}
/**
@@ -1032,11 +1013,11 @@
}
/**
- * Base class for Iterators for LinkedBlockingDeque
+ * Base class for LinkedBlockingDeque iterators.
*/
private abstract class AbstractItr implements Iterator<E> {
/**
- * The next node to return in next()
+ * The next node to return in next().
*/
Node<E> next;
@@ -1192,8 +1173,9 @@
if (i > 0) {
batch = i;
return Spliterators.spliterator
- (a, 0, i, Spliterator.ORDERED | Spliterator.NONNULL |
- Spliterator.CONCURRENT);
+ (a, 0, i, (Spliterator.ORDERED |
+ Spliterator.NONNULL |
+ Spliterator.CONCURRENT));
}
}
return null;
--- a/jdk/src/java.base/share/classes/java/util/concurrent/LinkedBlockingQueue.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/LinkedBlockingQueue.java Tue Oct 13 16:45:35 2015 -0700
@@ -35,15 +35,15 @@
package java.util.concurrent;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.locks.Condition;
-import java.util.concurrent.locks.ReentrantLock;
import java.util.AbstractQueue;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Spliterator;
import java.util.Spliterators;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
/**
@@ -75,7 +75,7 @@
*
* @since 1.5
* @author Doug Lea
- * @param <E> the type of elements held in this collection
+ * @param <E> the type of elements held in this queue
*/
public class LinkedBlockingQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable {
@@ -117,7 +117,7 @@
*/
/**
- * Linked list node class
+ * Linked list node class.
*/
static class Node<E> {
E item;
@@ -380,7 +380,7 @@
putLock.lockInterruptibly();
try {
while (count.get() == capacity) {
- if (nanos <= 0)
+ if (nanos <= 0L)
return false;
nanos = notFull.awaitNanos(nanos);
}
@@ -462,7 +462,7 @@
takeLock.lockInterruptibly();
try {
while (count.get() == 0) {
- if (nanos <= 0)
+ if (nanos <= 0L)
return null;
nanos = notEmpty.awaitNanos(nanos);
}
@@ -507,11 +507,7 @@
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();
try {
- Node<E> first = head.next;
- if (first == null)
- return null;
- else
- return first.item;
+ return (count.get() > 0) ? head.next.item : null;
} finally {
takeLock.unlock();
}
@@ -630,7 +626,7 @@
* The following code can be used to dump the queue into a newly
* allocated array of {@code String}:
*
- * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+ * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
*
* Note that {@code toArray(new Object[0])} is identical in function to
* {@code toArray()}.
@@ -665,25 +661,7 @@
}
public String toString() {
- fullyLock();
- try {
- Node<E> p = head.next;
- if (p == null)
- return "[]";
-
- StringBuilder sb = new StringBuilder();
- sb.append('[');
- for (;;) {
- E e = p.item;
- sb.append(e == this ? "(this Collection)" : e);
- p = p.next;
- if (p == null)
- return sb.append(']').toString();
- sb.append(',').append(' ');
- }
- } finally {
- fullyUnlock();
- }
+ return Helpers.collectionToString(this);
}
/**
@@ -801,34 +779,26 @@
return current != null;
}
- /**
- * Returns the next live successor of p, or null if no such.
- *
- * Unlike other traversal methods, iterators need to handle both:
- * - dequeued nodes (p.next == p)
- * - (possibly multiple) interior removed nodes (p.item == null)
- */
- private Node<E> nextNode(Node<E> p) {
- for (;;) {
- Node<E> s = p.next;
- if (s == p)
- return head.next;
- if (s == null || s.item != null)
- return s;
- p = s;
- }
- }
-
public E next() {
fullyLock();
try {
if (current == null)
throw new NoSuchElementException();
- E x = currentElement;
lastRet = current;
- current = nextNode(current);
- currentElement = (current == null) ? null : current.item;
- return x;
+ E item = null;
+ // Unlike other traversal methods, iterators must handle both:
+ // - dequeued nodes (p.next == p)
+ // - (possibly multiple) interior removed nodes (p.item == null)
+ for (Node<E> p = current, q;; p = q) {
+ if ((q = p.next) == p)
+ q = head.next;
+ if (q == null || (item = q.item) != null) {
+ current = q;
+ E x = currentElement;
+ currentElement = item;
+ return x;
+ }
+ }
} finally {
fullyUnlock();
}
@@ -901,8 +871,9 @@
if (i > 0) {
batch = i;
return Spliterators.spliterator
- (a, 0, i, Spliterator.ORDERED | Spliterator.NONNULL |
- Spliterator.CONCURRENT);
+ (a, 0, i, (Spliterator.ORDERED |
+ Spliterator.NONNULL |
+ Spliterator.CONCURRENT));
}
}
return null;
--- a/jdk/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java Tue Oct 13 16:45:35 2015 -0700
@@ -36,14 +36,14 @@
package java.util.concurrent;
import java.util.AbstractQueue;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Queue;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.LockSupport;
import java.util.Spliterator;
import java.util.Spliterators;
+import java.util.concurrent.locks.LockSupport;
import java.util.function.Consumer;
/**
@@ -83,7 +83,7 @@
*
* @since 1.7
* @author Doug Lea
- * @param <E> the type of elements held in this collection
+ * @param <E> the type of elements held in this queue
*/
public class LinkedTransferQueue<E> extends AbstractQueue<E>
implements TransferQueue<E>, java.io.Serializable {
@@ -108,7 +108,7 @@
*
* A FIFO dual queue may be implemented using a variation of the
* Michael & Scott (M&S) lock-free queue algorithm
- * (http://www.cs.rochester.edu/u/scott/papers/1996_PODC_queues.pdf).
+ * (http://www.cs.rochester.edu/~scott/papers/1996_PODC_queues.pdf).
* It maintains two pointer fields, "head", pointing to a
* (matched) node that in turn points to the first actual
* (unmatched) queue node (or null if empty); and "tail" that
@@ -215,7 +215,7 @@
* of costly-to-reclaim garbage caused by the sequential "next"
* links of nodes starting at old forgotten head nodes: As first
* described in detail by Boehm
- * (http://portal.acm.org/citation.cfm?doid=503272.503282) if a GC
+ * (http://portal.acm.org/citation.cfm?doid=503272.503282), if a GC
* delays noticing that any arbitrarily old node has become
* garbage, all newer dead nodes will also be unreclaimed.
* (Similar issues arise in non-GC environments.) To cope with
@@ -456,12 +456,12 @@
// CAS methods for fields
final boolean casNext(Node cmp, Node val) {
- return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
+ return U.compareAndSwapObject(this, NEXT, cmp, val);
}
final boolean casItem(Object cmp, Object val) {
// assert cmp == null || cmp.getClass() != Node.class;
- return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);
+ return U.compareAndSwapObject(this, ITEM, cmp, val);
}
/**
@@ -469,7 +469,7 @@
* only be seen after publication via casNext.
*/
Node(Object item, boolean isData) {
- UNSAFE.putObject(this, itemOffset, item); // relaxed write
+ U.putObject(this, ITEM, item); // relaxed write
this.isData = isData;
}
@@ -478,7 +478,7 @@
* only after CASing head field, so uses relaxed write.
*/
final void forgetNext() {
- UNSAFE.putObject(this, nextOffset, this);
+ U.putObject(this, NEXT, this);
}
/**
@@ -491,8 +491,8 @@
* else we don't care).
*/
final void forgetContents() {
- UNSAFE.putObject(this, itemOffset, this);
- UNSAFE.putObject(this, waiterOffset, null);
+ U.putObject(this, ITEM, this);
+ U.putObject(this, WAITER, null);
}
/**
@@ -538,21 +538,19 @@
private static final long serialVersionUID = -3375979862319811754L;
// Unsafe mechanics
- private static final sun.misc.Unsafe UNSAFE;
- private static final long itemOffset;
- private static final long nextOffset;
- private static final long waiterOffset;
+ private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+ private static final long ITEM;
+ private static final long NEXT;
+ private static final long WAITER;
static {
try {
- UNSAFE = sun.misc.Unsafe.getUnsafe();
- Class<?> k = Node.class;
- itemOffset = UNSAFE.objectFieldOffset
- (k.getDeclaredField("item"));
- nextOffset = UNSAFE.objectFieldOffset
- (k.getDeclaredField("next"));
- waiterOffset = UNSAFE.objectFieldOffset
- (k.getDeclaredField("waiter"));
- } catch (Exception e) {
+ ITEM = U.objectFieldOffset
+ (Node.class.getDeclaredField("item"));
+ NEXT = U.objectFieldOffset
+ (Node.class.getDeclaredField("next"));
+ WAITER = U.objectFieldOffset
+ (Node.class.getDeclaredField("waiter"));
+ } catch (ReflectiveOperationException e) {
throw new Error(e);
}
}
@@ -569,15 +567,15 @@
// CAS methods for fields
private boolean casTail(Node cmp, Node val) {
- return UNSAFE.compareAndSwapObject(this, tailOffset, cmp, val);
+ return U.compareAndSwapObject(this, TAIL, cmp, val);
}
private boolean casHead(Node cmp, Node val) {
- return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val);
+ return U.compareAndSwapObject(this, HEAD, cmp, val);
}
private boolean casSweepVotes(int cmp, int val) {
- return UNSAFE.compareAndSwapInt(this, sweepVotesOffset, cmp, val);
+ return U.compareAndSwapInt(this, SWEEPVOTES, cmp, val);
}
/*
@@ -588,12 +586,6 @@
private static final int SYNC = 2; // for transfer, take
private static final int TIMED = 3; // for timed poll, tryTransfer
- @SuppressWarnings("unchecked")
- static <E> E cast(Object item) {
- // assert item == null || item.getClass() != Node.class;
- return (E) item;
- }
-
/**
* Implements all queuing methods. See above for explanation.
*
@@ -630,7 +622,8 @@
break; // unless slack < 2
}
LockSupport.unpark(p.waiter);
- return LinkedTransferQueue.<E>cast(item);
+ @SuppressWarnings("unchecked") E itemE = (E) item;
+ return itemE;
}
}
Node n = p.next;
@@ -708,15 +701,15 @@
if (item != e) { // matched
// assert item != s;
s.forgetContents(); // avoid garbage
- return LinkedTransferQueue.<E>cast(item);
+ @SuppressWarnings("unchecked") E itemE = (E) item;
+ return itemE;
}
- if ((w.isInterrupted() || (timed && nanos <= 0)) &&
- s.casItem(e, s)) { // cancel
- unsplice(pred, s);
- return e;
+ else if (w.isInterrupted() || (timed && nanos <= 0L)) {
+ unsplice(pred, s); // try to unlink and cancel
+ if (s.casItem(e, s)) // return normally if lost CAS
+ return e;
}
-
- if (spins < 0) { // establish spins at/near front
+ else if (spins < 0) { // establish spins at/near front
if ((spins = spinsFor(pred, s.isData)) > 0)
randomYields = ThreadLocalRandom.current();
}
@@ -768,52 +761,25 @@
}
/**
- * Returns the first unmatched node of the given mode, or null if
- * none. Used by methods isEmpty, hasWaitingConsumer.
- */
- private Node firstOfMode(boolean isData) {
- for (Node p = head; p != null; p = succ(p)) {
- if (!p.isMatched())
- return (p.isData == isData) ? p : null;
- }
- return null;
- }
-
- /**
- * Version of firstOfMode used by Spliterator. Callers must
- * recheck if the returned node's item field is null or
- * self-linked before using.
+ * Returns the first unmatched data node, or null if none.
+ * Callers must recheck if the returned node's item field is null
+ * or self-linked before using.
*/
final Node firstDataNode() {
- for (Node p = head; p != null;) {
- Object item = p.item;
- if (p.isData) {
- if (item != null && item != p)
- return p;
+ restartFromHead: for (;;) {
+ for (Node p = head; p != null;) {
+ Object item = p.item;
+ if (p.isData) {
+ if (item != null && item != p)
+ return p;
+ }
+ else if (item == null)
+ break;
+ if (p == (p = p.next))
+ continue restartFromHead;
}
- else if (item == null)
- break;
- if (p == (p = p.next))
- p = head;
+ return null;
}
- return null;
- }
-
- /**
- * Returns the item in the first unmatched node with isData; or
- * null if none. Used by peek.
- */
- private E firstDataItem() {
- for (Node p = head; p != null; p = succ(p)) {
- Object item = p.item;
- if (p.isData) {
- if (item != null && item != p)
- return LinkedTransferQueue.<E>cast(item);
- }
- else if (item == null)
- return null;
- }
- return null;
}
/**
@@ -821,23 +787,140 @@
* Used by methods size and getWaitingConsumerCount.
*/
private int countOfMode(boolean data) {
- int count = 0;
- for (Node p = head; p != null; ) {
- if (!p.isMatched()) {
- if (p.isData != data)
- return 0;
- if (++count == Integer.MAX_VALUE) // saturated
+ restartFromHead: for (;;) {
+ int count = 0;
+ for (Node p = head; p != null;) {
+ if (!p.isMatched()) {
+ if (p.isData != data)
+ return 0;
+ if (++count == Integer.MAX_VALUE)
+ break; // @see Collection.size()
+ }
+ if (p == (p = p.next))
+ continue restartFromHead;
+ }
+ return count;
+ }
+ }
+
+ public String toString() {
+ String[] a = null;
+ restartFromHead: for (;;) {
+ int charLength = 0;
+ int size = 0;
+ for (Node p = head; p != null;) {
+ Object item = p.item;
+ if (p.isData) {
+ if (item != null && item != p) {
+ if (a == null)
+ a = new String[4];
+ else if (size == a.length)
+ a = Arrays.copyOf(a, 2 * size);
+ String s = item.toString();
+ a[size++] = s;
+ charLength += s.length();
+ }
+ } else if (item == null)
break;
+ if (p == (p = p.next))
+ continue restartFromHead;
+ }
+
+ if (size == 0)
+ return "[]";
+
+ return Helpers.toString(a, size, charLength);
+ }
+ }
+
+ private Object[] toArrayInternal(Object[] a) {
+ Object[] x = a;
+ restartFromHead: for (;;) {
+ int size = 0;
+ for (Node p = head; p != null;) {
+ Object item = p.item;
+ if (p.isData) {
+ if (item != null && item != p) {
+ if (x == null)
+ x = new Object[4];
+ else if (size == x.length)
+ x = Arrays.copyOf(x, 2 * (size + 4));
+ x[size++] = item;
+ }
+ } else if (item == null)
+ break;
+ if (p == (p = p.next))
+ continue restartFromHead;
}
- Node n = p.next;
- if (n != p)
- p = n;
- else {
- count = 0;
- p = head;
+ if (x == null)
+ return new Object[0];
+ else if (a != null && size <= a.length) {
+ if (a != x)
+ System.arraycopy(x, 0, a, 0, size);
+ if (size < a.length)
+ a[size] = null;
+ return a;
}
+ return (size == x.length) ? x : Arrays.copyOf(x, size);
}
- return count;
+ }
+
+ /**
+ * Returns an array containing all of the elements in this queue, in
+ * proper sequence.
+ *
+ * <p>The returned array will be "safe" in that no references to it are
+ * maintained by this queue. (In other words, this method must allocate
+ * a new array). The caller is thus free to modify the returned array.
+ *
+ * <p>This method acts as bridge between array-based and collection-based
+ * APIs.
+ *
+ * @return an array containing all of the elements in this queue
+ */
+ public Object[] toArray() {
+ return toArrayInternal(null);
+ }
+
+ /**
+ * Returns an array containing all of the elements in this queue, in
+ * proper sequence; the runtime type of the returned array is that of
+ * the specified array. If the queue fits in the specified array, it
+ * is returned therein. Otherwise, a new array is allocated with the
+ * runtime type of the specified array and the size of this queue.
+ *
+ * <p>If this queue fits in the specified array with room to spare
+ * (i.e., the array has more elements than this queue), the element in
+ * the array immediately following the end of the queue is set to
+ * {@code null}.
+ *
+ * <p>Like the {@link #toArray()} method, this method acts as bridge between
+ * array-based and collection-based APIs. Further, this method allows
+ * precise control over the runtime type of the output array, and may,
+ * under certain circumstances, be used to save allocation costs.
+ *
+ * <p>Suppose {@code x} is a queue known to contain only strings.
+ * The following code can be used to dump the queue into a newly
+ * allocated array of {@code String}:
+ *
+ * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+ *
+ * Note that {@code toArray(new Object[0])} is identical in function to
+ * {@code toArray()}.
+ *
+ * @param a the array into which the elements of the queue 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 all of the elements in this queue
+ * @throws ArrayStoreException if the runtime type of the specified array
+ * is not a supertype of the runtime type of every element in
+ * this queue
+ * @throws NullPointerException if the specified array is null
+ */
+ @SuppressWarnings("unchecked")
+ public <T> T[] toArray(T[] a) {
+ if (a == null) throw new NullPointerException();
+ return (T[]) toArrayInternal(a);
}
final class Itr implements Iterator<E> {
@@ -886,7 +969,8 @@
Object item = s.item;
if (s.isData) {
if (item != null && item != s) {
- nextItem = LinkedTransferQueue.<E>cast(item);
+ @SuppressWarnings("unchecked") E itemE = (E) item;
+ nextItem = itemE;
nextNode = s;
return;
}
@@ -934,23 +1018,19 @@
}
/** A customized variant of Spliterators.IteratorSpliterator */
- static final class LTQSpliterator<E> implements Spliterator<E> {
+ final class LTQSpliterator<E> implements Spliterator<E> {
static final int MAX_BATCH = 1 << 25; // max batch array size;
- final LinkedTransferQueue<E> queue;
- Node current; // current node; null until initialized
+ Node current; // current node; null until initialized
int batch; // batch size for splits
boolean exhausted; // true when no more nodes
- LTQSpliterator(LinkedTransferQueue<E> queue) {
- this.queue = queue;
- }
+ LTQSpliterator() {}
public Spliterator<E> trySplit() {
Node p;
- final LinkedTransferQueue<E> q = this.queue;
int b = batch;
int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
if (!exhausted &&
- ((p = current) != null || (p = q.firstDataNode()) != null) &&
+ ((p = current) != null || (p = firstDataNode()) != null) &&
p.next != null) {
Object[] a = new Object[n];
int i = 0;
@@ -959,15 +1039,16 @@
if (e != p && (a[i] = e) != null)
++i;
if (p == (p = p.next))
- p = q.firstDataNode();
+ p = firstDataNode();
} while (p != null && i < n && p.isData);
if ((current = p) == null)
exhausted = true;
if (i > 0) {
batch = i;
return Spliterators.spliterator
- (a, 0, i, Spliterator.ORDERED | Spliterator.NONNULL |
- Spliterator.CONCURRENT);
+ (a, 0, i, (Spliterator.ORDERED |
+ Spliterator.NONNULL |
+ Spliterator.CONCURRENT));
}
}
return null;
@@ -977,16 +1058,15 @@
public void forEachRemaining(Consumer<? super E> action) {
Node p;
if (action == null) throw new NullPointerException();
- final LinkedTransferQueue<E> q = this.queue;
if (!exhausted &&
- ((p = current) != null || (p = q.firstDataNode()) != null)) {
+ ((p = current) != null || (p = firstDataNode()) != null)) {
exhausted = true;
do {
Object e = p.item;
if (e != null && e != p)
action.accept((E)e);
if (p == (p = p.next))
- p = q.firstDataNode();
+ p = firstDataNode();
} while (p != null && p.isData);
}
}
@@ -995,15 +1075,14 @@
public boolean tryAdvance(Consumer<? super E> action) {
Node p;
if (action == null) throw new NullPointerException();
- final LinkedTransferQueue<E> q = this.queue;
if (!exhausted &&
- ((p = current) != null || (p = q.firstDataNode()) != null)) {
+ ((p = current) != null || (p = firstDataNode()) != null)) {
Object e;
do {
if ((e = p.item) == p)
e = null;
if (p == (p = p.next))
- p = q.firstDataNode();
+ p = firstDataNode();
} while (e == null && p != null && p.isData);
if ((current = p) == null)
exhausted = true;
@@ -1040,7 +1119,7 @@
* @since 1.8
*/
public Spliterator<E> spliterator() {
- return new LTQSpliterator<E>(this);
+ return new LTQSpliterator<E>();
}
/* -------------- Removal methods -------------- */
@@ -1054,7 +1133,7 @@
* @param s the node to be unspliced
*/
final void unsplice(Node pred, Node s) {
- s.forgetContents(); // forget unneeded fields
+ s.waiter = null; // disable signals
/*
* See above for rationale. Briefly: if pred still points to
* s, try to unlink s. If s cannot be unlinked, because it is
@@ -1332,7 +1411,22 @@
}
public E peek() {
- return firstDataItem();
+ restartFromHead: for (;;) {
+ for (Node p = head; p != null;) {
+ Object item = p.item;
+ if (p.isData) {
+ if (item != null && item != p) {
+ @SuppressWarnings("unchecked") E e = (E) item;
+ return e;
+ }
+ }
+ else if (item == null)
+ break;
+ if (p == (p = p.next))
+ continue restartFromHead;
+ }
+ return null;
+ }
}
/**
@@ -1341,15 +1435,24 @@
* @return {@code true} if this queue contains no elements
*/
public boolean isEmpty() {
- for (Node p = head; p != null; p = succ(p)) {
- if (!p.isMatched())
- return !p.isData;
- }
- return true;
+ return firstDataNode() == null;
}
public boolean hasWaitingConsumer() {
- return firstOfMode(false) != null;
+ restartFromHead: for (;;) {
+ for (Node p = head; p != null;) {
+ Object item = p.item;
+ if (p.isData) {
+ if (item != null && item != p)
+ break;
+ }
+ else if (item == null)
+ return true;
+ if (p == (p = p.next))
+ continue restartFromHead;
+ }
+ return false;
+ }
}
/**
@@ -1396,15 +1499,16 @@
* @return {@code true} if this queue contains the specified element
*/
public boolean contains(Object o) {
- if (o == null) return false;
- for (Node p = head; p != null; p = succ(p)) {
- Object item = p.item;
- if (p.isData) {
- if (item != null && item != p && o.equals(item))
- return true;
+ if (o != null) {
+ for (Node p = head; p != null; p = succ(p)) {
+ Object item = p.item;
+ if (p.isData) {
+ if (item != null && item != p && o.equals(item))
+ return true;
+ }
+ else if (item == null)
+ break;
}
- else if (item == null)
- break;
}
return false;
}
@@ -1460,22 +1564,24 @@
// Unsafe mechanics
- private static final sun.misc.Unsafe UNSAFE;
- private static final long headOffset;
- private static final long tailOffset;
- private static final long sweepVotesOffset;
+ private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+ private static final long HEAD;
+ private static final long TAIL;
+ private static final long SWEEPVOTES;
static {
try {
- UNSAFE = sun.misc.Unsafe.getUnsafe();
- Class<?> k = LinkedTransferQueue.class;
- headOffset = UNSAFE.objectFieldOffset
- (k.getDeclaredField("head"));
- tailOffset = UNSAFE.objectFieldOffset
- (k.getDeclaredField("tail"));
- sweepVotesOffset = UNSAFE.objectFieldOffset
- (k.getDeclaredField("sweepVotes"));
- } catch (Exception e) {
+ HEAD = U.objectFieldOffset
+ (LinkedTransferQueue.class.getDeclaredField("head"));
+ TAIL = U.objectFieldOffset
+ (LinkedTransferQueue.class.getDeclaredField("tail"));
+ SWEEPVOTES = U.objectFieldOffset
+ (LinkedTransferQueue.class.getDeclaredField("sweepVotes"));
+ } catch (ReflectiveOperationException e) {
throw new Error(e);
}
+
+ // Reduce the risk of rare disastrous classloading in first call to
+ // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+ Class<?> ensureLoaded = LockSupport.class;
}
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/Phaser.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/Phaser.java Tue Oct 13 16:45:35 2015 -0700
@@ -35,8 +35,6 @@
package java.util.concurrent;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.LockSupport;
@@ -73,7 +71,7 @@
*
* <ul>
*
- * <li> <b>Arrival.</b> Methods {@link #arrive} and
+ * <li><b>Arrival.</b> Methods {@link #arrive} and
* {@link #arriveAndDeregister} record arrival. These methods
* do not block, but return an associated <em>arrival phase
* number</em>; that is, the phase number of the phaser to which
@@ -86,7 +84,7 @@
* flexible than, providing a barrier action to a {@code
* CyclicBarrier}.
*
- * <li> <b>Waiting.</b> Method {@link #awaitAdvance} requires an
+ * <li><b>Waiting.</b> Method {@link #awaitAdvance} requires an
* argument indicating an arrival phase number, and returns when
* the phaser advances to (or is already at) a different phase.
* Unlike similar constructions using {@code CyclicBarrier},
@@ -97,9 +95,10 @@
* state of the phaser. If necessary, you can perform any
* associated recovery within handlers of those exceptions,
* often after invoking {@code forceTermination}. Phasers may
- * also be used by tasks executing in a {@link ForkJoinPool},
- * which will ensure sufficient parallelism to execute tasks
- * when others are blocked waiting for a phase to advance.
+ * also be used by tasks executing in a {@link ForkJoinPool}.
+ * Progress is ensured if the pool's parallelismLevel can
+ * accommodate the maximum number of simultaneously blocked
+ * parties.
*
* </ul>
*
@@ -155,7 +154,7 @@
* The typical idiom is for the method setting this up to first
* register, then start the actions, then deregister, as in:
*
- * <pre> {@code
+ * <pre> {@code
* void runTasks(List<Runnable> tasks) {
* final Phaser phaser = new Phaser(1); // "1" to register self
* // create and start threads
@@ -176,7 +175,7 @@
* <p>One way to cause a set of threads to repeatedly perform actions
* for a given number of iterations is to override {@code onAdvance}:
*
- * <pre> {@code
+ * <pre> {@code
* void startTasks(List<Runnable> tasks, final int iterations) {
* final Phaser phaser = new Phaser() {
* protected boolean onAdvance(int phase, int registeredParties) {
@@ -200,7 +199,7 @@
*
* If the main task must later await termination, it
* may re-register and then execute a similar loop:
- * <pre> {@code
+ * <pre> {@code
* // ...
* phaser.register();
* while (!phaser.isTerminated())
@@ -210,7 +209,7 @@
* in contexts where you are sure that the phase will never wrap around
* {@code Integer.MAX_VALUE}. For example:
*
- * <pre> {@code
+ * <pre> {@code
* void awaitPhase(Phaser phaser, int phase) {
* int p = phaser.register(); // assumes caller not already registered
* while (p < phase) {
@@ -230,7 +229,7 @@
* new Phaser())}, these tasks could then be started, for example by
* submitting to a pool:
*
- * <pre> {@code
+ * <pre> {@code
* void build(Task[] tasks, int lo, int hi, Phaser ph) {
* if (hi - lo > TASKS_PER_PHASER) {
* for (int i = lo; i < hi; i += TASKS_PER_PHASER) {
@@ -331,7 +330,7 @@
}
/**
- * The parent of this phaser, or null if none
+ * The parent of this phaser, or null if none.
*/
private final Phaser parent;
@@ -389,7 +388,7 @@
int unarrived = (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);
if (unarrived <= 0)
throw new IllegalStateException(badArrive(s));
- if (UNSAFE.compareAndSwapLong(this, stateOffset, s, s-=adjust)) {
+ if (U.compareAndSwapLong(this, STATE, s, s-=adjust)) {
if (unarrived == 1) {
long n = s & PARTIES_MASK; // base of next state
int nextUnarrived = (int)n >>> PARTIES_SHIFT;
@@ -402,13 +401,12 @@
n |= nextUnarrived;
int nextPhase = (phase + 1) & MAX_PHASE;
n |= (long)nextPhase << PHASE_SHIFT;
- UNSAFE.compareAndSwapLong(this, stateOffset, s, n);
+ U.compareAndSwapLong(this, STATE, s, n);
releaseWaiters(phase);
}
else if (nextUnarrived == 0) { // propagate deregistration
phase = parent.doArrive(ONE_DEREGISTER);
- UNSAFE.compareAndSwapLong(this, stateOffset,
- s, s | EMPTY);
+ U.compareAndSwapLong(this, STATE, s, s | EMPTY);
}
else
phase = parent.doArrive(ONE_ARRIVAL);
@@ -419,7 +417,7 @@
}
/**
- * Implementation of register, bulkRegister
+ * Implementation of register, bulkRegister.
*
* @param registrations number to add to both parties and
* unarrived fields. Must be greater than zero.
@@ -443,14 +441,13 @@
if (parent == null || reconcileState() == s) {
if (unarrived == 0) // wait out advance
root.internalAwaitAdvance(phase, null);
- else if (UNSAFE.compareAndSwapLong(this, stateOffset,
- s, s + adjust))
+ else if (U.compareAndSwapLong(this, STATE, s, s + adjust))
break;
}
}
else if (parent == null) { // 1st root registration
long next = ((long)phase << PHASE_SHIFT) | adjust;
- if (UNSAFE.compareAndSwapLong(this, stateOffset, s, next))
+ if (U.compareAndSwapLong(this, STATE, s, next))
break;
}
else {
@@ -462,8 +459,8 @@
// finish registration whenever parent registration
// succeeded, even when racing with termination,
// since these are part of the same "transaction".
- while (!UNSAFE.compareAndSwapLong
- (this, stateOffset, s,
+ while (!U.compareAndSwapLong
+ (this, STATE, s,
((long)phase << PHASE_SHIFT) | adjust)) {
s = state;
phase = (int)(root.state >>> PHASE_SHIFT);
@@ -494,8 +491,8 @@
// CAS to root phase with current parties, tripping unarrived
while ((phase = (int)(root.state >>> PHASE_SHIFT)) !=
(int)(s >>> PHASE_SHIFT) &&
- !UNSAFE.compareAndSwapLong
- (this, stateOffset, s,
+ !U.compareAndSwapLong
+ (this, STATE, s,
s = (((long)phase << PHASE_SHIFT) |
((phase < 0) ? (s & COUNTS_MASK) :
(((p = (int)s >>> PARTIES_SHIFT) == 0) ? EMPTY :
@@ -684,8 +681,7 @@
int unarrived = (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);
if (unarrived <= 0)
throw new IllegalStateException(badArrive(s));
- if (UNSAFE.compareAndSwapLong(this, stateOffset, s,
- s -= ONE_ARRIVAL)) {
+ if (U.compareAndSwapLong(this, STATE, s, s -= ONE_ARRIVAL)) {
if (unarrived > 1)
return root.internalAwaitAdvance(phase, null);
if (root != this)
@@ -700,7 +696,7 @@
n |= nextUnarrived;
int nextPhase = (phase + 1) & MAX_PHASE;
n |= (long)nextPhase << PHASE_SHIFT;
- if (!UNSAFE.compareAndSwapLong(this, stateOffset, s, n))
+ if (!U.compareAndSwapLong(this, STATE, s, n))
return (int)(state >>> PHASE_SHIFT); // terminated
releaseWaiters(phase);
return nextPhase;
@@ -816,8 +812,7 @@
final Phaser root = this.root;
long s;
while ((s = root.state) >= 0) {
- if (UNSAFE.compareAndSwapLong(root, stateOffset,
- s, s | TERMINATION_BIT)) {
+ if (U.compareAndSwapLong(root, STATE, s, s | TERMINATION_BIT)) {
// signal all threads
releaseWaiters(0); // Waiters on evenQ
releaseWaiters(1); // Waiters on oddQ
@@ -956,7 +951,7 @@
}
/**
- * Implementation of toString and string-based error messages
+ * Implementation of toString and string-based error messages.
*/
private String stateToString(long s) {
return super.toString() +
@@ -1065,7 +1060,7 @@
else {
try {
ForkJoinPool.managedBlock(node);
- } catch (InterruptedException ie) {
+ } catch (InterruptedException cantHappen) {
node.wasInterrupted = true;
}
}
@@ -1084,7 +1079,7 @@
}
/**
- * Wait nodes for Treiber stack representing wait queue
+ * Wait nodes for Treiber stack representing wait queue.
*/
static final class QNode implements ForkJoinPool.ManagedBlocker {
final Phaser phaser;
@@ -1121,41 +1116,39 @@
thread = null;
return true;
}
- if (timed) {
- if (nanos > 0L) {
- nanos = deadline - System.nanoTime();
- }
- if (nanos <= 0L) {
- thread = null;
- return true;
- }
+ if (timed &&
+ (nanos <= 0L || (nanos = deadline - System.nanoTime()) <= 0L)) {
+ thread = null;
+ return true;
}
return false;
}
public boolean block() {
- if (isReleasable())
- return true;
- else if (!timed)
- LockSupport.park(this);
- else if (nanos > 0L)
- LockSupport.parkNanos(this, nanos);
- return isReleasable();
+ while (!isReleasable()) {
+ if (timed)
+ LockSupport.parkNanos(this, nanos);
+ else
+ LockSupport.park(this);
+ }
+ return true;
}
}
// Unsafe mechanics
- private static final sun.misc.Unsafe UNSAFE;
- private static final long stateOffset;
+ private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+ private static final long STATE;
static {
try {
- UNSAFE = sun.misc.Unsafe.getUnsafe();
- Class<?> k = Phaser.class;
- stateOffset = UNSAFE.objectFieldOffset
- (k.getDeclaredField("state"));
- } catch (Exception e) {
+ STATE = U.objectFieldOffset
+ (Phaser.class.getDeclaredField("state"));
+ } catch (ReflectiveOperationException e) {
throw new Error(e);
}
+
+ // Reduce the risk of rare disastrous classloading in first call to
+ // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+ Class<?> ensureLoaded = LockSupport.class;
}
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/PriorityBlockingQueue.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/PriorityBlockingQueue.java Tue Oct 13 16:45:35 2015 -0700
@@ -35,8 +35,6 @@
package java.util.concurrent;
-import java.util.concurrent.locks.Condition;
-import java.util.concurrent.locks.ReentrantLock;
import java.util.AbstractQueue;
import java.util.Arrays;
import java.util.Collection;
@@ -47,6 +45,8 @@
import java.util.Queue;
import java.util.SortedSet;
import java.util.Spliterator;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
/**
@@ -78,7 +78,7 @@
* tie-breaking to comparable elements. To use it, you would insert a
* {@code new FIFOEntry(anEntry)} instead of a plain entry object.
*
- * <pre> {@code
+ * <pre> {@code
* class FIFOEntry<E extends Comparable<? super E>>
* implements Comparable<FIFOEntry<E>> {
* static final AtomicLong seq = new AtomicLong(0);
@@ -103,7 +103,7 @@
*
* @since 1.5
* @author Doug Lea
- * @param <E> the type of elements held in this collection
+ * @param <E> the type of elements held in this queue
*/
@SuppressWarnings("unchecked")
public class PriorityBlockingQueue<E> extends AbstractQueue<E>
@@ -161,12 +161,12 @@
private transient Comparator<? super E> comparator;
/**
- * Lock used for all public operations
+ * Lock used for all public operations.
*/
private final ReentrantLock lock;
/**
- * Condition for blocking when empty
+ * Condition for blocking when empty.
*/
private final Condition notEmpty;
@@ -289,8 +289,7 @@
lock.unlock(); // must release and then re-acquire main lock
Object[] newArray = null;
if (allocationSpinLock == 0 &&
- UNSAFE.compareAndSwapInt(this, allocationSpinLockOffset,
- 0, 1)) {
+ U.compareAndSwapInt(this, ALLOCATIONSPINLOCK, 0, 1)) {
try {
int newCap = oldCap + ((oldCap < 64) ?
(oldCap + 2) : // grow faster if small
@@ -672,7 +671,7 @@
}
/**
- * Identity-based version for use in Itr.remove
+ * Identity-based version for use in Itr.remove.
*/
void removeEQ(Object o) {
final ReentrantLock lock = this.lock;
@@ -708,48 +707,8 @@
}
}
- /**
- * Returns an array containing all of the elements in this queue.
- * The returned array elements are in no particular order.
- *
- * <p>The returned array will be "safe" in that no references to it are
- * maintained by this queue. (In other words, this method must allocate
- * a new array). The caller is thus free to modify the returned array.
- *
- * <p>This method acts as bridge between array-based and collection-based
- * APIs.
- *
- * @return an array containing all of the elements in this queue
- */
- public Object[] toArray() {
- final ReentrantLock lock = this.lock;
- lock.lock();
- try {
- return Arrays.copyOf(queue, size);
- } finally {
- lock.unlock();
- }
- }
-
public String toString() {
- final ReentrantLock lock = this.lock;
- lock.lock();
- try {
- int n = size;
- if (n == 0)
- return "[]";
- StringBuilder sb = new StringBuilder();
- sb.append('[');
- for (int i = 0; i < n; ++i) {
- Object e = queue[i];
- sb.append(e == this ? "(this Collection)" : e);
- if (i != n - 1)
- sb.append(',').append(' ');
- }
- return sb.append(']').toString();
- } finally {
- lock.unlock();
- }
+ return Helpers.collectionToString(this);
}
/**
@@ -808,6 +767,29 @@
}
/**
+ * Returns an array containing all of the elements in this queue.
+ * The returned array elements are in no particular order.
+ *
+ * <p>The returned array will be "safe" in that no references to it are
+ * maintained by this queue. (In other words, this method must allocate
+ * a new array). The caller is thus free to modify the returned array.
+ *
+ * <p>This method acts as bridge between array-based and collection-based
+ * APIs.
+ *
+ * @return an array containing all of the elements in this queue
+ */
+ public Object[] toArray() {
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ return Arrays.copyOf(queue, size);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
* Returns an array containing all of the elements in this queue; the
* runtime type of the returned array is that of the specified array.
* The returned array elements are in no particular order.
@@ -829,7 +811,7 @@
* The following code can be used to dump the queue into a newly
* allocated array of {@code String}:
*
- * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+ * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
*
* Note that {@code toArray(new Object[0])} is identical in function to
* {@code toArray()}.
@@ -971,7 +953,7 @@
return hi;
}
- public Spliterator<E> trySplit() {
+ public PBQSpliterator<E> trySplit() {
int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
return (lo >= mid) ? null :
new PBQSpliterator<E>(queue, array, lo, index = mid);
@@ -1028,15 +1010,13 @@
}
// Unsafe mechanics
- private static final sun.misc.Unsafe UNSAFE;
- private static final long allocationSpinLockOffset;
+ private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+ private static final long ALLOCATIONSPINLOCK;
static {
try {
- UNSAFE = sun.misc.Unsafe.getUnsafe();
- Class<?> k = PriorityBlockingQueue.class;
- allocationSpinLockOffset = UNSAFE.objectFieldOffset
- (k.getDeclaredField("allocationSpinLock"));
- } catch (Exception e) {
+ ALLOCATIONSPINLOCK = U.objectFieldOffset
+ (PriorityBlockingQueue.class.getDeclaredField("allocationSpinLock"));
+ } catch (ReflectiveOperationException e) {
throw new Error(e);
}
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/RecursiveAction.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/RecursiveAction.java Tue Oct 13 16:45:35 2015 -0700
@@ -45,7 +45,7 @@
* <p><b>Sample Usages.</b> Here is a simple but complete ForkJoin
* sort that sorts a given {@code long[]} array:
*
- * <pre> {@code
+ * <pre> {@code
* static class SortTask extends RecursiveAction {
* final long[] array; final int lo, hi;
* SortTask(long[] array, int lo, int hi) {
@@ -79,7 +79,7 @@
* SortTask(anArray)} and invoking it in a ForkJoinPool. As a more
* concrete simple example, the following task increments each element
* of an array:
- * <pre> {@code
+ * <pre> {@code
* class IncrementTask extends RecursiveAction {
* final long[] array; final int lo, hi;
* IncrementTask(long[] array, int lo, int hi) {
@@ -110,7 +110,7 @@
* performing leaf actions on unstolen tasks rather than further
* subdividing.
*
- * <pre> {@code
+ * <pre> {@code
* double sumOfSquares(ForkJoinPool pool, double[] array) {
* int n = array.length;
* Applyer a = new Applyer(array, 0, n, null);
--- a/jdk/src/java.base/share/classes/java/util/concurrent/RecursiveTask.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/RecursiveTask.java Tue Oct 13 16:45:35 2015 -0700
@@ -40,11 +40,11 @@
*
* <p>For a classic example, here is a task computing Fibonacci numbers:
*
- * <pre> {@code
+ * <pre> {@code
* class Fibonacci extends RecursiveTask<Integer> {
* final int n;
* Fibonacci(int n) { this.n = n; }
- * Integer compute() {
+ * protected Integer compute() {
* if (n <= 1)
* return n;
* Fibonacci f1 = new Fibonacci(n - 1);
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ScheduledExecutorService.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ScheduledExecutorService.java Tue Oct 13 16:45:35 2015 -0700
@@ -70,7 +70,7 @@
* Here is a class with a method that sets up a ScheduledExecutorService
* to beep every ten seconds for an hour:
*
- * <pre> {@code
+ * <pre> {@code
* import static java.util.concurrent.TimeUnit.*;
* class BeeperControl {
* private final ScheduledExecutorService scheduler =
@@ -129,23 +129,37 @@
/**
* Creates and executes a periodic action that becomes enabled first
* after the given initial delay, and subsequently with the given
- * period; that is executions will commence after
- * {@code initialDelay} then {@code initialDelay+period}, then
+ * period; that is, executions will commence after
+ * {@code initialDelay}, then {@code initialDelay + period}, then
* {@code initialDelay + 2 * period}, and so on.
- * If any execution of the task
- * encounters an exception, subsequent executions are suppressed.
- * Otherwise, the task will only terminate via cancellation or
- * termination of the executor. If any execution of this task
- * takes longer than its period, then subsequent executions
- * may start late, but will not concurrently execute.
+ *
+ * <p>The sequence of task executions continues indefinitely until
+ * one of the following exceptional completions occur:
+ * <ul>
+ * <li>The task is {@linkplain Future#cancel explicitly cancelled}
+ * via the returned future.
+ * <li>The executor terminates, also resulting in task cancellation.
+ * <li>An execution of the task throws an exception. In this case
+ * calling {@link Future#get() get} on the returned future will
+ * throw {@link ExecutionException}.
+ * </ul>
+ * Subsequent executions are suppressed. Subsequent calls to
+ * {@link Future#isDone isDone()} on the returned future will
+ * return {@code true}.
+ *
+ * <p>If any execution of this task takes longer than its period, then
+ * subsequent executions may start late, but will not concurrently
+ * execute.
*
* @param command the task to execute
* @param initialDelay the time to delay first execution
* @param period the period between successive executions
* @param unit the time unit of the initialDelay and period parameters
* @return a ScheduledFuture representing pending completion of
- * the task, and whose {@code get()} method will throw an
- * exception upon cancellation
+ * the series of repeated tasks. The future's {@link
+ * Future#get() get()} method will never return normally,
+ * and will throw an exception upon task cancellation or
+ * abnormal termination of a task execution.
* @throws RejectedExecutionException if the task cannot be
* scheduled for execution
* @throws NullPointerException if command is null
@@ -160,10 +174,21 @@
* Creates and executes a periodic action that becomes enabled first
* after the given initial delay, and subsequently with the
* given delay between the termination of one execution and the
- * commencement of the next. If any execution of the task
- * encounters an exception, subsequent executions are suppressed.
- * Otherwise, the task will only terminate via cancellation or
- * termination of the executor.
+ * commencement of the next.
+ *
+ * <p>The sequence of task executions continues indefinitely until
+ * one of the following exceptional completions occur:
+ * <ul>
+ * <li>The task is {@linkplain Future#cancel explicitly cancelled}
+ * via the returned future.
+ * <li>The executor terminates, also resulting in task cancellation.
+ * <li>An execution of the task throws an exception. In this case
+ * calling {@link Future#get() get} on the returned future will
+ * throw {@link ExecutionException}.
+ * </ul>
+ * Subsequent executions are suppressed. Subsequent calls to
+ * {@link Future#isDone isDone()} on the returned future will
+ * return {@code true}.
*
* @param command the task to execute
* @param initialDelay the time to delay first execution
@@ -171,8 +196,10 @@
* execution and the commencement of the next
* @param unit the time unit of the initialDelay and delay parameters
* @return a ScheduledFuture representing pending completion of
- * the task, and whose {@code get()} method will throw an
- * exception upon cancellation
+ * the series of repeated tasks. The future's {@link
+ * Future#get() get()} method will never return normally,
+ * and will throw an exception upon task cancellation or
+ * abnormal termination of a task execution.
* @throws RejectedExecutionException if the task cannot be
* scheduled for execution
* @throws NullPointerException if command is null
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java Tue Oct 13 16:45:35 2015 -0700
@@ -34,19 +34,27 @@
*/
package java.util.concurrent;
+
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
+
+import java.util.AbstractQueue;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
-import java.util.*;
/**
* A {@link ThreadPoolExecutor} that can additionally schedule
- * commands to run after a given delay, or to execute
- * periodically. This class is preferable to {@link java.util.Timer}
- * when multiple worker threads are needed, or when the additional
- * flexibility or capabilities of {@link ThreadPoolExecutor} (which
- * this class extends) are required.
+ * commands to run after a given delay, or to execute periodically.
+ * This class is preferable to {@link java.util.Timer} when multiple
+ * worker threads are needed, or when the additional flexibility or
+ * capabilities of {@link ThreadPoolExecutor} (which this class
+ * extends) are required.
*
* <p>Delayed tasks execute no sooner than they are enabled, but
* without any real-time guarantees about when, after they are
@@ -55,20 +63,19 @@
* submission.
*
* <p>When a submitted task is cancelled before it is run, execution
- * is suppressed. By default, such a cancelled task is not
- * automatically removed from the work queue until its delay
- * elapses. While this enables further inspection and monitoring, it
- * may also cause unbounded retention of cancelled tasks. To avoid
- * this, set {@link #setRemoveOnCancelPolicy} to {@code true}, which
- * causes tasks to be immediately removed from the work queue at
- * time of cancellation.
+ * is suppressed. By default, such a cancelled task is not
+ * automatically removed from the work queue until its delay elapses.
+ * While this enables further inspection and monitoring, it may also
+ * cause unbounded retention of cancelled tasks. To avoid this, use
+ * {@link #setRemoveOnCancelPolicy} to cause tasks to be immediately
+ * removed from the work queue at time of cancellation.
*
- * <p>Successive executions of a task scheduled via
- * {@code scheduleAtFixedRate} or
- * {@code scheduleWithFixedDelay} do not overlap. While different
- * executions may be performed by different threads, the effects of
- * prior executions <a
- * href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * <p>Successive executions of a periodic task scheduled via
+ * {@link #scheduleAtFixedRate scheduleAtFixedRate} or
+ * {@link #scheduleWithFixedDelay scheduleWithFixedDelay}
+ * do not overlap. While different executions may be performed by
+ * different threads, the effects of prior executions
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
* those of subsequent ones.
*
* <p>While this class inherits from {@link ThreadPoolExecutor}, a few
@@ -98,7 +105,7 @@
* {@link FutureTask}. However, this may be modified or replaced using
* subclasses of the form:
*
- * <pre> {@code
+ * <pre> {@code
* public class CustomScheduledExecutor extends ScheduledThreadPoolExecutor {
*
* static class CustomTask<V> implements RunnableScheduledFuture<V> { ... }
@@ -160,9 +167,9 @@
private volatile boolean executeExistingDelayedTasksAfterShutdown = true;
/**
- * True if ScheduledFutureTask.cancel should remove from queue
+ * True if ScheduledFutureTask.cancel should remove from queue.
*/
- private volatile boolean removeOnCancel = false;
+ volatile boolean removeOnCancel;
/**
* Sequence number to break scheduling ties, and in turn to
@@ -173,7 +180,7 @@
/**
* Returns current nanosecond time.
*/
- final long now() {
+ static final long now() {
return System.nanoTime();
}
@@ -184,13 +191,13 @@
private final long sequenceNumber;
/** The time the task is enabled to execute in nanoTime units */
- private long time;
+ private volatile long time;
/**
- * Period in nanoseconds for repeating tasks. A positive
- * value indicates fixed-rate execution. A negative value
- * indicates fixed-delay execution. A value of 0 indicates a
- * non-repeating task.
+ * Period in nanoseconds for repeating tasks.
+ * A positive value indicates fixed-rate execution.
+ * A negative value indicates fixed-delay execution.
+ * A value of 0 indicates a non-repeating (one-shot) task.
*/
private final long period;
@@ -205,31 +212,35 @@
/**
* Creates a one-shot action with given nanoTime-based trigger time.
*/
- ScheduledFutureTask(Runnable r, V result, long ns) {
+ ScheduledFutureTask(Runnable r, V result, long triggerTime,
+ long sequenceNumber) {
super(r, result);
- this.time = ns;
+ this.time = triggerTime;
this.period = 0;
- this.sequenceNumber = sequencer.getAndIncrement();
+ this.sequenceNumber = sequenceNumber;
}
/**
- * Creates a periodic action with given nano time and period.
+ * Creates a periodic action with given nanoTime-based initial
+ * trigger time and period.
*/
- ScheduledFutureTask(Runnable r, V result, long ns, long period) {
+ ScheduledFutureTask(Runnable r, V result, long triggerTime,
+ long period, long sequenceNumber) {
super(r, result);
- this.time = ns;
+ this.time = triggerTime;
this.period = period;
- this.sequenceNumber = sequencer.getAndIncrement();
+ this.sequenceNumber = sequenceNumber;
}
/**
* Creates a one-shot action with given nanoTime-based trigger time.
*/
- ScheduledFutureTask(Callable<V> callable, long ns) {
+ ScheduledFutureTask(Callable<V> callable, long triggerTime,
+ long sequenceNumber) {
super(callable);
- this.time = ns;
+ this.time = triggerTime;
this.period = 0;
- this.sequenceNumber = sequencer.getAndIncrement();
+ this.sequenceNumber = sequenceNumber;
}
public long getDelay(TimeUnit unit) {
@@ -290,8 +301,8 @@
if (!canRunInCurrentRunState(periodic))
cancel(false);
else if (!periodic)
- ScheduledFutureTask.super.run();
- else if (ScheduledFutureTask.super.runAndReset()) {
+ super.run();
+ else if (super.runAndReset()) {
setNextRunTime();
reExecutePeriodic(outerTask);
}
@@ -419,6 +430,22 @@
}
/**
+ * The default keep-alive time for pool threads.
+ *
+ * Normally, this value is unused because all pool threads will be
+ * core threads, but if a user creates a pool with a corePoolSize
+ * of zero (against our advice), we keep a thread alive as long as
+ * there are queued tasks. If the keep alive time is zero (the
+ * historic value), we end up hot-spinning in getTask, wasting a
+ * CPU. But on the other hand, if we set the value too high, and
+ * users create a one-shot pool which they don't cleanly shutdown,
+ * the pool's non-daemon threads will prevent JVM termination. A
+ * small but non-zero value (relative to a JVM's lifetime) seems
+ * best.
+ */
+ private static final long DEFAULT_KEEPALIVE_MILLIS = 10L;
+
+ /**
* Creates a new {@code ScheduledThreadPoolExecutor} with the
* given core pool size.
*
@@ -427,7 +454,8 @@
* @throws IllegalArgumentException if {@code corePoolSize < 0}
*/
public ScheduledThreadPoolExecutor(int corePoolSize) {
- super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
+ super(corePoolSize, Integer.MAX_VALUE,
+ DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue());
}
@@ -444,13 +472,14 @@
*/
public ScheduledThreadPoolExecutor(int corePoolSize,
ThreadFactory threadFactory) {
- super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
+ super(corePoolSize, Integer.MAX_VALUE,
+ DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue(), threadFactory);
}
/**
- * Creates a new ScheduledThreadPoolExecutor with the given
- * initial parameters.
+ * Creates a new {@code ScheduledThreadPoolExecutor} with the
+ * given initial parameters.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
@@ -461,13 +490,14 @@
*/
public ScheduledThreadPoolExecutor(int corePoolSize,
RejectedExecutionHandler handler) {
- super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
+ super(corePoolSize, Integer.MAX_VALUE,
+ DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue(), handler);
}
/**
- * Creates a new ScheduledThreadPoolExecutor with the given
- * initial parameters.
+ * Creates a new {@code ScheduledThreadPoolExecutor} with the
+ * given initial parameters.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
@@ -482,19 +512,20 @@
public ScheduledThreadPoolExecutor(int corePoolSize,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
- super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
+ super(corePoolSize, Integer.MAX_VALUE,
+ DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue(), threadFactory, handler);
}
/**
- * Returns the trigger time of a delayed action.
+ * Returns the nanoTime-based trigger time of a delayed action.
*/
private long triggerTime(long delay, TimeUnit unit) {
return triggerTime(unit.toNanos((delay < 0) ? 0 : delay));
}
/**
- * Returns the trigger time of a delayed action.
+ * Returns the nanoTime-based trigger time of a delayed action.
*/
long triggerTime(long delay) {
return now() +
@@ -527,9 +558,10 @@
TimeUnit unit) {
if (command == null || unit == null)
throw new NullPointerException();
- RunnableScheduledFuture<?> t = decorateTask(command,
+ RunnableScheduledFuture<Void> t = decorateTask(command,
new ScheduledFutureTask<Void>(command, null,
- triggerTime(delay, unit)));
+ triggerTime(delay, unit),
+ sequencer.getAndIncrement()));
delayedExecute(t);
return t;
}
@@ -545,7 +577,8 @@
throw new NullPointerException();
RunnableScheduledFuture<V> t = decorateTask(callable,
new ScheduledFutureTask<V>(callable,
- triggerTime(delay, unit)));
+ triggerTime(delay, unit),
+ sequencer.getAndIncrement()));
delayedExecute(t);
return t;
}
@@ -561,13 +594,14 @@
TimeUnit unit) {
if (command == null || unit == null)
throw new NullPointerException();
- if (period <= 0)
+ if (period <= 0L)
throw new IllegalArgumentException();
ScheduledFutureTask<Void> sft =
new ScheduledFutureTask<Void>(command,
null,
triggerTime(initialDelay, unit),
- unit.toNanos(period));
+ unit.toNanos(period),
+ sequencer.getAndIncrement());
RunnableScheduledFuture<Void> t = decorateTask(command, sft);
sft.outerTask = t;
delayedExecute(t);
@@ -585,13 +619,14 @@
TimeUnit unit) {
if (command == null || unit == null)
throw new NullPointerException();
- if (delay <= 0)
+ if (delay <= 0L)
throw new IllegalArgumentException();
ScheduledFutureTask<Void> sft =
new ScheduledFutureTask<Void>(command,
null,
triggerTime(initialDelay, unit),
- unit.toNanos(-delay));
+ -unit.toNanos(delay),
+ sequencer.getAndIncrement());
RunnableScheduledFuture<Void> t = decorateTask(command, sft);
sft.outerTask = t;
delayedExecute(t);
@@ -764,7 +799,8 @@
/**
* Attempts to stop all actively executing tasks, halts the
* processing of waiting tasks, and returns a list of the tasks
- * that were awaiting execution.
+ * that were awaiting execution. These tasks are drained (removed)
+ * from the task queue upon return from this method.
*
* <p>This method does not wait for actively executing tasks to
* terminate. Use {@link #awaitTermination awaitTermination} to
@@ -772,13 +808,15 @@
*
* <p>There are no guarantees beyond best-effort attempts to stop
* processing actively executing tasks. This implementation
- * cancels tasks via {@link Thread#interrupt}, so any task that
+ * interrupts tasks via {@link Thread#interrupt}; any task that
* fails to respond to interrupts may never terminate.
*
* @return list of tasks that never commenced execution.
- * Each element of this list is a {@link ScheduledFuture},
- * including those tasks submitted using {@code execute},
- * which are for scheduling purposes used as the basis of a
+ * Each element of this list is a {@link ScheduledFuture}.
+ * For tasks submitted via one of the {@code schedule}
+ * methods, the element will be identical to the returned
+ * {@code ScheduledFuture}. For tasks submitted using
+ * {@link #execute execute}, the element will be a
* zero-delay {@code ScheduledFuture}.
* @throws SecurityException {@inheritDoc}
*/
@@ -787,13 +825,19 @@
}
/**
- * Returns the task queue used by this executor. Each element of
- * this queue is a {@link ScheduledFuture}, including those
- * tasks submitted using {@code execute} which are for scheduling
- * purposes used as the basis of a zero-delay
- * {@code ScheduledFuture}. Iteration over this queue is
- * <em>not</em> guaranteed to traverse tasks in the order in
- * which they will execute.
+ * Returns the task queue used by this executor. Access to the
+ * task queue is intended primarily for debugging and monitoring.
+ * This queue may be in active use. Retrieving the task queue
+ * does not prevent queued tasks from executing.
+ *
+ * <p>Each element of this queue is a {@link ScheduledFuture}.
+ * For tasks submitted via one of the {@code schedule} methods, the
+ * element will be identical to the returned {@code ScheduledFuture}.
+ * For tasks submitted using {@link #execute execute}, the element
+ * will be a zero-delay {@code ScheduledFuture}.
+ *
+ * <p>Iteration over this queue is <em>not</em> guaranteed to traverse
+ * tasks in the order in which they will execute.
*
* @return the task queue
*/
@@ -836,7 +880,7 @@
private RunnableScheduledFuture<?>[] queue =
new RunnableScheduledFuture<?>[INITIAL_CAPACITY];
private final ReentrantLock lock = new ReentrantLock();
- private int size = 0;
+ private int size;
/**
* Thread designated to wait for the task at the head of the
@@ -854,7 +898,7 @@
* signalled. So waiting threads must be prepared to acquire
* and lose leadership while waiting.
*/
- private Thread leader = null;
+ private Thread leader;
/**
* Condition signalled when a newer task becomes available at the
@@ -1062,10 +1106,9 @@
lock.lock();
try {
RunnableScheduledFuture<?> first = queue[0];
- if (first == null || first.getDelay(NANOSECONDS) > 0)
- return null;
- else
- return finishPoll(first);
+ return (first == null || first.getDelay(NANOSECONDS) > 0)
+ ? null
+ : finishPoll(first);
} finally {
lock.unlock();
}
@@ -1081,7 +1124,7 @@
available.await();
else {
long delay = first.getDelay(NANOSECONDS);
- if (delay <= 0)
+ if (delay <= 0L)
return finishPoll(first);
first = null; // don't retain ref while waiting
if (leader != null)
@@ -1114,15 +1157,15 @@
for (;;) {
RunnableScheduledFuture<?> first = queue[0];
if (first == null) {
- if (nanos <= 0)
+ if (nanos <= 0L)
return null;
else
nanos = available.awaitNanos(nanos);
} else {
long delay = first.getDelay(NANOSECONDS);
- if (delay <= 0)
+ if (delay <= 0L)
return finishPoll(first);
- if (nanos <= 0)
+ if (nanos <= 0L)
return null;
first = null; // don't retain ref while waiting
if (nanos < delay || leader != null)
@@ -1254,8 +1297,8 @@
*/
private class Itr implements Iterator<Runnable> {
final RunnableScheduledFuture<?>[] array;
- int cursor = 0; // index of next element to return
- int lastRet = -1; // index of last element, or -1 if no such
+ int cursor; // index of next element to return; initially 0
+ int lastRet = -1; // index of last element returned; -1 if no such
Itr(RunnableScheduledFuture<?>[] array) {
this.array = array;
--- a/jdk/src/java.base/share/classes/java/util/concurrent/Semaphore.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/Semaphore.java Tue Oct 13 16:45:35 2015 -0700
@@ -34,6 +34,7 @@
*/
package java.util.concurrent;
+
import java.util.Collection;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
@@ -48,7 +49,7 @@
* <p>Semaphores are often used to restrict the number of threads than can
* access some (physical or logical) resource. For example, here is
* a class that uses a semaphore to control access to a pool of items:
- * <pre> {@code
+ * <pre> {@code
* class Pool {
* private static final int MAX_AVAILABLE = 100;
* private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);
@@ -114,7 +115,7 @@
* ownership). This can be useful in some specialized contexts, such
* as deadlock recovery.
*
- * <p> The constructor for this class optionally accepts a
+ * <p>The constructor for this class optionally accepts a
* <em>fairness</em> parameter. When set false, this class makes no
* guarantees about the order in which threads acquire permits. In
* particular, <em>barging</em> is permitted, that is, a thread
@@ -141,8 +142,13 @@
*
* <p>This class also provides convenience methods to {@link
* #acquire(int) acquire} and {@link #release(int) release} multiple
- * permits at a time. Beware of the increased risk of indefinite
- * postponement when these methods are used without fairness set true.
+ * permits at a time. These methods are generally more efficient and
+ * effective than loops. However, they do not establish any preference
+ * order. For example, if thread A invokes {@code s.acquire(3}) and
+ * thread B invokes {@code s.acquire(2)}, and two permits become
+ * available, then there is no guarantee that thread B will obtain
+ * them unless its acquire came first and Semaphore {@code s} is in
+ * fair mode.
*
* <p>Memory consistency effects: Actions in a thread prior to calling
* a "release" method such as {@code release()}
@@ -433,14 +439,16 @@
*
* <p>Acquires the given number of permits, if they are available,
* and returns immediately, reducing the number of available permits
- * by the given amount.
+ * by the given amount. This method has the same effect as the
+ * loop {@code for (int i = 0; i < permits; ++i) acquire();} except
+ * that it atomically acquires the permits all at once:
*
* <p>If insufficient permits are available then the current thread becomes
* disabled for thread scheduling purposes and lies dormant until
* one of two things happens:
* <ul>
* <li>Some other thread invokes one of the {@link #release() release}
- * methods for this semaphore, the current thread is next to be assigned
+ * methods for this semaphore and the current thread is next to be assigned
* permits and the number of available permits satisfies this request; or
* <li>Some other thread {@linkplain Thread#interrupt interrupts}
* the current thread.
@@ -473,12 +481,14 @@
*
* <p>Acquires the given number of permits, if they are available,
* and returns immediately, reducing the number of available permits
- * by the given amount.
+ * by the given amount. This method has the same effect as the
+ * loop {@code for (int i = 0; i < permits; ++i) acquireUninterruptibly();}
+ * except that it atomically acquires the permits all at once:
*
* <p>If insufficient permits are available then the current thread becomes
* disabled for thread scheduling purposes and lies dormant until
* some other thread invokes one of the {@link #release() release}
- * methods for this semaphore, the current thread is next to be assigned
+ * methods for this semaphore and the current thread is next to be assigned
* permits and the number of available permits satisfies this request.
*
* <p>If the current thread is {@linkplain Thread#interrupt interrupted}
@@ -540,7 +550,7 @@
* purposes and lies dormant until one of three things happens:
* <ul>
* <li>Some other thread invokes one of the {@link #release() release}
- * methods for this semaphore, the current thread is next to be assigned
+ * methods for this semaphore and the current thread is next to be assigned
* permits and the number of available permits satisfies this request; or
* <li>Some other thread {@linkplain Thread#interrupt interrupts}
* the current thread; or
@@ -587,7 +597,7 @@
*
* <p>Releases the given number of permits, increasing the number of
* available permits by that amount.
- * If any threads are trying to acquire permits, then one
+ * If any threads are trying to acquire permits, then one thread
* is selected and given the permits that were just released.
* If the number of available permits satisfies that thread's request
* then that thread is (re)enabled for thread scheduling purposes;
@@ -671,7 +681,7 @@
* Returns an estimate of the number of threads waiting to acquire.
* The value is only an estimate because the number of threads may
* change dynamically while this method traverses internal data
- * structures. This method is designed for use in monitoring of the
+ * structures. This method is designed for use in monitoring
* system state, not for synchronization control.
*
* @return the estimated number of threads waiting for this lock
--- a/jdk/src/java.base/share/classes/java/util/concurrent/SynchronousQueue.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/SynchronousQueue.java Tue Oct 13 16:45:35 2015 -0700
@@ -35,11 +35,15 @@
*/
package java.util.concurrent;
+
+import java.util.AbstractQueue;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;
-import java.util.*;
-import java.util.Spliterator;
-import java.util.Spliterators;
/**
* A {@linkplain BlockingQueue blocking queue} in which each insert
@@ -79,7 +83,7 @@
*
* @since 1.5
* @author Doug Lea and Bill Scherer and Michael Scott
- * @param <E> the type of elements held in this collection
+ * @param <E> the type of elements held in this queue
*/
public class SynchronousQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable {
@@ -182,9 +186,6 @@
abstract E transfer(E e, boolean timed, long nanos);
}
- /** The number of CPUs, for spin control */
- static final int NCPUS = Runtime.getRuntime().availableProcessors();
-
/**
* The number of times to spin before blocking in timed waits.
* The value is empirically derived -- it works well across a
@@ -192,20 +193,21 @@
* seems not to vary with number of CPUs (beyond 2) so is just
* a constant.
*/
- static final int maxTimedSpins = (NCPUS < 2) ? 0 : 32;
+ static final int MAX_TIMED_SPINS =
+ (Runtime.getRuntime().availableProcessors() < 2) ? 0 : 32;
/**
* The number of times to spin before blocking in untimed waits.
* This is greater than timed value because untimed waits spin
* faster since they don't need to check times on each spin.
*/
- static final int maxUntimedSpins = maxTimedSpins * 16;
+ static final int MAX_UNTIMED_SPINS = MAX_TIMED_SPINS * 16;
/**
* The number of nanoseconds for which it is faster to spin
* rather than to use timed park. A rough estimate suffices.
*/
- static final long spinForTimeoutThreshold = 1000L;
+ static final long SPIN_FOR_TIMEOUT_THRESHOLD = 1000L;
/** Dual stack */
static final class TransferStack<E> extends Transferer<E> {
@@ -245,7 +247,7 @@
boolean casNext(SNode cmp, SNode val) {
return cmp == next &&
- UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
+ U.compareAndSwapObject(this, NEXT, cmp, val);
}
/**
@@ -258,7 +260,7 @@
*/
boolean tryMatch(SNode s) {
if (match == null &&
- UNSAFE.compareAndSwapObject(this, matchOffset, null, s)) {
+ U.compareAndSwapObject(this, MATCH, null, s)) {
Thread w = waiter;
if (w != null) { // waiters need at most one unpark
waiter = null;
@@ -273,7 +275,7 @@
* Tries to cancel a wait by matching node to itself.
*/
void tryCancel() {
- UNSAFE.compareAndSwapObject(this, matchOffset, null, this);
+ U.compareAndSwapObject(this, MATCH, null, this);
}
boolean isCancelled() {
@@ -281,19 +283,17 @@
}
// Unsafe mechanics
- private static final sun.misc.Unsafe UNSAFE;
- private static final long matchOffset;
- private static final long nextOffset;
+ private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+ private static final long MATCH;
+ private static final long NEXT;
static {
try {
- UNSAFE = sun.misc.Unsafe.getUnsafe();
- Class<?> k = SNode.class;
- matchOffset = UNSAFE.objectFieldOffset
- (k.getDeclaredField("match"));
- nextOffset = UNSAFE.objectFieldOffset
- (k.getDeclaredField("next"));
- } catch (Exception e) {
+ MATCH = U.objectFieldOffset
+ (SNode.class.getDeclaredField("match"));
+ NEXT = U.objectFieldOffset
+ (SNode.class.getDeclaredField("next"));
+ } catch (ReflectiveOperationException e) {
throw new Error(e);
}
}
@@ -304,7 +304,7 @@
boolean casHead(SNode h, SNode nh) {
return h == head &&
- UNSAFE.compareAndSwapObject(this, headOffset, h, nh);
+ U.compareAndSwapObject(this, HEAD, h, nh);
}
/**
@@ -353,7 +353,7 @@
for (;;) {
SNode h = head;
if (h == null || h.mode == mode) { // empty or same-mode
- if (timed && nanos <= 0) { // can't wait
+ if (timed && nanos <= 0L) { // can't wait
if (h != null && h.isCancelled())
casHead(h, h.next); // pop cancelled node
else
@@ -435,8 +435,9 @@
*/
final long deadline = timed ? System.nanoTime() + nanos : 0L;
Thread w = Thread.currentThread();
- int spins = (shouldSpin(s) ?
- (timed ? maxTimedSpins : maxUntimedSpins) : 0);
+ int spins = shouldSpin(s)
+ ? (timed ? MAX_TIMED_SPINS : MAX_UNTIMED_SPINS)
+ : 0;
for (;;) {
if (w.isInterrupted())
s.tryCancel();
@@ -451,12 +452,12 @@
}
}
if (spins > 0)
- spins = shouldSpin(s) ? (spins-1) : 0;
+ spins = shouldSpin(s) ? (spins - 1) : 0;
else if (s.waiter == null)
s.waiter = w; // establish waiter so can park next iter
else if (!timed)
LockSupport.park(this);
- else if (nanos > spinForTimeoutThreshold)
+ else if (nanos > SPIN_FOR_TIMEOUT_THRESHOLD)
LockSupport.parkNanos(this, nanos);
}
}
@@ -508,15 +509,13 @@
}
// Unsafe mechanics
- private static final sun.misc.Unsafe UNSAFE;
- private static final long headOffset;
+ private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+ private static final long HEAD;
static {
try {
- UNSAFE = sun.misc.Unsafe.getUnsafe();
- Class<?> k = TransferStack.class;
- headOffset = UNSAFE.objectFieldOffset
- (k.getDeclaredField("head"));
- } catch (Exception e) {
+ HEAD = U.objectFieldOffset
+ (TransferStack.class.getDeclaredField("head"));
+ } catch (ReflectiveOperationException e) {
throw new Error(e);
}
}
@@ -547,19 +546,19 @@
boolean casNext(QNode cmp, QNode val) {
return next == cmp &&
- UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
+ U.compareAndSwapObject(this, NEXT, cmp, val);
}
boolean casItem(Object cmp, Object val) {
return item == cmp &&
- UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);
+ U.compareAndSwapObject(this, ITEM, cmp, val);
}
/**
* Tries to cancel by CAS'ing ref to this as item.
*/
void tryCancel(Object cmp) {
- UNSAFE.compareAndSwapObject(this, itemOffset, cmp, this);
+ U.compareAndSwapObject(this, ITEM, cmp, this);
}
boolean isCancelled() {
@@ -576,19 +575,17 @@
}
// Unsafe mechanics
- private static final sun.misc.Unsafe UNSAFE;
- private static final long itemOffset;
- private static final long nextOffset;
+ private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+ private static final long ITEM;
+ private static final long NEXT;
static {
try {
- UNSAFE = sun.misc.Unsafe.getUnsafe();
- Class<?> k = QNode.class;
- itemOffset = UNSAFE.objectFieldOffset
- (k.getDeclaredField("item"));
- nextOffset = UNSAFE.objectFieldOffset
- (k.getDeclaredField("next"));
- } catch (Exception e) {
+ ITEM = U.objectFieldOffset
+ (QNode.class.getDeclaredField("item"));
+ NEXT = U.objectFieldOffset
+ (QNode.class.getDeclaredField("next"));
+ } catch (ReflectiveOperationException e) {
throw new Error(e);
}
}
@@ -617,7 +614,7 @@
*/
void advanceHead(QNode h, QNode nh) {
if (h == head &&
- UNSAFE.compareAndSwapObject(this, headOffset, h, nh))
+ U.compareAndSwapObject(this, HEAD, h, nh))
h.next = h; // forget old next
}
@@ -626,7 +623,7 @@
*/
void advanceTail(QNode t, QNode nt) {
if (tail == t)
- UNSAFE.compareAndSwapObject(this, tailOffset, t, nt);
+ U.compareAndSwapObject(this, TAIL, t, nt);
}
/**
@@ -634,7 +631,7 @@
*/
boolean casCleanMe(QNode cmp, QNode val) {
return cleanMe == cmp &&
- UNSAFE.compareAndSwapObject(this, cleanMeOffset, cmp, val);
+ U.compareAndSwapObject(this, CLEANME, cmp, val);
}
/**
@@ -684,7 +681,7 @@
advanceTail(t, tn);
continue;
}
- if (timed && nanos <= 0) // can't wait
+ if (timed && nanos <= 0L) // can't wait
return null;
if (s == null)
s = new QNode(e, isData);
@@ -739,8 +736,9 @@
/* Same idea as TransferStack.awaitFulfill */
final long deadline = timed ? System.nanoTime() + nanos : 0L;
Thread w = Thread.currentThread();
- int spins = ((head.next == s) ?
- (timed ? maxTimedSpins : maxUntimedSpins) : 0);
+ int spins = (head.next == s)
+ ? (timed ? MAX_TIMED_SPINS : MAX_UNTIMED_SPINS)
+ : 0;
for (;;) {
if (w.isInterrupted())
s.tryCancel(e);
@@ -760,7 +758,7 @@
s.waiter = w;
else if (!timed)
LockSupport.park(this);
- else if (nanos > spinForTimeoutThreshold)
+ else if (nanos > SPIN_FOR_TIMEOUT_THRESHOLD)
LockSupport.parkNanos(this, nanos);
}
}
@@ -819,21 +817,19 @@
}
}
- private static final sun.misc.Unsafe UNSAFE;
- private static final long headOffset;
- private static final long tailOffset;
- private static final long cleanMeOffset;
+ private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+ private static final long HEAD;
+ private static final long TAIL;
+ private static final long CLEANME;
static {
try {
- UNSAFE = sun.misc.Unsafe.getUnsafe();
- Class<?> k = TransferQueue.class;
- headOffset = UNSAFE.objectFieldOffset
- (k.getDeclaredField("head"));
- tailOffset = UNSAFE.objectFieldOffset
- (k.getDeclaredField("tail"));
- cleanMeOffset = UNSAFE.objectFieldOffset
- (k.getDeclaredField("cleanMe"));
- } catch (Exception e) {
+ HEAD = U.objectFieldOffset
+ (TransferQueue.class.getDeclaredField("head"));
+ TAIL = U.objectFieldOffset
+ (TransferQueue.class.getDeclaredField("tail"));
+ CLEANME = U.objectFieldOffset
+ (TransferQueue.class.getDeclaredField("cleanMe"));
+ } catch (ReflectiveOperationException e) {
throw new Error(e);
}
}
@@ -1088,7 +1084,7 @@
}
/**
- * Sets the zeroeth element of the specified array to {@code null}
+ * Sets the zeroth element of the specified array to {@code null}
* (if the array has non-zero length) and returns it.
*
* @param a the array
@@ -1102,6 +1098,14 @@
}
/**
+ * Always returns {@code "[]"}.
+ * @return {@code "[]"}
+ */
+ public String toString() {
+ return "[]";
+ }
+
+ /**
* @throws UnsupportedOperationException {@inheritDoc}
* @throws ClassCastException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
@@ -1196,17 +1200,9 @@
transferer = new TransferStack<E>();
}
- // Unsafe mechanics
- static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
- String field, Class<?> klazz) {
- try {
- return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
- } catch (NoSuchFieldException e) {
- // Convert Exception to corresponding Error
- NoSuchFieldError error = new NoSuchFieldError(field);
- error.initCause(e);
- throw error;
- }
+ static {
+ // Reduce the risk of rare disastrous classloading in first call to
+ // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+ Class<?> ensureLoaded = LockSupport.class;
}
-
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ThreadFactory.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ThreadFactory.java Tue Oct 13 16:45:35 2015 -0700
@@ -42,7 +42,7 @@
*
* <p>
* The simplest implementation of this interface is just:
- * <pre> {@code
+ * <pre> {@code
* class SimpleThreadFactory implements ThreadFactory {
* public Thread newThread(Runnable r) {
* return new Thread(r);
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java Tue Oct 13 16:45:35 2015 -0700
@@ -126,8 +126,7 @@
*/
/** Generates per-thread initialization/probe field */
- private static final AtomicInteger probeGenerator =
- new AtomicInteger();
+ private static final AtomicInteger probeGenerator = new AtomicInteger();
/**
* The next seed for default constructors.
@@ -150,17 +149,17 @@
}
/**
- * The seed increment
+ * The seed increment.
*/
private static final long GAMMA = 0x9e3779b97f4a7c15L;
/**
- * The increment for generating probe values
+ * The increment for generating probe values.
*/
private static final int PROBE_INCREMENT = 0x9e3779b9;
/**
- * The increment of seeder per new instance
+ * The increment of seeder per new instance.
*/
private static final long SEEDER_INCREMENT = 0xbb67ae8584caa73bL;
@@ -170,7 +169,7 @@
/** Rarely-used holder for the second of a pair of Gaussians */
private static final ThreadLocal<Double> nextLocalGaussian =
- new ThreadLocal<Double>();
+ new ThreadLocal<>();
private static long mix64(long z) {
z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL;
@@ -209,8 +208,8 @@
int probe = (p == 0) ? 1 : p; // skip 0
long seed = mix64(seeder.getAndAdd(SEEDER_INCREMENT));
Thread t = Thread.currentThread();
- UNSAFE.putLong(t, SEED, seed);
- UNSAFE.putInt(t, PROBE, probe);
+ U.putLong(t, SEED, seed);
+ U.putInt(t, PROBE, probe);
}
/**
@@ -219,7 +218,7 @@
* @return the current thread's {@code ThreadLocalRandom}
*/
public static ThreadLocalRandom current() {
- if (UNSAFE.getInt(Thread.currentThread(), PROBE) == 0)
+ if (U.getInt(Thread.currentThread(), PROBE) == 0)
localInit();
return instance;
}
@@ -238,8 +237,8 @@
final long nextSeed() {
Thread t; long r; // read and update per-thread seed
- UNSAFE.putLong(t = Thread.currentThread(), SEED,
- r = UNSAFE.getLong(t, SEED) + GAMMA);
+ U.putLong(t = Thread.currentThread(), SEED,
+ r = U.getLong(t, SEED) + GAMMA);
return r;
}
@@ -249,9 +248,9 @@
}
// IllegalArgumentException messages
- static final String BadBound = "bound must be positive";
- static final String BadRange = "bound must be greater than origin";
- static final String BadSize = "size must be non-negative";
+ static final String BAD_BOUND = "bound must be positive";
+ static final String BAD_RANGE = "bound must be greater than origin";
+ static final String BAD_SIZE = "size must be non-negative";
/**
* The form of nextLong used by LongStream Spliterators. If
@@ -349,7 +348,7 @@
*/
public int nextInt(int bound) {
if (bound <= 0)
- throw new IllegalArgumentException(BadBound);
+ throw new IllegalArgumentException(BAD_BOUND);
int r = mix32(nextSeed());
int m = bound - 1;
if ((bound & m) == 0) // power of two
@@ -376,7 +375,7 @@
*/
public int nextInt(int origin, int bound) {
if (origin >= bound)
- throw new IllegalArgumentException(BadRange);
+ throw new IllegalArgumentException(BAD_RANGE);
return internalNextInt(origin, bound);
}
@@ -400,7 +399,7 @@
*/
public long nextLong(long bound) {
if (bound <= 0)
- throw new IllegalArgumentException(BadBound);
+ throw new IllegalArgumentException(BAD_BOUND);
long r = mix64(nextSeed());
long m = bound - 1;
if ((bound & m) == 0L) // power of two
@@ -427,7 +426,7 @@
*/
public long nextLong(long origin, long bound) {
if (origin >= bound)
- throw new IllegalArgumentException(BadRange);
+ throw new IllegalArgumentException(BAD_RANGE);
return internalNextLong(origin, bound);
}
@@ -453,9 +452,9 @@
*/
public double nextDouble(double bound) {
if (!(bound > 0.0))
- throw new IllegalArgumentException(BadBound);
+ throw new IllegalArgumentException(BAD_BOUND);
double result = (mix64(nextSeed()) >>> 11) * DOUBLE_UNIT * bound;
- return (result < bound) ? result : // correct for rounding
+ return (result < bound) ? result : // correct for rounding
Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1);
}
@@ -472,7 +471,7 @@
*/
public double nextDouble(double origin, double bound) {
if (!(origin < bound))
- throw new IllegalArgumentException(BadRange);
+ throw new IllegalArgumentException(BAD_RANGE);
return internalNextDouble(origin, bound);
}
@@ -529,7 +528,7 @@
*/
public IntStream ints(long streamSize) {
if (streamSize < 0L)
- throw new IllegalArgumentException(BadSize);
+ throw new IllegalArgumentException(BAD_SIZE);
return StreamSupport.intStream
(new RandomIntsSpliterator
(0L, streamSize, Integer.MAX_VALUE, 0),
@@ -571,9 +570,9 @@
public IntStream ints(long streamSize, int randomNumberOrigin,
int randomNumberBound) {
if (streamSize < 0L)
- throw new IllegalArgumentException(BadSize);
+ throw new IllegalArgumentException(BAD_SIZE);
if (randomNumberOrigin >= randomNumberBound)
- throw new IllegalArgumentException(BadRange);
+ throw new IllegalArgumentException(BAD_RANGE);
return StreamSupport.intStream
(new RandomIntsSpliterator
(0L, streamSize, randomNumberOrigin, randomNumberBound),
@@ -598,7 +597,7 @@
*/
public IntStream ints(int randomNumberOrigin, int randomNumberBound) {
if (randomNumberOrigin >= randomNumberBound)
- throw new IllegalArgumentException(BadRange);
+ throw new IllegalArgumentException(BAD_RANGE);
return StreamSupport.intStream
(new RandomIntsSpliterator
(0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
@@ -617,7 +616,7 @@
*/
public LongStream longs(long streamSize) {
if (streamSize < 0L)
- throw new IllegalArgumentException(BadSize);
+ throw new IllegalArgumentException(BAD_SIZE);
return StreamSupport.longStream
(new RandomLongsSpliterator
(0L, streamSize, Long.MAX_VALUE, 0L),
@@ -659,9 +658,9 @@
public LongStream longs(long streamSize, long randomNumberOrigin,
long randomNumberBound) {
if (streamSize < 0L)
- throw new IllegalArgumentException(BadSize);
+ throw new IllegalArgumentException(BAD_SIZE);
if (randomNumberOrigin >= randomNumberBound)
- throw new IllegalArgumentException(BadRange);
+ throw new IllegalArgumentException(BAD_RANGE);
return StreamSupport.longStream
(new RandomLongsSpliterator
(0L, streamSize, randomNumberOrigin, randomNumberBound),
@@ -686,7 +685,7 @@
*/
public LongStream longs(long randomNumberOrigin, long randomNumberBound) {
if (randomNumberOrigin >= randomNumberBound)
- throw new IllegalArgumentException(BadRange);
+ throw new IllegalArgumentException(BAD_RANGE);
return StreamSupport.longStream
(new RandomLongsSpliterator
(0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
@@ -706,7 +705,7 @@
*/
public DoubleStream doubles(long streamSize) {
if (streamSize < 0L)
- throw new IllegalArgumentException(BadSize);
+ throw new IllegalArgumentException(BAD_SIZE);
return StreamSupport.doubleStream
(new RandomDoublesSpliterator
(0L, streamSize, Double.MAX_VALUE, 0.0),
@@ -750,9 +749,9 @@
public DoubleStream doubles(long streamSize, double randomNumberOrigin,
double randomNumberBound) {
if (streamSize < 0L)
- throw new IllegalArgumentException(BadSize);
+ throw new IllegalArgumentException(BAD_SIZE);
if (!(randomNumberOrigin < randomNumberBound))
- throw new IllegalArgumentException(BadRange);
+ throw new IllegalArgumentException(BAD_RANGE);
return StreamSupport.doubleStream
(new RandomDoublesSpliterator
(0L, streamSize, randomNumberOrigin, randomNumberBound),
@@ -777,7 +776,7 @@
*/
public DoubleStream doubles(double randomNumberOrigin, double randomNumberBound) {
if (!(randomNumberOrigin < randomNumberBound))
- throw new IllegalArgumentException(BadRange);
+ throw new IllegalArgumentException(BAD_RANGE);
return StreamSupport.doubleStream
(new RandomDoublesSpliterator
(0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
@@ -792,7 +791,8 @@
* approach. The long and double versions of this class are
* identical except for types.
*/
- static final class RandomIntsSpliterator implements Spliterator.OfInt {
+ private static final class RandomIntsSpliterator
+ implements Spliterator.OfInt {
long index;
final long fence;
final int origin;
@@ -846,7 +846,8 @@
/**
* Spliterator for long streams.
*/
- static final class RandomLongsSpliterator implements Spliterator.OfLong {
+ private static final class RandomLongsSpliterator
+ implements Spliterator.OfLong {
long index;
final long fence;
final long origin;
@@ -901,7 +902,8 @@
/**
* Spliterator for double streams.
*/
- static final class RandomDoublesSpliterator implements Spliterator.OfDouble {
+ private static final class RandomDoublesSpliterator
+ implements Spliterator.OfDouble {
long index;
final long fence;
final double origin;
@@ -978,7 +980,7 @@
* can be used to force initialization on zero return.
*/
static final int getProbe() {
- return UNSAFE.getInt(Thread.currentThread(), PROBE);
+ return U.getInt(Thread.currentThread(), PROBE);
}
/**
@@ -989,7 +991,7 @@
probe ^= probe << 13; // xorshift
probe ^= probe >>> 17;
probe ^= probe << 5;
- UNSAFE.putInt(Thread.currentThread(), PROBE, probe);
+ U.putInt(Thread.currentThread(), PROBE, probe);
return probe;
}
@@ -999,17 +1001,14 @@
static final int nextSecondarySeed() {
int r;
Thread t = Thread.currentThread();
- if ((r = UNSAFE.getInt(t, SECONDARY)) != 0) {
+ if ((r = U.getInt(t, SECONDARY)) != 0) {
r ^= r << 13; // xorshift
r ^= r >>> 17;
r ^= r << 5;
}
- else {
- localInit();
- if ((r = (int)UNSAFE.getLong(t, SEED)) == 0)
- r = 1; // avoid zero
- }
- UNSAFE.putInt(t, SECONDARY, r);
+ else if ((r = mix32(seeder.getAndAdd(SEEDER_INCREMENT))) == 0)
+ r = 1; // avoid zero
+ U.putInt(t, SECONDARY, r);
return r;
}
@@ -1024,8 +1023,8 @@
* always true
*/
private static final ObjectStreamField[] serialPersistentFields = {
- new ObjectStreamField("rnd", long.class),
- new ObjectStreamField("initialized", boolean.class),
+ new ObjectStreamField("rnd", long.class),
+ new ObjectStreamField("initialized", boolean.class),
};
/**
@@ -1037,7 +1036,7 @@
throws java.io.IOException {
java.io.ObjectOutputStream.PutField fields = s.putFields();
- fields.put("rnd", UNSAFE.getLong(Thread.currentThread(), SEED));
+ fields.put("rnd", U.getLong(Thread.currentThread(), SEED));
fields.put("initialized", true);
s.writeFields();
}
@@ -1051,21 +1050,19 @@
}
// Unsafe mechanics
- private static final sun.misc.Unsafe UNSAFE;
+ private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
private static final long SEED;
private static final long PROBE;
private static final long SECONDARY;
static {
try {
- UNSAFE = sun.misc.Unsafe.getUnsafe();
- Class<?> tk = Thread.class;
- SEED = UNSAFE.objectFieldOffset
- (tk.getDeclaredField("threadLocalRandomSeed"));
- PROBE = UNSAFE.objectFieldOffset
- (tk.getDeclaredField("threadLocalRandomProbe"));
- SECONDARY = UNSAFE.objectFieldOffset
- (tk.getDeclaredField("threadLocalRandomSecondarySeed"));
- } catch (Exception e) {
+ SEED = U.objectFieldOffset
+ (Thread.class.getDeclaredField("threadLocalRandomSeed"));
+ PROBE = U.objectFieldOffset
+ (Thread.class.getDeclaredField("threadLocalRandomProbe"));
+ SECONDARY = U.objectFieldOffset
+ (Thread.class.getDeclaredField("threadLocalRandomSecondarySeed"));
+ } catch (ReflectiveOperationException e) {
throw new Error(e);
}
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java Tue Oct 13 16:45:35 2015 -0700
@@ -34,11 +34,16 @@
*/
package java.util.concurrent;
+
+import java.util.ArrayList;
+import java.util.ConcurrentModificationException;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.*;
/**
* An {@link ExecutorService} that executes each submitted task using
@@ -69,7 +74,8 @@
*
* <dt>Core and maximum pool sizes</dt>
*
- * <dd>A {@code ThreadPoolExecutor} will automatically adjust the
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * A {@code ThreadPoolExecutor} will automatically adjust the
* pool size (see {@link #getPoolSize})
* according to the bounds set by
* corePoolSize (see {@link #getCorePoolSize}) and
@@ -91,7 +97,8 @@
*
* <dt>On-demand construction</dt>
*
- * <dd>By default, even core threads are initially created and
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * By default, even core threads are initially created and
* started only when new tasks arrive, but this can be overridden
* dynamically using method {@link #prestartCoreThread} or {@link
* #prestartAllCoreThreads}. You probably want to prestart threads if
@@ -99,7 +106,8 @@
*
* <dt>Creating new threads</dt>
*
- * <dd>New threads are created using a {@link ThreadFactory}. If not
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * New threads are created using a {@link ThreadFactory}. If not
* otherwise specified, a {@link Executors#defaultThreadFactory} is
* used, that creates threads to all be in the same {@link
* ThreadGroup} and with the same {@code NORM_PRIORITY} priority and
@@ -116,7 +124,8 @@
*
* <dt>Keep-alive times</dt>
*
- * <dd>If the pool currently has more than corePoolSize threads,
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * If the pool currently has more than corePoolSize threads,
* excess threads will be terminated if they have been idle for more
* than the keepAliveTime (see {@link #getKeepAliveTime(TimeUnit)}).
* This provides a means of reducing resource consumption when the
@@ -126,36 +135,37 @@
* TimeUnit)}. Using a value of {@code Long.MAX_VALUE} {@link
* TimeUnit#NANOSECONDS} effectively disables idle threads from ever
* terminating prior to shut down. By default, the keep-alive policy
- * applies only when there are more than corePoolSize threads. But
+ * applies only when there are more than corePoolSize threads, but
* method {@link #allowCoreThreadTimeOut(boolean)} can be used to
* apply this time-out policy to core threads as well, so long as the
* keepAliveTime value is non-zero. </dd>
*
* <dt>Queuing</dt>
*
- * <dd>Any {@link BlockingQueue} may be used to transfer and hold
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * Any {@link BlockingQueue} may be used to transfer and hold
* submitted tasks. The use of this queue interacts with pool sizing:
*
* <ul>
*
- * <li> If fewer than corePoolSize threads are running, the Executor
+ * <li>If fewer than corePoolSize threads are running, the Executor
* always prefers adding a new thread
- * rather than queuing.</li>
+ * rather than queuing.
*
- * <li> If corePoolSize or more threads are running, the Executor
+ * <li>If corePoolSize or more threads are running, the Executor
* always prefers queuing a request rather than adding a new
- * thread.</li>
+ * thread.
*
- * <li> If a request cannot be queued, a new thread is created unless
+ * <li>If a request cannot be queued, a new thread is created unless
* this would exceed maximumPoolSize, in which case, the task will be
- * rejected.</li>
+ * rejected.
*
* </ul>
*
* There are three general strategies for queuing:
* <ol>
*
- * <li> <em> Direct handoffs.</em> A good default choice for a work
+ * <li><em> Direct handoffs.</em> A good default choice for a work
* queue is a {@link SynchronousQueue} that hands off tasks to threads
* without otherwise holding them. Here, an attempt to queue a task
* will fail if no threads are immediately available to run it, so a
@@ -164,7 +174,7 @@
* Direct handoffs generally require unbounded maximumPoolSizes to
* avoid rejection of new submitted tasks. This in turn admits the
* possibility of unbounded thread growth when commands continue to
- * arrive on average faster than they can be processed. </li>
+ * arrive on average faster than they can be processed.
*
* <li><em> Unbounded queues.</em> Using an unbounded queue (for
* example a {@link LinkedBlockingQueue} without a predefined
@@ -177,7 +187,7 @@
* While this style of queuing can be useful in smoothing out
* transient bursts of requests, it admits the possibility of
* unbounded work queue growth when commands continue to arrive on
- * average faster than they can be processed. </li>
+ * average faster than they can be processed.
*
* <li><em>Bounded queues.</em> A bounded queue (for example, an
* {@link ArrayBlockingQueue}) helps prevent resource exhaustion when
@@ -190,7 +200,7 @@
* time for more threads than you otherwise allow. Use of small queues
* generally requires larger pool sizes, which keeps CPUs busier but
* may encounter unacceptable scheduling overhead, which also
- * decreases throughput. </li>
+ * decreases throughput.
*
* </ol>
*
@@ -198,7 +208,8 @@
*
* <dt>Rejected tasks</dt>
*
- * <dd>New tasks submitted in method {@link #execute(Runnable)} will be
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * New tasks submitted in method {@link #execute(Runnable)} will be
* <em>rejected</em> when the Executor has been shut down, and also when
* the Executor uses finite bounds for both maximum threads and work queue
* capacity, and is saturated. In either case, the {@code execute} method
@@ -209,22 +220,22 @@
*
* <ol>
*
- * <li> In the default {@link ThreadPoolExecutor.AbortPolicy}, the
+ * <li>In the default {@link ThreadPoolExecutor.AbortPolicy}, the
* handler throws a runtime {@link RejectedExecutionException} upon
- * rejection. </li>
+ * rejection.
*
- * <li> In {@link ThreadPoolExecutor.CallerRunsPolicy}, the thread
+ * <li>In {@link ThreadPoolExecutor.CallerRunsPolicy}, the thread
* that invokes {@code execute} itself runs the task. This provides a
* simple feedback control mechanism that will slow down the rate that
- * new tasks are submitted. </li>
+ * new tasks are submitted.
*
- * <li> In {@link ThreadPoolExecutor.DiscardPolicy}, a task that
- * cannot be executed is simply dropped. </li>
+ * <li>In {@link ThreadPoolExecutor.DiscardPolicy}, a task that
+ * cannot be executed is simply dropped.
*
* <li>In {@link ThreadPoolExecutor.DiscardOldestPolicy}, if the
* executor is not shut down, the task at the head of the work queue
* is dropped, and then execution is retried (which can fail again,
- * causing this to be repeated.) </li>
+ * causing this to be repeated.)
*
* </ol>
*
@@ -235,7 +246,8 @@
*
* <dt>Hook methods</dt>
*
- * <dd>This class provides {@code protected} overridable
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * This class provides {@code protected} overridable
* {@link #beforeExecute(Thread, Runnable)} and
* {@link #afterExecute(Runnable, Throwable)} methods that are called
* before and after execution of each task. These can be used to
@@ -245,12 +257,14 @@
* any special processing that needs to be done once the Executor has
* fully terminated.
*
- * <p>If hook or callback methods throw exceptions, internal worker
- * threads may in turn fail and abruptly terminate.</dd>
+ * <p>If hook, callback, or BlockingQueue methods throw exceptions,
+ * internal worker threads may in turn fail, abruptly terminate, and
+ * possibly be replaced.</dd>
*
* <dt>Queue maintenance</dt>
*
- * <dd>Method {@link #getQueue()} allows access to the work queue
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * Method {@link #getQueue()} allows access to the work queue
* for purposes of monitoring and debugging. Use of this method for
* any other purpose is strongly discouraged. Two supplied methods,
* {@link #remove(Runnable)} and {@link #purge} are available to
@@ -259,7 +273,8 @@
*
* <dt>Finalization</dt>
*
- * <dd>A pool that is no longer referenced in a program <em>AND</em>
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * A pool that is no longer referenced in a program <em>AND</em>
* has no remaining threads will be {@code shutdown} automatically. If
* you would like to ensure that unreferenced pools are reclaimed even
* if users forget to call {@link #shutdown}, then you must arrange
@@ -273,7 +288,7 @@
* override one or more of the protected hook methods. For example,
* here is a subclass that adds a simple pause/resume feature:
*
- * <pre> {@code
+ * <pre> {@code
* class PausableThreadPoolExecutor extends ThreadPoolExecutor {
* private boolean isPaused;
* private ReentrantLock pauseLock = new ReentrantLock();
@@ -462,10 +477,10 @@
* Set containing all worker threads in pool. Accessed only when
* holding mainLock.
*/
- private final HashSet<Worker> workers = new HashSet<Worker>();
+ private final HashSet<Worker> workers = new HashSet<>();
/**
- * Wait condition to support awaitTermination
+ * Wait condition to support awaitTermination.
*/
private final Condition termination = mainLock.newCondition();
@@ -541,7 +556,7 @@
private volatile int maximumPoolSize;
/**
- * The default rejected execution handler
+ * The default rejected execution handler.
*/
private static final RejectedExecutionHandler defaultHandler =
new AbortPolicy();
@@ -612,7 +627,7 @@
this.thread = getThreadFactory().newThread(this);
}
- /** Delegates main run loop to outer runWorker */
+ /** Delegates main run loop to outer runWorker. */
public void run() {
runWorker(this);
}
@@ -668,6 +683,7 @@
* (but not TIDYING or TERMINATED -- use tryTerminate for that)
*/
private void advanceRunState(int targetState) {
+ // assert targetState == SHUTDOWN || targetState == STOP;
for (;;) {
int c = ctl.get();
if (runStateAtLeast(c, targetState) ||
@@ -850,7 +866,7 @@
*/
private List<Runnable> drainQueue() {
BlockingQueue<Runnable> q = workQueue;
- ArrayList<Runnable> taskList = new ArrayList<Runnable>();
+ ArrayList<Runnable> taskList = new ArrayList<>();
q.drainTo(taskList);
if (!q.isEmpty()) {
for (Runnable r : q.toArray(new Runnable[0])) {
@@ -1406,7 +1422,7 @@
*
* <p>There are no guarantees beyond best-effort attempts to stop
* processing actively executing tasks. This implementation
- * cancels tasks via {@link Thread#interrupt}, so any task that
+ * interrupts tasks via {@link Thread#interrupt}; any task that
* fails to respond to interrupts may never terminate.
*
* @throws SecurityException {@inheritDoc}
@@ -1457,13 +1473,12 @@
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
- for (;;) {
- if (runStateAtLeast(ctl.get(), TERMINATED))
- return true;
- if (nanos <= 0)
+ while (!runStateAtLeast(ctl.get(), TERMINATED)) {
+ if (nanos <= 0L)
return false;
nanos = termination.awaitNanos(nanos);
}
+ return true;
} finally {
mainLock.unlock();
}
@@ -1680,11 +1695,13 @@
}
/**
- * Sets the time limit for which threads may remain idle before
- * being terminated. If there are more than the core number of
- * threads currently in the pool, after waiting this amount of
- * time without processing a task, excess threads will be
- * terminated. This overrides any value set in the constructor.
+ * Sets the thread keep-alive time, which is the amount of time
+ * that threads may remain idle before being terminated.
+ * Threads that wait this amount of time without processing a
+ * task will be terminated if there are more than the core
+ * number of threads currently in the pool, or if this pool
+ * {@linkplain #allowsCoreThreadTimeOut() allows core thread timeout}.
+ * This overrides any value set in the constructor.
*
* @param time the time to wait. A time value of zero will cause
* excess threads to terminate immediately after executing tasks.
@@ -1707,8 +1724,11 @@
/**
* Returns the thread keep-alive time, which is the amount of time
- * that threads in excess of the core pool size may remain
- * idle before being terminated.
+ * that threads may remain idle before being terminated.
+ * Threads that wait this amount of time without processing a
+ * task will be terminated if there are more than the core
+ * number of threads currently in the pool, or if this pool
+ * {@linkplain #allowsCoreThreadTimeOut() allows core thread timeout}.
*
* @param unit the desired time unit of the result
* @return the time limit
@@ -1739,8 +1759,8 @@
*
* <p>This method may be useful as one part of a cancellation
* scheme. It may fail to remove tasks that have been converted
- * into other forms before being placed on the internal queue. For
- * example, a task entered using {@code submit} might be
+ * into other forms before being placed on the internal queue.
+ * For example, a task entered using {@code submit} might be
* converted into a form that maintains {@code Future} status.
* However, in such cases, method {@link #purge} may be used to
* remove those Futures that have been cancelled.
@@ -1912,11 +1932,12 @@
mainLock.unlock();
}
int c = ctl.get();
- String rs = (runStateLessThan(c, SHUTDOWN) ? "Running" :
- (runStateAtLeast(c, TERMINATED) ? "Terminated" :
- "Shutting down"));
+ String runState =
+ runStateLessThan(c, SHUTDOWN) ? "Running" :
+ runStateAtLeast(c, TERMINATED) ? "Terminated" :
+ "Shutting down";
return super.toString() +
- "[" + rs +
+ "[" + runState +
", pool size = " + nworkers +
", active threads = " + nactive +
", queued tasks = " + workQueue.size() +
@@ -1963,20 +1984,23 @@
* as in this sample subclass that prints either the direct cause
* or the underlying exception if a task has been aborted:
*
- * <pre> {@code
+ * <pre> {@code
* class ExtendedExecutor extends ThreadPoolExecutor {
* // ...
* protected void afterExecute(Runnable r, Throwable t) {
* super.afterExecute(r, t);
- * if (t == null && r instanceof Future<?>) {
+ * if (t == null
+ * && r instanceof Future<?>
+ * && ((Future<?>)r).isDone()) {
* try {
* Object result = ((Future<?>) r).get();
* } catch (CancellationException ce) {
- * t = ce;
+ * t = ce;
* } catch (ExecutionException ee) {
- * t = ee.getCause();
+ * t = ee.getCause();
* } catch (InterruptedException ie) {
- * Thread.currentThread().interrupt(); // ignore/reset
+ * // ignore/reset
+ * Thread.currentThread().interrupt();
* }
* }
* if (t != null)
--- a/jdk/src/java.base/share/classes/java/util/concurrent/TimeUnit.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/TimeUnit.java Tue Oct 13 16:45:35 2015 -0700
@@ -52,12 +52,12 @@
* the following code will timeout in 50 milliseconds if the {@link
* java.util.concurrent.locks.Lock lock} is not available:
*
- * <pre> {@code
+ * <pre> {@code
* Lock lock = ...;
* if (lock.tryLock(50L, TimeUnit.MILLISECONDS)) ...}</pre>
*
* while this code will timeout in 50 seconds:
- * <pre> {@code
+ * <pre> {@code
* Lock lock = ...;
* if (lock.tryLock(50L, TimeUnit.SECONDS)) ...}</pre>
*
@@ -70,7 +70,7 @@
*/
public enum TimeUnit {
/**
- * Time unit representing one thousandth of a microsecond
+ * Time unit representing one thousandth of a microsecond.
*/
NANOSECONDS {
public long toNanos(long d) { return d; }
@@ -85,7 +85,7 @@
},
/**
- * Time unit representing one thousandth of a millisecond
+ * Time unit representing one thousandth of a millisecond.
*/
MICROSECONDS {
public long toNanos(long d) { return x(d, C1/C0, MAX/(C1/C0)); }
@@ -100,7 +100,7 @@
},
/**
- * Time unit representing one thousandth of a second
+ * Time unit representing one thousandth of a second.
*/
MILLISECONDS {
public long toNanos(long d) { return x(d, C2/C0, MAX/(C2/C0)); }
@@ -115,7 +115,7 @@
},
/**
- * Time unit representing one second
+ * Time unit representing one second.
*/
SECONDS {
public long toNanos(long d) { return x(d, C3/C0, MAX/(C3/C0)); }
@@ -130,7 +130,7 @@
},
/**
- * Time unit representing sixty seconds
+ * Time unit representing sixty seconds.
* @since 1.6
*/
MINUTES {
@@ -146,7 +146,7 @@
},
/**
- * Time unit representing sixty minutes
+ * Time unit representing sixty minutes.
* @since 1.6
*/
HOURS {
@@ -162,7 +162,7 @@
},
/**
- * Time unit representing twenty four hours
+ * Time unit representing twenty four hours.
* @since 1.6
*/
DAYS {
@@ -193,7 +193,7 @@
* This has a short name to make above code more readable.
*/
static long x(long d, long m, long over) {
- if (d > over) return Long.MAX_VALUE;
+ if (d > +over) return Long.MAX_VALUE;
if (d < -over) return Long.MIN_VALUE;
return d * m;
}
@@ -329,7 +329,7 @@
* method (see {@link BlockingQueue#poll BlockingQueue.poll})
* using:
*
- * <pre> {@code
+ * <pre> {@code
* public synchronized Object poll(long timeout, TimeUnit unit)
* throws InterruptedException {
* while (empty) {
--- a/jdk/src/java.base/share/classes/java/util/concurrent/TransferQueue.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/TransferQueue.java Tue Oct 13 16:45:35 2015 -0700
@@ -63,7 +63,7 @@
*
* @since 1.7
* @author Doug Lea
- * @param <E> the type of elements held in this collection
+ * @param <E> the type of elements held in this queue
*/
public interface TransferQueue<E> extends BlockingQueue<E> {
/**
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java Tue Oct 13 16:45:35 2015 -0700
@@ -53,9 +53,9 @@
private static final long serialVersionUID = -6209656149925076980L;
private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+ private static final long ARRAY;
private static final int ABASE;
private static final int ASHIFT;
- private static final long ARRAY;
private final Object[] array; // must have exact type Object[]
static {
--- a/jdk/src/java.base/share/classes/java/util/concurrent/package-info.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/package-info.java Tue Oct 13 16:45:35 2015 -0700
@@ -226,8 +226,9 @@
*
* <h2 id="MemoryVisibility">Memory Consistency Properties</h2>
*
- * <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4.5">
- * Chapter 17 of the Java Language Specification</a> defines the
+ * <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4.5">
+ * Chapter 17 of
+ * <cite>The Java™ Language Specification</cite></a> defines the
* <i>happens-before</i> relation on memory operations such as reads and
* writes of shared variables. The results of a write by one thread are
* guaranteed to be visible to a read by another thread only if the write
--- a/jdk/test/java/util/AbstractList/CheckForComodification.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/AbstractList/CheckForComodification.java Tue Oct 13 16:45:35 2015 -0700
@@ -42,7 +42,7 @@
for (int i : list)
if (i == LENGTH - 2)
list.remove(i);
- } catch(ConcurrentModificationException e) {
+ } catch (ConcurrentModificationException e) {
return;
}
throw new RuntimeException("No ConcurrentModificationException");
--- a/jdk/test/java/util/AbstractList/FailFastIterator.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/AbstractList/FailFastIterator.java Tue Oct 13 16:45:35 2015 -0700
@@ -24,7 +24,7 @@
/**
* @test
* @bug 4189896
- * @summary AbstractList iterators previously checked for co-modificatin
+ * @summary AbstractList iterators previously checked for co-modification
* *after* the set/add/remove operations were performed.
*/
@@ -44,7 +44,7 @@
copy.add(new Integer(99));
i.remove();
throw new Exception("remove: iterator didn't fail fast");
- } catch(ConcurrentModificationException e) {
+ } catch (ConcurrentModificationException e) {
}
if (!copy.equals(orig))
throw new Exception("remove: iterator didn't fail fast enough");
@@ -56,7 +56,7 @@
copy.add(new Integer(99));
i.set(new Integer(666));
throw new Exception("set: iterator didn't fail fast");
- } catch(ConcurrentModificationException e) {
+ } catch (ConcurrentModificationException e) {
}
if (!copy.equals(orig))
throw new Exception("set: iterator didn't fail fast enough");
@@ -67,7 +67,7 @@
copy.add(new Integer(99));
i.add(new Integer(666));
throw new Exception("add: iterator didn't fail fast");
- } catch(ConcurrentModificationException e) {
+ } catch (ConcurrentModificationException e) {
}
if (!copy.equals(orig))
throw new Exception("add: iterator didn't fail fast enough");
--- a/jdk/test/java/util/Collection/BiggernYours.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/Collection/BiggernYours.java Tue Oct 13 16:45:35 2015 -0700
@@ -41,16 +41,16 @@
Object[] c2Array = c2.toArray();
check(c1Array.length == c2Array.length);
- for(Object aC1 : c1Array) {
+ for (Object aC1 : c1Array) {
boolean found = false;
- for(Object aC2 : c2Array) {
- if(Objects.equals(aC1, aC2)) {
+ for (Object aC2 : c2Array) {
+ if (Objects.equals(aC1, aC2)) {
found = true;
break;
}
}
- if(!found)
+ if (!found)
fail(aC1 + " not found in " + Arrays.toString(c2Array));
}
}
--- a/jdk/test/java/util/Collection/MOAT.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/Collection/MOAT.java Tue Oct 13 16:45:35 2015 -0700
@@ -101,7 +101,12 @@
testMap(new HashMap<Integer,Integer>());
testMap(new LinkedHashMap<Integer,Integer>());
- testMap(new WeakHashMap<Integer,Integer>());
+
+ // TODO: Add reliable support for WeakHashMap.
+ // This test is subject to very rare failures because the GC
+ // may remove unreferenced-keys from the map at any time.
+ // testMap(new WeakHashMap<Integer,Integer>());
+
testMap(new IdentityHashMap<Integer,Integer>());
testMap(new TreeMap<Integer,Integer>());
testMap(new Hashtable<Integer,Integer>());
@@ -343,6 +348,12 @@
return true;
}
+ // 6260652: (coll) Arrays.asList(x).toArray().getClass()
+ // should be Object[].class
+ // Fixed in jdk9, but not jdk8 ...
+ static final boolean needToWorkAround6260652 =
+ Arrays.asList("").toArray().getClass() != Object[].class;
+
private static void checkFunctionalInvariants(Collection<Integer> c) {
try {
checkContainsSelf(c);
@@ -356,7 +367,10 @@
}
check(c.toArray().length == c.size());
- check(c.toArray().getClass() == Object[].class);
+ check(c.toArray().getClass() == Object[].class
+ ||
+ (needToWorkAround6260652 &&
+ c.getClass().getName().equals("java.util.Arrays$ArrayList")));
for (int size : new int[]{0,1,c.size(), c.size()+1}) {
Integer[] a = c.toArray(new Integer[size]);
check((size > c.size()) || a.length == c.size());
@@ -408,7 +422,6 @@
catch (Throwable t) { unexpected(t); }
}
-
//----------------------------------------------------------------
// If add("x") succeeds, contains("x") & remove("x") should succeed
//----------------------------------------------------------------
@@ -1291,7 +1304,7 @@
equalNext(descItr, expected[idx--]);
descItr.remove();
- while(idx >= 0 && descItr.hasNext()) {
+ while (idx >= 0 && descItr.hasNext()) {
equalNext(descItr, expected[idx--]);
}
equal(descItr.hasNext(), false);
--- a/jdk/test/java/util/Collection/testlibrary/CollectionAsserts.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/Collection/testlibrary/CollectionAsserts.java Tue Oct 13 16:45:35 2015 -0700
@@ -113,7 +113,7 @@
}
Set<T> uniq = new HashSet<>();
- while(iter.hasNext()) {
+ while (iter.hasNext()) {
T each = iter.next();
assertTrue(!uniq.contains(each));
uniq.add(each);
@@ -209,7 +209,7 @@
assertTrue(!pI.hasNext());
}
- while(mI.hasNext()) {
+ while (mI.hasNext()) {
pI = mI.next().iterator();
assertTrue(!pI.hasNext());
}
--- a/jdk/test/java/util/Collections/BigBinarySearch.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/Collections/BigBinarySearch.java Tue Oct 13 16:45:35 2015 -0700
@@ -61,13 +61,13 @@
}
}
- /** Check that binarySearch finds an element where we got it */
+ /** Checks that binarySearch finds an element where we got it. */
private static void checkBinarySearch(List<Integer> l, int i) {
try { equal(i, Collections.binarySearch(l, l.get(i))); }
catch (Throwable t) { unexpected(t); }
}
- /** Check that binarySearch finds an element where we got it */
+ /** Checks that binarySearch finds an element where we got it. */
private static void checkBinarySearch(List<Integer> l, int i,
Comparator<Integer> comparator) {
try { equal(i, Collections.binarySearch(l, l.get(i), comparator)); }
--- a/jdk/test/java/util/Collections/BinarySearchNullComparator.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/Collections/BinarySearchNullComparator.java Tue Oct 13 16:45:35 2015 -0700
@@ -27,11 +27,10 @@
* @summary Test Collections.binarySearch() with a null comparator
*/
-
import java.util.*;
public class BinarySearchNullComparator {
- public static void main (String args[]) throws Exception {
+ public static void main(String args[]) throws Exception {
List list = Arrays.asList(new String[] {"I", "Love", "You"});
int result = Collections.binarySearch(list, "You", null);
--- a/jdk/test/java/util/Collections/CheckedListBash.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/Collections/CheckedListBash.java Tue Oct 13 16:45:35 2015 -0700
@@ -109,19 +109,19 @@
List even = clone(s);
Iterator it = even.iterator();
- while(it.hasNext())
- if(((Integer)it.next()).intValue() % 2 == 1)
+ while (it.hasNext())
+ if (((Integer)it.next()).intValue() % 2 == 1)
it.remove();
it = even.iterator();
- while(it.hasNext())
- if(((Integer)it.next()).intValue() % 2 == 1)
+ while (it.hasNext())
+ if (((Integer)it.next()).intValue() % 2 == 1)
fail("Failed to remove all odd nubmers.");
List odd = clone(s);
for (int i=0; i<(listSize/2); i++)
odd.remove(i);
for (int i=0; i<(listSize/2); i++)
- if(((Integer)odd.get(i)).intValue() % 2 != 1)
+ if (((Integer)odd.get(i)).intValue() % 2 != 1)
fail("Failed to remove all even nubmers.");
List all = clone(odd);
@@ -145,8 +145,8 @@
}
itAll = all.listIterator();
it = s.iterator();
- while(it.hasNext())
- if(it.next()==itAll.next())
+ while (it.hasNext())
+ if (it.next()==itAll.next())
fail("Iterator.set failed to change value.");
if (!all.equals(s))
fail("Failed to reconstruct ints with ListIterator.");
@@ -215,10 +215,10 @@
int preSize = s.size();
if (!s.add(e))
- fail ("Add failed.");
+ fail("Add failed.");
int postSize = s.size();
if (postSize-preSize != 1)
- fail ("Add didn't increase size by 1.");
+ fail("Add didn't increase size by 1.");
}
}
--- a/jdk/test/java/util/Collections/CheckedMapBash.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/Collections/CheckedMapBash.java Tue Oct 13 16:45:35 2015 -0700
@@ -134,7 +134,7 @@
fail("clear failed.");
Iterator i = m.entrySet().iterator();
- while(i.hasNext()) {
+ while (i.hasNext()) {
i.next();
i.remove();
}
@@ -142,12 +142,11 @@
fail("Iterator.remove() failed");
}
-
@DataProvider(name = "Bash.Supplier<Map<Integer,Integer>>", parallel = true)
public static Iterator<Object[]> bashNavigableMapProvider() {
ArrayList<Object[]> iters = new ArrayList<>(makeCheckedMaps());
iters.ensureCapacity(numItr * iters.size());
- for(int each=1; each < numItr; each++) {
+ for (int each=1; each < numItr; each++) {
iters.addAll( makeCheckedMaps());
}
return iters.iterator();
--- a/jdk/test/java/util/Collections/CheckedSetBash.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/Collections/CheckedSetBash.java Tue Oct 13 16:45:35 2015 -0700
@@ -130,14 +130,14 @@
boolean prePresent = s.contains(e);
boolean added = s.add(e);
if (!s.contains(e))
- fail ("Element not present after addition.");
+ fail("Element not present after addition.");
if (added == prePresent)
- fail ("added == alreadyPresent");
+ fail("added == alreadyPresent");
int postSize = s.size();
if (added && preSize == postSize)
- fail ("Add returned true, but size didn't change.");
+ fail("Add returned true, but size didn't change.");
if (!added && preSize != postSize)
- fail ("Add returned false, but size changed.");
+ fail("Add returned false, but size changed.");
}
}
@@ -145,7 +145,7 @@
public static Iterator<Object[]> navigableSetsProvider() {
ArrayList<Object[]> iters = new ArrayList<>(makeCheckedSets());
iters.ensureCapacity(numItr * iters.size());
- for(int each=1; each < numItr; each++) {
+ for (int each=1; each < numItr; each++) {
iters.addAll( makeCheckedSets());
}
return iters.iterator();
--- a/jdk/test/java/util/Collections/EmptyCollectionSerialization.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/Collections/EmptyCollectionSerialization.java Tue Oct 13 16:45:35 2015 -0700
@@ -62,7 +62,7 @@
copy.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(copy)) +
" is not the singleton " +
singleton.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(singleton)));
- } catch(Exception all) {
+ } catch (Exception all) {
fail(description + ": Unexpected Exception", all);
}
}
--- a/jdk/test/java/util/Collections/EmptyIterator.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/Collections/EmptyIterator.java Tue Oct 13 16:45:35 2015 -0700
@@ -29,13 +29,14 @@
import static java.util.Collections.*;
import java.util.*;
+import java.util.concurrent.SynchronousQueue;
public class EmptyIterator {
void test(String[] args) throws Throwable {
testEmptyCollection(emptyList());
testEmptyCollection(emptySet());
-
+ testEmptyCollection(new SynchronousQueue<Object>());
testEmptyMap(emptyMap());
Hashtable<?,?> emptyTable = new Hashtable<>();
--- a/jdk/test/java/util/Collections/EmptyNavigableMap.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/Collections/EmptyNavigableMap.java Tue Oct 13 16:45:35 2015 -0700
@@ -282,7 +282,7 @@
// slightly smaller
NavigableMap ns = subMap.subMap(first, false, last, false);
- // slight exapansion
+ // slight expansion
assertThrows(() -> {
ns.subMap(first, true, last, true);
},
@@ -303,7 +303,7 @@
// slightly smaller
NavigableMap ns = subMap.headMap(BigInteger.ONE, false);
- // slight exapansion
+ // slight expansion
assertThrows(() -> {
ns.headMap(BigInteger.ONE, true);
},
@@ -324,7 +324,7 @@
// slightly smaller
NavigableMap ns = subMap.tailMap(BigInteger.ONE, false);
- // slight exapansion
+ // slight expansion
assertThrows(() -> {
ns.tailMap(BigInteger.ONE, true);
},
--- a/jdk/test/java/util/Collections/EmptyNavigableSet.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/Collections/EmptyNavigableSet.java Tue Oct 13 16:45:35 2015 -0700
@@ -301,7 +301,7 @@
// slightly smaller
NavigableSet ns = subSet.subSet(first, false, last, false);
- // slight exapansion
+ // slight expansion
assertThrows(() -> {
ns.subSet(first, true, last, true);
},
@@ -322,7 +322,7 @@
// slightly smaller
NavigableSet ns = subSet.headSet(BigInteger.ONE, false);
- // slight exapansion
+ // slight expansion
assertThrows(() -> {
ns.headSet(BigInteger.ONE, true);
},
@@ -343,7 +343,7 @@
// slightly smaller
NavigableSet ns = subSet.tailSet(BigInteger.ONE, false);
- // slight exapansion
+ // slight expansion
assertThrows(() -> {
ns.tailSet(BigInteger.ONE, true);
},
--- a/jdk/test/java/util/Collections/RacingCollections.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/Collections/RacingCollections.java Tue Oct 13 16:45:35 2015 -0700
@@ -62,14 +62,16 @@
this.start();
}
- @SuppressWarnings("unchecked") void clear(Object o) {
+ @SuppressWarnings("unchecked")
+ void clear(Object o) {
if (o instanceof Collection)
((Collection<?>)o).clear();
else
((Map<?,?>)o).clear();
}
- @SuppressWarnings("unchecked") void realRun() {
+ @SuppressWarnings("unchecked")
+ void realRun() {
// Mutate elLoco wildly forever, checking occasionally for "done"
clear(elLoco);
if (elLoco instanceof List) {
@@ -156,7 +158,7 @@
quittingTime = System.nanoTime() + workTimeMillis * 1024 * 1024;
}
boolean keepGoing() {
- return (i++ % 128 != 0) || (System.nanoTime() < quittingTime);
+ return (i++ % 128 != 0) || (System.nanoTime() - quittingTime < 0);
}
}
@@ -233,6 +235,7 @@
private static List<Queue<Integer>> newConcurrentQueues() {
List<Queue<Integer>> list =
new ArrayList<Queue<Integer>>(newConcurrentDeques());
+ list.add(new ArrayBlockingQueue<Integer>(10));
list.add(new LinkedBlockingQueue<Integer>(10));
list.add(new LinkedTransferQueue<Integer>());
list.add(new ConcurrentLinkedQueue<Integer>());
--- a/jdk/test/java/util/Collections/ReverseOrder.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/Collections/ReverseOrder.java Tue Oct 13 16:45:35 2015 -0700
@@ -25,7 +25,7 @@
* @test
* @bug 4593209 8001667
* @summary Reverse comparator was subtly broken
- * @author Josh bloch
+ * @author Josh Bloch
*/
import java.util.*;
--- a/jdk/test/java/util/Collections/RotateEmpty.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/Collections/RotateEmpty.java Tue Oct 13 16:45:35 2015 -0700
@@ -33,6 +33,6 @@
public static void main(String[] args) throws Exception {
List l = new ArrayList();
- Collections.rotate (l, 1);
+ Collections.rotate(l, 1);
}
}
--- a/jdk/test/java/util/Collections/T6433170.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/Collections/T6433170.java Tue Oct 13 16:45:35 2015 -0700
@@ -58,7 +58,6 @@
checkEmpty(checked);
}
-
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
--- a/jdk/test/java/util/Collections/WrappedNull.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/Collections/WrappedNull.java Tue Oct 13 16:45:35 2015 -0700
@@ -33,133 +33,133 @@
public class WrappedNull {
public static void main(String argv[]) throws Exception {
boolean testSucceeded = false;
- try{
+ try {
List l = Arrays.asList(null);
}
catch (NullPointerException e) {
testSucceeded = true;
}
- if(!testSucceeded)
+ if (!testSucceeded)
throw new Exception("Arrays.asList");
testSucceeded = false;
- try{
+ try {
Collection c = Collections.unmodifiableCollection(null);
}
catch (NullPointerException e) {
testSucceeded = true;
}
- if(!testSucceeded)
+ if (!testSucceeded)
throw new Exception("unmodifiableCollection");
testSucceeded = false;
- try{
+ try {
Set c = Collections.unmodifiableSet(null);
}
catch (NullPointerException e) {
testSucceeded = true;
}
- if(!testSucceeded)
+ if (!testSucceeded)
throw new Exception("unmodifiableSet");
testSucceeded = false;
- try{
+ try {
List c = Collections.unmodifiableList(null);
}
catch (NullPointerException e) {
testSucceeded = true;
}
- if(!testSucceeded)
+ if (!testSucceeded)
throw new Exception("unmodifiableList");
testSucceeded = false;
- try{
+ try {
Map c = Collections.unmodifiableMap(null);
}
catch (NullPointerException e) {
testSucceeded = true;
}
- if(!testSucceeded)
+ if (!testSucceeded)
throw new Exception("unmodifiableMap");
testSucceeded = false;
- try{
+ try {
SortedSet c = Collections.unmodifiableSortedSet(null);
}
catch (NullPointerException e) {
testSucceeded = true;
}
- if(!testSucceeded)
+ if (!testSucceeded)
throw new Exception("unmodifiableSortedSet");
testSucceeded = false;
- try{
+ try {
SortedMap c = Collections.unmodifiableSortedMap(null);
}
catch (NullPointerException e) {
testSucceeded = true;
}
- if(!testSucceeded)
+ if (!testSucceeded)
throw new Exception("unmodifiableSortedMap");
testSucceeded = false;
- try{
+ try {
Collection c = Collections.synchronizedCollection(null);
}
catch (NullPointerException e) {
testSucceeded = true;
}
- if(!testSucceeded)
+ if (!testSucceeded)
throw new Exception("synchronizedCollection");
testSucceeded = false;
- try{
+ try {
Set c = Collections.synchronizedSet(null);
}
catch (NullPointerException e) {
testSucceeded = true;
}
- if(!testSucceeded)
+ if (!testSucceeded)
throw new Exception("synchronizedSet");
testSucceeded = false;
- try{
+ try {
List c = Collections.synchronizedList(null);
}
catch (NullPointerException e) {
testSucceeded = true;
}
- if(!testSucceeded)
+ if (!testSucceeded)
throw new Exception("synchronizedList");
testSucceeded = false;
- try{
+ try {
Map c = Collections.synchronizedMap(null);
}
catch (NullPointerException e) {
testSucceeded = true;
}
- if(!testSucceeded)
+ if (!testSucceeded)
throw new Exception("synchronizedMap");
testSucceeded = false;
- try{
+ try {
SortedSet c = Collections.synchronizedSortedSet(null);
}
catch (NullPointerException e) {
testSucceeded = true;
}
- if(!testSucceeded)
+ if (!testSucceeded)
throw new Exception("synchronizedSortedSet");
testSucceeded = false;
- try{
+ try {
SortedMap c = Collections.synchronizedSortedMap(null);
}
catch (NullPointerException e) {
testSucceeded = true;
}
- if(!testSucceeded)
+ if (!testSucceeded)
throw new Exception("synchronizedSortedMap");
// Make sure that non-null arguments don't throw exc.
--- a/jdk/test/java/util/Hashtable/IllegalLoadFactor.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/Hashtable/IllegalLoadFactor.java Tue Oct 13 16:45:35 2015 -0700
@@ -26,8 +26,6 @@
@summary Test for an illegalargumentexception on loadFactor
*/
-
-
import java.util.*;
/**
@@ -38,92 +36,92 @@
public static void main(String argv[]) throws Exception {
boolean testSucceeded = false;
- try{
+ try {
// this should generate an IllegalArgumentException
Hashtable bad1 = new Hashtable(100, -3);
}
catch (IllegalArgumentException e1) {
testSucceeded = true;
}
- if(!testSucceeded)
+ if (!testSucceeded)
throw new Exception("Hashtable, negative load factor");
testSucceeded = false;
- try{
+ try {
// this should generate an IllegalArgumentException
Hashtable bad1 = new Hashtable(100, Float.NaN);
}
catch (IllegalArgumentException e1) {
testSucceeded = true;
}
- if(!testSucceeded)
+ if (!testSucceeded)
throw new Exception("Hashtable, NaN load factor");
testSucceeded = false;
- try{
+ try {
// this should generate an IllegalArgumentException
HashMap bad1 = new HashMap(100, -3);
}
catch (IllegalArgumentException e1) {
testSucceeded = true;
}
- if(!testSucceeded)
+ if (!testSucceeded)
throw new Exception("HashMap, negative load factor");
testSucceeded = false;
- try{
+ try {
// this should generate an IllegalArgumentException
HashMap bad1 = new HashMap(100, Float.NaN);
}
catch (IllegalArgumentException e1) {
testSucceeded = true;
}
- if(!testSucceeded)
+ if (!testSucceeded)
throw new Exception("HashMap, NaN load factor");
testSucceeded = false;
- try{
+ try {
// this should generate an IllegalArgumentException
HashSet bad1 = new HashSet(100, -3);
}
catch (IllegalArgumentException e1) {
testSucceeded = true;
}
- if(!testSucceeded)
+ if (!testSucceeded)
throw new Exception("HashSet, negative load factor");
testSucceeded = false;
- try{
+ try {
// this should generate an IllegalArgumentException
HashSet bad1 = new HashSet(100, Float.NaN);
}
catch (IllegalArgumentException e1) {
testSucceeded = true;
}
- if(!testSucceeded)
+ if (!testSucceeded)
throw new Exception("HashSet, NaN load factor");
testSucceeded = false;
- try{
+ try {
// this should generate an IllegalArgumentException
WeakHashMap bad1 = new WeakHashMap(100, -3);
}
catch (IllegalArgumentException e1) {
testSucceeded = true;
}
- if(!testSucceeded)
+ if (!testSucceeded)
throw new Exception("WeakHashMap, negative load factor");
testSucceeded = false;
- try{
+ try {
// this should generate an IllegalArgumentException
WeakHashMap bad1 = new WeakHashMap(100, Float.NaN);
}
catch (IllegalArgumentException e1) {
testSucceeded = true;
}
- if(!testSucceeded)
+ if (!testSucceeded)
throw new Exception("WeakHashMap, NaN load factor");
// Make sure that legal creates don't throw exceptions
--- a/jdk/test/java/util/Hashtable/ReadObject.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/Hashtable/ReadObject.java Tue Oct 13 16:45:35 2015 -0700
@@ -57,13 +57,13 @@
public Object get(Object key) {
ValueWrapper valueWrapper = (ValueWrapper)super.get(key);
Object value = valueWrapper.getValue();
- if(value instanceof ValueWrapper)
+ if (value instanceof ValueWrapper)
throw new RuntimeException("Hashtable.get bug");
return value;
}
public Object put(Object key, Object value) {
- if(value instanceof ValueWrapper)
+ if (value instanceof ValueWrapper)
throw new RuntimeException(
"Hashtable.put bug: value is already wrapped");
ValueWrapper valueWrapper = new ValueWrapper(value);
@@ -98,4 +98,4 @@
ReadObject myHashtableCopy = (ReadObject)copyObject(myHashtable);
String value = (String)myHashtableCopy.get("key");
}
-};
+}
--- a/jdk/test/java/util/IdentityHashMap/ToString.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/IdentityHashMap/ToString.java Tue Oct 13 16:45:35 2015 -0700
@@ -28,7 +28,6 @@
* @author Josh Bloch
*/
-
import java.util.*;
public class ToString {
--- a/jdk/test/java/util/LinkedHashMap/Basic.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/LinkedHashMap/Basic.java Tue Oct 13 16:45:35 2015 -0700
@@ -83,12 +83,12 @@
Map<Integer,Integer> m = new LinkedHashMap();
for (int i=0; i<mapSize; i++)
if (m.put(new Integer(i), new Integer(2*i)) != null)
- throw new Exception("put returns non-null value erroenously.");
+ throw new Exception("put returns non-null value erroneously.");
for (int i=0; i<2*mapSize; i++)
if (m.containsValue(new Integer(i)) != (i%2==0))
throw new Exception("contains value "+i);
if (m.put(nil, nil) == null)
- throw new Exception("put returns a null value erroenously.");
+ throw new Exception("put returns a null value erroneously.");
Map<Integer,Integer> m2 = new LinkedHashMap(); m2.putAll(m);
if (!m.equals(m2))
throw new Exception("Clone not equal to original. (1)");
@@ -129,7 +129,7 @@
throw new Exception("clear failed.");
Iterator it = m.entrySet().iterator();
- while(it.hasNext()) {
+ while (it.hasNext()) {
it.next();
it.remove();
}
@@ -240,8 +240,8 @@
for (int i=0; i<mapSize; i++) {
Integer x = (Integer) l2.get(i);
- if(!x.equals(m.remove(x)))
- throw new Exception("Missing key: "+i+", "+x);
+ if (!x.equals(m.remove(x)))
+ throw new Exception("Missing key: "+i+", "+x);
if (!x.equals(m.computeIfAbsent(x, Integer::valueOf)))
throw new Exception("Wrong value: "+i+", "+m.get(x)+", "+x);
}
@@ -292,7 +292,7 @@
ObjectInputStream in = new ObjectInputStream(bis);
result = (Map)in.readObject();
in.close();
- } catch(Exception e) {
+ } catch (Exception e) {
e.printStackTrace();
}
return result;
--- a/jdk/test/java/util/LinkedHashMap/Cache.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/LinkedHashMap/Cache.java Tue Oct 13 16:45:35 2015 -0700
@@ -33,7 +33,7 @@
private static final int MAP_SIZE = 10;
private static final int NUM_KEYS = 100;
- public static void main(String[] args) throws Exception {
+ public static void main(String[] args) throws Exception {
Map m = new LinkedHashMap() {
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > MAP_SIZE;
--- a/jdk/test/java/util/LinkedHashSet/Basic.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/LinkedHashSet/Basic.java Tue Oct 13 16:45:35 2015 -0700
@@ -99,7 +99,7 @@
static Set clone(Set s) throws Exception {
Set clone;
int method = rnd.nextInt(3);
- clone = (method==0 ? (Set) ((LinkedHashSet)s).clone() :
+ clone = (method==0 ? (Set) ((LinkedHashSet)s).clone() :
(method==1 ? new LinkedHashSet(Arrays.asList(s.toArray())) :
serClone(s)));
if (!s.equals(clone))
@@ -126,7 +126,7 @@
ObjectInputStream in = new ObjectInputStream(bis);
result = (Set)in.readObject();
in.close();
- } catch(Exception e) {
+ } catch (Exception e) {
e.printStackTrace();
}
return result;
--- a/jdk/test/java/util/LinkedList/Clone.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/LinkedList/Clone.java Tue Oct 13 16:45:35 2015 -0700
@@ -74,7 +74,7 @@
throw new RuntimeException("TreeMap.clone() is broken.");
}
- private static class LinkedList2 extends LinkedList {};
- private static class TreeSet2 extends TreeSet {};
- private static class TreeMap2 extends TreeMap {};
+ private static class LinkedList2 extends LinkedList {}
+ private static class TreeSet2 extends TreeSet {}
+ private static class TreeMap2 extends TreeMap {}
}
--- a/jdk/test/java/util/LinkedList/ComodifiedRemove.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/LinkedList/ComodifiedRemove.java Tue Oct 13 16:45:35 2015 -0700
@@ -41,10 +41,10 @@
list.add(o1);
ListIterator e = list.listIterator();
e.next();
- Object o2 = new Integer (2);
+ Object o2 = new Integer(2);
list.add(o2);
- try{
+ try {
e.remove();
} catch (ConcurrentModificationException cme) {
return;
--- a/jdk/test/java/util/List/ListDefaults.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/List/ListDefaults.java Tue Oct 13 16:45:35 2015 -0700
@@ -381,7 +381,7 @@
minBitCount = bitCount;
}
- // Resuse the supplier to store AtomicInteger instead of Integer
+ // Reuse the supplier to store AtomicInteger instead of Integer
// Hence the use of raw type and cast
List<AtomicInteger> incomparablesData = new ArrayList<>();
for (int i = 0; i < test.expected.size(); i++) {
--- a/jdk/test/java/util/Map/Defaults.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/Map/Defaults.java Tue Oct 13 16:45:35 2015 -0700
@@ -464,7 +464,7 @@
@Test(dataProvider = "MergeCases")
private void testMerge(String description, Map<IntegerEnum, String> map, Merging.Value oldValue, Merging.Value newValue, Merging.Merger merger, Merging.Value put, Merging.Value result) {
// add and check initial conditions.
- switch(oldValue) {
+ switch (oldValue) {
case ABSENT :
map.remove(EXTRA_KEY);
assertFalse(map.containsKey(EXTRA_KEY), "key not absent");
@@ -490,7 +490,7 @@
// check result
- switch(result) {
+ switch (result) {
case NULL :
assertNull(returned, "wrong value");
break;
@@ -505,7 +505,7 @@
}
// check map
- switch(put) {
+ switch (put) {
case ABSENT :
assertFalse(map.containsKey(EXTRA_KEY), "key not absent");
break;
@@ -610,7 +610,6 @@
return all;
}
-
private static Collection<Object[]> makeRWMapsNoNulls() {
Collection<Object[]> all = new ArrayList<>();
@@ -656,8 +655,8 @@
return all;
}
+
/**
- *
* @param nullKeys include null keys
* @param nullValues include null values
* @return
@@ -674,7 +673,6 @@
}
/**
- *
* @param nulls include null values
* @return
*/
@@ -702,7 +700,6 @@
}
/**
- *
* @param nulls include nulls
* @return
*/
@@ -712,8 +709,7 @@
});
}
- /**
- *
+ /**
* @param supplier a supplier of mutable map instances.
*
* @param nullKeys include null keys
@@ -774,15 +770,15 @@
static Collection<Object[]> makeMergeTestCases() {
Collection<Object[]> cases = new ArrayList<>();
- for( Object[] mapParams : makeAllRWMaps() ) {
+ for (Object[] mapParams : makeAllRWMaps() ) {
cases.add(new Object[] { mapParams[0], mapParams[1], Merging.Value.ABSENT, Merging.Value.NEWVALUE, Merging.Merger.UNUSED, Merging.Value.NEWVALUE, Merging.Value.NEWVALUE });
}
- for( Object[] mapParams : makeAllRWMaps() ) {
+ for (Object[] mapParams : makeAllRWMaps() ) {
cases.add(new Object[] { mapParams[0], mapParams[1], Merging.Value.OLDVALUE, Merging.Value.NEWVALUE, Merging.Merger.NULL, Merging.Value.ABSENT, Merging.Value.NULL });
}
- for( Object[] mapParams : makeAllRWMaps() ) {
+ for (Object[] mapParams : makeAllRWMaps() ) {
cases.add(new Object[] { mapParams[0], mapParams[1], Merging.Value.OLDVALUE, Merging.Value.NEWVALUE, Merging.Merger.RESULT, Merging.Value.RESULT, Merging.Value.RESULT });
}
@@ -813,7 +809,7 @@
}
public static <T extends Throwable> void assertThrows(Class<T> throwable, String message, Thrower<T>... throwers) {
- for(Thrower<T> thrower : throwers) {
+ for (Thrower<T> thrower : throwers) {
assertThrows(thrower, throwable, message);
}
}
@@ -834,7 +830,7 @@
* @param <K> Type of keys
* @param <V> Type of values
*/
- public static class ExtendsAbstractMap<M extends Map<K,V>, K, V> extends AbstractMap<K, V> {
+ public static class ExtendsAbstractMap<M extends Map<K,V>, K, V> extends AbstractMap<K,V> {
protected final M map;
@@ -842,8 +838,8 @@
protected ExtendsAbstractMap(M map) { this.map = map; }
- public Set<Map.Entry<K, V>> entrySet() {
- return new AbstractSet<Map.Entry<K, V>>() {
+ public Set<Map.Entry<K,V>> entrySet() {
+ return new AbstractSet<Map.Entry<K,V>>() {
public int size() {
return map.size();
}
@@ -876,7 +872,7 @@
* @param <K> Type of keys
* @param <V> Type of values
*/
- public static class ImplementsConcurrentMap<K, V> extends ExtendsAbstractMap<ConcurrentMap<K,V>, K, V> implements ConcurrentMap<K,V> {
+ public static class ImplementsConcurrentMap<K,V> extends ExtendsAbstractMap<ConcurrentMap<K,V>, K, V> implements ConcurrentMap<K,V> {
public ImplementsConcurrentMap() { super(new ConcurrentHashMap<K,V>()); }
// ConcurrentMap reabstracts these methods
--- a/jdk/test/java/util/Map/Get.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/Map/Get.java Tue Oct 13 16:45:35 2015 -0700
@@ -119,7 +119,7 @@
static void check(boolean cond) { if (cond) pass(); else fail(); }
static void check(String desc, boolean cond) { if (cond) pass(); else fail(desc); }
static void equal(Object x, Object y) {
- if(Objects.equals(x,y)) pass(); else fail(x + " not equal to " + y);
+ if (Objects.equals(x,y)) pass(); else fail(x + " not equal to " + y);
}
public static void main(String[] args) throws Throwable {
--- a/jdk/test/java/util/NavigableMap/LockStep.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/NavigableMap/LockStep.java Tue Oct 13 16:45:35 2015 -0700
@@ -228,8 +228,8 @@
if (maybe(4) && s instanceof Serializable) {
try {
equal2(s, serialClone(s));
- } catch(RuntimeException uhoh) {
- if(!(uhoh.getCause() instanceof NotSerializableException)) {
+ } catch (RuntimeException uhoh) {
+ if (!(uhoh.getCause() instanceof NotSerializableException)) {
throw uhoh;
}
}
--- a/jdk/test/java/util/Spliterator/SpliteratorCharacteristics.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/Spliterator/SpliteratorCharacteristics.java Tue Oct 13 16:45:35 2015 -0700
@@ -126,19 +126,19 @@
}
{
- Spliterator<?> s = Spliterators.spliterator(l.iterator( ), 1, 0);
+ Spliterator<?> s = Spliterators.spliterator(l.iterator(), 1, 0);
assertCharacteristics(s, Spliterator.SIZED | Spliterator.SUBSIZED);
assertHasNotCharacteristics(s, Spliterator.CONCURRENT);
}
{
- Spliterator<?> s = Spliterators.spliterator(l.iterator( ), 1, Spliterator.CONCURRENT);
+ Spliterator<?> s = Spliterators.spliterator(l.iterator(), 1, Spliterator.CONCURRENT);
assertHasNotCharacteristics(s, Spliterator.SIZED | Spliterator.SUBSIZED);
assertCharacteristics(s, Spliterator.CONCURRENT);
}
{
- Spliterator<?> s = Spliterators.spliteratorUnknownSize(l.iterator( ), 0);
+ Spliterator<?> s = Spliterators.spliteratorUnknownSize(l.iterator(), 0);
assertHasNotCharacteristics(s, Spliterator.SIZED | Spliterator.SUBSIZED);
}
--- a/jdk/test/java/util/Spliterator/SpliteratorLateBindingFailFastTest.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/Spliterator/SpliteratorLateBindingFailFastTest.java Tue Oct 13 16:45:35 2015 -0700
@@ -214,7 +214,7 @@
db.addMap(LinkedHashMap::new);
- // This fails when run through jrteg but passes when run though
+ // This fails when run through jtreg but passes when run through
// ant
// db.addMap(IdentityHashMap::new);
--- a/jdk/test/java/util/TimSort/Sorter.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/TimSort/Sorter.java Tue Oct 13 16:45:35 2015 -0700
@@ -46,7 +46,7 @@
for (int i=0; i < 10000; i++) {
for (Sorter s : values()) {
- Integer[] test= gold.clone();
+ Integer[] test = gold.clone();
s.sort(test);
}
}
--- a/jdk/test/java/util/TreeMap/ContainsValue.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/TreeMap/ContainsValue.java Tue Oct 13 16:45:35 2015 -0700
@@ -30,7 +30,7 @@
import java.util.*;
public class ContainsValue {
- public static void main (String[] args) {
+ public static void main(String[] args) {
Map map = new TreeMap();
if (map.containsValue ("gemutlichkeit"))
--- a/jdk/test/java/util/TreeMap/HeadTailTypeError.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/TreeMap/HeadTailTypeError.java Tue Oct 13 16:45:35 2015 -0700
@@ -32,71 +32,70 @@
public class HeadTailTypeError {
public static void main(String argv[]) throws Exception {
- try{
+ try {
SortedMap m = new TreeMap();
m.headMap(new Object());
throw new Exception("headMap, natural ordering");
} catch (ClassCastException e) {
}
- try{
+ try {
SortedMap m = new TreeMap();
m.tailMap(new Object());
throw new Exception("tailMap, natural ordering");
} catch (ClassCastException e) {
}
-
- try{
+ try {
SortedMap m = new TreeMap(String.CASE_INSENSITIVE_ORDER);
m.headMap(new Integer(0));
throw new Exception("headMap, explicit comparator");
} catch (ClassCastException e) {
}
- try{
+ try {
SortedMap m = new TreeMap(String.CASE_INSENSITIVE_ORDER);
m.tailMap(new Integer(0));
throw new Exception("tailMap, explicit comparator");
} catch (ClassCastException e) {
}
- try{
+ try {
SortedSet m = new TreeSet();
m.headSet(new Object());
throw new Exception("headSet, natural ordering");
} catch (ClassCastException e) {
}
- try{
+ try {
SortedSet m = new TreeSet();
m.tailSet(new Object());
throw new Exception("tailSet, natural ordering");
} catch (ClassCastException e) {
}
- try{
+ try {
SortedSet m = new TreeSet(String.CASE_INSENSITIVE_ORDER);
m.headSet(new Integer(0));
throw new Exception("headSet, explicit comparator");
} catch (ClassCastException e) {
}
- try{
+ try {
SortedSet m = new TreeSet(String.CASE_INSENSITIVE_ORDER);
m.tailSet(new Integer(0));
throw new Exception("tailSet, explicit comparator");
} catch (ClassCastException e) {
}
- try{
+ try {
SortedMap m = new TreeMap();
m.headMap(null);
throw new Exception("(null endpoint)headMap, natural ordering");
} catch (NullPointerException e) {
}
- try{
+ try {
SortedMap m = new TreeMap();
m.tailMap(null);
throw new Exception("(null endpoint)tailMap, natural ordering");
@@ -104,42 +103,42 @@
}
- try{
+ try {
SortedMap m = new TreeMap(String.CASE_INSENSITIVE_ORDER);
m.headMap(null);
throw new Exception("(null endpoint)headMap, explicit comparator");
} catch (NullPointerException e) {
}
- try{
+ try {
SortedMap m = new TreeMap(String.CASE_INSENSITIVE_ORDER);
m.tailMap(null);
throw new Exception("(null endpoint)tailMap, explicit comparator");
} catch (NullPointerException e) {
}
- try{
+ try {
SortedSet m = new TreeSet();
m.headSet(null);
throw new Exception("(null endpoint)headSet, natural ordering");
} catch (NullPointerException e) {
}
- try{
+ try {
SortedSet m = new TreeSet();
m.tailSet(null);
throw new Exception("(null endpoint)tailSet, natural ordering");
} catch (NullPointerException e) {
}
- try{
+ try {
SortedSet m = new TreeSet(String.CASE_INSENSITIVE_ORDER);
m.headSet(null);
throw new Exception("(null endpoint)headSet, explicit comparator");
} catch (NullPointerException e) {
}
- try{
+ try {
SortedSet m = new TreeSet(String.CASE_INSENSITIVE_ORDER);
m.tailSet(null);
throw new Exception("(null endpoint)tailSet, explicit comparator");
--- a/jdk/test/java/util/TreeMap/SubMap.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/TreeMap/SubMap.java Tue Oct 13 16:45:35 2015 -0700
@@ -40,7 +40,7 @@
boolean exc = false;
try {
m2.firstKey();
- } catch(NoSuchElementException e) {
+ } catch (NoSuchElementException e) {
exc = true;
}
if (!exc)
@@ -49,7 +49,7 @@
exc = false;
try {
m2.lastKey();
- } catch(NoSuchElementException e) {
+ } catch (NoSuchElementException e) {
exc = true;
}
if (!exc)
@@ -70,7 +70,7 @@
exc = false;
try {
s2.first();
- } catch(NoSuchElementException e) {
+ } catch (NoSuchElementException e) {
exc = true;
}
if (!exc)
@@ -79,7 +79,7 @@
exc = false;
try {
s2.last();
- } catch(NoSuchElementException e) {
+ } catch (NoSuchElementException e) {
exc = true;
}
if (!exc)
--- a/jdk/test/java/util/Vector/ComodifiedRemoveAllElements.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/Vector/ComodifiedRemoveAllElements.java Tue Oct 13 16:45:35 2015 -0700
@@ -25,7 +25,7 @@
* @test
* @bug 4298133
* @summary Due to a bug in Vector's removeAllElements(),
- * the modification counter would not get incremented.
+ * the modification counter would not get incremented.
* @author Konstantin Kladko
*/
@@ -37,7 +37,7 @@
v.addElement(null);
Iterator it = v.iterator();
v.removeAllElements();
- try{
+ try {
it.next();
} catch (ConcurrentModificationException cme) {
return;
--- a/jdk/test/java/util/Vector/IllegalConstructorArgs.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/Vector/IllegalConstructorArgs.java Tue Oct 13 16:45:35 2015 -0700
@@ -39,7 +39,7 @@
public static void main(String argv[]) {
int testSucceeded=0;
- try{
+ try {
// this should generate an IllegalArgumentException
Vector bad1 = new Vector(-100, 10);
}
@@ -50,8 +50,8 @@
testSucceeded =0;
}
- if(testSucceeded == 0)
- throw new RuntimeException("Wrong exception thrown.");
+ if (testSucceeded == 0)
+ throw new RuntimeException("Wrong exception thrown.");
}
--- a/jdk/test/java/util/Vector/LastIndexOf.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/Vector/LastIndexOf.java Tue Oct 13 16:45:35 2015 -0700
@@ -34,7 +34,7 @@
public static void main(String argv[]) throws Exception {
Vector v = new Vector(10);
- try{
+ try {
int i = v.lastIndexOf(null, 5);
throw new Exception("lastIndexOf(5/10) " + i);
} catch (IndexOutOfBoundsException e) {
--- a/jdk/test/java/util/Vector/SyncLastIndexOf.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/Vector/SyncLastIndexOf.java Tue Oct 13 16:45:35 2015 -0700
@@ -36,7 +36,7 @@
static class RemovingThread extends Thread {
public void run() {
- synchronized(v) {
+ synchronized (v) {
try {
sleep(200);
} catch (InterruptedException e) {
--- a/jdk/test/java/util/WeakHashMap/GCDuringIteration.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/WeakHashMap/GCDuringIteration.java Tue Oct 13 16:45:35 2015 -0700
@@ -24,7 +24,6 @@
/*
* @test
* @bug 6499848
- * @ignore until 6842353 is resolved
* @summary Check that iterators work properly in the presence of
* concurrent finalization and removal of elements.
* @key randomness
@@ -116,7 +115,7 @@
it.next(); // protects first entry
System.out.println(map.values());
foos[first] = null;
- tryWaitForFinalizersToRun()
+ tryWaitForFinalizersToRun();
equal(map.size(), first+1);
System.out.println(map.values());
checkIterator(it, first-1);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/ArrayBlockingQueue/IteratorConsistency.java Tue Oct 13 16:45:35 2015 -0700
@@ -0,0 +1,755 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Martin Buchholz with assistance from members of JCP
+ * JSR-166 Expert Group and released to the public domain, as
+ * explained at http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.ArrayDeque;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Queue;
+import java.util.Random;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.CountDownLatch;
+
+/*
+ * @test
+ * @bug 7014263
+ * @summary White box testing of ArrayBlockingQueue iterators.
+ */
+
+/**
+ * Highly coupled to the implementation of ArrayBlockingQueue.
+ * Uses reflection to inspect queue and iterator state.
+ */
+@SuppressWarnings({"unchecked", "rawtypes"})
+public class IteratorConsistency {
+ final Random rnd = new Random();
+ final int CAPACITY = 20;
+ Field itrsField;
+ Field itemsField;
+ Field takeIndexField;
+ Field headField;
+ Field nextField;
+ Field prevTakeIndexField;
+
+ void test(String[] args) throws Throwable {
+ itrsField = ArrayBlockingQueue.class.getDeclaredField("itrs");
+ itemsField = ArrayBlockingQueue.class.getDeclaredField("items");
+ takeIndexField = ArrayBlockingQueue.class.getDeclaredField("takeIndex");
+ headField = Class.forName("java.util.concurrent.ArrayBlockingQueue$Itrs").getDeclaredField("head");
+ nextField = Class.forName("java.util.concurrent.ArrayBlockingQueue$Itrs$Node").getDeclaredField("next");
+ prevTakeIndexField = Class.forName("java.util.concurrent.ArrayBlockingQueue$Itr").getDeclaredField("prevTakeIndex");
+ itrsField.setAccessible(true);
+ itemsField.setAccessible(true);
+ takeIndexField.setAccessible(true);
+ headField.setAccessible(true);
+ nextField.setAccessible(true);
+ prevTakeIndexField.setAccessible(true);
+ test(CAPACITY, true);
+ test(CAPACITY, false);
+ }
+
+ Object itrs(ArrayBlockingQueue q) {
+ try {
+ return itrsField.get(q);
+ } catch (Throwable t) { throw new Error(); }
+ }
+
+ int takeIndex(ArrayBlockingQueue q) {
+ try {
+ return takeIndexField.getInt(q);
+ } catch (Throwable t) { throw new Error(); }
+ }
+
+ List<Iterator> trackedIterators(Object itrs) {
+ try {
+ List<Iterator> its = new ArrayList<Iterator>();
+ if (itrs != null)
+ for (Object p = headField.get(itrs); p != null; p = nextField.get(p))
+ its.add(((WeakReference<Iterator>)(p)).get());
+ Collections.reverse(its);
+ return its;
+ } catch (Throwable t) { throw new Error(); }
+ }
+
+ List<Iterator> trackedIterators(ArrayBlockingQueue q) {
+ return trackedIterators(itrs(q));
+ }
+
+ List<Iterator> attachedIterators(Object itrs) {
+ try {
+ List<Iterator> its = new ArrayList<Iterator>();
+ if (itrs != null)
+ for (Object p = headField.get(itrs); p != null; p = nextField.get(p)) {
+ Iterator it = ((WeakReference<Iterator>)(p)).get();
+ if (it != null && !isDetached(it))
+ its.add(it);
+ }
+ Collections.reverse(its);
+ return its;
+ } catch (Throwable t) { unexpected(t); return null; }
+ }
+
+ List<Iterator> attachedIterators(ArrayBlockingQueue q) {
+ return attachedIterators(itrs(q));
+ }
+
+ Object[] internalArray(ArrayBlockingQueue q) {
+ try {
+ return (Object[]) itemsField.get(q);
+ } catch (Throwable t) { throw new Error(t); }
+ }
+
+ void printInternalArray(ArrayBlockingQueue q) {
+ System.err.println(Arrays.toString(internalArray(q)));
+ }
+
+ void checkExhausted(Iterator it) {
+ if (rnd.nextBoolean()) {
+ check(!it.hasNext());
+ check(isDetached(it));
+ }
+ if (rnd.nextBoolean())
+ try { it.next(); fail("should throw"); }
+ catch (NoSuchElementException success) {}
+ }
+
+ boolean isDetached(Iterator it) {
+ try {
+ return prevTakeIndexField.getInt(it) < 0;
+ } catch (IllegalAccessException t) { unexpected(t); return false; }
+ }
+
+ void checkDetached(Iterator it) {
+ check(isDetached(it));
+ }
+
+ void removeUsingIterator(ArrayBlockingQueue q, Object element) {
+ Iterator it = q.iterator();
+ while (it.hasNext()) {
+ Object x = it.next();
+ if (element.equals(x))
+ it.remove();
+ checkRemoveThrowsISE(it);
+ }
+ }
+
+ void checkRemoveThrowsISE(Iterator it) {
+ if (rnd.nextBoolean())
+ return;
+ try { it.remove(); fail("should throw"); }
+ catch (IllegalStateException success) {}
+ }
+
+ void checkRemoveHasNoEffect(Iterator it, Collection c) {
+ if (rnd.nextBoolean())
+ return;
+ int size = c.size();
+ it.remove(); // no effect
+ equal(c.size(), size);
+ checkRemoveThrowsISE(it);
+ }
+
+ void checkIterationSanity(Queue q) {
+ if (rnd.nextBoolean())
+ return;
+ int size = q.size();
+ Object[] a = q.toArray();
+ Object[] b = new Object[size+2];
+ Arrays.fill(b, Boolean.TRUE);
+ Object[] c = q.toArray(b);
+ equal(a.length, size);
+ check(b == c);
+ check(b[size] == null);
+ check(b[size+1] == Boolean.TRUE);
+ equal(q.toString(), Arrays.toString(a));
+ Integer[] xx = null, yy = null;
+ if (size > 0) {
+ xx = new Integer[size - 1];
+ Arrays.fill(xx, 42);
+ yy = ((Queue<Integer>)q).toArray(xx);
+ for (Integer zz : xx)
+ equal(42, zz);
+ }
+ Iterator it = q.iterator();
+ for (int i = 0; i < size; i++) {
+ check(it.hasNext());
+ Object x = it.next();
+ check(x == a[i]);
+ check(x == b[i]);
+ if (xx != null) check(x == yy[i]);
+ }
+ check(!it.hasNext());
+ }
+
+ private static void waitForFinalizersToRun() {
+ for (int i = 0; i < 2; i++)
+ tryWaitForFinalizersToRun();
+ }
+
+ private static void tryWaitForFinalizersToRun() {
+ System.gc();
+ final CountDownLatch fin = new CountDownLatch(1);
+ new Object() { protected void finalize() { fin.countDown(); }};
+ System.gc();
+ try { fin.await(); }
+ catch (InterruptedException ie) { throw new Error(ie); }
+ }
+
+ void test(int capacity, boolean fair) {
+ //----------------------------------------------------------------
+ // q.clear will clear out itrs.
+ //----------------------------------------------------------------
+ try {
+ ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
+ List<Iterator> its = new ArrayList<Iterator>();
+ for (int i = 0; i < capacity; i++)
+ check(q.add(i));
+ check(itrs(q) == null);
+ for (int i = 0; i < capacity; i++) {
+ its.add(q.iterator());
+ equal(trackedIterators(q), its);
+ q.poll();
+ q.add(capacity+i);
+ }
+ q.clear();
+ check(itrs(q) == null);
+ int j = 0;
+ for (Iterator it : its) {
+ if (rnd.nextBoolean())
+ check(it.hasNext());
+ equal(it.next(), j++);
+ checkExhausted(it);
+ }
+ } catch (Throwable t) { unexpected(t); }
+
+ //----------------------------------------------------------------
+ // q emptying will clear out itrs.
+ //----------------------------------------------------------------
+ try {
+ ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
+ List<Iterator> its = new ArrayList<Iterator>();
+ for (int i = 0; i < capacity; i++)
+ q.add(i);
+ check(itrs(q) == null);
+ for (int i = 0; i < capacity; i++) {
+ its.add(q.iterator());
+ equal(trackedIterators(q), its);
+ q.poll();
+ q.add(capacity+i);
+ }
+ for (int i = 0; i < capacity; i++)
+ q.poll();
+ check(itrs(q) == null);
+ int j = 0;
+ for (Iterator it : its) {
+ if (rnd.nextBoolean())
+ check(it.hasNext());
+ equal(it.next(), j++);
+ checkExhausted(it);
+ }
+ } catch (Throwable t) { unexpected(t); }
+
+ //----------------------------------------------------------------
+ // Advancing 2 cycles will remove iterators.
+ //----------------------------------------------------------------
+ try {
+ ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
+ List<Iterator> its = new ArrayList<Iterator>();
+ for (int i = 0; i < capacity; i++)
+ q.add(i);
+ check(itrs(q) == null);
+ for (int i = capacity; i < 3 * capacity; i++) {
+ its.add(q.iterator());
+ equal(trackedIterators(q), its);
+ q.poll();
+ q.add(i);
+ }
+ for (int i = 3 * capacity; i < 4 * capacity; i++) {
+ equal(trackedIterators(q), its.subList(capacity,2*capacity));
+ q.poll();
+ q.add(i);
+ }
+ check(itrs(q) == null);
+ int j = 0;
+ for (Iterator it : its) {
+ if (rnd.nextBoolean())
+ check(it.hasNext());
+ equal(it.next(), j++);
+ checkExhausted(it);
+ }
+ } catch (Throwable t) { unexpected(t); }
+
+ //----------------------------------------------------------------
+ // Interior removal of elements used by an iterator will cause
+ // it to be untracked.
+ //----------------------------------------------------------------
+ try {
+ ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
+ q.add(0);
+ for (int i = 1; i < 2 * capacity; i++) {
+ q.add(i);
+ Integer[] elts = { -1, -2, -3 };
+ for (Integer elt : elts) q.add(elt);
+ equal(q.remove(), i - 1);
+ Iterator it = q.iterator();
+ equal(it.next(), i);
+ equal(it.next(), elts[0]);
+ Collections.shuffle(Arrays.asList(elts));
+ check(q.remove(elts[0]));
+ check(q.remove(elts[1]));
+ equal(trackedIterators(q), Collections.singletonList(it));
+ check(q.remove(elts[2]));
+ check(itrs(q) == null);
+ equal(it.next(), -2);
+ if (rnd.nextBoolean()) checkExhausted(it);
+ if (rnd.nextBoolean()) checkDetached(it);
+ }
+ } catch (Throwable t) { unexpected(t); }
+
+ //----------------------------------------------------------------
+ // Check iterators on an empty q
+ //----------------------------------------------------------------
+ try {
+ ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
+ for (int i = 0; i < 4; i++) {
+ Iterator it = q.iterator();
+ check(itrs(q) == null);
+ if (rnd.nextBoolean()) checkExhausted(it);
+ if (rnd.nextBoolean()) checkDetached(it);
+ checkRemoveThrowsISE(it);
+ }
+ } catch (Throwable t) { unexpected(t); }
+
+ //----------------------------------------------------------------
+ // Check "interior" removal of iterator's last element
+ //----------------------------------------------------------------
+ try {
+ ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
+ List<Iterator> its = new ArrayList<Iterator>();
+ for (int i = 0; i < capacity; i++)
+ q.add(i);
+ for (int i = 0; i < capacity; i++) {
+ Iterator it = q.iterator();
+ its.add(it);
+ for (int j = 0; j < i; j++)
+ equal(j, it.next());
+ equal(attachedIterators(q), its);
+ }
+ q.remove(capacity - 1);
+ equal(attachedIterators(q), its);
+ for (int i = 1; i < capacity - 1; i++) {
+ q.remove(capacity - i - 1);
+ Iterator it = its.get(capacity - i);
+ checkDetached(it);
+ equal(attachedIterators(q), its.subList(0, capacity - i));
+ if (rnd.nextBoolean()) check(it.hasNext());
+ equal(it.next(), capacity - i);
+ checkExhausted(it);
+ }
+ equal(attachedIterators(q), its.subList(0, 2));
+ q.remove(0);
+ check(q.isEmpty());
+ check(itrs(q) == null);
+ Iterator it = its.get(0);
+ equal(it.next(), 0);
+ checkRemoveHasNoEffect(it, q);
+ checkExhausted(it);
+ checkDetached(it);
+ checkRemoveHasNoEffect(its.get(1), q);
+ } catch (Throwable t) { unexpected(t); }
+
+ //----------------------------------------------------------------
+ // Check "interior" removal of alternating elements, straddling 2 cycles
+ //----------------------------------------------------------------
+ try {
+ ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
+ List<Iterator> its = new ArrayList<Iterator>();
+ // Move takeIndex to middle
+ for (int i = 0; i < capacity/2; i++) {
+ check(q.add(i));
+ equal(q.poll(), i);
+ }
+ check(takeIndex(q) == capacity/2);
+ for (int i = 0; i < capacity; i++)
+ q.add(i);
+ for (int i = 0; i < capacity; i++) {
+ Iterator it = q.iterator();
+ its.add(it);
+ for (int j = 0; j < i; j++)
+ equal(j, it.next());
+ equal(attachedIterators(q), its);
+ }
+ // Remove all even elements, in either direction using
+ // q.remove(), or iterator.remove()
+ switch (rnd.nextInt(3)) {
+ case 0:
+ for (int i = 0; i < capacity; i+=2) {
+ check(q.remove(i));
+ equal(attachedIterators(q), its);
+ }
+ break;
+ case 1:
+ for (int i = capacity - 2; i >= 0; i-=2) {
+ check(q.remove(i));
+ equal(attachedIterators(q), its);
+ }
+ break;
+ case 2:
+ Iterator it = q.iterator();
+ while (it.hasNext()) {
+ int i = (Integer) it.next();
+ if ((i & 1) == 0)
+ it.remove();
+ }
+ equal(attachedIterators(q), its);
+ break;
+ default: throw new Error();
+ }
+
+ for (int i = 0; i < capacity; i++) {
+ Iterator it = its.get(i);
+ boolean even = ((i & 1) == 0);
+ if (even) {
+ if (rnd.nextBoolean()) check(it.hasNext());
+ equal(i, it.next());
+ for (int j = i+1; j < capacity; j += 2)
+ equal(j, it.next());
+ check(!isDetached(it));
+ check(!it.hasNext());
+ check(isDetached(it));
+ } else { /* odd */
+ if (rnd.nextBoolean()) check(it.hasNext());
+ checkRemoveHasNoEffect(it, q);
+ equal(i, it.next());
+ for (int j = i+2; j < capacity; j += 2)
+ equal(j, it.next());
+ check(!isDetached(it));
+ check(!it.hasNext());
+ check(isDetached(it));
+ }
+ }
+ equal(trackedIterators(q), Collections.emptyList());
+ check(itrs(q) == null);
+ } catch (Throwable t) { unexpected(t); }
+
+ //----------------------------------------------------------------
+ // Check garbage collection of discarded iterators
+ //----------------------------------------------------------------
+ try {
+ ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
+ List<Iterator> its = new ArrayList<Iterator>();
+ for (int i = 0; i < capacity; i++)
+ q.add(i);
+ for (int i = 0; i < capacity; i++) {
+ its.add(q.iterator());
+ equal(attachedIterators(q), its);
+ }
+ its = null;
+ waitForFinalizersToRun();
+ List<Iterator> trackedIterators = trackedIterators(q);
+ equal(trackedIterators.size(), capacity);
+ for (Iterator x : trackedIterators)
+ check(x == null);
+ Iterator it = q.iterator();
+ equal(trackedIterators(q), Collections.singletonList(it));
+ } catch (Throwable t) { unexpected(t); }
+
+ //----------------------------------------------------------------
+ // Check garbage collection of discarded iterators,
+ // with a randomly retained subset.
+ //----------------------------------------------------------------
+ try {
+ ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
+ List<Iterator> its = new ArrayList<Iterator>();
+ List<Iterator> retained = new ArrayList<Iterator>();
+ final int size = 1 + rnd.nextInt(capacity);
+ for (int i = 0; i < size; i++)
+ q.add(i);
+ for (int i = 0; i < size; i++) {
+ Iterator it = q.iterator();
+ its.add(it);
+ equal(attachedIterators(q), its);
+ }
+ // Leave sufficient gaps in retained
+ for (int i = 0; i < size; i+= 2+rnd.nextInt(3))
+ retained.add(its.get(i));
+ its = null;
+ waitForFinalizersToRun();
+ List<Iterator> trackedIterators = trackedIterators(q);
+ equal(trackedIterators.size(), size);
+ for (Iterator it : trackedIterators)
+ check((it == null) ^ retained.contains(it));
+ Iterator it = q.iterator(); // trigger another sweep
+ retained.add(it);
+ equal(trackedIterators(q), retained);
+ } catch (Throwable t) { unexpected(t); }
+
+ //----------------------------------------------------------------
+ // Check incremental sweeping of discarded iterators.
+ // Excessively white box?!
+ //----------------------------------------------------------------
+ try {
+ final int SHORT_SWEEP_PROBES = 4;
+ final int LONG_SWEEP_PROBES = 16;
+ final int PROBE_HOP = LONG_SWEEP_PROBES + 6 * SHORT_SWEEP_PROBES;
+ final int PROBE_HOP_COUNT = 10;
+ // Expect around 8 sweeps per PROBE_HOP
+ final int SWEEPS_PER_PROBE_HOP = 8;
+ ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
+ List<Iterator> its = new ArrayList<Iterator>();
+ for (int i = 0; i < capacity; i++)
+ q.add(i);
+ for (int i = 0; i < PROBE_HOP_COUNT * PROBE_HOP; i++) {
+ its.add(q.iterator());
+ equal(attachedIterators(q), its);
+ }
+ // make some garbage, separated by PROBE_HOP
+ for (int i = 0; i < its.size(); i += PROBE_HOP)
+ its.set(i, null);
+ waitForFinalizersToRun();
+ int retries;
+ for (retries = 0;
+ trackedIterators(q).contains(null) && retries < 1000;
+ retries++)
+ // one round of sweeping
+ its.add(q.iterator());
+ check(retries >= PROBE_HOP_COUNT * (SWEEPS_PER_PROBE_HOP - 2));
+ check(retries <= PROBE_HOP_COUNT * (SWEEPS_PER_PROBE_HOP + 2));
+ Iterator itsit = its.iterator();
+ while (itsit.hasNext())
+ if (itsit.next() == null)
+ itsit.remove();
+ equal(trackedIterators(q), its);
+ } catch (Throwable t) { unexpected(t); }
+
+ //----------------------------------------------------------------
+ // Check safety of iterator.remove while in detached mode.
+ //----------------------------------------------------------------
+ try {
+ ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
+ List<Iterator> its = new ArrayList<Iterator>();
+ for (int i = 0; i < capacity/2; i++) {
+ q.add(i);
+ q.remove();
+ }
+ check(takeIndex(q) == capacity/2);
+ for (int i = 0; i < capacity; i++)
+ q.add(i);
+ for (int i = 0; i < capacity; i++) {
+ Iterator it = q.iterator();
+ its.add(it);
+ for (int j = 0; j < i; j++)
+ equal(j, it.next());
+ equal(attachedIterators(q), its);
+ }
+ for (int i = capacity - 1; i >= 0; i--) {
+ Iterator it = its.get(i);
+ equal(i, it.next()); // last element
+ check(!isDetached(it));
+ check(!it.hasNext()); // first hasNext failure
+ check(isDetached(it));
+ int size = q.size();
+ check(q.contains(i));
+ switch (rnd.nextInt(3)) {
+ case 0:
+ it.remove();
+ check(!q.contains(i));
+ equal(q.size(), size - 1);
+ break;
+ case 1:
+ // replace i with impostor
+ if (q.remainingCapacity() == 0) {
+ check(q.remove(i));
+ check(q.add(-1));
+ } else {
+ check(q.add(-1));
+ check(q.remove(i));
+ }
+ it.remove(); // should have no effect
+ equal(size, q.size());
+ check(q.contains(-1));
+ check(q.remove(-1));
+ break;
+ case 2:
+ // replace i with true impostor
+ if (i != 0) {
+ check(q.remove(i));
+ check(q.add(i));
+ }
+ it.remove();
+ check(!q.contains(i));
+ equal(q.size(), size - 1);
+ break;
+ default: throw new Error();
+ }
+ checkRemoveThrowsISE(it);
+ check(isDetached(it));
+ check(!trackedIterators(q).contains(it));
+ }
+ check(q.isEmpty());
+ check(itrs(q) == null);
+ for (Iterator it : its)
+ checkExhausted(it);
+ } catch (Throwable t) { unexpected(t); }
+
+ //----------------------------------------------------------------
+ // Check dequeues bypassing iterators' current positions.
+ //----------------------------------------------------------------
+ try {
+ ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
+ Queue<Iterator> its0
+ = new ArrayDeque<Iterator>();
+ Queue<Iterator> itsMid
+ = new ArrayDeque<Iterator>();
+ List<Iterator> its = new ArrayList<Iterator>();
+ for (int i = 0; i < capacity; i++)
+ q.add(i);
+ for (int i = 0; i < 2 * capacity + 1; i++) {
+ Iterator it = q.iterator();
+ its.add(it);
+ its0.add(it);
+ }
+ for (int i = 0; i < 2 * capacity + 1; i++) {
+ Iterator it = q.iterator();
+ for (int j = 0; j < capacity/2; j++)
+ equal(j, it.next());
+ its.add(it);
+ itsMid.add(it);
+ }
+ for (int i = capacity; i < 3 * capacity; i++) {
+ Iterator it;
+
+ it = its0.remove();
+ checkRemoveThrowsISE(it);
+ if (rnd.nextBoolean()) check(it.hasNext());
+ equal(0, it.next());
+ int victim = i - capacity;
+ for (int j = victim + (victim == 0 ? 1 : 0); j < i; j++) {
+ if (rnd.nextBoolean()) check(it.hasNext());
+ equal(j, it.next());
+ }
+ checkExhausted(it);
+
+ it = itsMid.remove();
+ if (victim >= capacity/2)
+ checkRemoveHasNoEffect(it, q);
+ equal(capacity/2, it.next());
+ if (victim > capacity/2)
+ checkRemoveHasNoEffect(it, q);
+ for (int j = Math.max(victim, capacity/2 + 1); j < i; j++) {
+ if (rnd.nextBoolean()) check(it.hasNext());
+ equal(j, it.next());
+ }
+ checkExhausted(it);
+
+ if (rnd.nextBoolean()) {
+ equal(victim, q.remove());
+ } else {
+ ArrayList list = new ArrayList(1);
+ q.drainTo(list, 1);
+ equal(list.size(), 1);
+ equal(victim, list.get(0));
+ }
+ check(q.add(i));
+ }
+ // takeIndex has wrapped twice.
+ Iterator it0 = its0.remove();
+ Iterator itMid = itsMid.remove();
+ check(isDetached(it0));
+ check(isDetached(itMid));
+ if (rnd.nextBoolean()) check(it0.hasNext());
+ if (rnd.nextBoolean()) check(itMid.hasNext());
+ checkRemoveThrowsISE(it0);
+ checkRemoveHasNoEffect(itMid, q);
+ if (rnd.nextBoolean()) equal(0, it0.next());
+ if (rnd.nextBoolean()) equal(capacity/2, itMid.next());
+ check(isDetached(it0));
+ check(isDetached(itMid));
+ equal(capacity, q.size());
+ equal(0, q.remainingCapacity());
+ } catch (Throwable t) { unexpected(t); }
+
+ //----------------------------------------------------------------
+ // Check collective sanity of iteration, toArray() and toString()
+ //----------------------------------------------------------------
+ try {
+ ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
+ for (int i = 0; i < capacity; i++) {
+ checkIterationSanity(q);
+ equal(capacity, q.size() + q.remainingCapacity());
+ q.add(i);
+ }
+ for (int i = 0; i < (capacity + (capacity >> 1)); i++) {
+ checkIterationSanity(q);
+ equal(capacity, q.size() + q.remainingCapacity());
+ equal(i, q.peek());
+ equal(i, q.poll());
+ checkIterationSanity(q);
+ equal(capacity, q.size() + q.remainingCapacity());
+ q.add(capacity + i);
+ }
+ for (int i = 0; i < capacity; i++) {
+ checkIterationSanity(q);
+ equal(capacity, q.size() + q.remainingCapacity());
+ int expected = i + capacity + (capacity >> 1);
+ equal(expected, q.peek());
+ equal(expected, q.poll());
+ }
+ checkIterationSanity(q);
+ } catch (Throwable t) { unexpected(t); }
+
+ }
+
+ //--------------------- Infrastructure ---------------------------
+ volatile int passed = 0, failed = 0;
+ void pass() {passed++;}
+ void fail() {failed++; Thread.dumpStack();}
+ void fail(String msg) {System.err.println(msg); fail();}
+ void unexpected(Throwable t) {failed++; t.printStackTrace();}
+ void check(boolean cond) {if (cond) pass(); else fail();}
+ void equal(Object x, Object y) {
+ if (x == null ? y == null : x.equals(y)) pass();
+ else fail(x + " not equal to " + y);}
+ public static void main(String[] args) throws Throwable {
+ new IteratorConsistency().instanceMain(args);}
+ public void instanceMain(String[] args) throws Throwable {
+ try {test(args);} catch (Throwable t) {unexpected(t);}
+ System.err.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
+ if (failed > 0) throw new AssertionError("Some tests failed");}
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/BlockingQueue/DrainToFails.java Tue Oct 13 16:45:35 2015 -0700
@@ -0,0 +1,207 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea and Martin Buchholz with assistance from
+ * members of JCP JSR-166 Expert Group and released to the public
+ * domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/*
+ * @test
+ * @summary Test drainTo failing due to c.add throwing
+ */
+
+import java.util.*;
+import java.util.concurrent.*;
+
+@SuppressWarnings({"unchecked", "rawtypes"})
+public class DrainToFails {
+ final int CAPACITY = 10;
+ final int SMALL = 2;
+
+ void test(String[] args) throws Throwable {
+ testDelayQueue(new DelayQueue());
+ testDelayQueue(new ScheduledThreadPoolExecutor(1).getQueue());
+
+ testUnbounded(new LinkedBlockingQueue());
+ testUnbounded(new LinkedBlockingDeque());
+ testUnbounded(new PriorityBlockingQueue());
+
+ testBounded(new LinkedBlockingQueue(CAPACITY));
+ testBounded(new LinkedBlockingDeque(CAPACITY));
+ testBounded(new ArrayBlockingQueue(CAPACITY));
+ }
+
+ static class PDelay
+ extends FutureTask<Void>
+ implements Delayed, RunnableScheduledFuture<Void> {
+ int pseudodelay;
+ PDelay(int i) {
+ super(new Runnable() { public void run() {}}, null);
+ pseudodelay = i;
+ }
+ public int compareTo(PDelay other) {
+ int a = this.pseudodelay;
+ int b = other.pseudodelay;
+ return (a < b) ? -1 : (a > b) ? 1 : 0;
+ }
+ public int compareTo(Delayed y) {
+ return compareTo((PDelay)y);
+ }
+ public boolean equals(Object other) {
+ return (other instanceof PDelay) &&
+ this.pseudodelay == ((PDelay)other).pseudodelay;
+ }
+ public long getDelay(TimeUnit ignore) {
+ return Integer.MIN_VALUE + pseudodelay;
+ }
+ public String toString() {
+ return String.valueOf(pseudodelay);
+ }
+ public boolean isPeriodic() { return false; }
+ }
+
+ void testDelayQueue(final BlockingQueue q) throws Throwable {
+ System.err.println(q.getClass().getSimpleName());
+ for (int i = 0; i < CAPACITY; i++)
+ q.add(new PDelay(i));
+ ArrayBlockingQueue q2 = new ArrayBlockingQueue(SMALL);
+ try {
+ q.drainTo(q2, SMALL + 3);
+ fail("should throw");
+ } catch (IllegalStateException success) {
+ equal(SMALL, q2.size());
+ equal(new PDelay(0), q2.poll());
+ equal(new PDelay(1), q2.poll());
+ check(q2.isEmpty());
+ for (int i = SMALL; i < CAPACITY; i++)
+ equal(new PDelay(i), q.poll());
+ equal(0, q.size());
+ }
+ }
+
+ void testUnbounded(final BlockingQueue q) throws Throwable {
+ System.err.println(q.getClass().getSimpleName());
+ for (int i = 0; i < CAPACITY; i++)
+ q.add(i);
+ ArrayBlockingQueue q2 = new ArrayBlockingQueue(SMALL);
+ try {
+ q.drainTo(q2, 7);
+ fail("should throw");
+ } catch (IllegalStateException success) {
+ assertContentsInOrder(q2, 0, 1);
+ q2.clear();
+ equal(q.size(), CAPACITY - SMALL);
+ equal(SMALL, q.peek());
+ }
+
+ try {
+ q.drainTo(q2);
+ fail("should throw");
+ } catch (IllegalStateException success) {
+ assertContentsInOrder(q2, 2, 3);
+ equal(q.size(), CAPACITY - 2 * SMALL);
+ for (int i = 2 * SMALL; i < CAPACITY; i++)
+ equal(i, q.poll());
+ equal(0, q.size());
+ }
+ }
+
+ void testBounded(final BlockingQueue q) throws Throwable {
+ System.err.println(q.getClass().getSimpleName());
+ for (int i = 0; i < CAPACITY; i++)
+ q.add(i);
+ List<Thread> putters = new ArrayList<Thread>();
+ for (int i = 0; i < 4; i++) {
+ Thread putter = new Thread(putter(q, 42 + i));
+ putters.add(putter);
+ putter.setDaemon(true);
+ putter.start();
+ }
+ ArrayBlockingQueue q2 = new ArrayBlockingQueue(SMALL);
+ try {
+ q.drainTo(q2, 7);
+ fail("should throw");
+ } catch (IllegalStateException success) {
+ while (q.size() < CAPACITY)
+ Thread.yield();
+ assertContentsInOrder(q2, 0, 1);
+ q2.clear();
+ }
+
+ try {
+ q.drainTo(q2);
+ fail("should throw");
+ } catch (IllegalStateException success) {
+ for (Thread putter : putters) {
+ putter.join(2000L);
+ check(! putter.isAlive());
+ }
+ assertContentsInOrder(q2, 2, 3);
+ for (int i = 2 * SMALL; i < CAPACITY; i++)
+ equal(i, q.poll());
+ equal(4, q.size());
+ check(q.contains(42));
+ check(q.contains(43));
+ check(q.contains(44));
+ check(q.contains(45));
+ }
+ }
+
+ Runnable putter(final BlockingQueue q, final int elt) {
+ return new Runnable() {
+ public void run() {
+ try { q.put(elt); }
+ catch (Throwable t) { unexpected(t); }}};
+ }
+
+ void assertContentsInOrder(Iterable it, Object... contents) {
+ int i = 0;
+ for (Object e : it)
+ equal(contents[i++], e);
+ equal(contents.length, i);
+ }
+
+ //--------------------- Infrastructure ---------------------------
+ volatile int passed = 0, failed = 0;
+ void pass() {passed++;}
+ void fail() {failed++; Thread.dumpStack();}
+ void fail(String msg) {System.err.println(msg); fail();}
+ void unexpected(Throwable t) {failed++; t.printStackTrace();}
+ void check(boolean cond) {if (cond) pass(); else fail();}
+ void equal(Object x, Object y) {
+ if (x == null ? y == null : x.equals(y)) pass();
+ else fail(x + " not equal to " + y);}
+ public static void main(String[] args) throws Throwable {
+ new DrainToFails().instanceMain(args);}
+ public void instanceMain(String[] args) throws Throwable {
+ try {test(args);} catch (Throwable t) {unexpected(t);}
+ System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
+ if (failed > 0) throw new AssertionError("Some tests failed");}
+}
--- a/jdk/test/java/util/concurrent/BlockingQueue/Interrupt.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/concurrent/BlockingQueue/Interrupt.java Tue Oct 13 16:45:35 2015 -0700
@@ -48,7 +48,8 @@
}
}
- static void checkInterrupted(Iterable<Fun> fs) {
+ static void checkInterrupted(Iterable<Fun> fs)
+ throws InterruptedException {
final Executor immediateExecutor = new Executor() {
public void execute(Runnable r) {
r.run(); }};
@@ -60,6 +61,7 @@
checkInterrupted0(fs, immediateExecutor);
checkInterrupted0(fs, delayedExecutor);
stpe.shutdown();
+ check(stpe.awaitTermination(10, SECONDS));
}
static void testQueue(final BlockingQueue<Object> q) {
@@ -96,8 +98,10 @@
}
checkInterrupted(fs);
} catch (Throwable t) {
- System.out.printf("Failed: %s%n", q.getClass().getSimpleName());
- unexpected(t);
+ System.out.printf("Failed: %s%n", q.getClass().getSimpleName());
+ unexpected(t);
+ } finally {
+ Thread.interrupted(); // clear interrupts, just in case
}
}
--- a/jdk/test/java/util/concurrent/ConcurrentHashMap/ConcurrentAssociateTest.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/concurrent/ConcurrentHashMap/ConcurrentAssociateTest.java Tue Oct 13 16:45:35 2015 -0700
@@ -23,14 +23,18 @@
import org.testng.annotations.Test;
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CompletionException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
import java.util.function.BiConsumer;
import java.util.function.Supplier;
import java.util.stream.IntStream;
@@ -39,48 +43,52 @@
/**
* @test
* @bug 8028564
- * @run testng ConcurrentAssociateTest
+ * @run testng/timeout=1200 ConcurrentAssociateTest
* @summary Test that association operations, such as put and compute,
* place entries in the map
*/
@Test
public class ConcurrentAssociateTest {
- // The number of entries for each thread to place in a map
+ /** Maximum time (in seconds) to wait for a test method to complete. */
+ private static final int TIMEOUT = Integer.getInteger("timeout", 200);
+
+ /** The number of entries for each thread to place in a map. */
private static final int N = Integer.getInteger("n", 128);
- // The number of iterations of the test
- private static final int I = Integer.getInteger("i", 256);
- // Object to be placed in the concurrent map
+ /** The number of iterations of the test. */
+ private static final int I = Integer.getInteger("i", 64);
+
+ /** Objects to be placed in the concurrent map. */
static class X {
// Limit the hash code to trigger collisions
- int hc = ThreadLocalRandom.current().nextInt(1, 9);
+ final int hc = ThreadLocalRandom.current().nextInt(1, 9);
public int hashCode() { return hc; }
}
@Test
- public void testPut() {
+ public void testPut() throws Throwable {
test("CHM.put", (m, o) -> m.put(o, o));
}
@Test
- public void testCompute() {
+ public void testCompute() throws Throwable {
test("CHM.compute", (m, o) -> m.compute(o, (k, v) -> o));
}
@Test
- public void testComputeIfAbsent() {
+ public void testComputeIfAbsent() throws Throwable {
test("CHM.computeIfAbsent", (m, o) -> m.computeIfAbsent(o, (k) -> o));
}
@Test
- public void testMerge() {
+ public void testMerge() throws Throwable {
test("CHM.merge", (m, o) -> m.merge(o, o, (v1, v2) -> v1));
}
@Test
- public void testPutAll() {
+ public void testPutAll() throws Throwable {
test("CHM.putAll", (m, o) -> {
Map<Object, Object> hm = new HashMap<>();
hm.put(o, o);
@@ -88,7 +96,7 @@
});
}
- private static void test(String desc, BiConsumer<ConcurrentMap<Object, Object>, Object> associator) {
+ private static void test(String desc, BiConsumer<ConcurrentMap<Object, Object>, Object> associator) throws Throwable {
for (int i = 0; i < I; i++) {
testOnce(desc, associator);
}
@@ -100,13 +108,16 @@
}
}
- private static void testOnce(String desc, BiConsumer<ConcurrentMap<Object, Object>, Object> associator) {
+ private static void testOnce(String desc, BiConsumer<ConcurrentMap<Object, Object>, Object> associator) throws Throwable {
ConcurrentHashMap<Object, Object> m = new ConcurrentHashMap<>();
CountDownLatch s = new CountDownLatch(1);
Supplier<Runnable> sr = () -> () -> {
try {
- s.await();
+ if (!s.await(TIMEOUT, TimeUnit.SECONDS)) {
+ dumpTestThreads();
+ throw new AssertionError("timed out");
+ }
}
catch (InterruptedException e) {
}
@@ -121,7 +132,7 @@
};
// Bound concurrency to avoid degenerate performance
- int ps = Math.min(Runtime.getRuntime().availableProcessors(), 32);
+ int ps = Math.min(Runtime.getRuntime().availableProcessors(), 8);
Stream<CompletableFuture> runners = IntStream.range(0, ps)
.mapToObj(i -> sr.get())
.map(CompletableFuture::runAsync);
@@ -131,16 +142,41 @@
// Trigger the runners to start associating
s.countDown();
+
try {
- all.join();
- } catch (CompletionException e) {
- Throwable t = e.getCause();
- if (t instanceof AssociationFailure) {
- throw (AssociationFailure) t;
+ all.get(TIMEOUT, TimeUnit.SECONDS);
+ } catch (TimeoutException e) {
+ dumpTestThreads();
+ throw e;
+ } catch (Throwable e) {
+ dumpTestThreads();
+ Throwable cause = e.getCause();
+ if (cause instanceof AssociationFailure) {
+ throw cause;
}
- else {
- throw e;
- }
+ throw e;
}
}
+
+ /**
+ * A debugging tool to print stack traces of most threads, as jstack does.
+ * Uninteresting threads are filtered out.
+ */
+ static void dumpTestThreads() {
+ ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
+ System.err.println("------ stacktrace dump start ------");
+ for (ThreadInfo info : threadMXBean.dumpAllThreads(true, true)) {
+ String name = info.getThreadName();
+ if ("Signal Dispatcher".equals(name))
+ continue;
+ if ("Reference Handler".equals(name)
+ && info.getLockName().startsWith("java.lang.ref.Reference$Lock"))
+ continue;
+ if ("Finalizer".equals(name)
+ && info.getLockName().startsWith("java.lang.ref.ReferenceQueue$Lock"))
+ continue;
+ System.err.print(info);
+ }
+ System.err.println("------ stacktrace dump end ------");
+ }
}
--- a/jdk/test/java/util/concurrent/ConcurrentHashMap/ConcurrentContainsKeyTest.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/concurrent/ConcurrentHashMap/ConcurrentContainsKeyTest.java Tue Oct 13 16:45:35 2015 -0700
@@ -80,7 +80,6 @@
test(content, m);
}
-
private static void test(X[] content, ConcurrentHashMap<Object, Object> m) {
for (int i = 0; i < I; i++) {
testOnce(content, m);
--- a/jdk/test/java/util/concurrent/ConcurrentHashMap/MapCheck.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/concurrent/ConcurrentHashMap/MapCheck.java Tue Oct 13 16:45:35 2015 -0700
@@ -68,7 +68,6 @@
}
}
-
if (args.length > 1)
numTests = Integer.parseInt(args[1]);
@@ -92,7 +91,6 @@
TestTimer.printStats();
-
if (doSerializeTest)
stest(newMap(mapClass), size);
}
--- a/jdk/test/java/util/concurrent/ConcurrentHashMap/MapLoops.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/concurrent/ConcurrentHashMap/MapLoops.java Tue Oct 13 16:45:35 2015 -0700
@@ -175,7 +175,7 @@
int position;
int total;
- Runner(Map<Integer,Integer> map, Integer[] key, CyclicBarrier barrier) {
+ Runner(Map<Integer,Integer> map, Integer[] key, CyclicBarrier barrier) {
this.map = map;
this.key = key;
this.barrier = barrier;
@@ -183,7 +183,7 @@
}
int step() {
- // random-walk around key positions, bunching accesses
+ // random-walk around key positions, bunching accesses
int r = rng.next();
position += (r & 7) - 3;
while (position >= key.length) position -= key.length;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/ConcurrentLinkedQueue/RemoveLeak.java Tue Oct 13 16:45:35 2015 -0700
@@ -0,0 +1,60 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Martin Buchholz with assistance from members of JCP
+ * JSR-166 Expert Group and released to the public domain, as
+ * explained at http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/*
+ * @test
+ * @bug 8054446 8137184 8137185
+ * @summary Regression test for memory leak in remove(Object)
+ * @run main/othervm -Xmx2200k RemoveLeak
+ */
+
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+public class RemoveLeak {
+ public static void main(String[] args) {
+ int i = 0;
+ // Without bug fix, OutOfMemoryError was observed at iteration 65120
+ int iterations = 10 * 65120;
+ try {
+ ConcurrentLinkedQueue<Long> queue = new ConcurrentLinkedQueue<>();
+ queue.add(0L);
+ while (i++ < iterations) {
+ queue.add(1L);
+ queue.remove(1L);
+ }
+ } catch (Error t) {
+ System.err.printf("failed at iteration %d/%d%n", i, iterations);
+ throw t;
+ }
+ }
+}
--- a/jdk/test/java/util/concurrent/ConcurrentQueues/ConcurrentQueueLoops.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/concurrent/ConcurrentQueues/ConcurrentQueueLoops.java Tue Oct 13 16:45:35 2015 -0700
@@ -47,10 +47,10 @@
AtomicInteger totalItems;
boolean print;
- // Suitable for benchmarking. Overriden by args[0] for testing.
+ // Suitable for benchmarking. Overridden by args[0] for testing.
int maxStages = 20;
- // Suitable for benchmarking. Overriden by args[1] for testing.
+ // Suitable for benchmarking. Overridden by args[1] for testing.
int items = 1024 * 1024;
Collection<Queue<Integer>> concurrentQueues() {
--- a/jdk/test/java/util/concurrent/ConcurrentQueues/GCRetention.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/concurrent/ConcurrentQueues/GCRetention.java Tue Oct 13 16:45:35 2015 -0700
@@ -56,7 +56,7 @@
import java.util.Map;
public class GCRetention {
- // Suitable for benchmarking. Overriden by args[0] for testing.
+ // Suitable for benchmarking. Overridden by args[0] for testing.
int count = 1024 * 1024;
final Map<String,String> results = new ConcurrentHashMap<String,String>();
--- a/jdk/test/java/util/concurrent/ConcurrentQueues/IteratorWeakConsistency.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/concurrent/ConcurrentQueues/IteratorWeakConsistency.java Tue Oct 13 16:45:35 2015 -0700
@@ -42,6 +42,7 @@
@SuppressWarnings({"unchecked", "rawtypes"})
public class IteratorWeakConsistency {
+ final Random rnd = new Random();
void test(String[] args) throws Throwable {
test(new LinkedBlockingQueue());
@@ -51,14 +52,46 @@
test(new ConcurrentLinkedDeque());
test(new ConcurrentLinkedQueue());
test(new LinkedTransferQueue());
- // Other concurrent queues (e.g. ArrayBlockingQueue) do not
- // currently have weakly consistent iterators.
- // As of 2010-09, ArrayBlockingQueue passes this test, but
- // does not fully implement weak consistency.
test(new ArrayBlockingQueue(20));
}
+ void checkExhausted(Iterator it) {
+ if (rnd.nextBoolean()) {
+ check(!it.hasNext());
+ }
+ if (rnd.nextBoolean())
+ try { it.next(); fail("should throw"); }
+ catch (NoSuchElementException success) {}
+ }
+
+ void checkRemoveThrowsISE(Iterator it) {
+ if (rnd.nextBoolean()) {
+ try { it.remove(); fail("should throw"); }
+ catch (IllegalStateException success) {}
+ }
+ }
+
+ void checkRemoveHasNoEffect(Iterator it, Collection c) {
+ if (rnd.nextBoolean()) {
+ int size = c.size();
+ it.remove(); // no effect
+ equal(c.size(), size);
+ checkRemoveThrowsISE(it);
+ }
+ }
+
void test(Queue q) {
+ //----------------------------------------------------------------
+ // Check iterators on an empty q
+ //----------------------------------------------------------------
+ try {
+ for (int i = 0; i < 4; i++) {
+ Iterator it = q.iterator();
+ if (rnd.nextBoolean()) checkExhausted(it);
+ checkRemoveThrowsISE(it);
+ }
+ } catch (Throwable t) { unexpected(t); }
+
// TODO: make this more general
try {
for (int i = 0; i < 10; i++)
@@ -73,7 +106,7 @@
list.add(it.next());
equal(list, Arrays.asList(0, 3, 4, 5, 6, 8, 9));
check(! list.contains(null));
- System.out.printf("%s: %s%n",
+ System.err.printf("%s: %s%n",
q.getClass().getSimpleName(),
list);
} catch (Throwable t) { unexpected(t); }
@@ -96,6 +129,118 @@
check(found4);
} catch (Throwable t) { unexpected(t); }
+ try {
+ q.clear();
+ Object x = new Object();
+ for (int i = 0; i < 20; i++)
+ q.add(x);
+ equal(20, q.size());
+ Iterator it1 = q.iterator();
+ Iterator it2 = q.iterator();
+ try { it1.remove(); fail(); }
+ catch (IllegalStateException success) {}
+ try { it2.remove(); fail(); }
+ catch (IllegalStateException success) {}
+
+ check(it1.next() == x);
+ check(it2.hasNext());
+ check(it2.next() == x);
+ it1.remove();
+ it2.remove();
+ equal(19, q.size());
+ try { it1.remove(); fail(); }
+ catch (IllegalStateException success) {}
+ try { it2.remove(); fail(); }
+ catch (IllegalStateException success) {}
+ equal(19, q.size());
+
+ it1.next();
+ check(it2.hasNext());
+ it2.next();
+ it2.remove();
+ it1.remove();
+ equal(18, q.size());
+
+ it1.next();
+ it2.next();
+ check(q.remove() == x);
+ equal(17, q.size());
+ it1.remove();
+ it2.remove();
+ equal(17, q.size());
+ } catch (Throwable t) { unexpected(t); }
+
+ //----------------------------------------------------------------
+ // Check "interior" removal of alternating elements
+ //----------------------------------------------------------------
+ try {
+ q.clear();
+ final int remainingCapacity = (q instanceof BlockingQueue) ?
+ ((BlockingQueue)q).remainingCapacity() :
+ Integer.MAX_VALUE;
+ final int capacity = Math.min(20, remainingCapacity);
+ List<Iterator> its = new ArrayList<Iterator>();
+ // Move to "middle"
+ for (int i = 0; i < capacity/2; i++) {
+ check(q.add(i));
+ equal(q.poll(), i);
+ }
+ for (int i = 0; i < capacity; i++)
+ check(q.add(i));
+ for (int i = 0; i < capacity; i++) {
+ Iterator it = q.iterator();
+ its.add(it);
+ for (int j = 0; j < i; j++)
+ equal(j, it.next());
+ }
+
+ // Remove all even elements, in either direction using
+ // q.remove(), or iterator.remove()
+ switch (rnd.nextInt(3)) {
+ case 0:
+ for (int i = 0; i < capacity; i+=2)
+ check(q.remove(i));
+ break;
+ case 1:
+ for (int i = capacity - 2; i >= 0; i-=2)
+ check(q.remove(i));
+ break;
+ case 2:
+ Iterator it = q.iterator();
+ while (it.hasNext()) {
+ int i = (Integer) it.next();
+ if ((i & 1) == 0)
+ it.remove();
+ }
+ break;
+ default: throw new Error();
+ }
+
+ for (int i = 0; i < capacity; i++) {
+ Iterator it = its.get(i);
+ boolean even = ((i & 1) == 0);
+ if (even) {
+ if (rnd.nextBoolean()) check(it.hasNext());
+ equal(i, it.next());
+ for (int j = i+1; j < capacity; j += 2)
+ equal(j, it.next());
+ check(!it.hasNext());
+ } else { /* odd */
+ if (rnd.nextBoolean()) check(it.hasNext());
+ checkRemoveHasNoEffect(it, q);
+ equal(i, it.next());
+ for (int j = i+2; j < capacity; j += 2)
+ equal(j, it.next());
+ check(!it.hasNext());
+ }
+ }
+
+ // q only contains odd elements
+ for (int i = 0; i < capacity; i++)
+ check(q.contains(i) ^ ((i & 1) == 0));
+
+ } catch (Throwable t) { unexpected(t); }
+
}
//--------------------- Infrastructure ---------------------------
@@ -112,6 +257,6 @@
new IteratorWeakConsistency().instanceMain(args);}
public void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
- System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
+ System.err.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}
--- a/jdk/test/java/util/concurrent/ConcurrentQueues/OfferRemoveLoops.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/concurrent/ConcurrentQueues/OfferRemoveLoops.java Tue Oct 13 16:45:35 2015 -0700
@@ -32,6 +32,7 @@
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
+import static java.util.concurrent.TimeUnit.*;
@SuppressWarnings({"unchecked", "rawtypes", "deprecation"})
public class OfferRemoveLoops {
@@ -65,15 +66,16 @@
}
void testQueue(final Queue q) throws Throwable {
- System.out.println(q.getClass().getSimpleName());
+ System.err.println(q.getClass().getSimpleName());
final long testDurationNanos = testDurationMillis * 1000L * 1000L;
final long quittingTimeNanos = System.nanoTime() + testDurationNanos;
final long timeoutMillis = 10L * 1000L;
final int maxChunkSize = 1042;
final int maxQueueSize = 10 * maxChunkSize;
+ final CountDownLatch done = new CountDownLatch(3);
- /** Poor man's bounded buffer. */
- final AtomicLong approximateCount = new AtomicLong(0L);
+ /** Poor man's bounded buffer; prevents unbounded queue expansion. */
+ final Semaphore offers = new Semaphore(maxQueueSize);
abstract class CheckedThread extends Thread {
CheckedThread(String name) {
@@ -89,42 +91,44 @@
protected boolean quittingTime(long i) {
return (i % 1024) == 0 && quittingTime();
}
- protected abstract void realRun();
+ protected abstract void realRun() throws Exception;
public void run() {
try { realRun(); } catch (Throwable t) { unexpected(t); }
}
}
Thread offerer = new CheckedThread("offerer") {
- protected void realRun() {
- final long chunkSize = getRandom().nextInt(maxChunkSize) + 2;
+ protected void realRun() throws InterruptedException {
+ final int chunkSize = getRandom().nextInt(maxChunkSize) + 20;
long c = 0;
- for (long i = 0; ! quittingTime(i); i++) {
+ while (! quittingTime()) {
if (q.offer(Long.valueOf(c))) {
if ((++c % chunkSize) == 0) {
- approximateCount.getAndAdd(chunkSize);
- while (approximateCount.get() > maxQueueSize)
- Thread.yield();
+ offers.acquire(chunkSize);
}
} else {
Thread.yield();
- }}}};
+ }
+ }
+ done.countDown();
+ }};
Thread remover = new CheckedThread("remover") {
protected void realRun() {
- final long chunkSize = getRandom().nextInt(maxChunkSize) + 2;
+ final int chunkSize = getRandom().nextInt(maxChunkSize) + 20;
long c = 0;
- for (long i = 0; ! quittingTime(i); i++) {
+ while (! quittingTime()) {
if (q.remove(Long.valueOf(c))) {
if ((++c % chunkSize) == 0) {
- approximateCount.getAndAdd(-chunkSize);
+ offers.release(chunkSize);
}
} else {
Thread.yield();
}
}
q.clear();
- approximateCount.set(0); // Releases waiting offerer thread
+ offers.release(1<<30); // Releases waiting offerer thread
+ done.countDown();
}};
Thread scanner = new CheckedThread("scanner") {
@@ -139,18 +143,19 @@
break;
}
Thread.yield();
- }}};
+ }
+ done.countDown();
+ }};
- for (Thread thread : new Thread[] { offerer, remover, scanner }) {
- thread.join(timeoutMillis + testDurationMillis);
- if (thread.isAlive()) {
- System.err.printf("Hung thread: %s%n", thread.getName());
- failed++;
- for (StackTraceElement e : thread.getStackTrace())
- System.err.println(e);
- // Kludge alert
- thread.stop();
- thread.join(timeoutMillis);
+ if (! done.await(timeoutMillis + testDurationMillis, MILLISECONDS)) {
+ for (Thread thread : new Thread[] { offerer, remover, scanner }) {
+ if (thread.isAlive()) {
+ System.err.printf("Hung thread: %s%n", thread.getName());
+ failed++;
+ for (StackTraceElement e : thread.getStackTrace())
+ System.err.println(e);
+ thread.interrupt();
+ }
}
}
}
--- a/jdk/test/java/util/concurrent/ConcurrentQueues/RemovePollRace.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/concurrent/ConcurrentQueues/RemovePollRace.java Tue Oct 13 16:45:35 2015 -0700
@@ -36,7 +36,7 @@
* @bug 6785442
* @summary Checks race between poll and remove(Object), while
* occasionally moonlighting as a microbenchmark.
- * @run main RemovePollRace 12345
+ * @run main RemovePollRace 1234
*/
import java.util.concurrent.ArrayBlockingQueue;
@@ -56,7 +56,7 @@
import java.util.Map;
public class RemovePollRace {
- // Suitable for benchmarking. Overriden by args[0] for testing.
+ // Suitable for benchmarking. Overridden by args[0] for testing.
int count = 1024 * 1024;
final Map<String,String> results = new ConcurrentHashMap<String,String>();
@@ -100,6 +100,7 @@
void test(String[] args) throws Throwable {
if (args.length > 0)
count = Integer.valueOf(args[0]);
+
// Warmup
for (Queue<Boolean> queue : concurrentQueues())
test(queue);
--- a/jdk/test/java/util/concurrent/CopyOnWriteArrayList/COWSubList.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/concurrent/CopyOnWriteArrayList/COWSubList.java Tue Oct 13 16:45:35 2015 -0700
@@ -51,8 +51,7 @@
r.run();
throw new RuntimeException("Failed: expected IOOBE to be thrown");
} catch (IndexOutOfBoundsException x) {
- // ok, excpeted
+ // ok, expected
}
}
}
-
--- a/jdk/test/java/util/concurrent/CountDownLatch/Basic.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/concurrent/CountDownLatch/Basic.java Tue Oct 13 16:45:35 2015 -0700
@@ -120,7 +120,7 @@
//----------------------------------------------------------------
// One thread interrupted
//----------------------------------------------------------------
- public static void threadInterrupted() throws Throwable{
+ public static void threadInterrupted() throws Throwable {
int count = 0;
Basic test = new Basic();
CountDownLatch latch = new CountDownLatch(3);
--- a/jdk/test/java/util/concurrent/Exchanger/ExchangeLoops.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/concurrent/Exchanger/ExchangeLoops.java Tue Oct 13 16:45:35 2015 -0700
@@ -49,7 +49,6 @@
Int(int i) { value = i; }
}
-
public static void main(String[] args) throws Exception {
int maxStages = 5;
int iters = 10000;
--- a/jdk/test/java/util/concurrent/ExecutorCompletionService/ExecutorCompletionServiceLoops.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/concurrent/ExecutorCompletionService/ExecutorCompletionServiceLoops.java Tue Oct 13 16:45:35 2015 -0700
@@ -111,8 +111,6 @@
if (r == 0) // avoid overoptimization
System.out.println("useless result: " + r);
-
-
}
}
--- a/jdk/test/java/util/concurrent/Executors/AutoShutdown.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/concurrent/Executors/AutoShutdown.java Tue Oct 13 16:45:35 2015 -0700
@@ -24,55 +24,71 @@
/*
* @test
* @bug 6399443
- * @run main/othervm AutoShutdown
+ * @run main/othervm/timeout=1000 AutoShutdown
* @summary Check for auto-shutdown and gc of singleThreadExecutors
* @author Martin Buchholz
*/
-import java.io.*;
-import java.util.*;
-import java.util.concurrent.*;
-import static java.util.concurrent.Executors.*;
-import java.util.concurrent.Phaser;
+import java.lang.ref.WeakReference;
+import java.util.Arrays;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+import static java.util.concurrent.Executors.defaultThreadFactory;
+import static java.util.concurrent.Executors.newFixedThreadPool;
+import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
+import static java.util.concurrent.Executors.newSingleThreadExecutor;
public class AutoShutdown {
- private static void waitForFinalizersToRun() {
- for (int i = 0; i < 2; i++)
- tryWaitForFinalizersToRun();
- }
- private static void tryWaitForFinalizersToRun() {
- System.gc();
- final CountDownLatch fin = new CountDownLatch(1);
- new Object() { protected void finalize() { fin.countDown(); }};
- System.gc();
- try { fin.await(); }
- catch (InterruptedException ie) { throw new Error(ie); }
+ static void await(CountDownLatch latch) throws InterruptedException {
+ if (!latch.await(100L, TimeUnit.SECONDS))
+ throw new AssertionError("timed out waiting for latch");
}
private static void realMain(String[] args) throws Throwable {
- final Phaser phaser = new Phaser(3);
- Runnable trivialRunnable = new Runnable() {
- public void run() {
- phaser.arriveAndAwaitAdvance();
- }
+ final Executor[] executors = {
+ newSingleThreadExecutor(),
+ newSingleThreadExecutor(defaultThreadFactory()),
+ // TODO: should these executors also auto-shutdown?
+ //newFixedThreadPool(1),
+ //newSingleThreadScheduledExecutor(),
+ //newSingleThreadScheduledExecutor(defaultThreadFactory()),
};
- int count0 = Thread.activeCount();
- Executor e1 = newSingleThreadExecutor();
- Executor e2 = newSingleThreadExecutor(defaultThreadFactory());
- e1.execute(trivialRunnable);
- e2.execute(trivialRunnable);
- phaser.arriveAndAwaitAdvance();
- equal(Thread.activeCount(), count0 + 2);
- e1 = e2 = null;
- for (int i = 0; i < 10 && Thread.activeCount() > count0; i++)
- tryWaitForFinalizersToRun();
- for (int i = 0; i < 10; ++i) { // give JVM a chance to settle.
- if (Thread.activeCount() == count0)
- return;
- Thread.sleep(1000);
+ final ConcurrentLinkedQueue<WeakReference<Thread>> poolThreads
+ = new ConcurrentLinkedQueue<>();
+ final CountDownLatch threadStarted
+ = new CountDownLatch(executors.length);
+ final CountDownLatch pleaseProceed
+ = new CountDownLatch(1);
+ Runnable task = new Runnable() { public void run() {
+ try {
+ poolThreads.add(new WeakReference<>(Thread.currentThread()));
+ threadStarted.countDown();
+ await(pleaseProceed);
+ } catch (Throwable t) { unexpected(t); }
+ }};
+ for (Executor executor : executors)
+ executor.execute(task);
+ await(threadStarted);
+ pleaseProceed.countDown();
+ Arrays.fill(executors, null); // make executors unreachable
+ boolean done = false;
+ for (long timeout = 1L; !done && timeout <= 128L; timeout *= 2) {
+ System.gc();
+ done = true;
+ for (WeakReference<Thread> ref : poolThreads) {
+ Thread thread = ref.get();
+ if (thread != null) {
+ TimeUnit.SECONDS.timedJoin(thread, timeout);
+ if (thread.isAlive())
+ done = false;
+ }
+ }
}
- equal(Thread.activeCount(), count0);
+ if (!done)
+ throw new AssertionError("pool threads did not terminate");
}
//--------------------- Infrastructure ---------------------------
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/FutureTask/DoneMeansDone.java Tue Oct 13 16:45:35 2015 -0700
@@ -0,0 +1,100 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Martin Buchholz with assistance from members of JCP
+ * JSR-166 Expert Group and released to the public domain, as
+ * explained at http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/*
+ * @test
+ * @bug 8073704
+ * @summary Checks that once isDone() returns true,
+ * get() never throws InterruptedException or TimeoutException
+ */
+
+import java.util.ArrayList;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+public class DoneMeansDone {
+ public static void main(String[] args) throws Throwable {
+ final int iters = 1000;
+ final int nThreads = 2;
+ final AtomicBoolean done = new AtomicBoolean(false);
+ final AtomicReference<FutureTask<Boolean>> a = new AtomicReference<>();
+ final CountDownLatch threadsStarted = new CountDownLatch(nThreads);
+ final Callable<Boolean> alwaysTrue = new Callable<Boolean>() {
+ public Boolean call() {
+ return true;
+ }};
+
+ final Runnable observer = new Runnable() { public void run() {
+ threadsStarted.countDown();
+ final ThreadLocalRandom rnd = ThreadLocalRandom.current();
+ try {
+ for (FutureTask<Boolean> f; !done.get();) {
+ f = a.get();
+ if (f != null) {
+ do {} while (!f.isDone());
+ Thread.currentThread().interrupt();
+ if (!(rnd.nextBoolean()
+ ? f.get()
+ : f.get(-1L, TimeUnit.DAYS)))
+ throw new AssertionError();
+ }
+ }
+ } catch (Exception t) { throw new AssertionError(t); }
+ }};
+
+ final ArrayList<Future<?>> futures = new ArrayList<>(nThreads);
+ final ExecutorService pool = Executors.newCachedThreadPool();
+ for (int i = 0; i < nThreads; i++)
+ futures.add(pool.submit(observer));
+ threadsStarted.await();
+ for (int i = 0; i < iters; i++) {
+ FutureTask<Boolean> f = new FutureTask<>(alwaysTrue);
+ a.set(f);
+ f.run();
+ }
+ done.set(true);
+ pool.shutdown();
+ if (!pool.awaitTermination(10L, TimeUnit.SECONDS))
+ throw new AssertionError();
+ for (Future<?> future : futures)
+ future.get();
+ }
+}
--- a/jdk/test/java/util/concurrent/FutureTask/DoneTimedGetLoops.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/concurrent/FutureTask/DoneTimedGetLoops.java Tue Oct 13 16:45:35 2015 -0700
@@ -1,5 +1,4 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -22,6 +21,11 @@
*/
/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
* Written by Martin Buchholz with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
--- a/jdk/test/java/util/concurrent/FutureTask/ExplicitSet.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/concurrent/FutureTask/ExplicitSet.java Tue Oct 13 16:45:35 2015 -0700
@@ -58,7 +58,7 @@
SettableTask() {
super(new Callable<Boolean>() {
public Boolean call() {
- fail ("The task should never be run!");
+ fail("The task should never be run!");
return null;
};
});
--- a/jdk/test/java/util/concurrent/FutureTask/NegativeTimeout.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/concurrent/FutureTask/NegativeTimeout.java Tue Oct 13 16:45:35 2015 -0700
@@ -44,4 +44,3 @@
} catch (TimeoutException success) {}
}
}
-
--- a/jdk/test/java/util/concurrent/Phaser/Basic.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/concurrent/Phaser/Basic.java Tue Oct 13 16:45:35 2015 -0700
@@ -97,7 +97,8 @@
equal(phase, atTheStartingGate.arrive());
int awaitPhase = atTheStartingGate.awaitAdvanceInterruptibly
(phase, 30, SECONDS);
- if (expectNextPhase) check(awaitPhase == (phase + 1));
+ if (expectNextPhase) check(awaitPhase == phase + 1);
+ else check(awaitPhase == phase || awaitPhase == phase + 1);
pass();
} catch (Throwable t) {
@@ -249,13 +250,11 @@
Phaser phaser = new Phaser(3);
Iterator<Arriver> arrivers = arriverIterator(phaser);
int phase = phaser.getPhase();
- for (int i = 0; i < 4; i++) {
+ for (int i = 0; i < 10; i++) {
check(phaser.getPhase() == phase);
Awaiter a1 = awaiter(phaser, 30, SECONDS); a1.start();
Arriver a2 = arrivers.next(); a2.start();
toTheStartingGate();
- // allow a1 to block in awaitAdvanceInterruptibly
- Thread.sleep(2000);
a1.interrupt();
a1.join();
phaser.arriveAndAwaitAdvance();
@@ -273,7 +272,7 @@
// Phaser is terminated while threads are waiting
//----------------------------------------------------------------
try {
- for (int i = 0; i < 4; i++) {
+ for (int i = 0; i < 10; i++) {
Phaser phaser = new Phaser(3);
Iterator<Awaiter> awaiters = awaiterIterator(phaser);
Arriver a1 = awaiters.next(); a1.start();
--- a/jdk/test/java/util/concurrent/ScheduledThreadPoolExecutor/DelayOverflow.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/concurrent/ScheduledThreadPoolExecutor/DelayOverflow.java Tue Oct 13 16:45:35 2015 -0700
@@ -88,7 +88,7 @@
/**
* Attempts to test exhaustively and deterministically, all 20
* possible ways that one task can be scheduled in the maximal
- * distant future, while at the same time an existing tasks's time
+ * distant future, while at the same time an existing task's time
* has already expired.
*/
void test(String[] args) throws Throwable {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/ScheduledThreadPoolExecutor/GCRetention.java Tue Oct 13 16:45:35 2015 -0700
@@ -0,0 +1,136 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea and Martin Buchholz with assistance from members of
+ * JCP JSR-166 Expert Group and released to the public domain, as explained
+ * at http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/*
+ * @test
+ * @summary Ensure that waiting pool threads don't retain refs to tasks.
+ */
+
+import java.lang.ref.*;
+import java.util.concurrent.*;
+
+public class GCRetention {
+ /**
+ * A custom thread pool with a custom RunnableScheduledFuture, for the
+ * sole purpose of ensuring that the task retains a strong reference to
+ * the Runnable even after cancellation.
+ */
+ static class CustomPool extends ScheduledThreadPoolExecutor {
+ CustomPool(int n) { super(n); }
+ protected <V> RunnableScheduledFuture<V> decorateTask(
+ final Runnable r,
+ final RunnableScheduledFuture<V> task) {
+ return new RunnableScheduledFuture<V>() {
+ public void run() { System.err.println(r); task.run(); }
+ public boolean isPeriodic() { return task.isPeriodic(); }
+ public V get()
+ throws InterruptedException,ExecutionException
+ { return task.get(); }
+ public V get(long x, TimeUnit y)
+ throws InterruptedException,ExecutionException,TimeoutException
+ { return task.get(x, y); }
+ public boolean isDone() { return task.isDone(); }
+ public boolean isCancelled() { return task.isCancelled(); }
+ public boolean cancel(boolean x) { return task.cancel(x); }
+ public long getDelay(TimeUnit x) { return task.getDelay(x); }
+ public int compareTo(Delayed x) { return task.compareTo(x); }
+ };
+ }
+ }
+
+ int countRefsCleared(WeakReference<?>[] refs) {
+ int count = 0;
+ for (WeakReference<?> ref : refs)
+ if (ref.get() == null)
+ count++;
+ return count;
+ }
+
+ void test(String[] args) throws Throwable {
+ CustomPool pool = new CustomPool(10);
+ final int size = 100;
+ WeakReference<?>[] refs = new WeakReference<?>[size];
+ Future<?>[] futures = new Future<?>[size];
+ for (int i = 0; i < size; i++) {
+ final Object x = new Object();
+ refs[i] = new WeakReference<Object>(x);
+ // Create a Runnable with a strong ref to x.
+ Runnable r = new Runnable() {
+ public void run() { System.out.println(x); }
+ };
+ // Schedule a custom task with a strong reference to r.
+ // Later tasks have earlier expiration, to ensure multiple
+ // residents of queue head.
+ futures[i] = pool.schedule(r, size*2-i, TimeUnit.MINUTES);
+ }
+ Thread.sleep(10);
+ for (int i = 0; i < size; i++) {
+ if (futures[i] != null) {
+ futures[i].cancel(false);
+ futures[i] = null;
+ }
+ }
+ pool.purge();
+ int cleared = 0;
+ for (int i = 0;
+ i < 10 && (cleared = countRefsCleared(refs)) < size;
+ i++) {
+ System.gc();
+ System.runFinalization();
+ Thread.sleep(10);
+ }
+ pool.shutdown();
+ pool.awaitTermination(10, TimeUnit.SECONDS);
+ if (cleared < size)
+ throw new Error(String.format
+ ("references to %d/%d tasks retained (\"leaked\")",
+ size - cleared, size));
+ }
+
+ //--------------------- Infrastructure ---------------------------
+ volatile int passed = 0, failed = 0;
+ void pass() {passed++;}
+ void fail() {failed++; Thread.dumpStack();}
+ void fail(String msg) {System.err.println(msg); fail();}
+ void unexpected(Throwable t) {failed++; t.printStackTrace();}
+ void check(boolean cond) {if (cond) pass(); else fail();}
+ void equal(Object x, Object y) {
+ if (x == null ? y == null : x.equals(y)) pass();
+ else fail(x + " not equal to " + y);}
+ public static void main(String[] args) throws Throwable {
+ new GCRetention().instanceMain(args);}
+ void instanceMain(String[] args) throws Throwable {
+ try {test(args);} catch (Throwable t) {unexpected(t);}
+ System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
+ if (failed > 0) throw new AssertionError("Some tests failed");}
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/ScheduledThreadPoolExecutor/ZeroCoreThreads.java Tue Oct 13 16:45:35 2015 -0700
@@ -0,0 +1,117 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Martin Buchholz with assistance from members of JCP
+ * JSR-166 Expert Group and released to the public domain, as
+ * explained at http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/*
+ * @test
+ * @bug 8022642 8065320 8129861
+ * @summary Ensure relative sanity when zero core threads
+ */
+
+import java.util.concurrent.*;
+import static java.util.concurrent.TimeUnit.*;
+import java.util.concurrent.locks.*;
+import java.lang.reflect.*;
+
+public class ZeroCoreThreads {
+ static boolean hasWaiters(ReentrantLock lock, Condition condition) {
+ lock.lock();
+ try {
+ return lock.hasWaiters(condition);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ static <T> T getField(Object x, String fieldName) {
+ try {
+ Field field = x.getClass().getDeclaredField(fieldName);
+ field.setAccessible(true);
+ return (T) field.get(x);
+ } catch (ReflectiveOperationException ex) {
+ throw new AssertionError(ex);
+ }
+ }
+
+ void test(String[] args) throws Throwable {
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(0);
+ try {
+ test(p);
+ } finally {
+ p.shutdownNow();
+ check(p.awaitTermination(10L, SECONDS));
+ }
+ }
+
+ void test(ScheduledThreadPoolExecutor p) throws Throwable {
+ Runnable dummy = new Runnable() { public void run() {
+ throw new AssertionError("shouldn't get here"); }};
+ BlockingQueue q = p.getQueue();
+ ReentrantLock lock = getField(q, "lock");
+ Condition available = getField(q, "available");
+
+ equal(0, p.getPoolSize());
+ equal(0, p.getLargestPoolSize());
+ equal(0L, p.getTaskCount());
+ equal(0L, p.getCompletedTaskCount());
+ p.schedule(dummy, 1L, HOURS);
+ // Ensure one pool thread actually waits in timed queue poll
+ long t0 = System.nanoTime();
+ while (!hasWaiters(lock, available)) {
+ if (System.nanoTime() - t0 > SECONDS.toNanos(10L))
+ throw new AssertionError
+ ("timed out waiting for a waiter to show up");
+ Thread.yield();
+ }
+ equal(1, p.getPoolSize());
+ equal(1, p.getLargestPoolSize());
+ equal(1L, p.getTaskCount());
+ equal(0L, p.getCompletedTaskCount());
+ }
+
+ //--------------------- Infrastructure ---------------------------
+ volatile int passed = 0, failed = 0;
+ void pass() {passed++;}
+ void fail() {failed++; Thread.dumpStack();}
+ void fail(String msg) {System.err.println(msg); fail();}
+ void unexpected(Throwable t) {failed++; t.printStackTrace();}
+ void check(boolean cond) {if (cond) pass(); else fail();}
+ void equal(Object x, Object y) {
+ if (x == null ? y == null : x.equals(y)) pass();
+ else fail(x + " not equal to " + y);}
+ public static void main(String[] args) throws Throwable {
+ new ZeroCoreThreads().instanceMain(args);}
+ void instanceMain(String[] args) throws Throwable {
+ try {test(args);} catch (Throwable t) {unexpected(t);}
+ System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
+ if (failed > 0) throw new AssertionError("Some tests failed");}
+}
--- a/jdk/test/java/util/concurrent/ThreadPoolExecutor/CoreThreadTimeOut.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/concurrent/ThreadPoolExecutor/CoreThreadTimeOut.java Tue Oct 13 16:45:35 2015 -0700
@@ -55,7 +55,7 @@
return count;
}
- long millisElapsedSince(long t0) {
+ static long millisElapsedSince(long t0) {
return (System.nanoTime() - t0) / (1000L * 1000L);
}
--- a/jdk/test/java/util/concurrent/ThreadPoolExecutor/Custom.java Tue Oct 13 16:35:22 2015 -0700
+++ b/jdk/test/java/util/concurrent/ThreadPoolExecutor/Custom.java Tue Oct 13 16:45:35 2015 -0700
@@ -41,7 +41,6 @@
if (x == null ? y == null : x.equals(y)) pass();
else {System.out.println(x + " not equal to " + y); fail(); }}
-
private static class CustomTask<V> extends FutureTask<V> {
public static final AtomicInteger births = new AtomicInteger(0);
CustomTask(Callable<V> c) { super(c); births.getAndIncrement(); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/ThreadPoolExecutor/FlakyThreadFactory.java Tue Oct 13 16:45:35 2015 -0700
@@ -0,0 +1,108 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Martin Buchholz and Doug Lea with assistance from
+ * members of JCP JSR-166 Expert Group and released to the public
+ * domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/*
+ * @test
+ * @summary Should be able to shutdown a pool when worker creation failed.
+ */
+
+import java.util.concurrent.*;
+
+public class FlakyThreadFactory {
+ void test(String[] args) throws Throwable {
+ test(NullPointerException.class,
+ new ThreadFactory() {
+ public Thread newThread(Runnable r) {
+ throw new NullPointerException();
+ }});
+ test(OutOfMemoryError.class,
+ new ThreadFactory() {
+ public Thread newThread(Runnable r) {
+ new Thread(null, r, "a natural OOME", 1L << 60);
+ // """On some platforms, the value of the stackSize
+ // parameter may have no effect whatsoever."""
+ throw new OutOfMemoryError("artificial OOME");
+ }});
+ test(null,
+ new ThreadFactory() {
+ public Thread newThread(Runnable r) {
+ return null;
+ }});
+ }
+
+ void test(final Class<?> exceptionClass,
+ final ThreadFactory failingThreadFactory)
+ throws Throwable {
+ ThreadFactory flakyThreadFactory = new ThreadFactory() {
+ int seq = 0;
+ public Thread newThread(Runnable r) {
+ if (seq++ < 4)
+ return new Thread(r);
+ else
+ return failingThreadFactory.newThread(r);
+ }};
+ ThreadPoolExecutor pool =
+ new ThreadPoolExecutor(10, 10,
+ 0L, TimeUnit.SECONDS,
+ new LinkedBlockingQueue(),
+ flakyThreadFactory);
+ try {
+ for (int i = 0; i < 8; i++)
+ pool.submit(new Runnable() { public void run() {} });
+ check(exceptionClass == null);
+ } catch (Throwable t) {
+ /* t.printStackTrace(); */
+ check(exceptionClass.isInstance(t));
+ }
+ pool.shutdown();
+ check(pool.awaitTermination(10L, TimeUnit.SECONDS));
+ }
+
+ //--------------------- Infrastructure ---------------------------
+ volatile int passed = 0, failed = 0;
+ void pass() {passed++;}
+ void fail() {failed++; Thread.dumpStack();}
+ void fail(String msg) {System.err.println(msg); fail();}
+ void unexpected(Throwable t) {failed++; t.printStackTrace();}
+ void check(boolean cond) {if (cond) pass(); else fail();}
+ void equal(Object x, Object y) {
+ if (x == null ? y == null : x.equals(y)) pass();
+ else fail(x + " not equal to " + y);}
+ public static void main(String[] args) throws Throwable {
+ new FlakyThreadFactory().instanceMain(args);}
+ public void instanceMain(String[] args) throws Throwable {
+ try {test(args);} catch (Throwable t) {unexpected(t);}
+ System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
+ if (failed > 0) throw new AssertionError("Some tests failed");}
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/ThreadPoolExecutor/ThreadRestarts.java Tue Oct 13 16:45:35 2015 -0700
@@ -0,0 +1,80 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Martin Buchholz and Jason Mehrens with assistance from
+ * members of JCP JSR-166 Expert Group and released to the public
+ * domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/*
+ * @test
+ * @summary Only one thread should be created when a thread needs to
+ * be kept alive to service a delayed task waiting in the queue.
+ */
+
+import java.util.concurrent.*;
+import static java.util.concurrent.TimeUnit.*;
+import java.util.concurrent.atomic.*;
+
+public class ThreadRestarts {
+ public static void main(String[] args) throws Exception {
+ test(false);
+ test(true);
+ }
+
+ private static void test(boolean allowTimeout) throws Exception {
+ CountingThreadFactory ctf = new CountingThreadFactory();
+ ScheduledThreadPoolExecutor stpe
+ = new ScheduledThreadPoolExecutor(10, ctf);
+ try {
+ Runnable nop = new Runnable() { public void run() {}};
+ stpe.schedule(nop, 10*1000L, MILLISECONDS);
+ stpe.setKeepAliveTime(1L, MILLISECONDS);
+ stpe.allowCoreThreadTimeOut(allowTimeout);
+ MILLISECONDS.sleep(100L);
+ } finally {
+ stpe.shutdownNow();
+ stpe.awaitTermination(Long.MAX_VALUE, MILLISECONDS);
+ }
+ if (ctf.count.get() > 1)
+ throw new AssertionError(
+ String.format("%d threads created, 1 expected",
+ ctf.count.get()));
+ }
+
+ static class CountingThreadFactory implements ThreadFactory {
+ final AtomicLong count = new AtomicLong(0L);
+
+ public Thread newThread(Runnable r) {
+ Thread t = new Thread(r);
+ count.getAndIncrement();
+ return t;
+ }
+ }
+}