OpenJDK / bsd-port / jdk9 / jdk
changeset 12883:6e50b992bef4 jdk9-b88
Merge
author | lana |
---|---|
date | Wed, 21 Oct 2015 15:16:00 -0700 |
parents | 0198481aa9bd 0440acded788 |
children | 4a00f31b3995 35f286a7dd46 |
files | src/java.base/share/classes/sun/misc/ConditionLock.java src/java.base/share/classes/sun/misc/Lock.java src/java.base/share/native/libfdlibm/s_cbrt.c |
diffstat | 196 files changed, 14041 insertions(+), 4956 deletions(-) [+] |
line wrap: on
line diff
--- a/make/mapfiles/libjava/mapfile-vers Mon Oct 19 00:25:06 2015 -0700 +++ b/make/mapfiles/libjava/mapfile-vers Wed Oct 21 15:16:00 2015 -0700 @@ -152,7 +152,6 @@ Java_java_lang_StrictMath_log10; Java_java_lang_StrictMath_sin; Java_java_lang_StrictMath_sqrt; - Java_java_lang_StrictMath_cbrt; Java_java_lang_StrictMath_tan; Java_java_lang_StrictMath_cosh; Java_java_lang_StrictMath_sinh;
--- a/src/java.base/share/classes/java/lang/FdLibm.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/lang/FdLibm.java Wed Oct 21 15:16:00 2015 -0700 @@ -100,6 +100,64 @@ } /** + * cbrt(x) + * Return cube root of x + */ + public static class Cbrt { + // unsigned + private static final int B1 = 715094163; /* B1 = (682-0.03306235651)*2**20 */ + private static final int B2 = 696219795; /* B2 = (664-0.03306235651)*2**20 */ + + private static final double C = 0x1.15f15f15f15f1p-1; // 19/35 ~= 5.42857142857142815906e-01 + private static final double D = -0x1.691de2532c834p-1; // -864/1225 ~= 7.05306122448979611050e-01 + private static final double E = 0x1.6a0ea0ea0ea0fp0; // 99/70 ~= 1.41428571428571436819e+00 + private static final double F = 0x1.9b6db6db6db6ep0; // 45/28 ~= 1.60714285714285720630e+00 + private static final double G = 0x1.6db6db6db6db7p-2; // 5/14 ~= 3.57142857142857150787e-01 + + public static strictfp double compute(double x) { + double t = 0.0; + double sign; + + if (x == 0.0 || !Double.isFinite(x)) + return x; // Handles signed zeros properly + + sign = (x < 0.0) ? -1.0: 1.0; + + x = Math.abs(x); // x <- |x| + + // Rough cbrt to 5 bits + if (x < 0x1.0p-1022) { // subnormal number + t = 0x1.0p54; // set t= 2**54 + t *= x; + t = __HI(t, __HI(t)/3 + B2); + } else { + int hx = __HI(x); // high word of x + t = __HI(t, hx/3 + B1); + } + + // New cbrt to 23 bits, may be implemented in single precision + double r, s, w; + r = t * t/x; + s = C + r*t; + t *= G + F/(s + E + D/s); + + // Chopped to 20 bits and make it larger than cbrt(x) + t = __LO(t, 0); + t = __HI(t, __HI(t) + 0x00000001); + + // One step newton iteration to 53 bits with error less than 0.667 ulps + s = t * t; // t*t is exact + r = x / s; + w = t + t; + r = (r - t)/(w + r); // r-s is exact + t = t + t*r; + + // Restore the original sign bit + return sign * t; + } + } + + /** * hypot(x,y) * * Method :
--- a/src/java.base/share/classes/java/lang/StrictMath.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/lang/StrictMath.java Wed Oct 21 15:16:00 2015 -0700 @@ -307,7 +307,9 @@ * @return the cube root of {@code a}. * @since 1.5 */ - public static native double cbrt(double a); + public static double cbrt(double a) { + return FdLibm.Cbrt.compute(a); + } /** * Computes the remainder operation on two arguments as prescribed
--- a/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java Wed Oct 21 15:16:00 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2015, 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 @@ -834,7 +834,7 @@ static MethodHandle makeCbmhCtor(Class<? extends BoundMethodHandle> cbmh, String types) { try { - return LOOKUP.findStatic(cbmh, "make", MethodType.fromMethodDescriptorString(makeSignature(types, false), null)); + return LOOKUP.findStatic(cbmh, "make", MethodType.fromDescriptor(makeSignature(types, false), null)); } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | TypeNotPresentException e) { throw newInternalError(e); }
--- a/src/java.base/share/classes/java/lang/invoke/MemberName.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/lang/invoke/MemberName.java Wed Oct 21 15:16:00 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2015, 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 @@ -141,7 +141,7 @@ synchronized (this) { if (type instanceof String) { String sig = (String) type; - MethodType res = MethodType.fromMethodDescriptorString(sig, getClassLoader()); + MethodType res = MethodType.fromDescriptor(sig, getClassLoader()); type = res; } else if (type instanceof Object[]) { Object[] typeInfo = (Object[]) type; @@ -206,7 +206,7 @@ synchronized (this) { if (type instanceof String) { String sig = (String) type; - MethodType mtype = MethodType.fromMethodDescriptorString("()"+sig, getClassLoader()); + MethodType mtype = MethodType.fromDescriptor("()"+sig, getClassLoader()); Class<?> res = mtype.returnType(); type = res; }
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java Wed Oct 21 15:16:00 2015 -0700 @@ -383,7 +383,7 @@ if (type instanceof MethodType) return (MethodType) type; else - return MethodType.fromMethodDescriptorString((String)type, callerClass.getClassLoader()); + return MethodType.fromDescriptor((String)type, callerClass.getClassLoader()); } // Tracing logic: static MemberName linkMethodTracing(Class<?> callerClass, int refKind,
--- a/src/java.base/share/classes/java/lang/invoke/MethodType.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/lang/invoke/MethodType.java Wed Oct 21 15:16:00 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2015, 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 @@ -1058,6 +1058,23 @@ public static MethodType fromMethodDescriptorString(String descriptor, ClassLoader loader) throws IllegalArgumentException, TypeNotPresentException { + return fromDescriptor(descriptor, + (loader == null) ? ClassLoader.getSystemClassLoader() : loader); + } + + /** + * Same as {@link #fromMethodDescriptorString(String, ClassLoader)}, but + * {@code null} ClassLoader means the bootstrap loader is used here. + * <p> + * IMPORTANT: This method is preferable for JDK internal use as it more + * correctly interprets {@code null} ClassLoader than + * {@link #fromMethodDescriptorString(String, ClassLoader)}. + * Use of this method also avoids early initialization issues when system + * ClassLoader is not initialized yet. + */ + static MethodType fromDescriptor(String descriptor, ClassLoader loader) + throws IllegalArgumentException, TypeNotPresentException + { if (!descriptor.startsWith("(") || // also generates NPE if needed descriptor.indexOf(')') < 0 || descriptor.indexOf('.') >= 0)
--- a/src/java.base/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java Wed Oct 21 15:16:00 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2015, 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 @@ -131,7 +131,7 @@ } private static String boxingDescriptor(Wrapper w) { - return String.format("(%s)L%s;", w.basicTypeChar(), wrapperName(w)); + return "(" + w.basicTypeChar() + ")L" + wrapperName(w) + ";"; } private static String unboxingDescriptor(Wrapper w) {
--- a/src/java.base/share/classes/java/net/URLStreamHandlerFactory.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/net/URLStreamHandlerFactory.java Wed Oct 21 15:16:00 2015 -0700 @@ -28,9 +28,9 @@ /** * This interface defines a factory for {@code URL} stream * protocol handlers. - * <p> - * It is used by the {@code URL} class to create a - * {@code URLStreamHandler} for a specific protocol. + * + * <p> A URL stream handler factory is used as specified in the + * {@linkplain java.net.URL#URL(String,String,int,String) URL constructor}. * * @author Arthur van Hoff * @see java.net.URL
--- a/src/java.base/share/classes/java/net/spi/URLStreamHandlerProvider.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/net/spi/URLStreamHandlerProvider.java Wed Oct 21 15:16:00 2015 -0700 @@ -41,6 +41,9 @@ * fully-qualified concrete URL stream handler provider class names, one per * line. * + * <p> URL stream handler providers are located at runtime, as specified in the + * {@linkplain java.net.URL#URL(String,String,int,String) URL constructor}. + * * @since 1.9 */ public abstract class URLStreamHandlerProvider
--- a/src/java.base/share/classes/java/util/AbstractQueue.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/AbstractQueue.java Wed Oct 21 15:16:00 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/src/java.base/share/classes/java/util/ArrayDeque.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/ArrayDeque.java Wed Oct 21 15:16:00 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/src/java.base/share/classes/java/util/ArrayPrefixHelpers.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/ArrayPrefixHelpers.java Wed Oct 21 15:16:00 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/ */ +package java.util; + +import java.util.concurrent.CountedCompleter; import java.util.concurrent.ForkJoinPool; -import java.util.concurrent.CountedCompleter; 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/src/java.base/share/classes/java/util/Collections.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/Collections.java Wed Oct 21 15:16:00 2015 -0700 @@ -537,8 +537,9 @@ * Copies all of the elements from one list into another. After the * operation, the index of each copied element in the destination list * will be identical to its index in the source list. The destination - * list must be at least as long as the source list. If it is longer, the - * remaining elements in the destination list are unaffected. <p> + * list's size must be greater than or equal to the source list's size. + * If it is greater, the remaining elements in the destination list are + * unaffected. <p> * * This method runs in linear time. *
--- a/src/java.base/share/classes/java/util/Deque.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/Deque.java Wed Oct 21 15:16:00 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/src/java.base/share/classes/java/util/NavigableMap.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/NavigableMap.java Wed Oct 21 15:16:00 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/src/java.base/share/classes/java/util/NavigableSet.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/NavigableSet.java Wed Oct 21 15:16:00 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/src/java.base/share/classes/java/util/PriorityQueue.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/PriorityQueue.java Wed Oct 21 15:16:00 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/src/java.base/share/classes/java/util/Queue.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/Queue.java Wed Oct 21 15:16:00 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/src/java.base/share/classes/java/util/SplittableRandom.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/SplittableRandom.java Wed Oct 21 15:16:00 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/src/java.base/share/classes/java/util/concurrent/AbstractExecutorService.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/concurrent/AbstractExecutorService.java Wed Oct 21 15:16:00 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/src/java.base/share/classes/java/util/concurrent/ArrayBlockingQueue.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/concurrent/ArrayBlockingQueue.java Wed Oct 21 15:16:00 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/src/java.base/share/classes/java/util/concurrent/BlockingDeque.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/concurrent/BlockingDeque.java Wed Oct 21 15:16:00 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/src/java.base/share/classes/java/util/concurrent/BlockingQueue.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/concurrent/BlockingQueue.java Wed Oct 21 15:16:00 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/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java Wed Oct 21 15:16:00 2015 -0700 @@ -34,23 +34,13 @@ */ package java.util.concurrent; + +import java.util.concurrent.locks.LockSupport; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Supplier; -import java.util.function.Consumer; -import java.util.function.BiConsumer; -import java.util.function.Function; -import java.util.function.BiFunction; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.ForkJoinPool; -import java.util.concurrent.ForkJoinTask; -import java.util.concurrent.Executor; -import java.util.concurrent.ThreadLocalRandom; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.CancellationException; -import java.util.concurrent.CompletionException; -import java.util.concurrent.CompletionStage; -import java.util.concurrent.locks.LockSupport; /** * A {@link Future} that may be explicitly completed (setting its @@ -71,19 +61,32 @@ * <li>Actions supplied for dependent completions of * <em>non-async</em> methods may be performed by the thread that * completes the current CompletableFuture, or by any other caller of - * a completion method.</li> + * a completion method. * * <li>All <em>async</em> methods without an explicit Executor * argument are performed using the {@link ForkJoinPool#commonPool()} * (unless it does not support a parallelism level of at least two, in - * which case, a new Thread is created to run each task). To simplify - * monitoring, debugging, and tracking, all generated asynchronous - * tasks are instances of the marker interface {@link - * AsynchronousCompletionTask}. </li> + * which case, a new Thread is created to run each task). This may be + * overridden for non-static methods in subclasses by defining method + * {@link #defaultExecutor()}. To simplify monitoring, debugging, + * and tracking, all generated asynchronous tasks are instances of the + * marker interface {@link AsynchronousCompletionTask}. Operations + * with time-delays can use adapter methods defined in this class, for + * example: {@code supplyAsync(supplier, delayedExecutor(timeout, + * timeUnit))}. To support methods with delays and timeouts, this + * class maintains at most one daemon thread for triggering and + * cancelling actions, not for running them. * * <li>All CompletionStage methods are implemented independently of * other public methods, so the behavior of one method is not impacted - * by overrides of others in subclasses. </li> </ul> + * by overrides of others in subclasses. + * + * <li>All CompletionStage methods return CompletableFutures. To + * restrict usages to only those methods defined in interface + * CompletionStage, use method {@link #minimalCompletionStage}. Or to + * ensure only that clients do not themselves modify a future, use + * method {@link #copy}. + * </ul> * * <p>CompletableFuture also implements {@link Future} with the following * policies: <ul> @@ -94,7 +97,7 @@ * completion. Method {@link #cancel cancel} has the same effect as * {@code completeExceptionally(new CancellationException())}. Method * {@link #isCompletedExceptionally} can be used to determine if a - * CompletableFuture completed in any exceptional fashion.</li> + * CompletableFuture completed in any exceptional fashion. * * <li>In case of exceptional completion with a CompletionException, * methods {@link #get()} and {@link #get(long, TimeUnit)} throw an @@ -102,10 +105,38 @@ * corresponding CompletionException. To simplify usage in most * contexts, this class also defines methods {@link #join()} and * {@link #getNow} that instead throw the CompletionException directly - * in these cases.</li> </ul> + * in these cases. + * </ul> + * + * <p>Arguments used to pass a completion result (that is, for + * parameters of type {@code T}) for methods accepting them may be + * null, but passing a null value for any other parameter will result + * in a {@link NullPointerException} being thrown. + * + * <p>Subclasses of this class should normally override the "virtual + * constructor" method {@link #newIncompleteFuture}, which establishes + * the concrete type returned by CompletionStage methods. For example, + * here is a class that substitutes a different default Executor and + * disables the {@code obtrude} methods: + * + * <pre> {@code + * class MyCompletableFuture<T> extends CompletableFuture<T> { + * static final Executor myExecutor = ...; + * public MyCompletableFuture() { } + * public <U> CompletableFuture<U> newIncompleteFuture() { + * return new MyCompletableFuture<U>(); } + * public Executor defaultExecutor() { + * return myExecutor; } + * public void obtrudeValue(T value) { + * throw new UnsupportedOperationException(); } + * public void obtrudeException(Throwable ex) { + * throw new UnsupportedOperationException(); } + * }}</pre> * * @author Doug Lea * @since 1.8 + * @param <T> The result type returned by this future's {@code join} + * and {@code get} methods */ public class CompletableFuture<T> implements Future<T>, CompletionStage<T> { @@ -150,9 +181,7 @@ * fields for source(s), actions, and dependent. They are * boringly similar, differing from others only with respect to * underlying functional forms. We do this so that users don't - * encounter layers of adaptors in common usages. We also - * include "Relay" classes/methods that don't correspond to user - * methods; they copy results from one stage to another. + * encounter layers of adapters in common usages. * * * Boolean CompletableFuture method x(...) (for example * uniApply) takes all of the arguments needed to check that an @@ -219,18 +248,18 @@ volatile Completion stack; // Top of Treiber stack of dependent actions final boolean internalComplete(Object r) { // CAS from null to r - return UNSAFE.compareAndSwapObject(this, RESULT, null, r); + return U.compareAndSwapObject(this, RESULT, null, r); } final boolean casStack(Completion cmp, Completion val) { - return UNSAFE.compareAndSwapObject(this, STACK, cmp, val); + return U.compareAndSwapObject(this, STACK, cmp, val); } /** Returns true if successfully pushed c onto stack. */ final boolean tryPushStack(Completion c) { Completion h = stack; lazySetNext(c, h); - return UNSAFE.compareAndSwapObject(this, STACK, h, c); + return U.compareAndSwapObject(this, STACK, h, c); } /** Unconditionally pushes c onto stack, retrying if necessary. */ @@ -250,8 +279,8 @@ /** Completes with the null value, unless already completed. */ final boolean completeNull() { - return UNSAFE.compareAndSwapObject(this, RESULT, null, - NIL); + return U.compareAndSwapObject(this, RESULT, null, + NIL); } /** Returns the encoding of the given non-exceptional value. */ @@ -261,8 +290,8 @@ /** Completes with a non-exceptional result, unless already completed. */ final boolean completeValue(T t) { - return UNSAFE.compareAndSwapObject(this, RESULT, null, - (t == null) ? NIL : t); + return U.compareAndSwapObject(this, RESULT, null, + (t == null) ? NIL : t); } /** @@ -276,8 +305,8 @@ /** Completes with an exceptional result, unless already completed. */ final boolean completeThrowable(Throwable x) { - return UNSAFE.compareAndSwapObject(this, RESULT, null, - encodeThrowable(x)); + return U.compareAndSwapObject(this, RESULT, null, + encodeThrowable(x)); } /** @@ -304,8 +333,8 @@ * existing CompletionException. */ final boolean completeThrowable(Throwable x, Object r) { - return UNSAFE.compareAndSwapObject(this, RESULT, null, - encodeThrowable(x, r)); + return U.compareAndSwapObject(this, RESULT, null, + encodeThrowable(x, r)); } /** @@ -334,8 +363,8 @@ * If exceptional, r is first coerced to a CompletionException. */ final boolean completeRelay(Object r) { - return UNSAFE.compareAndSwapObject(this, RESULT, null, - encodeRelay(r)); + return U.compareAndSwapObject(this, RESULT, null, + encodeRelay(r)); } /** @@ -390,14 +419,14 @@ public static interface AsynchronousCompletionTask { } - private static final boolean useCommonPool = + private static final boolean USE_COMMON_POOL = (ForkJoinPool.getCommonPoolParallelism() > 1); /** * Default executor -- ForkJoinPool.commonPool() unless it cannot * support parallelism. */ - private static final Executor asyncPool = useCommonPool ? + private static final Executor ASYNC_POOL = USE_COMMON_POOL ? ForkJoinPool.commonPool() : new ThreadPerTaskExecutor(); /** Fallback if ForkJoinPool.commonPool() cannot support parallelism */ @@ -407,11 +436,11 @@ /** * Null-checks user executor argument, and translates uses of - * commonPool to asyncPool in case parallelism disabled. + * commonPool to ASYNC_POOL in case parallelism disabled. */ static Executor screenExecutor(Executor e) { - if (!useCommonPool && e == ForkJoinPool.commonPool()) - return asyncPool; + if (!USE_COMMON_POOL && e == ForkJoinPool.commonPool()) + return ASYNC_POOL; if (e == null) throw new NullPointerException(); return e; } @@ -421,6 +450,12 @@ static final int ASYNC = 1; static final int NESTED = -1; + /** + * Spins before blocking in waitingGet + */ + static final int SPINS = (Runtime.getRuntime().availableProcessors() > 1 ? + 1 << 8 : 0); + /* ------------- Base Completion classes and operations -------------- */ @SuppressWarnings("serial") @@ -440,13 +475,13 @@ abstract boolean isLive(); public final void run() { tryFire(ASYNC); } - public final boolean exec() { tryFire(ASYNC); return true; } + public final boolean exec() { tryFire(ASYNC); return false; } public final Void getRawResult() { return null; } public final void setRawResult(Void v) {} } static void lazySetNext(Completion c, Completion next) { - UNSAFE.putOrderedObject(c, NEXT, next); + U.putOrderedObject(c, NEXT, next); } /** @@ -610,7 +645,7 @@ private <V> CompletableFuture<V> uniApplyStage( Executor e, Function<? super T,? extends V> f) { if (f == null) throw new NullPointerException(); - CompletableFuture<V> d = new CompletableFuture<V>(); + CompletableFuture<V> d = newIncompleteFuture(); if (e != null || !d.uniApply(this, f, null)) { UniApply<T,V> c = new UniApply<T,V>(e, d, this, f); push(c); @@ -665,7 +700,7 @@ private CompletableFuture<Void> uniAcceptStage(Executor e, Consumer<? super T> f) { if (f == null) throw new NullPointerException(); - CompletableFuture<Void> d = new CompletableFuture<Void>(); + CompletableFuture<Void> d = newIncompleteFuture(); if (e != null || !d.uniAccept(this, f, null)) { UniAccept<T> c = new UniAccept<T>(e, d, this, f); push(c); @@ -713,7 +748,7 @@ private CompletableFuture<Void> uniRunStage(Executor e, Runnable f) { if (f == null) throw new NullPointerException(); - CompletableFuture<Void> d = new CompletableFuture<Void>(); + CompletableFuture<Void> d = newIncompleteFuture(); if (e != null || !d.uniRun(this, f, null)) { UniRun<T> c = new UniRun<T>(e, d, this, f); push(c); @@ -774,7 +809,7 @@ private CompletableFuture<T> uniWhenCompleteStage( Executor e, BiConsumer<? super T, ? super Throwable> f) { if (f == null) throw new NullPointerException(); - CompletableFuture<T> d = new CompletableFuture<T>(); + CompletableFuture<T> d = newIncompleteFuture(); if (e != null || !d.uniWhenComplete(this, f, null)) { UniWhenComplete<T> c = new UniWhenComplete<T>(e, d, this, f); push(c); @@ -830,7 +865,7 @@ private <V> CompletableFuture<V> uniHandleStage( Executor e, BiFunction<? super T, Throwable, ? extends V> f) { if (f == null) throw new NullPointerException(); - CompletableFuture<V> d = new CompletableFuture<V>(); + CompletableFuture<V> d = newIncompleteFuture(); if (e != null || !d.uniHandle(this, f, null)) { UniHandle<T,V> c = new UniHandle<T,V>(e, d, this, f); push(c); @@ -880,7 +915,7 @@ private CompletableFuture<T> uniExceptionallyStage( Function<Throwable, ? extends T> f) { if (f == null) throw new NullPointerException(); - CompletableFuture<T> d = new CompletableFuture<T>(); + CompletableFuture<T> d = newIncompleteFuture(); if (!d.uniExceptionally(this, f, null)) { UniExceptionally<T> c = new UniExceptionally<T>(d, this, f); push(c); @@ -912,6 +947,30 @@ return true; } + private CompletableFuture<T> uniCopyStage() { + Object r; + CompletableFuture<T> d = newIncompleteFuture(); + if ((r = result) != null) + d.completeRelay(r); + else { + UniRelay<T> c = new UniRelay<T>(d, this); + push(c); + c.tryFire(SYNC); + } + return d; + } + + private MinimalStage<T> uniAsMinimalStage() { + Object r; + if ((r = result) != null) + return new MinimalStage<T>(encodeRelay(r)); + MinimalStage<T> d = new MinimalStage<T>(); + UniRelay<T> c = new UniRelay<T>(d, this); + push(c); + c.tryFire(SYNC); + return d; + } + @SuppressWarnings("serial") static final class UniCompose<T,V> extends UniCompletion<T,V> { Function<? super T, ? extends CompletionStage<V>> fn; @@ -967,31 +1026,32 @@ private <V> CompletableFuture<V> uniComposeStage( Executor e, Function<? super T, ? extends CompletionStage<V>> f) { if (f == null) throw new NullPointerException(); - Object r; Throwable x; + Object r, s; Throwable x; + CompletableFuture<V> d = newIncompleteFuture(); if (e == null && (r = result) != null) { - // try to return function result directly if (r instanceof AltResult) { if ((x = ((AltResult)r).ex) != null) { - return new CompletableFuture<V>(encodeThrowable(x, r)); + d.result = encodeThrowable(x, r); + return d; } r = null; } try { @SuppressWarnings("unchecked") T t = (T) r; CompletableFuture<V> g = f.apply(t).toCompletableFuture(); - Object s = g.result; - if (s != null) - return new CompletableFuture<V>(encodeRelay(s)); - CompletableFuture<V> d = new CompletableFuture<V>(); - UniRelay<V> copy = new UniRelay<V>(d, g); - g.push(copy); - copy.tryFire(SYNC); + if ((s = g.result) != null) + d.completeRelay(s); + else { + UniRelay<V> c = new UniRelay<V>(d, g); + g.push(c); + c.tryFire(SYNC); + } return d; } catch (Throwable ex) { - return new CompletableFuture<V>(encodeThrowable(ex)); + d.result = encodeThrowable(ex); + return d; } } - CompletableFuture<V> d = new CompletableFuture<V>(); UniCompose<T,V> c = new UniCompose<T,V>(e, d, this, f); push(c); c.tryFire(SYNC); @@ -1116,7 +1176,7 @@ CompletableFuture<U> b; if (f == null || (b = o.toCompletableFuture()) == null) throw new NullPointerException(); - CompletableFuture<V> d = new CompletableFuture<V>(); + CompletableFuture<V> d = newIncompleteFuture(); if (e != null || !d.biApply(this, b, f, null)) { BiApply<T,U,V> c = new BiApply<T,U,V>(e, d, this, b, f); bipush(b, c); @@ -1188,7 +1248,7 @@ CompletableFuture<U> b; if (f == null || (b = o.toCompletableFuture()) == null) throw new NullPointerException(); - CompletableFuture<Void> d = new CompletableFuture<Void>(); + CompletableFuture<Void> d = newIncompleteFuture(); if (e != null || !d.biAccept(this, b, f, null)) { BiAccept<T,U> c = new BiAccept<T,U>(e, d, this, b, f); bipush(b, c); @@ -1247,7 +1307,7 @@ CompletableFuture<?> b; if (f == null || (b = o.toCompletableFuture()) == null) throw new NullPointerException(); - CompletableFuture<Void> d = new CompletableFuture<Void>(); + CompletableFuture<Void> d = newIncompleteFuture(); if (e != null || !d.biRun(this, b, f, null)) { BiRun<T,?> c = new BiRun<>(e, d, this, b, f); bipush(b, c); @@ -1302,7 +1362,7 @@ if ((a = (lo == mid ? cfs[lo] : andTree(cfs, lo, mid))) == null || (b = (lo == hi ? a : (hi == mid+1) ? cfs[hi] : - andTree(cfs, mid+1, hi))) == null) + andTree(cfs, mid+1, hi))) == null) throw new NullPointerException(); if (!d.biRelay(a, b)) { BiRelay<?,?> c = new BiRelay<>(d, a, b); @@ -1388,7 +1448,7 @@ CompletableFuture<U> b; if (f == null || (b = o.toCompletableFuture()) == null) throw new NullPointerException(); - CompletableFuture<V> d = new CompletableFuture<V>(); + CompletableFuture<V> d = newIncompleteFuture(); if (e != null || !d.orApply(this, b, f, null)) { OrApply<T,U,V> c = new OrApply<T,U,V>(e, d, this, b, f); orpush(b, c); @@ -1452,7 +1512,7 @@ CompletableFuture<U> b; if (f == null || (b = o.toCompletableFuture()) == null) throw new NullPointerException(); - CompletableFuture<Void> d = new CompletableFuture<Void>(); + CompletableFuture<Void> d = newIncompleteFuture(); if (e != null || !d.orAccept(this, b, f, null)) { OrAccept<T,U> c = new OrAccept<T,U>(e, d, this, b, f); orpush(b, c); @@ -1510,7 +1570,7 @@ CompletableFuture<?> b; if (f == null || (b = o.toCompletableFuture()) == null) throw new NullPointerException(); - CompletableFuture<Void> d = new CompletableFuture<Void>(); + CompletableFuture<Void> d = newIncompleteFuture(); if (e != null || !d.orRun(this, b, f, null)) { OrRun<T,?> c = new OrRun<>(e, d, this, b, f); orpush(b, c); @@ -1556,7 +1616,7 @@ if ((a = (lo == mid ? cfs[lo] : orTree(cfs, lo, mid))) == null || (b = (lo == hi ? a : (hi == mid+1) ? cfs[hi] : - orTree(cfs, mid+1, hi))) == null) + orTree(cfs, mid+1, hi))) == null) throw new NullPointerException(); if (!d.orRelay(a, b)) { OrRelay<?,?> c = new OrRelay<>(d, a, b); @@ -1571,9 +1631,9 @@ @SuppressWarnings("serial") static final class AsyncSupply<T> extends ForkJoinTask<Void> - implements Runnable, AsynchronousCompletionTask { - CompletableFuture<T> dep; Supplier<T> fn; - AsyncSupply(CompletableFuture<T> dep, Supplier<T> fn) { + implements Runnable, AsynchronousCompletionTask { + CompletableFuture<T> dep; Supplier<? extends T> fn; + AsyncSupply(CompletableFuture<T> dep, Supplier<? extends T> fn) { this.dep = dep; this.fn = fn; } @@ -1582,7 +1642,7 @@ public final boolean exec() { run(); return true; } public void run() { - CompletableFuture<T> d; Supplier<T> f; + CompletableFuture<T> d; Supplier<? extends T> f; if ((d = dep) != null && (f = fn) != null) { dep = null; fn = null; if (d.result == null) { @@ -1607,7 +1667,7 @@ @SuppressWarnings("serial") static final class AsyncRun extends ForkJoinTask<Void> - implements Runnable, AsynchronousCompletionTask { + implements Runnable, AsynchronousCompletionTask { CompletableFuture<Void> dep; Runnable fn; AsyncRun(CompletableFuture<Void> dep, Runnable fn) { this.dep = dep; this.fn = fn; @@ -1651,14 +1711,15 @@ @SuppressWarnings("serial") static final class Signaller extends Completion implements ForkJoinPool.ManagedBlocker { - long nanos; // wait time if timed + long nanos; // remaining wait time if timed final long deadline; // non-zero if timed - volatile int interruptControl; // > 0: interruptible, < 0: interrupted + final boolean interruptible; + boolean interrupted; volatile Thread thread; Signaller(boolean interruptible, long nanos, long deadline) { this.thread = Thread.currentThread(); - this.interruptControl = interruptible ? 1 : 0; + this.interruptible = interruptible; this.nanos = nanos; this.deadline = deadline; } @@ -1671,29 +1732,22 @@ return null; } public boolean isReleasable() { - if (thread == null) - return true; - if (Thread.interrupted()) { - int i = interruptControl; - interruptControl = -1; - if (i > 0) - return true; - } - if (deadline != 0L && - (nanos <= 0L || (nanos = deadline - System.nanoTime()) <= 0L)) { - thread = null; - return true; - } - return false; + if (Thread.interrupted()) + interrupted = true; + return ((interrupted && interruptible) || + (deadline != 0L && + (nanos <= 0L || + (nanos = deadline - System.nanoTime()) <= 0L)) || + thread == null); } public boolean block() { - if (isReleasable()) - return true; - else if (deadline == 0L) - LockSupport.park(this); - else if (nanos > 0L) - LockSupport.parkNanos(this, nanos); - return isReleasable(); + while (!isReleasable()) { + if (deadline == 0L) + LockSupport.park(this); + else + LockSupport.parkNanos(this, nanos); + } + return true; } final boolean isLive() { return thread != null; } } @@ -1705,13 +1759,10 @@ private Object waitingGet(boolean interruptible) { Signaller q = null; boolean queued = false; - int spins = -1; + int spins = SPINS; Object r; while ((r = result) == null) { - if (spins < 0) - spins = (Runtime.getRuntime().availableProcessors() > 1) ? - 1 << 8 : 0; // Use brief spin-wait on multiprocessors - else if (spins > 0) { + if (spins > 0) { if (ThreadLocalRandom.nextSecondarySeed() >= 0) --spins; } @@ -1719,29 +1770,27 @@ q = new Signaller(interruptible, 0L, 0L); else if (!queued) queued = tryPushStack(q); - else if (interruptible && q.interruptControl < 0) { - q.thread = null; - cleanStack(); - return null; - } - else if (q.thread != null && result == null) { + else { try { ForkJoinPool.managedBlock(q); - } catch (InterruptedException ie) { - q.interruptControl = -1; + } catch (InterruptedException ie) { // currently cannot happen + q.interrupted = true; } + if (q.interrupted && interruptible) + break; } } if (q != null) { q.thread = null; - if (q.interruptControl < 0) { + if (q.interrupted) { if (interruptible) - r = null; // report interruption + cleanStack(); else Thread.currentThread().interrupt(); } } - postComplete(); + if (r != null) + postComplete(); return r; } @@ -1752,37 +1801,39 @@ private Object timedGet(long nanos) throws TimeoutException { if (Thread.interrupted()) return null; - if (nanos <= 0L) - throw new TimeoutException(); - long d = System.nanoTime() + nanos; - Signaller q = new Signaller(true, nanos, d == 0L ? 1L : d); // avoid 0 - boolean queued = false; - Object r; - // We intentionally don't spin here (as waitingGet does) because - // the call to nanoTime() above acts much like a spin. - while ((r = result) == null) { - if (!queued) - queued = tryPushStack(q); - else if (q.interruptControl < 0 || q.nanos <= 0L) { - q.thread = null; - cleanStack(); - if (q.interruptControl < 0) - return null; - throw new TimeoutException(); - } - else if (q.thread != null && result == null) { - try { - ForkJoinPool.managedBlock(q); - } catch (InterruptedException ie) { - q.interruptControl = -1; + if (nanos > 0L) { + long d = System.nanoTime() + nanos; + long deadline = (d == 0L) ? 1L : d; // avoid 0 + Signaller q = null; + boolean queued = false; + Object r; + while ((r = result) == null) { // similar to untimed, without spins + if (q == null) + q = new Signaller(true, nanos, deadline); + else if (!queued) + queued = tryPushStack(q); + else if (q.nanos <= 0L) + break; + else { + try { + ForkJoinPool.managedBlock(q); + } catch (InterruptedException ie) { + q.interrupted = true; + } + if (q.interrupted) + break; } } + if (q != null) + q.thread = null; + if (r != null) + postComplete(); + else + cleanStack(); + if (r != null || (q != null && q.interrupted)) + return r; } - if (q.interruptControl < 0) - r = null; - q.thread = null; - postComplete(); - return r; + throw new TimeoutException(); } /* ------------- public methods -------------- */ @@ -1796,7 +1847,7 @@ /** * Creates a new complete CompletableFuture with given encoded result. */ - private CompletableFuture(Object r) { + CompletableFuture(Object r) { this.result = r; } @@ -1811,7 +1862,7 @@ * @return the new CompletableFuture */ public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) { - return asyncSupplyStage(asyncPool, supplier); + return asyncSupplyStage(ASYNC_POOL, supplier); } /** @@ -1840,7 +1891,7 @@ * @return the new CompletableFuture */ public static CompletableFuture<Void> runAsync(Runnable runnable) { - return asyncRunStage(asyncPool, runnable); + return asyncRunStage(ASYNC_POOL, runnable); } /** @@ -1985,7 +2036,7 @@ public <U> CompletableFuture<U> thenApplyAsync( Function<? super T,? extends U> fn) { - return uniApplyStage(asyncPool, fn); + return uniApplyStage(defaultExecutor(), fn); } public <U> CompletableFuture<U> thenApplyAsync( @@ -1998,7 +2049,7 @@ } public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action) { - return uniAcceptStage(asyncPool, action); + return uniAcceptStage(defaultExecutor(), action); } public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action, @@ -2011,7 +2062,7 @@ } public CompletableFuture<Void> thenRunAsync(Runnable action) { - return uniRunStage(asyncPool, action); + return uniRunStage(defaultExecutor(), action); } public CompletableFuture<Void> thenRunAsync(Runnable action, @@ -2028,7 +2079,7 @@ public <U,V> CompletableFuture<V> thenCombineAsync( CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn) { - return biApplyStage(asyncPool, other, fn); + return biApplyStage(defaultExecutor(), other, fn); } public <U,V> CompletableFuture<V> thenCombineAsync( @@ -2046,7 +2097,7 @@ public <U> CompletableFuture<Void> thenAcceptBothAsync( CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action) { - return biAcceptStage(asyncPool, other, action); + return biAcceptStage(defaultExecutor(), other, action); } public <U> CompletableFuture<Void> thenAcceptBothAsync( @@ -2062,7 +2113,7 @@ public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other, Runnable action) { - return biRunStage(asyncPool, other, action); + return biRunStage(defaultExecutor(), other, action); } public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other, @@ -2078,7 +2129,7 @@ public <U> CompletableFuture<U> applyToEitherAsync( CompletionStage<? extends T> other, Function<? super T, U> fn) { - return orApplyStage(asyncPool, other, fn); + return orApplyStage(defaultExecutor(), other, fn); } public <U> CompletableFuture<U> applyToEitherAsync( @@ -2094,7 +2145,7 @@ public CompletableFuture<Void> acceptEitherAsync( CompletionStage<? extends T> other, Consumer<? super T> action) { - return orAcceptStage(asyncPool, other, action); + return orAcceptStage(defaultExecutor(), other, action); } public CompletableFuture<Void> acceptEitherAsync( @@ -2110,7 +2161,7 @@ public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other, Runnable action) { - return orRunStage(asyncPool, other, action); + return orRunStage(defaultExecutor(), other, action); } public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other, @@ -2126,7 +2177,7 @@ public <U> CompletableFuture<U> thenComposeAsync( Function<? super T, ? extends CompletionStage<U>> fn) { - return uniComposeStage(asyncPool, fn); + return uniComposeStage(defaultExecutor(), fn); } public <U> CompletableFuture<U> thenComposeAsync( @@ -2142,7 +2193,7 @@ public CompletableFuture<T> whenCompleteAsync( BiConsumer<? super T, ? super Throwable> action) { - return uniWhenCompleteStage(asyncPool, action); + return uniWhenCompleteStage(defaultExecutor(), action); } public CompletableFuture<T> whenCompleteAsync( @@ -2157,7 +2208,7 @@ public <U> CompletableFuture<U> handleAsync( BiFunction<? super T, Throwable, ? extends U> fn) { - return uniHandleStage(asyncPool, fn); + return uniHandleStage(defaultExecutor(), fn); } public <U> CompletableFuture<U> handleAsync( @@ -2196,6 +2247,7 @@ return uniExceptionallyStage(fn); } + /* ------------- Arbitrary-arity constructions -------------- */ /** @@ -2353,10 +2405,12 @@ */ public String toString() { Object r = result; - int count; + int count = 0; // avoid call to getNumberOfDependents in case disabled + for (Completion p = stack; p != null; p = p.next) + ++count; return super.toString() + ((r == null) ? - (((count = getNumberOfDependents()) == 0) ? + ((count == 0) ? "[Not completed]" : "[Not completed, " + count + " dependents]") : (((r instanceof AltResult) && ((AltResult)r).ex != null) ? @@ -2364,22 +2418,381 @@ "[Completed normally]")); } + // jdk9 additions + + /** + * Returns a new incomplete CompletableFuture of the type to be + * returned by a CompletionStage method. Subclasses should + * normally override this method to return an instance of the same + * class as this CompletableFuture. The default implementation + * returns an instance of class CompletableFuture. + * + * @param <U> the type of the value + * @return a new CompletableFuture + * @since 1.9 + */ + public <U> CompletableFuture<U> newIncompleteFuture() { + return new CompletableFuture<U>(); + } + + /** + * Returns the default Executor used for async methods that do not + * specify an Executor. This class uses the {@link + * ForkJoinPool#commonPool()} if it supports more than one + * parallel thread, or else an Executor using one thread per async + * task. This method may be overridden in subclasses to return + * an Executor that provides at least one independent thread. + * + * @return the executor + * @since 1.9 + */ + public Executor defaultExecutor() { + return ASYNC_POOL; + } + + /** + * Returns a new CompletableFuture that is completed normally with + * the same value as this CompletableFuture when it completes + * normally. If this CompletableFuture completes exceptionally, + * then the returned CompletableFuture completes exceptionally + * with a CompletionException with this exception as cause. The + * behavior is equivalent to {@code thenApply(x -> x)}. This + * method may be useful as a form of "defensive copying", to + * prevent clients from completing, while still being able to + * arrange dependent actions. + * + * @return the new CompletableFuture + * @since 1.9 + */ + public CompletableFuture<T> copy() { + return uniCopyStage(); + } + + /** + * Returns a new CompletionStage that is completed normally with + * the same value as this CompletableFuture when it completes + * normally, and cannot be independently completed or otherwise + * used in ways not defined by the methods of interface {@link + * CompletionStage}. If this CompletableFuture completes + * exceptionally, then the returned CompletionStage completes + * exceptionally with a CompletionException with this exception as + * cause. + * + * @return the new CompletionStage + * @since 1.9 + */ + public CompletionStage<T> minimalCompletionStage() { + return uniAsMinimalStage(); + } + + /** + * Completes this CompletableFuture with the result of + * the given Supplier function invoked from an asynchronous + * task using the given executor. + * + * @param supplier a function returning the value to be used + * to complete this CompletableFuture + * @param executor the executor to use for asynchronous execution + * @return this CompletableFuture + * @since 1.9 + */ + public CompletableFuture<T> completeAsync(Supplier<? extends T> supplier, + Executor executor) { + if (supplier == null || executor == null) + throw new NullPointerException(); + executor.execute(new AsyncSupply<T>(this, supplier)); + return this; + } + + /** + * Completes this CompletableFuture with the result of the given + * Supplier function invoked from an asynchronous task using the + * default executor. + * + * @param supplier a function returning the value to be used + * to complete this CompletableFuture + * @return this CompletableFuture + * @since 1.9 + */ + public CompletableFuture<T> completeAsync(Supplier<? extends T> supplier) { + return completeAsync(supplier, defaultExecutor()); + } + + /** + * Exceptionally completes this CompletableFuture with + * a {@link TimeoutException} if not otherwise completed + * before the given timeout. + * + * @param timeout how long to wait before completing exceptionally + * with a TimeoutException, in units of {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the + * {@code timeout} parameter + * @return this CompletableFuture + * @since 1.9 + */ + public CompletableFuture<T> orTimeout(long timeout, TimeUnit unit) { + if (unit == null) + throw new NullPointerException(); + if (result == null) + whenComplete(new Canceller(Delayer.delay(new Timeout(this), + timeout, unit))); + return this; + } + + /** + * Completes this CompletableFuture with the given value if not + * otherwise completed before the given timeout. + * + * @param value the value to use upon timeout + * @param timeout how long to wait before completing normally + * with the given value, in units of {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the + * {@code timeout} parameter + * @return this CompletableFuture + * @since 1.9 + */ + public CompletableFuture<T> completeOnTimeout(T value, long timeout, + TimeUnit unit) { + if (unit == null) + throw new NullPointerException(); + if (result == null) + whenComplete(new Canceller(Delayer.delay( + new DelayedCompleter<T>(this, value), + timeout, unit))); + return this; + } + + /** + * Returns a new Executor that submits a task to the given base + * executor after the given delay (or no delay if non-positive). + * Each delay commences upon invocation of the returned executor's + * {@code execute} method. + * + * @param delay how long to delay, in units of {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the + * {@code delay} parameter + * @param executor the base executor + * @return the new delayed executor + * @since 1.9 + */ + public static Executor delayedExecutor(long delay, TimeUnit unit, + Executor executor) { + if (unit == null || executor == null) + throw new NullPointerException(); + return new DelayedExecutor(delay, unit, executor); + } + + /** + * Returns a new Executor that submits a task to the default + * executor after the given delay (or no delay if non-positive). + * Each delay commences upon invocation of the returned executor's + * {@code execute} method. + * + * @param delay how long to delay, in units of {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the + * {@code delay} parameter + * @return the new delayed executor + * @since 1.9 + */ + public static Executor delayedExecutor(long delay, TimeUnit unit) { + if (unit == null) + throw new NullPointerException(); + return new DelayedExecutor(delay, unit, ASYNC_POOL); + } + + /** + * Returns a new CompletionStage that is already completed with + * the given value and supports only those methods in + * interface {@link CompletionStage}. + * + * @param value the value + * @param <U> the type of the value + * @return the completed CompletionStage + * @since 1.9 + */ + public static <U> CompletionStage<U> completedStage(U value) { + return new MinimalStage<U>((value == null) ? NIL : value); + } + + /** + * Returns a new CompletableFuture that is already completed + * exceptionally with the given exception. + * + * @param ex the exception + * @param <U> the type of the value + * @return the exceptionally completed CompletableFuture + * @since 1.9 + */ + public static <U> CompletableFuture<U> failedFuture(Throwable ex) { + if (ex == null) throw new NullPointerException(); + return new CompletableFuture<U>(new AltResult(ex)); + } + + /** + * Returns a new CompletionStage that is already completed + * exceptionally with the given exception and supports only those + * methods in interface {@link CompletionStage}. + * + * @param ex the exception + * @param <U> the type of the value + * @return the exceptionally completed CompletionStage + * @since 1.9 + */ + public static <U> CompletionStage<U> failedStage(Throwable ex) { + if (ex == null) throw new NullPointerException(); + return new MinimalStage<U>(new AltResult(ex)); + } + + /** + * Singleton delay scheduler, used only for starting and + * cancelling tasks. + */ + static final class Delayer { + static ScheduledFuture<?> delay(Runnable command, long delay, + TimeUnit unit) { + return delayer.schedule(command, delay, unit); + } + + static final class DaemonThreadFactory implements ThreadFactory { + public Thread newThread(Runnable r) { + Thread t = new Thread(r); + t.setDaemon(true); + t.setName("CompletableFutureDelayScheduler"); + return t; + } + } + + static final ScheduledThreadPoolExecutor delayer; + static { + (delayer = new ScheduledThreadPoolExecutor( + 1, new DaemonThreadFactory())). + setRemoveOnCancelPolicy(true); + } + } + + // Little class-ified lambdas to better support monitoring + + static final class DelayedExecutor implements Executor { + final long delay; + final TimeUnit unit; + final Executor executor; + DelayedExecutor(long delay, TimeUnit unit, Executor executor) { + this.delay = delay; this.unit = unit; this.executor = executor; + } + public void execute(Runnable r) { + Delayer.delay(new TaskSubmitter(executor, r), delay, unit); + } + } + + /** Action to submit user task */ + static final class TaskSubmitter implements Runnable { + final Executor executor; + final Runnable action; + TaskSubmitter(Executor executor, Runnable action) { + this.executor = executor; + this.action = action; + } + public void run() { executor.execute(action); } + } + + /** Action to completeExceptionally on timeout */ + static final class Timeout implements Runnable { + final CompletableFuture<?> f; + Timeout(CompletableFuture<?> f) { this.f = f; } + public void run() { + if (f != null && !f.isDone()) + f.completeExceptionally(new TimeoutException()); + } + } + + /** Action to complete on timeout */ + static final class DelayedCompleter<U> implements Runnable { + final CompletableFuture<U> f; + final U u; + DelayedCompleter(CompletableFuture<U> f, U u) { this.f = f; this.u = u; } + public void run() { + if (f != null) + f.complete(u); + } + } + + /** Action to cancel unneeded timeouts */ + static final class Canceller implements BiConsumer<Object, Throwable> { + final Future<?> f; + Canceller(Future<?> f) { this.f = f; } + public void accept(Object ignore, Throwable ex) { + if (ex == null && f != null && !f.isDone()) + f.cancel(false); + } + } + + /** + * A subclass that just throws UOE for most non-CompletionStage methods. + */ + static final class MinimalStage<T> extends CompletableFuture<T> { + MinimalStage() { } + MinimalStage(Object r) { super(r); } + @Override public <U> CompletableFuture<U> newIncompleteFuture() { + return new MinimalStage<U>(); } + @Override public T get() { + throw new UnsupportedOperationException(); } + @Override public T get(long timeout, TimeUnit unit) { + throw new UnsupportedOperationException(); } + @Override public T getNow(T valueIfAbsent) { + throw new UnsupportedOperationException(); } + @Override public T join() { + throw new UnsupportedOperationException(); } + @Override public boolean complete(T value) { + throw new UnsupportedOperationException(); } + @Override public boolean completeExceptionally(Throwable ex) { + throw new UnsupportedOperationException(); } + @Override public boolean cancel(boolean mayInterruptIfRunning) { + throw new UnsupportedOperationException(); } + @Override public void obtrudeValue(T value) { + throw new UnsupportedOperationException(); } + @Override public void obtrudeException(Throwable ex) { + throw new UnsupportedOperationException(); } + @Override public boolean isDone() { + throw new UnsupportedOperationException(); } + @Override public boolean isCancelled() { + throw new UnsupportedOperationException(); } + @Override public boolean isCompletedExceptionally() { + throw new UnsupportedOperationException(); } + @Override public int getNumberOfDependents() { + throw new UnsupportedOperationException(); } + @Override public CompletableFuture<T> completeAsync + (Supplier<? extends T> supplier, Executor executor) { + throw new UnsupportedOperationException(); } + @Override public CompletableFuture<T> completeAsync + (Supplier<? extends T> supplier) { + throw new UnsupportedOperationException(); } + @Override public CompletableFuture<T> orTimeout + (long timeout, TimeUnit unit) { + throw new UnsupportedOperationException(); } + @Override public CompletableFuture<T> completeOnTimeout + (T value, long timeout, TimeUnit unit) { + throw new UnsupportedOperationException(); } + } + // Unsafe mechanics - private static final sun.misc.Unsafe UNSAFE; + private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe(); private static final long RESULT; private static final long STACK; private static final long NEXT; static { try { - final sun.misc.Unsafe u; - UNSAFE = u = sun.misc.Unsafe.getUnsafe(); - Class<?> k = CompletableFuture.class; - RESULT = u.objectFieldOffset(k.getDeclaredField("result")); - STACK = u.objectFieldOffset(k.getDeclaredField("stack")); - NEXT = u.objectFieldOffset + RESULT = U.objectFieldOffset + (CompletableFuture.class.getDeclaredField("result")); + STACK = U.objectFieldOffset + (CompletableFuture.class.getDeclaredField("stack")); + NEXT = U.objectFieldOffset (Completion.class.getDeclaredField("next")); - } catch (Exception x) { - throw new Error(x); + } 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/src/java.base/share/classes/java/util/concurrent/CompletionStage.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/concurrent/CompletionStage.java Wed Oct 21 15:16:00 2015 -0700 @@ -34,12 +34,11 @@ */ package java.util.concurrent; -import java.util.function.Supplier; + +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.BiFunction; -import java.util.concurrent.Executor; /** * A stage of a possibly asynchronous computation, that performs an @@ -56,9 +55,9 @@ * For example, {@code stage.thenApply(x -> square(x)).thenAccept(x -> * System.out.print(x)).thenRun(() -> System.out.println())}. An * additional form (<em>compose</em>) applies functions of stages - * themselves, rather than their results. </li> + * themselves, rather than their results. * - * <li> One stage's execution may be triggered by completion of a + * <li>One stage's execution may be triggered by completion of a * single stage, or both of two stages, or either of two stages. * Dependencies on a single stage are arranged using methods with * prefix <em>then</em>. Those triggered by completion of @@ -66,9 +65,9 @@ * effects, using correspondingly named methods. Those triggered by * <em>either</em> of two stages make no guarantees about which of the * results or effects are used for the dependent stage's - * computation.</li> + * computation. * - * <li> Dependencies among stages control the triggering of + * <li>Dependencies among stages control the triggering of * computations, but do not otherwise guarantee any particular * ordering. Additionally, execution of a new stage's computations may * be arranged in any of three ways: default execution, default @@ -81,7 +80,7 @@ * properties, and might not even support concurrent execution, but * are arranged for processing in a way that accommodates asynchrony. * - * <li> Two method forms support processing whether the triggering + * <li>Two method forms support processing whether the triggering * stage completed normally or exceptionally: Method {@link * #whenComplete whenComplete} allows injection of an action * regardless of outcome, otherwise preserving the outcome in its @@ -100,7 +99,7 @@ * stage completes normally or exceptionally. In the case of method * {@code whenComplete}, when the supplied action itself encounters an * exception, then the stage exceptionally completes with this - * exception if not already completed exceptionally.</li> + * exception if not already completed exceptionally. * * </ul> * @@ -587,7 +586,7 @@ /** * Returns a new CompletionStage that, when this stage completes - * normally, is executed with this stage as the argument + * normally, is executed with this stage's result as the argument * to the supplied function. * * See the {@link CompletionStage} documentation for rules @@ -603,7 +602,7 @@ /** * Returns a new CompletionStage that, when this stage completes * normally, is executed using this stage's default asynchronous - * execution facility, with this stage as the argument to the + * execution facility, with this stage's result as the argument to the * supplied function. * * See the {@link CompletionStage} documentation for rules @@ -652,12 +651,14 @@ * Returns a new CompletionStage with the same result or exception as * this stage, that executes the given action when this stage completes. * - * <p>When this stage is complete, the given action is invoked with the - * result (or {@code null} if none) and the exception (or {@code null} - * if none) of this stage as arguments. The returned stage is completed - * when the action returns. If the supplied action itself encounters an - * exception, then the returned stage exceptionally completes with this - * exception unless this stage also completed exceptionally. + * <p>When this stage is complete, the given action is invoked + * with the result (or {@code null} if none) and the exception (or + * {@code null} if none) of this stage as arguments. The returned + * stage is completed when the action returns. If the supplied + * action itself encounters an exception, then the returned stage + * exceptionally completes with this exception unless this stage + * also completed exceptionally (in which case, the returned stage + * exceptionally completes with the original exception). * * @param action the action to perform * @return the new CompletionStage
--- a/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java Wed Oct 21 15:16:00 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/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java Wed Oct 21 15:16:00 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/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java Wed Oct 21 15:16:00 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); - } + /** + * 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; + } - boolean casItem(E cmp, E val) { - return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val); - } + static <E> boolean casItem(Node<E> node, E cmp, E val) { + return U.compareAndSwapObject(node, ITEM, cmp, val); + } - void lazySetNext(Node<E> val) { - UNSAFE.putOrderedObject(this, nextOffset, val); - } + static <E> void lazySetNext(Node<E> node, Node<E> val) { + U.putOrderedObject(node, NEXT, 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; - - 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 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/src/java.base/share/classes/java/util/concurrent/ConcurrentMap.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentMap.java Wed Oct 21 15:16:00 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/src/java.base/share/classes/java/util/concurrent/ConcurrentNavigableMap.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentNavigableMap.java Wed Oct 21 15:16:00 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/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java Wed Oct 21 15:16:00 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 Iterator<V> iterator() { + return (m instanceof ConcurrentSkipListMap) + ? ((ConcurrentSkipListMap<K,V>)m).new ValueIterator() + : ((SubMap<K,V>)m).new SubMapValueIterator(); } - public boolean isEmpty() { - return m.isEmpty(); - } - 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/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListSet.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListSet.java Wed Oct 21 15:16:00 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/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java Wed Oct 21 15:16:00 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/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArraySet.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArraySet.java Wed Oct 21 15:16:00 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/src/java.base/share/classes/java/util/concurrent/CountDownLatch.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/concurrent/CountDownLatch.java Wed Oct 21 15:16:00 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/src/java.base/share/classes/java/util/concurrent/CountedCompleter.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/concurrent/CountedCompleter.java Wed Oct 21 15:16:00 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/src/java.base/share/classes/java/util/concurrent/CyclicBarrier.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/concurrent/CyclicBarrier.java Wed Oct 21 15:16:00 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/src/java.base/share/classes/java/util/concurrent/DelayQueue.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/concurrent/DelayQueue.java Wed Oct 21 15:16:00 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/src/java.base/share/classes/java/util/concurrent/Exchanger.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/concurrent/Exchanger.java Wed Oct 21 15:16:00 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/src/java.base/share/classes/java/util/concurrent/Executor.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/concurrent/Executor.java Wed Oct 21 15:16:00 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/src/java.base/share/classes/java/util/concurrent/ExecutorCompletionService.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/concurrent/ExecutorCompletionService.java Wed Oct 21 15:16:00 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/src/java.base/share/classes/java/util/concurrent/ExecutorService.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/concurrent/ExecutorService.java Wed Oct 21 15:16:00 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/src/java.base/share/classes/java/util/concurrent/Executors.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/concurrent/Executors.java Wed Oct 21 15:16:00 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;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.base/share/classes/java/util/concurrent/Flow.java Wed Oct 21 15:16:00 2015 -0700 @@ -0,0 +1,319 @@ +/* + * 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 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/ + */ + +package java.util.concurrent; + +/** + * Interrelated interfaces and static methods for establishing + * flow-controlled components in which {@link Publisher Publishers} + * produce items consumed by one or more {@link Subscriber + * Subscribers}, each managed by a {@link Subscription + * Subscription}. + * + * <p>These interfaces correspond to the <a + * href="http://www.reactive-streams.org/"> reactive-streams</a> + * specification. They apply in both concurrent and distributed + * asynchronous settings: All (seven) methods are defined in {@code + * void} "one-way" message style. Communication relies on a simple form + * of flow control (method {@link Subscription#request}) that can be + * used to avoid resource management problems that may otherwise occur + * in "push" based systems. + * + * <p><b>Examples.</b> A {@link Publisher} usually defines its own + * {@link Subscription} implementation; constructing one in method + * {@code subscribe} and issuing it to the calling {@link + * Subscriber}. It publishes items to the subscriber asynchronously, + * normally using an {@link Executor}. For example, here is a very + * simple publisher that only issues (when requested) a single {@code + * TRUE} item to a single subscriber. Because the subscriber receives + * only a single item, this class does not use buffering and ordering + * control required in most implementations (for example {@link + * SubmissionPublisher}). + * + * <pre> {@code + * class OneShotPublisher implements Publisher<Boolean> { + * private final ExecutorService executor = ForkJoinPool.commonPool(); // daemon-based + * private boolean subscribed; // true after first subscribe + * public synchronized void subscribe(Subscriber<? super Boolean> subscriber) { + * if (subscribed) + * subscriber.onError(new IllegalStateException()); // only one allowed + * else { + * subscribed = true; + * subscriber.onSubscribe(new OneShotSubscription(subscriber, executor)); + * } + * } + * static class OneShotSubscription implements Subscription { + * private final Subscriber<? super Boolean> subscriber; + * private final ExecutorService executor; + * private Future<?> future; // to allow cancellation + * private boolean completed; + * OneShotSubscription(Subscriber<? super Boolean> subscriber, + * ExecutorService executor) { + * this.subscriber = subscriber; + * this.executor = executor; + * } + * public synchronized void request(long n) { + * if (n != 0 && !completed) { + * completed = true; + * if (n < 0) { + * IllegalArgumentException ex = new IllegalArgumentException(); + * executor.execute(() -> subscriber.onError(ex)); + * } else { + * future = executor.submit(() -> { + * subscriber.onNext(Boolean.TRUE); + * subscriber.onComplete(); + * }); + * } + * } + * } + * public synchronized void cancel() { + * completed = true; + * if (future != null) future.cancel(false); + * } + * } + * }}</pre> + * + * <p>A {@link Subscriber} arranges that items be requested and + * processed. Items (invocations of {@link Subscriber#onNext}) are + * not issued unless requested, but multiple items may be requested. + * Many Subscriber implementations can arrange this in the style of + * the following example, where a buffer size of 1 single-steps, and + * larger sizes usually allow for more efficient overlapped processing + * with less communication; for example with a value of 64, this keeps + * total outstanding requests between 32 and 64. + * Because Subscriber method invocations for a given {@link + * Subscription} are strictly ordered, there is no need for these + * methods to use locks or volatiles unless a Subscriber maintains + * multiple Subscriptions (in which case it is better to instead + * define multiple Subscribers, each with its own Subscription). + * + * <pre> {@code + * class SampleSubscriber<T> implements Subscriber<T> { + * final Consumer<? super T> consumer; + * Subscription subscription; + * final long bufferSize; + * long count; + * SampleSubscriber(long bufferSize, Consumer<? super T> consumer) { + * this.bufferSize = bufferSize; + * this.consumer = consumer; + * } + * public void onSubscribe(Subscription subscription) { + * long initialRequestSize = bufferSize; + * count = bufferSize - bufferSize / 2; // re-request when half consumed + * (this.subscription = subscription).request(initialRequestSize); + * } + * public void onNext(T item) { + * if (--count <= 0) + * subscription.request(count = bufferSize - bufferSize / 2); + * consumer.accept(item); + * } + * public void onError(Throwable ex) { ex.printStackTrace(); } + * public void onComplete() {} + * }}</pre> + * + * <p>The default value of {@link #defaultBufferSize} may provide a + * useful starting point for choosing request sizes and capacities in + * Flow components based on expected rates, resources, and usages. + * Or, when flow control is never needed, a subscriber may initially + * request an effectively unbounded number of items, as in: + * + * <pre> {@code + * class UnboundedSubscriber<T> implements Subscriber<T> { + * public void onSubscribe(Subscription subscription) { + * subscription.request(Long.MAX_VALUE); // effectively unbounded + * } + * public void onNext(T item) { use(item); } + * public void onError(Throwable ex) { ex.printStackTrace(); } + * public void onComplete() {} + * void use(T item) { ... } + * }}</pre> + * + * @author Doug Lea + * @since 1.9 + */ +public final class Flow { + + private Flow() {} // uninstantiable + + /** + * A producer of items (and related control messages) received by + * Subscribers. Each current {@link Subscriber} receives the same + * items (via method {@code onNext}) in the same order, unless + * drops or errors are encountered. If a Publisher encounters an + * error that does not allow items to be issued to a Subscriber, + * that Subscriber receives {@code onError}, and then receives no + * further messages. Otherwise, when it is known that no further + * messages will be issued to it, a subscriber receives {@code + * onComplete}. Publishers ensure that Subscriber method + * invocations for each subscription are strictly ordered in <a + * href="package-summary.html#MemoryVisibility"><i>happens-before</i></a> + * order. + * + * <p>Publishers may vary in policy about whether drops (failures + * to issue an item because of resource limitations) are treated + * as unrecoverable errors. Publishers may also vary about + * whether Subscribers receive items that were produced or + * available before they subscribed. + * + * @param <T> the published item type + */ + @FunctionalInterface + public static interface Publisher<T> { + /** + * Adds the given Subscriber if possible. If already + * subscribed, or the attempt to subscribe fails due to policy + * violations or errors, the Subscriber's {@code onError} + * method is invoked with an {@link IllegalStateException}. + * Otherwise, the Subscriber's {@code onSubscribe} method is + * invoked with a new {@link Subscription}. Subscribers may + * enable receiving items by invoking the {@code request} + * method of this Subscription, and may unsubscribe by + * invoking its {@code cancel} method. + * + * @param subscriber the subscriber + * @throws NullPointerException if subscriber is null + */ + public void subscribe(Subscriber<? super T> subscriber); + } + + /** + * A receiver of messages. The methods in this interface are + * invoked in strict sequential order for each {@link + * Subscription}. + * + * @param <T> the subscribed item type + */ + public static interface Subscriber<T> { + /** + * Method invoked prior to invoking any other Subscriber + * methods for the given Subscription. If this method throws + * an exception, resulting behavior is not guaranteed, but may + * cause the Subscription not to be established or to be cancelled. + * + * <p>Typically, implementations of this method invoke {@code + * subscription.request} to enable receiving items. + * + * @param subscription a new subscription + */ + public void onSubscribe(Subscription subscription); + + /** + * Method invoked with a Subscription's next item. If this + * method throws an exception, resulting behavior is not + * guaranteed, but may cause the Subscription to be cancelled. + * + * @param item the item + */ + public void onNext(T item); + + /** + * Method invoked upon an unrecoverable error encountered by a + * Publisher or Subscription, after which no other Subscriber + * methods are invoked by the Subscription. If this method + * itself throws an exception, resulting behavior is + * undefined. + * + * @param throwable the exception + */ + public void onError(Throwable throwable); + + /** + * Method invoked when it is known that no additional + * Subscriber method invocations will occur for a Subscription + * that is not already terminated by error, after which no + * other Subscriber methods are invoked by the Subscription. + * If this method throws an exception, resulting behavior is + * undefined. + */ + public void onComplete(); + } + + /** + * Message control linking a {@link Publisher} and {@link + * Subscriber}. Subscribers receive items only when requested, + * and may cancel at any time. The methods in this interface are + * intended to be invoked only by their Subscribers; usages in + * other contexts have undefined effects. + */ + public static interface Subscription { + /** + * Adds the given number {@code n} of items to the current + * unfulfilled demand for this subscription. If {@code n} is + * negative, the Subscriber will receive an {@code onError} + * signal with an {@link IllegalArgumentException} argument. + * Otherwise, the Subscriber will receive up to {@code n} + * additional {@code onNext} invocations (or fewer if + * terminated). + * + * @param n the increment of demand; a value of {@code + * Long.MAX_VALUE} may be considered as effectively unbounded + */ + public void request(long n); + + /** + * Causes the Subscriber to (eventually) stop receiving + * messages. Implementation is best-effort -- additional + * messages may be received after invoking this method. + * A cancelled subscription need not ever receive an + * {@code onComplete} or {@code onError} signal. + */ + public void cancel(); + } + + /** + * A component that acts as both a Subscriber and Publisher. + * + * @param <T> the subscribed item type + * @param <R> the published item type + */ + public static interface Processor<T,R> extends Subscriber<T>, Publisher<R> { + } + + static final int DEFAULT_BUFFER_SIZE = 256; + + /** + * Returns a default value for Publisher or Subscriber buffering, + * that may be used in the absence of other constraints. + * + * @implNote + * The current value returned is 256. + * + * @return the buffer size value + */ + public static int defaultBufferSize() { + return DEFAULT_BUFFER_SIZE; + } + +}
--- a/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java Mon Oct 19 00:25:06 2015 -0700 +++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java Wed Oct 21 15:16:00 2015 -0700 @@ -36,23 +36,16 @@ package java.util.concurrent; import java.lang.Thread.UncaughtExceptionHandler; +import java.security.AccessControlContext; +import java.security.Permissions; +import java.security.ProtectionDomain; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.concurrent.AbstractExecutorService; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Future; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.RunnableFuture; -import java.util.concurrent.ThreadLocalRandom; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; -import java.security.AccessControlContext; -import java.security.ProtectionDomain; -import java.security.Permissions; +import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.locks.LockSupport; /** * An {@link ExecutorService} for running {@link ForkJoinTask}s. @@ -216,42 +209,60 @@ * arbitrating pop vs poll (steal) from being on the indices * ("base" and "top") to the slots themselves. * - * Adding tasks then takes the form of a classic array push(task): - * q.array[q.top] = task; ++q.top; + * Adding tasks then takes the form of a classic array push(task) + * in a circular buffer: + * q.array[q.top++ % length] = task; * * (The actual code needs to null-check and size-check the array, - * properly fence the accesses, and possibly signal waiting - * workers to start scanning -- see below.) Both a successful pop - * and poll mainly entail a CAS of a slot from non-null to null. + * uses masking, not mod, for indexing a power-of-two-sized array, + * properly fences accesses, and possibly signals waiting workers + * to start scanning -- see below.) Both a successful pop and + * poll mainly entail a CAS of a slot from non-null to null. * * The pop operation (always performed by owner) is: - * if ((base != top) and - * (the task at top slot is not null) and + * if ((the task at top slot is not null) and * (CAS slot to null)) * decrement top and return task; * * And the poll operation (usually by a stealer) is - * if ((base != top) and - * (the task at base slot is not null) and - * (base has not changed) and + * if ((the task at base slot is not null) and * (CAS slot to null)) * increment base and return task; * - * Because we rely on CASes of references, we do not need tag bits - * on base or top. They are simple ints as used in any circular - * array-based queue (see for example ArrayDeque). Updates to the - * indices guarantee that top == base means the queue is empty, - * but otherwise may err on the side of possibly making the queue - * appear nonempty when a push, pop, or poll have not fully - * committed. (Method isEmpty() checks the case of a partially + * There are several variants of each of these; for example most + * versions of poll pre-screen the CAS by rechecking that the base + * has not changed since reading the slot, and most methods only + * attempt the CAS if base appears not to be equal to top. + * + * Memory ordering. See "Correct and Efficient Work-Stealing for + * Weak Memory Models" by Le, Pop, Cohen, and Nardelli, PPoPP 2013 + * (http://www.di.ens.fr/~zappa/readings/ppopp13.pdf) for an + * analysis of memory ordering requirements in work-stealing + * algorithms similar to (but different than) the one used here. + * Extracting tasks in array slots via (fully fenced) CAS provides + * primary synchronization. The base and top indices imprecisely + * guide where to extract from. We do not always require strict + * orderings of array and index updates, so sometimes let them be + * subject to compiler and processor reorderings. However, the + * volatile "base" index also serves as a basis for memory + * ordering: Slot accesses are preceded by a read of base, + * ensuring happens-before ordering with respect to stealers (so + * the slots themselves can be read via plain array reads.) The + * only other memory orderings relied on are maintained in the + * course of signalling and activation (see below). A check that + * base == top indicates (momentary) emptiness, but otherwise may + * err on the side of possibly making the queue appear nonempty + * when a push, pop, or poll have not fully committed, or making + * it appear empty when an update of top has not yet been visibly + * written. (Method isEmpty() checks the case of a partially * completed removal of the last element.) Because of this, the * poll operation, considered individually, is not wait-free. One * thief cannot successfully continue until another in-progress - * one (or, if previously empty, a push) completes. However, in - * the aggregate, we ensure at least probabilistic - * non-blockingness. If an attempted steal fails, a thief always - * chooses a different random victim target to try next. So, in - * order for one thief to progress, it suffices for any + * one (or, if previously empty, a push) visibly completes. + * However, in the aggregate, we ensure at least probabilistic + * non-blockingness. If an attempted steal fails, a scanning + * thief chooses a different random victim target to try next. So, + * in order for one thief to progress, it suffices for any * in-progress poll or new push on any empty queue to * complete. (This is why we normally use method pollAt and its * variants that try once at the apparent base index, else @@ -262,19 +273,6 @@ * local task processing is in FIFO, not LIFO order, simply by * using poll rather than pop. This can be useful in * message-passing frameworks in which tasks are never joined. - * However neither mode considers affinities, loads, cache - * localities, etc, so rarely provide the best possible - * performance on a given machine, but portably provide good - * throughput by averaging over these factors. Further, even if - * we did try to use such information, we do not usually have a - * basis for exploiting it. For example, some sets of tasks - * profit from cache affinities, but others are harmed by cache - * pollution effects. Additionally, even though it requires - * scanning, long-term throughput is often best using random - * selection rather than directed selection policies, so cheap - * randomization of sufficient quality is used whenever - * applicable. Various Marsaglia XorShifts (some with different - * shift constants) are inlined at use points. * * WorkQueues are also used in a similar way for tasks submitted * to the pool. We cannot mix these tasks in the same queues used @@ -286,14 +284,14 @@ * like workers except that they are restricted to executing local * tasks that they submitted (or in the case of CountedCompleters, * others with the same root task). Insertion of tasks in shared - * mode requires a lock (mainly to protect in the case of - * resizing) but we use only a simple spinlock (using field - * qlock), because submitters encountering a busy queue move on to - * try or create other queues -- they block only when creating and - * registering new queues. Additionally, "qlock" saturates to an - * unlockable value (-1) at shutdown. Unlocking still can be and - * is performed by cheaper ordered writes of "qlock" in successful - * cases, but uses CAS in unsuccessful cases. + * mode requires a lock but we use only a simple spinlock (using + * field qlock), because submitters encountering a busy queue move + * on to try or create other queues -- they block only when + * creating and registering new queues. Because it is used only as + * a spinlock, unlocking requires only a "releasing" store (using + * putOrderedInt). The qlock is also used during termination + * detection, in which case it is forced to a negative + * non-lockable value. * * Management * ========== @@ -320,46 +318,36 @@ * and their negations (used for thresholding) to fit into 16bit * subfields. * - * Field "runState" holds lockable state bits (STARTED, STOP, etc) - * also protecting updates to the workQueues array. When used as - * a lock, it is normally held only for a few instructions (the - * only exceptions are one-time array initialization and uncommon - * resizing), so is nearly always available after at most a brief - * spin. But to be extra-cautious, after spinning, method - * awaitRunStateLock (called only if an initial CAS fails), uses a - * wait/notify mechanics on a builtin monitor to block when - * (rarely) needed. This would be a terrible idea for a highly - * contended lock, but most pools run without the lock ever - * contending after the spin limit, so this works fine as a more - * conservative alternative. Because we don't otherwise have an - * internal Object to use as a monitor, the "stealCounter" (an - * AtomicLong) is used when available (it too must be lazily - * initialized; see externalSubmit). + * Field "runState" holds lifetime status, atomically and + * monotonically setting STARTED, SHUTDOWN, STOP, and finally + * TERMINATED bits. * - * Usages of "runState" vs "ctl" interact in only one case: - * deciding to add a worker thread (see tryAddWorker), in which - * case the ctl CAS is performed while the lock is held. + * Field "auxState" is a ReentrantLock subclass that also + * opportunistically holds some other bookkeeping fields accessed + * only when locked. It is mainly used to lock (infrequent) + * updates to workQueues. The auxState instance is itself lazily + * constructed (see tryInitialize), requiring a double-check-style + * bootstrapping use of field runState, and locking a private + * static. * - * Recording WorkQueues. WorkQueues are recorded in the - * "workQueues" array. The array is created upon first use (see - * externalSubmit) and expanded if necessary. Updates to the - * array while recording new workers and unrecording terminated - * ones are protected from each other by the runState lock, but - * the array is otherwise concurrently readable, and accessed + * Field "workQueues" holds references to WorkQueues. It is + * updated (only during worker creation and termination) under the + * lock, but is otherwise concurrently readable, and accessed * directly. We also ensure that reads of the array reference - * itself never become too stale. To simplify index-based - * operations, the array size is always a power of two, and all - * readers must tolerate null slots. Worker queues are at odd - * indices. Shared (submission) queues are at even indices, up to - * a maximum of 64 slots, to limit growth even if array needs to - * expand to add more workers. Grouping them together in this way - * simplifies and speeds up task scanning. + * itself never become too stale (for example, re-reading before + * each scan). To simplify index-based operations, the array size + * is always a power of two, and all readers must tolerate null + * slots. Worker queues are at odd indices. Shared (submission) + * queues are at even indices, up to a maximum of 64 slots, to + * limit growth even if array needs to expand to add more + * workers. Grouping them together in this way simplifies and + * speeds up task scanning. * * All worker thread creation is on-demand, triggered by task * submissions, replacement of terminated workers, and/or * compensation for blocked workers. However, all other support * code is set up to work with other policies. To ensure that we - * do not hold on to worker references that would prevent GC, All + * do not hold on to worker references that would prevent GC, all * accesses to workQueues are via indices into the workQueues * array (which is one source of some of the messy code * constructions here). In essence, the workQueues array serves as @@ -386,7 +374,7 @@ * activating threads in most-recently used order. This improves * performance and locality, outweighing the disadvantages of * being prone to contention and inability to release a worker - * unless it is topmost on stack. We park/unpark workers after + * unless it is topmost on stack. We block/unblock workers after * pushing on the idle worker stack (represented by the lower * 32bit subfield of ctl) when they cannot find work. The top * stack state holds the value of the "scanState" field of the @@ -394,48 +382,14 @@ * addition to the count subfields (also serving as version * stamps) provide protection against Treiber stack ABA effects. * - * Field scanState is used by both workers and the pool to manage - * and track whether a worker is INACTIVE (possibly blocked - * waiting for a signal), or SCANNING for tasks (when neither hold - * it is busy running tasks). When a worker is inactivated, its - * scanState field is set, and is prevented from executing tasks, - * even though it must scan once for them to avoid queuing - * races. Note that scanState updates lag queue CAS releases so - * usage requires care. When queued, the lower 16 bits of - * scanState must hold its pool index. So we place the index there - * upon initialization (see registerWorker) and otherwise keep it - * there or restore it when necessary. - * - * Memory ordering. See "Correct and Efficient Work-Stealing for - * Weak Memory Models" by Le, Pop, Cohen, and Nardelli, PPoPP 2013 - * (http://www.di.ens.fr/~zappa/readings/ppopp13.pdf) for an - * analysis of memory ordering requirements in work-stealing - * algorithms similar to the one used here. We usually need - * stronger than minimal ordering because we must sometimes signal - * workers, requiring Dekker-like full-fences to avoid lost - * signals. Arranging for enough ordering without expensive - * over-fencing requires tradeoffs among the supported means of - * expressing access constraints. The most central operations, - * taking from queues and updating ctl state, require full-fence - * CAS. Array slots are read using the emulation of volatiles - * provided by Unsafe. Access from other threads to WorkQueue - * base, top, and array requires a volatile load of the first of - * any of these read. We use the convention of declaring the - * "base" index volatile, and always read it before other fields. - * The owner thread must ensure ordered updates, so writes use - * ordered intrinsics unless they can piggyback on those for other - * writes. Similar conventions and rationales hold for other - * WorkQueue fields (such as "currentSteal") that are only written - * by owners but observed by others. - * * Creating workers. To create a worker, we pre-increment total * count (serving as a reservation), and attempt to construct a * ForkJoinWorkerThread via its factory. Upon construction, the * new thread invokes registerWorker, where it constructs a * WorkQueue and is assigned an index in the workQueues array - * (expanding the array if necessary). The thread is then - * started. Upon any exception across these steps, or null return - * from factory, deregisterWorker adjusts counts and records + * (expanding the array if necessary). The thread is then started. + * Upon any exception across these steps, or null return from + * factory, deregisterWorker adjusts counts and records * accordingly. If a null return, the pool continues running with * fewer than the target number workers. If exceptional, the * exception is propagated, generally to some external caller. @@ -448,80 +402,106 @@ * probability of collision low. We cannot use * ThreadLocalRandom.getProbe() for similar purposes here because * the thread has not started yet, but do so for creating - * submission queues for existing external threads. + * submission queues for existing external threads (see + * externalPush). + * + * WorkQueue field scanState is used by both workers and the pool + * to manage and track whether a worker is UNSIGNALLED (possibly + * blocked waiting for a signal). When a worker is inactivated, + * its scanState field is set, and is prevented from executing + * tasks, even though it must scan once for them to avoid queuing + * races. Note that scanState updates lag queue CAS releases so + * usage requires care. When queued, the lower 16 bits of + * scanState must hold its pool index. So we place the index there + * upon initialization (see registerWorker) and otherwise keep it + * there or restore it when necessary. + * + * The ctl field also serves as the basis for memory + * synchronization surrounding activation. This uses a more + * efficient version of a Dekker-like rule that task producers and + * consumers sync with each other by both writing/CASing ctl (even + * if to its current value). This would be extremely costly. So + * we relax it in several ways: (1) Producers only signal when + * their queue is empty. Other workers propagate this signal (in + * method scan) when they find tasks. (2) Workers only enqueue + * after scanning (see below) and not finding any tasks. (3) + * Rather than CASing ctl to its current value in the common case + * where no action is required, we reduce write contention by + * equivalently prefacing signalWork when called by an external + * task producer using a memory access with full-volatile + * semantics or a "fullFence". (4) For internal task producers we + * rely on the fact that even if no other workers awaken, the + * producer itself will eventually see the task and execute it. + * + * Almost always, too many signals are issued. A task producer + * cannot in general tell if some existing worker is in the midst + * of finishing one task (or already scanning) and ready to take + * another without being signalled. So the producer might instead + * activate a different worker that does not find any work, and + * then inactivates. This scarcely matters in steady-state + * computations involving all workers, but can create contention + * and bookkeeping bottlenecks during ramp-up, ramp-down, and small + * computations involving only a few workers. + * + * Scanning. Method scan() performs top-level scanning for tasks. + * Each scan traverses (and tries to poll from) each queue in + * pseudorandom permutation order by randomly selecting an origin + * index and a step value. (The pseudorandom generator need not + * have high-quality statistical properties in the long term, but + * just within computations; We use 64bit and 32bit Marsaglia + * XorShifts, which are cheap and suffice here.) Scanning also + * employs contention reduction: When scanning workers fail a CAS + * polling for work, they soon restart with a different + * pseudorandom scan order (thus likely retrying at different + * intervals). This improves throughput when many threads are + * trying to take tasks from few queues. Scans do not otherwise + * explicitly take into account core affinities, loads, cache + * localities, etc, However, they do exploit temporal locality + * (which usually approximates these) by preferring to re-poll (up + * to POLL_LIMIT times) from the same queue after a successful + * poll before trying others. Restricted forms of scanning occur + * in methods helpComplete and findNonEmptyStealQueue, and take + * similar but simpler forms. * * Deactivation and waiting. Queuing encounters several intrinsic - * races; most notably that a task-producing thread can miss - * seeing (and signalling) another thread that gave up looking for - * work but has not yet entered the wait queue. When a worker - * cannot find a task to steal, it deactivates and enqueues. Very - * often, the lack of tasks is transient due to GC or OS - * scheduling. To reduce false-alarm deactivation, scanners - * compute checksums of queue states during sweeps. (The - * stability checks used here and elsewhere are probabilistic - * variants of snapshot techniques -- see Herlihy & Shavit.) - * Workers give up and try to deactivate only after the sum is - * stable across scans. Further, to avoid missed signals, they - * repeat this scanning process after successful enqueuing until - * again stable. In this state, the worker cannot take/run a task - * it sees until it is released from the queue, so the worker - * itself eventually tries to release itself or any successor (see - * tryRelease). Otherwise, upon an empty scan, a deactivated - * worker uses an adaptive local spin construction (see awaitWork) - * before blocking (via park). Note the unusual conventions about - * Thread.interrupts surrounding parking and other blocking: - * Because interrupts are used solely to alert threads to check - * termination, which is checked anyway upon blocking, we clear - * status (using Thread.interrupted) before any call to park, so - * that park does not immediately return due to status being set - * via some other unrelated call to interrupt in user code. + * races; most notably that an inactivating scanning worker can + * miss seeing a task produced during a scan. So when a worker + * cannot find a task to steal, it inactivates and enqueues, and + * then rescans to ensure that it didn't miss one, reactivating + * upon seeing one with probability approximately proportional to + * probability of a miss. (In most cases, the worker will be + * signalled before self-signalling, avoiding cascades of multiple + * signals for the same task). * - * Signalling and activation. Workers are created or activated - * only when there appears to be at least one task they might be - * able to find and execute. Upon push (either by a worker or an - * external submission) to a previously (possibly) empty queue, - * workers are signalled if idle, or created if fewer exist than - * the given parallelism level. These primary signals are - * buttressed by others whenever other threads remove a task from - * a queue and notice that there are other tasks there as well. - * On most platforms, signalling (unpark) overhead time is - * noticeably long, and the time between signalling a thread and - * it actually making progress can be very noticeably long, so it - * is worth offloading these delays from critical paths as much as - * possible. Also, because inactive workers are often rescanning - * or spinning rather than blocking, we set and clear the "parker" - * field of WorkQueues to reduce unnecessary calls to unpark. - * (This requires a secondary recheck to avoid missed signals.) + * Workers block (in method awaitWork) using park/unpark; + * advertising the need for signallers to unpark by setting their + * "parker" fields. * * Trimming workers. To release resources after periods of lack of * use, a worker starting to wait when the pool is quiescent will * time out and terminate (see awaitWork) if the pool has remained - * quiescent for period IDLE_TIMEOUT, increasing the period as the - * number of threads decreases, eventually removing all workers. - * Also, when more than two spare threads exist, excess threads - * are immediately terminated at the next quiescent point. - * (Padding by two avoids hysteresis.) + * quiescent for period given by IDLE_TIMEOUT_MS, increasing the + * period as the number of threads decreases, eventually removing + * all workers. * * Shutdown and Termination. A call to shutdownNow invokes * tryTerminate to atomically set a runState bit. The calling * thread, as well as every other worker thereafter terminating, * helps terminate others by setting their (qlock) status, * cancelling their unprocessed tasks, and waking them up, doing - * so repeatedly until stable (but with a loop bounded by the - * number of workers). Calls to non-abrupt shutdown() preface - * this by checking whether termination should commence. This - * relies primarily on the active count bits of "ctl" maintaining - * consensus -- tryTerminate is called from awaitWork whenever - * quiescent. However, external submitters do not take part in - * this consensus. So, tryTerminate sweeps through queues (until - * stable) to ensure lack of in-flight submissions and workers - * about to process them before triggering the "STOP" phase of - * termination. (Note: there is an intrinsic conflict if + * so repeatedly until stable. Calls to non-abrupt shutdown() + * preface this by checking whether termination should commence. + * This relies primarily on the active count bits of "ctl" + * maintaining consensus -- tryTerminate is called from awaitWork + * whenever quiescent. However, external submitters do not take + * part in this consensus. So, tryTerminate sweeps through queues + * (until stable) to ensure lack of in-flight submissions and + * workers about to process them before triggering the "STOP" + * phase of termination. (Note: there is an intrinsic conflict if * helpQuiescePool is called when shutdown is enabled. Both wait * for quiescence, but tryTerminate is biased to not trigger until * helpQuiescePool completes.) * - * * Joining Tasks * ============= * @@ -605,8 +585,13 @@ * continuation tasks) blocks on a join and there still remain * enough threads to ensure liveness. * + * Spare threads are removed as soon as they notice that the + * target parallelism level has been exceeded, in method + * tryDropSpare. (Method scan arranges returns for rechecks upon + * each probe via the "bound" parameter.) + * * The compensation mechanism may be bounded. Bounds for the - * commonPool (see commonMaxSpares) better enable JVMs to cope + * commonPool (see COMMON_MAX_SPARES) better enable JVMs to cope * with programming errors and abuse before running out of * resources to do so. In other cases, users may supply factories * that limit thread construction. The effects of bounding in this @@ -728,7 +713,7 @@ * Default ForkJoinWorkerThreadFactory implementation; creates a * new ForkJoinWorkerThread. */ - static final class DefaultForkJoinWorkerThreadFactory + private static final class DefaultForkJoinWorkerThreadFactory implements ForkJoinWorkerThreadFactory { public final ForkJoinWorkerThread newThread(ForkJoinPool pool) { return new ForkJoinWorkerThread(pool); @@ -741,7 +726,7 @@ * in WorkQueue.tryRemoveAndExec. We don't need the proxy to * actually do anything beyond having a unique identity. */ - static final class EmptyTask extends ForkJoinTask<Void> { + private static final class EmptyTask extends ForkJoinTask<Void> { private static final long serialVersionUID = -7721805057305804111L; EmptyTask() { status = ForkJoinTask.NORMAL; } // force done public final Void getRawResult() { return null; } @@ -749,6 +734,16 @@ public final boolean exec() { return true; } } + /** + * Additional fields and lock created upon initialization. + */ + private static final class AuxState extends ReentrantLock { + private static final long serialVersionUID = -6001602636862214147L; + volatile long stealCount; // cumulative steal count + long indexSeed; // index bits for registerWorker + AuxState() {} + } + // Constants shared across ForkJoinPool and WorkQueue // Bounds @@ -758,15 +753,23 @@ static final int SQMASK = 0x007e; // max 64 (even) slots // Masks and units for WorkQueue.scanState and ctl sp subfield - static final int SCANNING = 1; // false when running tasks - static final int INACTIVE = 1 << 31; // must be negative + static final int UNSIGNALLED = 1 << 31; // must be negative static final int SS_SEQ = 1 << 16; // version count // Mode bits for ForkJoinPool.config and WorkQueue.config static final int MODE_MASK = 0xffff << 16; // top half of int - static final int LIFO_QUEUE = 0; - static final int FIFO_QUEUE = 1 << 16; - static final int SHARED_QUEUE = 1 << 31; // must be negative + static final int SPARE_WORKER = 1 << 17; // set if tc > 0 on creation + static final int UNREGISTERED = 1 << 18; // to skip some of deregister + static final int FIFO_QUEUE = 1 << 31; // must be negative + static final int LIFO_QUEUE = 0; // for clarity + static final int IS_OWNED = 1; // low bit 0 if shared + + /** + * The maximum number of task executions from the same queue + * before checking other queues, bounding unfairness and impact of + * infinite user task recursion. Must be a power of two minus 1. + */ + static final int POLL_LIMIT = (1 << 10) - 1; /** * Queues supporting work-stealing as well as external task @@ -801,7 +804,8 @@ static final int MAXIMUM_QUEUE_CAPACITY = 1 << 26; // 64M // Instance fields - volatile int scanState; // versioned, <0: inactive; odd:scanning + + volatile int scanState; // versioned, negative if inactive int stackPred; // pool stack (ctl) predecessor int nsteals; // number of steals int hint; // randomization and stealer index hint @@ -814,7 +818,8 @@ final ForkJoinWorkerThread owner; // owning thread or null if shared volatile Thread parker; // == owner during call to park; else null volatile ForkJoinTask<?> currentJoin; // task being joined in awaitJoin - volatile ForkJoinTask<?> currentSteal; // mainly used by helpStealer + @sun.misc.Contended("group2") // separate from other fields + volatile ForkJoinTask<?> currentSteal; // nonnull when running some task WorkQueue(ForkJoinPool pool, ForkJoinWorkerThread owner) { this.pool = pool; @@ -834,7 +839,7 @@ * Returns the approximate number of tasks in the queue. */ final int queueSize() { - int n = base - top; // non-owner callers must read base first + int n = base - top; // read base first return (n >= 0) ? 0 : -n; // ignore transient negative } @@ -844,33 +849,31 @@ * near-empty queue has at least one unclaimed task. */ final boolean isEmpty() { - ForkJoinTask<?>[] a; int n, m, s; - return ((n = base - (s = top)) >= 0 || - (n == -1 && // possibly one task - ((a = array) == null || (m = a.length - 1) < 0 || - U.getObject - (a, (long)((m & (s - 1)) << ASHIFT) + ABASE) == null))); + ForkJoinTask<?>[] a; int n, al, s; + return ((n = base - (s = top)) >= 0 || // possibly one task + (n == -1 && ((a = array) == null || + (al = a.length) == 0 || + a[(al - 1) & (s - 1)] == null))); } /** - * Pushes a task. Call only by owner in unshared queues. (The - * shared-queue version is embedded in method externalPush.) + * Pushes a task. Call only by owner in unshared queues. * * @param task the task. Caller must ensure non-null. * @throws RejectedExecutionException if array cannot be resized */ final void push(ForkJoinTask<?> task) { - ForkJoinTask<?>[] a; ForkJoinPool p; - int b = base, s = top, n; - if ((a = array) != null) { // ignore if queue removed - int m = a.length - 1; // fenced write for task visibility - U.putOrderedObject(a, ((m & s) << ASHIFT) + ABASE, task); - U.putOrderedInt(this, QTOP, s + 1); - if ((n = s - b) <= 1) { - if ((p = pool) != null) - p.signalWork(p.workQueues, this); + U.storeFence(); // ensure safe publication + int s = top, al, d; ForkJoinTask<?>[] a; + if ((a = array) != null && (al = a.length) > 0) { + a[(al - 1) & s] = task; // relaxed writes OK + top = s + 1; + ForkJoinPool p = pool; + if ((d = base - s) == 0 && p != null) { + U.fullFence(); + p.signalWork(); } - else if (n >= m) + else if (al + d == 1) growArray(); } } @@ -883,22 +886,23 @@ final ForkJoinTask<?>[] growArray() { ForkJoinTask<?>[] oldA = array; int size = oldA != null ? oldA.length << 1 : INITIAL_QUEUE_CAPACITY; - if (size > MAXIMUM_QUEUE_CAPACITY) + if (size < INITIAL_QUEUE_CAPACITY || size > MAXIMUM_QUEUE_CAPACITY) throw new RejectedExecutionException("Queue capacity exceeded"); int oldMask, t, b; ForkJoinTask<?>[] a = array = new ForkJoinTask<?>[size]; - if (oldA != null && (oldMask = oldA.length - 1) >= 0 && + if (oldA != null && (oldMask = oldA.length - 1) > 0 && (t = top) - (b = base) > 0) { int mask = size - 1; do { // emulate poll from old array, push to new array - ForkJoinTask<?> x; - int oldj = ((b & oldMask) << ASHIFT) + ABASE; - int j = ((b & mask) << ASHIFT) + ABASE; - x = (ForkJoinTask<?>)U.getObjectVolatile(oldA, oldj); + int index = b & oldMask; + long offset = ((long)index << ASHIFT) + ABASE; + ForkJoinTask<?> x = (ForkJoinTask<?>) + U.getObjectVolatile(oldA, offset); if (x != null && - U.compareAndSwapObject(oldA, oldj, x, null)) - U.putObjectVolatile(a, j, x); + U.compareAndSwapObject(oldA, offset, x, null)) + a[b & mask] = x; } while (++b != t); + U.storeFence(); } return a; } @@ -908,16 +912,16 @@ * by owner in unshared queues. */ final ForkJoinTask<?> pop() { - ForkJoinTask<?>[] a; ForkJoinTask<?> t; int m; - if ((a = array) != null && (m = a.length - 1) >= 0) { - for (int s; (s = top - 1) - base >= 0;) { - long j = ((m & s) << ASHIFT) + ABASE; - if ((t = (ForkJoinTask<?>)U.getObject(a, j)) == null) - break; - if (U.compareAndSwapObject(a, j, t, null)) { - U.putOrderedInt(this, QTOP, s); - return t; - } + int b = base, s = top, al, i; ForkJoinTask<?>[] a; + if ((a = array) != null && b != s && (al = a.length) > 0) { + int index = (al - 1) & --s; + long offset = ((long)index << ASHIFT) + ABASE; + ForkJoinTask<?> t = (ForkJoinTask<?>) + U.getObject(a, offset); + if (t != null && + U.compareAndSwapObject(a, offset, t, null)) { + top = s; + return t; } } return null; @@ -929,12 +933,15 @@ * appear in ForkJoinPool methods scan and helpStealer. */ final ForkJoinTask<?> pollAt(int b) { - ForkJoinTask<?> t; ForkJoinTask<?>[] a; - if ((a = array) != null) { - int j = (((a.length - 1) & b) << ASHIFT) + ABASE; - if ((t = (ForkJoinTask<?>)U.getObjectVolatile(a, j)) != null && - base == b && U.compareAndSwapObject(a, j, t, null)) { - base = b + 1; + ForkJoinTask<?>[] a; int al; + if ((a = array) != null && (al = a.length) > 0) { + int index = (al - 1) & b; + long offset = ((long)index << ASHIFT) + ABASE; + ForkJoinTask<?> t = (ForkJoinTask<?>) + U.getObjectVolatile(a, offset); + if (t != null && b++ == base && + U.compareAndSwapObject(a, offset, t, null)) { + base = b; return t; } } @@ -945,20 +952,27 @@ * Takes next task, if one exists, in FIFO order. */ final ForkJoinTask<?> poll() { - ForkJoinTask<?>[] a; int b; ForkJoinTask<?> t; - while ((b = base) - top < 0 && (a = array) != null) { - int j = (((a.length - 1) & b) << ASHIFT) + ABASE; - t = (ForkJoinTask<?>)U.getObjectVolatile(a, j); - if (base == b) { - if (t != null) { - if (U.compareAndSwapObject(a, j, t, null)) { - base = b + 1; - return t; + for (;;) { + int b = base, s = top, d, al; ForkJoinTask<?>[] a; + if ((a = array) != null && (d = b - s) < 0 && + (al = a.length) > 0) { + int index = (al - 1) & b; + long offset = ((long)index << ASHIFT) + ABASE; + ForkJoinTask<?> t = (ForkJoinTask<?>) + U.getObjectVolatile(a, offset); + if (b++ == base) { + if (t != null) { + if (U.compareAndSwapObject(a, offset, t, null)) { + base = b; + return t; + } } + else if (d == -1) + break; // now empty } - else if (b + 1 == top) // now empty - break; } + else + break; } return null; } @@ -967,37 +981,100 @@ * Takes next task, if one exists, in order specified by mode. */ final ForkJoinTask<?> nextLocalTask() { - return (config & FIFO_QUEUE) == 0 ? pop() : poll(); + return (config < 0) ? poll() : pop(); } /** * Returns next task, if one exists, in order specified by mode. */ final ForkJoinTask<?> peek() { - ForkJoinTask<?>[] a = array; int m; - if (a == null || (m = a.length - 1) < 0) - return null; - int i = (config & FIFO_QUEUE) == 0 ? top - 1 : base; - int j = ((i & m) << ASHIFT) + ABASE; - return (ForkJoinTask<?>)U.getObjectVolatile(a, j); + int al; ForkJoinTask<?>[] a; + return ((a = array) != null && (al = a.length) > 0) ? + a[(al - 1) & (config < 0 ? base : top - 1)] : null; } /** * Pops the given task only if it is at the current top. - * (A shared version is available only via FJP.tryExternalUnpush) - */ - final boolean tryUnpush(ForkJoinTask<?> t) { - ForkJoinTask<?>[] a; int s; - if ((a = array) != null && (s = top) != base && - U.compareAndSwapObject - (a, (((a.length - 1) & --s) << ASHIFT) + ABASE, t, null)) { - U.putOrderedInt(this, QTOP, s); - return true; + */ + final boolean tryUnpush(ForkJoinTask<?> task) { + int b = base, s = top, al; ForkJoinTask<?>[] a; + if ((a = array) != null && b != s && (al = a.length) > 0) { + int index = (al - 1) & --s; + long offset = ((long)index << ASHIFT) + ABASE; + if (U.compareAndSwapObject(a, offset, task, null)) { + top = s; + return true; + } } return false; } /** + * Shared version of push. Fails if already locked. + * + * @return status: > 0 locked, 0 possibly was empty, < 0 was nonempty + */ + final int sharedPush(ForkJoinTask<?> task) { + int stat; + if (U.compareAndSwapInt(this, QLOCK, 0, 1)) { + int b = base, s = top, al, d; ForkJoinTask<?>[] a; + if ((a = array) != null && (al = a.length) > 0 && + al - 1 + (d = b - s) > 0) { + a[(al - 1) & s] = task; + top = s + 1; // relaxed writes OK here + qlock = 0; + stat = (d < 0 && b == base) ? d : 0; + } + else { + growAndSharedPush(task); + stat = 0; + } + } + else + stat = 1; + return stat; + } + + /** + * Helper for sharedPush; called only when locked and resize + * needed. + */ + private void growAndSharedPush(ForkJoinTask<?> task) { + try { + growArray(); + int s = top, al; ForkJoinTask<?>[] a; + if ((a = array) != null && (al = a.length) > 0) { + a[(al - 1) & s] = task; + top = s + 1; + } + } finally { + qlock = 0; + } + } + + /** + * Shared version of pop. + */ + final boolean trySharedUnpush(ForkJoinTask<?> task) { + boolean popped = false; + int s = top - 1, al; ForkJoinTask<?>[] a; + if ((a = array) != null && (al = a.length) > 0) { + int index = (al - 1) & s; + long offset = ((long)index << ASHIFT) + ABASE; + ForkJoinTask<?> t = (ForkJoinTask<?>) U.getObject(a, offset); + if (t == task && + U.compareAndSwapInt(this, QLOCK, 0, 1)) { + if (U.compareAndSwapObject(a, offset, task, null)) { + popped = true; + top = s; + } + U.putOrderedInt(this, QLOCK, 0); + } + } + return popped; + } + + /** * Removes and cancels all known tasks, ignoring any exceptions. */ final void cancelAll() { @@ -1017,66 +1094,88 @@ // Specialized execution methods /** - * Polls and runs tasks until empty. + * Pops and executes up to POLL_LIMIT tasks or until empty. */ - final void pollAndExecAll() { - for (ForkJoinTask<?> t; (t = poll()) != null;) - t.doExec(); + final void localPopAndExec() { + for (int nexec = 0;;) { + int b = base, s = top, al; ForkJoinTask<?>[] a; + if ((a = array) != null && b != s && (al = a.length) > 0) { + int index = (al - 1) & --s; + long offset = ((long)index << ASHIFT) + ABASE; + ForkJoinTask<?> t = (ForkJoinTask<?>) + U.getAndSetObject(a, offset, null); + if (t != null) { + top = s; + (currentSteal = t).doExec(); + if (++nexec > POLL_LIMIT) + break; + } + else + break; + } + else + break; + } } /** - * Removes and executes all local tasks. If LIFO, invokes - * pollAndExecAll. Otherwise implements a specialized pop loop - * to exec until empty. + * Polls and executes up to POLL_LIMIT tasks or until empty. */ - final void execLocalTasks() { - int b = base, m, s; - ForkJoinTask<?>[] a = array; - if (b - (s = top - 1) <= 0 && a != null && - (m = a.length - 1) >= 0) { - if ((config & FIFO_QUEUE) == 0) { - for (ForkJoinTask<?> t;;) { - if ((t = (ForkJoinTask<?>)U.getAndSetObject - (a, ((m & s) << ASHIFT) + ABASE, null)) == null) - break; - U.putOrderedInt(this, QTOP, s); + final void localPollAndExec() { + for (int nexec = 0;;) { + int b = base, s = top, al; ForkJoinTask<?>[] a; + if ((a = array) != null && b != s && (al = a.length) > 0) { + int index = (al - 1) & b++; + long offset = ((long)index << ASHIFT) + ABASE; + ForkJoinTask<?> t = (ForkJoinTask<?>) + U.getAndSetObject(a, offset, null); + if (t != null) { + base = b; t.doExec(); - if (base - (s = top - 1) > 0) + if (++nexec > POLL_LIMIT) break; } } else - pollAndExecAll(); + break; } } /** - * Executes the given task and any remaining local tasks. + * Executes the given task and (some) remaining local tasks. */ final void runTask(ForkJoinTask<?> task) { if (task != null) { - scanState &= ~SCANNING; // mark as busy - (currentSteal = task).doExec(); - U.putOrderedObject(this, QCURRENTSTEAL, null); // release for GC - execLocalTasks(); + task.doExec(); + if (config < 0) + localPollAndExec(); + else + localPopAndExec(); + int ns = ++nsteals; ForkJoinWorkerThread thread = owner; - if (++nsteals < 0) // collect on overflow + currentSteal = null; + if (ns < 0) // collect on overflow transferStealCount(pool); - scanState |= SCANNING; if (thread != null) thread.afterTopLevelExec(); } } /** - * Adds steal count to pool stealCounter if it exists, and resets. + * Adds steal count to pool steal count if it exists, and resets. */ final void transferStealCount(ForkJoinPool p) { - AtomicLong sc; - if (p != null && (sc = p.stealCounter) != null) { - int s = nsteals; + AuxState aux; + if (p != null && (aux = p.auxState) != null) { + long s = nsteals; nsteals = 0; // if negative, correct for overflow - sc.getAndAdd((long)(s < 0 ? Integer.MAX_VALUE : s)); + if (s < 0) s = Integer.MAX_VALUE; + aux.lock(); + try { + aux.stealCount += s; + } finally { + aux.unlock(); + } } } @@ -1087,36 +1186,46 @@ * @return true if queue empty and task not known to be done */ final boolean tryRemoveAndExec(ForkJoinTask<?> task) { - ForkJoinTask<?>[] a; int m, s, b, n; - if ((a = array) != null && (m = a.length - 1) >= 0 && - task != null) { - while ((n = (s = top) - (b = base)) > 0) { - for (ForkJoinTask<?> t;;) { // traverse from s to b - long j = ((--s & m) << ASHIFT) + ABASE; - if ((t = (ForkJoinTask<?>)U.getObject(a, j)) == null) - return s + 1 == top; // shorter than expected + if (task != null && task.status >= 0) { + int b, s, d, al; ForkJoinTask<?>[] a; + while ((d = (b = base) - (s = top)) < 0 && + (a = array) != null && (al = a.length) > 0) { + for (;;) { // traverse from s to b + int index = --s & (al - 1); + long offset = (index << ASHIFT) + ABASE; + ForkJoinTask<?> t = (ForkJoinTask<?>) + U.getObjectVolatile(a, offset); + if (t == null) + break; // restart else if (t == task) { boolean removed = false; if (s + 1 == top) { // pop - if (U.compareAndSwapObject(a, j, task, null)) { - U.putOrderedInt(this, QTOP, s); + if (U.compareAndSwapObject(a, offset, t, null)) { + top = s; removed = true; } } else if (base == b) // replace with proxy - removed = U.compareAndSwapObject( - a, j, task, new EmptyTask()); - if (removed) - task.doExec(); + removed = U.compareAndSwapObject(a, offset, t, + new EmptyTask()); + if (removed) { + ForkJoinTask<?> ps = currentSteal; + (currentSteal = task).doExec(); + currentSteal = ps; + } break; } else if (t.status < 0 && s + 1 == top) { - if (U.compareAndSwapObject(a, j, t, null)) - U.putOrderedInt(this, QTOP, s); + if (U.compareAndSwapObject(a, offset, t, null)) { + top = s; + } break; // was cancelled } - if (--n == 0) + else if (++d == 0) { + if (base != b) // rescan + break; return false; + } } if (task.status < 0) return false; @@ -1130,27 +1239,31 @@ * in either shared or owned mode. Used only by helpComplete. */ final CountedCompleter<?> popCC(CountedCompleter<?> task, int mode) { - int s; ForkJoinTask<?>[] a; Object o; - if (base - (s = top) < 0 && (a = array) != null) { - long j = (((a.length - 1) & (s - 1)) << ASHIFT) + ABASE; - if ((o = U.getObjectVolatile(a, j)) != null && - (o instanceof CountedCompleter)) { + int b = base, s = top, al; ForkJoinTask<?>[] a; + if ((a = array) != null && b != s && (al = a.length) > 0) { + int index = (al - 1) & (s - 1); + long offset = ((long)index << ASHIFT) + ABASE; + ForkJoinTask<?> o = (ForkJoinTask<?>) + U.getObjectVolatile(a, offset); + if (o instanceof CountedCompleter) { CountedCompleter<?> t = (CountedCompleter<?>)o; for (CountedCompleter<?> r = t;;) { if (r == task) { - if (mode < 0) { // must lock + if ((mode & IS_OWNED) == 0) { + boolean popped; if (U.compareAndSwapInt(this, QLOCK, 0, 1)) { - if (top == s && array == a && - U.compareAndSwapObject(a, j, t, null)) { - U.putOrderedInt(this, QTOP, s - 1); - U.putOrderedInt(this, QLOCK, 0); + if (popped = + U.compareAndSwapObject(a, offset, + t, null)) + top = s - 1; + U.putOrderedInt(this, QLOCK, 0); + if (popped) return t; - } - U.compareAndSwapInt(this, QLOCK, 1, 0); } } - else if (U.compareAndSwapObject(a, j, t, null)) { - U.putOrderedInt(this, QTOP, s - 1); + else if (U.compareAndSwapObject(a, offset, + t, null)) { + top = s - 1; return t; } break; @@ -1174,36 +1287,40 @@ * the base index, forced negative. */ final int pollAndExecCC(CountedCompleter<?> task) { - int b, h; ForkJoinTask<?>[] a; Object o; - if ((b = base) - top >= 0 || (a = array) == null) - h = b | Integer.MIN_VALUE; // to sense movement on re-poll - else { - long j = (((a.length - 1) & b) << ASHIFT) + ABASE; - if ((o = U.getObjectVolatile(a, j)) == null) - h = 2; // retryable + ForkJoinTask<?>[] a; + int b = base, s = top, al, h; + if ((a = array) != null && b != s && (al = a.length) > 0) { + int index = (al - 1) & b; + long offset = ((long)index << ASHIFT) + ABASE; + ForkJoinTask<?> o = (ForkJoinTask<?>) + U.getObjectVolatile(a, offset); + if (o == null) + h = 2; // retryable else if (!(o instanceof CountedCompleter)) - h = -1; // unmatchable + h = -1; // unmatchable else { CountedCompleter<?> t = (CountedCompleter<?>)o; for (CountedCompleter<?> r = t;;) { if (r == task) { - if (base == b && - U.compareAndSwapObject(a, j, t, null)) { - base = b + 1; + if (b++ == base && + U.compareAndSwapObject(a, offset, t, null)) { + base = b; t.doExec(); - h = 1; // success + h = 1; // success } else - h = 2; // lost CAS + h = 2; // lost CAS break; } else if ((r = r.completer) == null) { - h = -1; // unmatched + h = -1; // unmatched break; } } } } + else + h = b | Integer.MIN_VALUE; // to sense movement on re-poll return h; } @@ -1220,29 +1337,20 @@ } // Unsafe mechanics. Note that some are (and must be) the same as in FJP - private static final sun.misc.Unsafe U; - private static final int ABASE; - private static final int ASHIFT; - private static final long QTOP; + private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe(); private static final long QLOCK; - private static final long QCURRENTSTEAL; + private static final int ABASE; + private static final int ASHIFT; static { try { - U = sun.misc.Unsafe.getUnsafe(); - Class<?> wk = WorkQueue.class; - Class<?> ak = ForkJoinTask[].class; - QTOP = U.objectFieldOffset - (wk.getDeclaredField("top")); QLOCK = U.objectFieldOffset - (wk.getDeclaredField("qlock")); - QCURRENTSTEAL = U.objectFieldOffset - (wk.getDeclaredField("currentSteal")); - ABASE = U.arrayBaseOffset(ak); - int scale = U.arrayIndexScale(ak); + (WorkQueue.class.getDeclaredField("qlock")); + ABASE = U.arrayBaseOffset(ForkJoinTask[].class); + int scale = U.arrayIndexScale(ForkJoinTask[].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); } } @@ -1259,9 +1367,9 @@ /** * Permission required for callers of methods that may start or - * kill threads. + * kill threads. Also used as a static lock in tryInitialize. */ - private static final RuntimePermission modifyThreadPermission; + static final RuntimePermission modifyThreadPermission; /** * Common (static) pool. Non-null for public use unless a static @@ -1277,12 +1385,12 @@ * common.parallelism field to be zero, but in that case still report * parallelism as 1 to reflect resulting caller-runs mechanics. */ - static final int commonParallelism; + static final int COMMON_PARALLELISM; /** * Limit on spare thread construction in tryCompensate. */ - private static int commonMaxSpares; + private static final int COMMON_MAX_SPARES; /** * Sequence number for creating workerNamePrefix. @@ -1300,46 +1408,30 @@ // static configuration constants /** - * Initial timeout value (in nanoseconds) for the thread + * Initial timeout value (in milliseconds) for the thread * triggering quiescence to park waiting for new work. On timeout, - * the thread will instead try to shrink the number of - * workers. The value should be large enough to avoid overly - * aggressive shrinkage during most transient stalls (long GCs - * etc). + * the thread will instead try to shrink the number of workers. + * The value should be large enough to avoid overly aggressive + * shrinkage during most transient stalls (long GCs etc). */ - private static final long IDLE_TIMEOUT = 2000L * 1000L * 1000L; // 2sec + private static final long IDLE_TIMEOUT_MS = 2000L; // 2sec /** - * Tolerance for idle timeouts, to cope with timer undershoots + * Tolerance for idle timeouts, to cope with timer undershoots. */ - private static final long TIMEOUT_SLOP = 20L * 1000L * 1000L; // 20ms + private static final long TIMEOUT_SLOP_MS = 20L; // 20ms /** - * The initial value for commonMaxSpares during static - * initialization unless overridden using System property - * "java.util.concurrent.ForkJoinPool.common.maximumSpares". The - * default value is far in excess of normal requirements, but also - * far short of MAX_CAP and typical OS thread limits, so allows - * JVMs to catch misuse/abuse before running out of resources - * needed to do so. + * The default value for COMMON_MAX_SPARES. Overridable using the + * "java.util.concurrent.ForkJoinPool.common.maximumSpares" system + * property. The default value is far in excess of normal + * requirements, but also far short of MAX_CAP and typical OS + * thread limits, so allows JVMs to catch misuse/abuse before + * running out of resources needed to do so. */ private static final int DEFAULT_COMMON_MAX_SPARES = 256; /** - * Number of times to spin-wait before blocking. The spins (in - * awaitRunStateLock and awaitWork) currently use randomized - * spins. Currently set to zero to reduce CPU usage. - * - * If greater than zero the value of SPINS must be a power - * of two, at least 4. A value of 2048 causes spinning for a - * small fraction of typical context-switch times. - * - * If/when MWAIT-like intrinsics becomes available, they - * may allow quieter spinning. - */ - private static final int SPINS = 0; - - /** * Increment for seed generators. See class ThreadLocal for * explanation. */ @@ -1384,92 +1476,49 @@ private static final long ADD_WORKER = 0x0001L << (TC_SHIFT + 15); // sign // runState bits: SHUTDOWN must be negative, others arbitrary powers of two - private static final int RSLOCK = 1; - private static final int RSIGNAL = 1 << 1; - private static final int STARTED = 1 << 2; - private static final int STOP = 1 << 29; - private static final int TERMINATED = 1 << 30; + private static final int STARTED = 1; + private static final int STOP = 1 << 1; + private static final int TERMINATED = 1 << 2; private static final int SHUTDOWN = 1 << 31; // Instance fields volatile long ctl; // main pool control - volatile int runState; // lockable status + volatile int runState; final int config; // parallelism, mode - int indexSeed; // to generate worker index + AuxState auxState; // lock, steal counts volatile WorkQueue[] workQueues; // main registry + final String workerNamePrefix; // to create worker name string final ForkJoinWorkerThreadFactory factory; final UncaughtExceptionHandler ueh; // per-worker UEH - final String workerNamePrefix; // to create worker name string - volatile AtomicLong stealCounter; // also used as sync monitor /** - * Acquires the runState lock; returns current (locked) runState. + * Instantiates fields upon first submission, or upon shutdown if + * no submissions. If checkTermination true, also responds to + * termination by external calls submitting tasks. */ - private int lockRunState() { - int rs; - return ((((rs = runState) & RSLOCK) != 0 || - !U.compareAndSwapInt(this, RUNSTATE, rs, rs |= RSLOCK)) ? - awaitRunStateLock() : rs); - } - - /** - * Spins and/or blocks until runstate lock is available. See - * above for explanation. - */ - private int awaitRunStateLock() { - Object lock; - boolean wasInterrupted = false; - for (int spins = SPINS, r = 0, rs, ns;;) { - if (((rs = runState) & RSLOCK) == 0) { - if (U.compareAndSwapInt(this, RUNSTATE, rs, ns = rs | RSLOCK)) { - if (wasInterrupted) { - try { - Thread.currentThread().interrupt(); - } catch (SecurityException ignore) { - } - } - return ns; - } - } - else if (r == 0) - r = ThreadLocalRandom.nextSecondarySeed(); - else if (spins > 0) { - r ^= r << 6; r ^= r >>> 21; r ^= r << 7; // xorshift - if (r >= 0) - --spins; - } - else if ((rs & STARTED) == 0 || (lock = stealCounter) == null) - Thread.yield(); // initialization race - else if (U.compareAndSwapInt(this, RUNSTATE, rs, rs | RSIGNAL)) { - synchronized (lock) { - if ((runState & RSIGNAL) != 0) { - try { - lock.wait(); - } catch (InterruptedException ie) { - if (!(Thread.currentThread() instanceof - ForkJoinWorkerThread)) - wasInterrupted = true; - } - } - else - lock.notifyAll(); + private void tryInitialize(boolean checkTermination) { + if (runState == 0) { // bootstrap by locking static field + int p = config & SMASK; + int n = (p > 1) ? p - 1 : 1; // ensure at least 2 slots + n |= n >>> 1; // create workQueues array with size a power of two + n |= n >>> 2; + n |= n >>> 4; + n |= n >>> 8; + n |= n >>> 16; + n = ((n + 1) << 1) & SMASK; + AuxState aux = new AuxState(); + WorkQueue[] ws = new WorkQueue[n]; + synchronized (modifyThreadPermission) { // double-check + if (runState == 0) { + workQueues = ws; + auxState = aux; + runState = STARTED; } } } - } - - /** - * Unlocks and sets runState to newRunState. - * - * @param oldRunState a value returned from lockRunState - * @param newRunState the next value (must have lock bit clear). - */ - private void unlockRunState(int oldRunState, int newRunState) { - if (!U.compareAndSwapInt(this, RUNSTATE, oldRunState, newRunState)) { - Object lock = stealCounter; - runState = newRunState; // clears RSIGNAL bit - if (lock != null) - synchronized (lock) { lock.notifyAll(); } + if (checkTermination && runState < 0) { + tryTerminate(false, false); // help terminate + throw new RejectedExecutionException(); } } @@ -1480,14 +1529,18 @@ * count has already been incremented as a reservation. Invokes * deregisterWorker on any failure. * + * @param isSpare true if this is a spare thread * @return true if successful */ - private boolean createWorker() { + private boolean createWorker(boolean isSpare) { ForkJoinWorkerThreadFactory fac = factory; Throwable ex = null; ForkJoinWorkerThread wt = null; + WorkQueue q; try { if (fac != null && (wt = fac.newThread(this)) != null) { + if (isSpare && (q = wt.workQueue) != null) + q.config |= SPARE_WORKER; wt.start(); return true; } @@ -1507,21 +1560,12 @@ * this holds (otherwise, a new worker is not needed). */ private void tryAddWorker(long c) { - boolean add = false; do { long nc = ((AC_MASK & (c + AC_UNIT)) | (TC_MASK & (c + TC_UNIT))); - if (ctl == c) { - int rs, stop; // check if terminating - if ((stop = (rs = lockRunState()) & STOP) == 0) - add = U.compareAndSwapLong(this, CTL, c, nc); - unlockRunState(rs, rs & ~RSLOCK); - if (stop != 0) - break; - if (add) { - createWorker(); - break; - } + if (ctl == c && U.compareAndSwapLong(this, CTL, c, nc)) { + createWorker(false); + break; } } while (((c = ctl) & ADD_WORKER) != 0L && (int)c == 0); } @@ -1535,37 +1579,39 @@ */ final WorkQueue registerWorker(ForkJoinWorkerThread wt) { UncaughtExceptionHandler handler; + AuxState aux; wt.setDaemon(true); // configure thread if ((handler = ueh) != null) wt.setUncaughtExceptionHandler(handler); WorkQueue w = new WorkQueue(this, wt); int i = 0; // assign a pool index int mode = config & MODE_MASK; - int rs = lockRunState(); - try { - WorkQueue[] ws; int n; // skip if no array - if ((ws = workQueues) != null && (n = ws.length) > 0) { - int s = indexSeed += SEED_INCREMENT; // unlikely to collide - int m = n - 1; - i = ((s << 1) | 1) & m; // odd-numbered indices - if (ws[i] != null) { // collision - int probes = 0; // step by approx half n - int step = (n <= 4) ? 2 : ((n >>> 1) & EVENMASK) + 2; - while (ws[i = (i + step) & m] != null) { - if (++probes >= n) { - workQueues = ws = Arrays.copyOf(ws, n <<= 1); - m = n - 1; - probes = 0; + if ((aux = auxState) != null) { + aux.lock(); + try { + int s = (int)(aux.indexSeed += SEED_INCREMENT), n, m; + WorkQueue[] ws = workQueues; + if (ws != null && (n = ws.length) > 0) { + i = (m = n - 1) & ((s << 1) | 1); // odd-numbered indices + if (ws[i] != null) { // collision + int probes = 0; // step by approx half n + int step = (n <= 4) ? 2 : ((n >>> 1) & EVENMASK) + 2; + while (ws[i = (i + step) & m] != null) { + if (++probes >= n) { + workQueues = ws = Arrays.copyOf(ws, n <<= 1); + m = n - 1; + probes = 0; + } } } + w.hint = s; // use as random seed + w.config = i | mode; + w.scanState = i | (s & 0x7fff0000); // random seq bits + ws[i] = w; } - w.hint = s; // use as random seed - w.config = i | mode; - w.scanState = i; // publication fence - ws[i] = w; + } finally { + aux.unlock(); } - } finally { - unlockRunState(rs, rs & ~RSLOCK); } wt.setName(workerNamePrefix.concat(Integer.toString(i >>> 1))); return w; @@ -1583,31 +1629,40 @@