mirror of
https://github.com/openjdk/jdk.git
synced 2026-04-16 01:40:31 +00:00
Merge
This commit is contained in:
commit
7291744cbf
@ -152,7 +152,6 @@ SUNWprivate_1.1 {
|
||||
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;
|
||||
|
||||
@ -99,6 +99,64 @@ class FdLibm {
|
||||
return Double.longBitsToDouble((transX & 0x0000_0000_FFFF_FFFFL)|( ((long)high)) << 32 );
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
*
|
||||
|
||||
@ -307,7 +307,9 @@ public final class StrictMath {
|
||||
* @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
|
||||
|
||||
@ -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 @@ import jdk.internal.org.objectweb.asm.Type;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -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 @@ import java.util.Objects;
|
||||
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 @@ import java.util.Objects;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -383,7 +383,7 @@ class MethodHandleNatives {
|
||||
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,
|
||||
|
||||
@ -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
|
||||
@ -1057,6 +1057,23 @@ class MethodType implements java.io.Serializable {
|
||||
*/
|
||||
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 ||
|
||||
|
||||
@ -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 @@ class TypeConvertingMethodAdapter extends MethodVisitor {
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
@ -28,9 +28,9 @@ package java.net;
|
||||
/**
|
||||
* 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
|
||||
|
||||
@ -41,6 +41,9 @@ import java.net.URLStreamHandlerFactory;
|
||||
* 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
|
||||
|
||||
@ -38,16 +38,16 @@ package java.util;
|
||||
/**
|
||||
* 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 @@ package java.util;
|
||||
*
|
||||
* @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 @@ public abstract class AbstractQueue<E>
|
||||
/**
|
||||
* 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 @@ public abstract class AbstractQueue<E>
|
||||
* 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 @@ public abstract class AbstractQueue<E>
|
||||
* 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 @@ public abstract class AbstractQueue<E>
|
||||
* 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 @@ public abstract class AbstractQueue<E>
|
||||
/**
|
||||
* 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 @@ public abstract class AbstractQueue<E>
|
||||
* 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
|
||||
|
||||
@ -47,16 +47,18 @@ import java.util.function.Consumer;
|
||||
* 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 @@ import java.util.function.Consumer;
|
||||
*
|
||||
* @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 @@ public class ArrayDeque<E> extends AbstractCollection<E>
|
||||
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];
|
||||
}
|
||||
@ -162,24 +164,6 @@ public class ArrayDeque<E> extends AbstractCollection<E>
|
||||
tail = n;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 class ArrayDeque<E> extends AbstractCollection<E>
|
||||
}
|
||||
|
||||
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 @@ public class ArrayDeque<E> extends AbstractCollection<E>
|
||||
* @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 @@ public class ArrayDeque<E> extends AbstractCollection<E>
|
||||
* @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 @@ public class ArrayDeque<E> extends AbstractCollection<E>
|
||||
*
|
||||
* @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 @@ public class ArrayDeque<E> extends AbstractCollection<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 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 @@ public class ArrayDeque<E> extends AbstractCollection<E>
|
||||
* @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 @@ public class ArrayDeque<E> extends AbstractCollection<E>
|
||||
* @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 @@ public class ArrayDeque<E> extends AbstractCollection<E>
|
||||
* 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 @@ public class ArrayDeque<E> extends AbstractCollection<E>
|
||||
*/
|
||||
@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 @@ public class ArrayDeque<E> extends AbstractCollection<E>
|
||||
/**
|
||||
* 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 @@ public class ArrayDeque<E> extends AbstractCollection<E>
|
||||
|
||||
/**
|
||||
* 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 @@ public class ArrayDeque<E> extends AbstractCollection<E>
|
||||
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 @@ public class ArrayDeque<E> extends AbstractCollection<E>
|
||||
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 @@ public class ArrayDeque<E> extends AbstractCollection<E>
|
||||
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)
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -22,20 +21,26 @@
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package java.util;
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* Written by Doug Lea with assistance from members of JCP JSR-166
|
||||
* Expert Group and released to the public domain, as explained at
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
package java.util;
|
||||
|
||||
import java.util.concurrent.CountedCompleter;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.function.BinaryOperator;
|
||||
import java.util.function.DoubleBinaryOperator;
|
||||
import java.util.function.IntBinaryOperator;
|
||||
import java.util.function.LongBinaryOperator;
|
||||
import java.util.function.DoubleBinaryOperator;
|
||||
|
||||
/**
|
||||
* ForkJoin tasks to perform Arrays.parallelPrefix operations.
|
||||
@ -44,7 +49,7 @@ import java.util.function.DoubleBinaryOperator;
|
||||
* @since 1.8
|
||||
*/
|
||||
class ArrayPrefixHelpers {
|
||||
private ArrayPrefixHelpers() {}; // non-instantiable
|
||||
private ArrayPrefixHelpers() {} // non-instantiable
|
||||
|
||||
/*
|
||||
* Parallel prefix (aka cumulate, scan) task classes
|
||||
@ -113,8 +118,8 @@ class ArrayPrefixHelpers {
|
||||
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 @@ class ArrayPrefixHelpers {
|
||||
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 @@ class ArrayPrefixHelpers {
|
||||
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 @@ class ArrayPrefixHelpers {
|
||||
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 @@ class ArrayPrefixHelpers {
|
||||
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 @@ class ArrayPrefixHelpers {
|
||||
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 @@ class ArrayPrefixHelpers {
|
||||
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 @@ class ArrayPrefixHelpers {
|
||||
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 @@ class ArrayPrefixHelpers {
|
||||
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 @@ class ArrayPrefixHelpers {
|
||||
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 @@ class ArrayPrefixHelpers {
|
||||
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 @@ class ArrayPrefixHelpers {
|
||||
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;
|
||||
|
||||
@ -537,8 +537,9 @@ public class Collections {
|
||||
* 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.
|
||||
*
|
||||
|
||||
@ -188,7 +188,7 @@ package java.util;
|
||||
* @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 @@ public interface Deque<E> extends Queue<E> {
|
||||
* 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 @@ public interface Deque<E> extends Queue<E> {
|
||||
* @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 @@ public interface Deque<E> extends Queue<E> {
|
||||
* 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 @@ public interface Deque<E> extends Queue<E> {
|
||||
* @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 @@ public interface Deque<E> extends Queue<E> {
|
||||
* 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 @@ public interface Deque<E> extends Queue<E> {
|
||||
* @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 @@ public interface Deque<E> extends Queue<E> {
|
||||
*
|
||||
* @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.
|
||||
|
||||
@ -38,30 +38,32 @@ package java.util;
|
||||
/**
|
||||
* 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 @@ package java.util;
|
||||
* 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 @@ public interface NavigableMap<K,V> extends SortedMap<K,V> {
|
||||
* 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}.
|
||||
*
|
||||
|
||||
@ -37,26 +37,30 @@ package java.util;
|
||||
|
||||
/**
|
||||
* 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 @@ public interface NavigableSet<E> extends SortedSet<E> {
|
||||
* 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}.
|
||||
*
|
||||
|
||||
@ -77,7 +77,7 @@ import java.util.function.Consumer;
|
||||
*
|
||||
* @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 @@ public class PriorityQueue<E> extends AbstractQueue<E>
|
||||
/**
|
||||
* 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 @@ public class PriorityQueue<E> extends AbstractQueue<E>
|
||||
* 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 @@ public class PriorityQueue<E> extends AbstractQueue<E>
|
||||
* 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 @@ public class PriorityQueue<E> extends AbstractQueue<E>
|
||||
* 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 @@ public class PriorityQueue<E> extends AbstractQueue<E>
|
||||
* 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 @@ public class PriorityQueue<E> extends AbstractQueue<E>
|
||||
* 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 @@ public class PriorityQueue<E> extends AbstractQueue<E>
|
||||
* 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 @@ public class PriorityQueue<E> extends AbstractQueue<E>
|
||||
* (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 @@ public class PriorityQueue<E> extends AbstractQueue<E>
|
||||
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;
|
||||
|
||||
@ -139,7 +139,7 @@ package java.util;
|
||||
* @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> {
|
||||
/**
|
||||
|
||||
@ -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 @@ import java.util.stream.DoubleStream;
|
||||
* 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 @@ import java.util.stream.DoubleStream;
|
||||
*
|
||||
* <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 @@ public final class SplittableRandom {
|
||||
}
|
||||
|
||||
// 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 final class SplittableRandom {
|
||||
*/
|
||||
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 final class SplittableRandom {
|
||||
*/
|
||||
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 final class SplittableRandom {
|
||||
*/
|
||||
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 final class SplittableRandom {
|
||||
*/
|
||||
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 final class SplittableRandom {
|
||||
*/
|
||||
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 final class SplittableRandom {
|
||||
*/
|
||||
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 final class SplittableRandom {
|
||||
*/
|
||||
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 final class SplittableRandom {
|
||||
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 final class SplittableRandom {
|
||||
*/
|
||||
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 final class SplittableRandom {
|
||||
*/
|
||||
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 final class SplittableRandom {
|
||||
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 final class SplittableRandom {
|
||||
*/
|
||||
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 final class SplittableRandom {
|
||||
*/
|
||||
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 final class SplittableRandom {
|
||||
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 final class SplittableRandom {
|
||||
*/
|
||||
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 @@ public final class SplittableRandom {
|
||||
* 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 @@ public final class SplittableRandom {
|
||||
/**
|
||||
* 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 @@ public final class SplittableRandom {
|
||||
/**
|
||||
* 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;
|
||||
|
||||
@ -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 @@ import java.util.*;
|
||||
* <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 @@ public abstract class AbstractExecutorService implements ExecutorService {
|
||||
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 @@ public abstract class AbstractExecutorService implements ExecutorService {
|
||||
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 @@ public abstract class AbstractExecutorService implements ExecutorService {
|
||||
throw ee;
|
||||
|
||||
} finally {
|
||||
for (int i = 0, size = futures.size(); i < size; i++)
|
||||
futures.get(i).cancel(true);
|
||||
cancelAll(futures);
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,8 +234,7 @@ public abstract class AbstractExecutorService implements ExecutorService {
|
||||
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 @@ public abstract class AbstractExecutorService implements ExecutorService {
|
||||
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 @@ public abstract class AbstractExecutorService implements ExecutorService {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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.Spliterators;
|
||||
import java.util.Objects;
|
||||
import java.util.Spliterator;
|
||||
import java.util.Spliterators;
|
||||
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 @@ import java.util.Spliterator;
|
||||
*
|
||||
* @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 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
* 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;
|
||||
@ -140,16 +143,6 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
return (E) items[i];
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
// 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 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
@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 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
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 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
// 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 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
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 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
* @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 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
* @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 class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
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 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
lock.lockInterruptibly();
|
||||
try {
|
||||
while (count == 0) {
|
||||
if (nanos <= 0)
|
||||
if (nanos <= 0L)
|
||||
return null;
|
||||
nanos = notEmpty.awaitNanos(nanos);
|
||||
}
|
||||
@ -492,11 +476,11 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
*/
|
||||
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 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
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 class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
*/
|
||||
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 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
* @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 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
* 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 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
*/
|
||||
@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 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
* 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 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
* @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 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
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 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
}
|
||||
|
||||
/** 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 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
|
||||
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 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
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 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
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 class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
*/
|
||||
public Spliterator<E> spliterator() {
|
||||
return Spliterators.spliterator
|
||||
(this, Spliterator.ORDERED | Spliterator.NONNULL |
|
||||
Spliterator.CONCURRENT);
|
||||
(this, (Spliterator.ORDERED |
|
||||
Spliterator.NONNULL |
|
||||
Spliterator.CONCURRENT));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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 @@ import java.util.*;
|
||||
*
|
||||
* @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 @@ public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> {
|
||||
* @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 @@ public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> {
|
||||
* @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 @@ public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> {
|
||||
* @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 @@ public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> {
|
||||
* @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.
|
||||
|
||||
@ -127,7 +127,7 @@ import java.util.Queue;
|
||||
* 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 @@ import java.util.Queue;
|
||||
*
|
||||
* @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 @@ public interface BlockingQueue<E> extends Queue<E> {
|
||||
* @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 @@ public interface BlockingQueue<E> extends Queue<E> {
|
||||
* @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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -34,12 +34,11 @@
|
||||
*/
|
||||
|
||||
package java.util.concurrent;
|
||||
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.Executor;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* A stage of a possibly asynchronous computation, that performs an
|
||||
@ -56,9 +55,9 @@ import java.util.concurrent.Executor;
|
||||
* 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 @@ import java.util.concurrent.Executor;
|
||||
* 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 @@ import java.util.concurrent.Executor;
|
||||
* 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 @@ import java.util.concurrent.Executor;
|
||||
* 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 @@ public interface CompletionStage<T> {
|
||||
|
||||
/**
|
||||
* 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 @@ public interface CompletionStage<T> {
|
||||
/**
|
||||
* 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 @@ public interface CompletionStage<T> {
|
||||
* 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
|
||||
|
||||
@ -42,7 +42,6 @@ import java.lang.reflect.Type;
|
||||
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.Map;
|
||||
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 @@ import java.util.stream.Stream;
|
||||
* 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 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
* 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 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
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 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
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 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
p.val = value;
|
||||
}
|
||||
}
|
||||
else if (f instanceof ReservationNode)
|
||||
throw new IllegalStateException("Recursive update");
|
||||
}
|
||||
}
|
||||
if (binCount != 0) {
|
||||
@ -1159,6 +1159,8 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (f instanceof ReservationNode)
|
||||
throw new IllegalStateException("Recursive update");
|
||||
}
|
||||
}
|
||||
if (validated) {
|
||||
@ -1366,7 +1368,7 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
|
||||
/**
|
||||
* 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 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
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 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
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 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
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 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
t.putTreeVal(h, key, val);
|
||||
}
|
||||
}
|
||||
else if (f instanceof ReservationNode)
|
||||
throw new IllegalStateException("Recursive update");
|
||||
}
|
||||
}
|
||||
if (binCount != 0) {
|
||||
@ -1840,6 +1847,8 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (f instanceof ReservationNode)
|
||||
throw new IllegalStateException("Recursive update");
|
||||
}
|
||||
}
|
||||
if (binCount != 0)
|
||||
@ -1931,6 +1940,8 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
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 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
setTabAt(tab, i, untreeify(t.first));
|
||||
}
|
||||
}
|
||||
else if (f instanceof ReservationNode)
|
||||
throw new IllegalStateException("Recursive update");
|
||||
}
|
||||
}
|
||||
if (binCount != 0) {
|
||||
@ -2072,6 +2085,8 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
setTabAt(tab, i, untreeify(t.first));
|
||||
}
|
||||
}
|
||||
else if (f instanceof ReservationNode)
|
||||
throw new IllegalStateException("Recursive update");
|
||||
}
|
||||
}
|
||||
if (binCount != 0) {
|
||||
@ -2089,12 +2104,13 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
// 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 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
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 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
* 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 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
/* ---------------- 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 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
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 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
(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 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
|
||||
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 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
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 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
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 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
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 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
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 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
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 class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
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 class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
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 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
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 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
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 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as Traverser version
|
||||
* Same as Traverser version.
|
||||
*/
|
||||
final Node<K,V> advance() {
|
||||
Node<K,V> e;
|
||||
@ -6323,38 +6330,40 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 @@ import java.util.function.Consumer;
|
||||
* @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 @@ public class ConcurrentLinkedDeque<E>
|
||||
* 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 @@ public class ConcurrentLinkedDeque<E>
|
||||
* 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 @@ public class ConcurrentLinkedDeque<E>
|
||||
* 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 (;;)
|
||||
@ -788,16 +785,6 @@ public class ConcurrentLinkedDeque<E>
|
||||
|
||||
// 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.
|
||||
@ -811,22 +798,6 @@ public class ConcurrentLinkedDeque<E>
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@ -847,8 +818,7 @@ public class ConcurrentLinkedDeque<E>
|
||||
// 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 class ConcurrentLinkedDeque<E>
|
||||
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 @@ public class ConcurrentLinkedDeque<E>
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public class ConcurrentLinkedDeque<E>
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public class ConcurrentLinkedDeque<E>
|
||||
* @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 @@ public class ConcurrentLinkedDeque<E>
|
||||
// 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 class ConcurrentLinkedDeque<E>
|
||||
;
|
||||
}
|
||||
|
||||
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 @@ public class ConcurrentLinkedDeque<E>
|
||||
* @return an array containing all of the elements in this deque
|
||||
*/
|
||||
public Object[] toArray() {
|
||||
return toArrayList().toArray();
|
||||
return toArrayInternal(null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1264,7 +1306,7 @@ public class ConcurrentLinkedDeque<E>
|
||||
* 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 @@ public class ConcurrentLinkedDeque<E>
|
||||
* 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 @@ public class ConcurrentLinkedDeque<E>
|
||||
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 @@ public class ConcurrentLinkedDeque<E>
|
||||
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 @@ public class ConcurrentLinkedDeque<E>
|
||||
|
||||
// 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 @@ public class ConcurrentLinkedDeque<E>
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 @@ import java.util.function.Consumer;
|
||||
* 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 @@ import java.util.function.Consumer;
|
||||
*
|
||||
* @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 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
|
||||
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 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
|
||||
* - 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 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
|
||||
* 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 class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
|
||||
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 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
|
||||
* 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 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
|
||||
* @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 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
|
||||
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 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
|
||||
* @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 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
|
||||
* @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 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
|
||||
* @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 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
|
||||
// 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 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
|
||||
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 class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
|
||||
* @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 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
|
||||
* 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 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
|
||||
*/
|
||||
@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 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
|
||||
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;
|
||||
}
|
||||
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;
|
||||
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;
|
||||
}
|
||||
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 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
|
||||
|
||||
// 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 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
|
||||
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 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,7 +89,7 @@ public interface ConcurrentMap<K,V> extends Map<K,V> {
|
||||
return ((v = get(key)) != null) ? v : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @implSpec The default implementation is equivalent to, for this
|
||||
@ -181,10 +181,10 @@ public interface ConcurrentMap<K,V> extends Map<K,V> {
|
||||
* 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);
|
||||
|
||||
|
||||
@ -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 @@ public interface ConcurrentNavigableMap<K,V>
|
||||
* 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 @@ public interface ConcurrentNavigableMap<K,V>
|
||||
*
|
||||
* @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 @@ public interface ConcurrentNavigableMap<K,V>
|
||||
*
|
||||
* @return a reverse order navigable set view of the keys in this map
|
||||
*/
|
||||
public NavigableSet<K> descendingKeySet();
|
||||
NavigableSet<K> descendingKeySet();
|
||||
}
|
||||
|
||||
@ -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.NavigableSet;
|
||||
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 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
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 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
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 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
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 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
}
|
||||
|
||||
// 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 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
*
|
||||
* 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 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
|
||||
// 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 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
* 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 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
* @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 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
* <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 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
}
|
||||
}
|
||||
|
||||
// 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 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
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 class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
}
|
||||
public Object[] toArray() { return toList(this).toArray(); }
|
||||
public <T> T[] toArray(T[] a) { return toList(this).toArray(a); }
|
||||
public Iterator<E> descendingIterator() {
|
||||
public Iterator<K> descendingIterator() {
|
||||
return descendingSet().iterator();
|
||||
}
|
||||
public NavigableSet<E> subSet(E fromElement,
|
||||
public NavigableSet<K> subSet(K fromElement,
|
||||
boolean fromInclusive,
|
||||
E toElement,
|
||||
K toElement,
|
||||
boolean toInclusive) {
|
||||
return new KeySet<E>(m.subMap(fromElement, fromInclusive,
|
||||
toElement, toInclusive));
|
||||
return new KeySet<>(m.subMap(fromElement, fromInclusive,
|
||||
toElement, toInclusive));
|
||||
}
|
||||
public NavigableSet<E> headSet(E toElement, boolean inclusive) {
|
||||
return new KeySet<E>(m.headMap(toElement, inclusive));
|
||||
public NavigableSet<K> headSet(K toElement, boolean inclusive) {
|
||||
return new KeySet<>(m.headMap(toElement, inclusive));
|
||||
}
|
||||
public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
|
||||
return new KeySet<E>(m.tailMap(fromElement, inclusive));
|
||||
public NavigableSet<K> tailSet(K fromElement, boolean inclusive) {
|
||||
return new KeySet<>(m.tailMap(fromElement, inclusive));
|
||||
}
|
||||
public NavigableSet<E> subSet(E fromElement, E toElement) {
|
||||
public NavigableSet<K> subSet(K fromElement, K toElement) {
|
||||
return subSet(fromElement, true, toElement, false);
|
||||
}
|
||||
public NavigableSet<E> headSet(E toElement) {
|
||||
public NavigableSet<K> headSet(K toElement) {
|
||||
return headSet(toElement, false);
|
||||
}
|
||||
public NavigableSet<E> tailSet(E fromElement) {
|
||||
public NavigableSet<K> tailSet(K fromElement) {
|
||||
return tailSet(fromElement, true);
|
||||
}
|
||||
public NavigableSet<E> descendingSet() {
|
||||
return new KeySet<E>(m.descendingMap());
|
||||
public NavigableSet<K> descendingSet() {
|
||||
return new KeySet<>(m.descendingMap());
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
public Spliterator<E> spliterator() {
|
||||
if (m instanceof ConcurrentSkipListMap)
|
||||
return ((ConcurrentSkipListMap<E,?>)m).keySpliterator();
|
||||
else
|
||||
return (Spliterator<E>)((SubMap<E,?>)m).keyIterator();
|
||||
|
||||
public Spliterator<K> spliterator() {
|
||||
return (m instanceof ConcurrentSkipListMap)
|
||||
? ((ConcurrentSkipListMap<K,V>)m).keySpliterator()
|
||||
: ((SubMap<K,V>)m).new SubMapKeyIterator();
|
||||
}
|
||||
}
|
||||
|
||||
static final class Values<E> extends AbstractCollection<E> {
|
||||
final ConcurrentNavigableMap<?, E> m;
|
||||
Values(ConcurrentNavigableMap<?, E> map) {
|
||||
static final class Values<K,V> extends AbstractCollection<V> {
|
||||
final ConcurrentNavigableMap<K,V> m;
|
||||
Values(ConcurrentNavigableMap<K,V> map) {
|
||||
m = map;
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
public Iterator<E> iterator() {
|
||||
if (m instanceof ConcurrentSkipListMap)
|
||||
return ((ConcurrentSkipListMap<?,E>)m).valueIterator();
|
||||
else
|
||||
return ((SubMap<?,E>)m).valueIterator();
|
||||
}
|
||||
public boolean isEmpty() {
|
||||
return m.isEmpty();
|
||||
}
|
||||
public int size() {
|
||||
return m.size();
|
||||
}
|
||||
public boolean contains(Object o) {
|
||||
return m.containsValue(o);
|
||||
}
|
||||
public void clear() {
|
||||
m.clear();
|
||||
public Iterator<V> iterator() {
|
||||
return (m instanceof ConcurrentSkipListMap)
|
||||
? ((ConcurrentSkipListMap<K,V>)m).new ValueIterator()
|
||||
: ((SubMap<K,V>)m).new SubMapValueIterator();
|
||||
}
|
||||
public int size() { return m.size(); }
|
||||
public boolean 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 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
}
|
||||
}
|
||||
|
||||
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 class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
}
|
||||
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 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
|
||||
/**
|
||||
* 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 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
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 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
/** 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 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
/* ---------------- 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 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
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 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
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 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
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 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
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 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,6 +34,7 @@
|
||||
*/
|
||||
|
||||
package java.util.concurrent;
|
||||
|
||||
import java.util.AbstractSet;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@ -323,8 +324,9 @@ public class ConcurrentSkipListSet<E>
|
||||
*
|
||||
* @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 @@ public class ConcurrentSkipListSet<E>
|
||||
|
||||
/* ---------------- SortedSet operations -------------- */
|
||||
|
||||
|
||||
public Comparator<? super E> comparator() {
|
||||
return m.comparator();
|
||||
}
|
||||
@ -498,28 +499,24 @@ public class ConcurrentSkipListSet<E>
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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.Objects;
|
||||
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 @@ import java.util.function.UnaryOperator;
|
||||
*
|
||||
* @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;
|
||||
@ -171,13 +174,6 @@ public class CopyOnWriteArrayList<E>
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@ -224,8 +220,7 @@ public class CopyOnWriteArrayList<E>
|
||||
/**
|
||||
* 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 @@ public class CopyOnWriteArrayList<E>
|
||||
* 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 @@ public class CopyOnWriteArrayList<E>
|
||||
* 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 @@ public class CopyOnWriteArrayList<E>
|
||||
* 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 @@ public class CopyOnWriteArrayList<E>
|
||||
* @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 @@ public class CopyOnWriteArrayList<E>
|
||||
return (E) a[index];
|
||||
}
|
||||
|
||||
static String outOfBounds(int index, int size) {
|
||||
return "Index: " + index + ", Size: " + size;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
@ -404,9 +403,7 @@ public class CopyOnWriteArrayList<E>
|
||||
* @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 @@ public class CopyOnWriteArrayList<E>
|
||||
setArray(elements);
|
||||
}
|
||||
return oldValue;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@ -432,17 +427,13 @@ public class CopyOnWriteArrayList<E>
|
||||
* @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 @@ public class CopyOnWriteArrayList<E>
|
||||
* @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 @@ public class CopyOnWriteArrayList<E>
|
||||
}
|
||||
newElements[index] = element;
|
||||
setArray(newElements);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@ -487,9 +473,7 @@ public class CopyOnWriteArrayList<E>
|
||||
* @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 @@ public class CopyOnWriteArrayList<E>
|
||||
setArray(newElements);
|
||||
}
|
||||
return oldValue;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@ -513,8 +495,7 @@ public class CopyOnWriteArrayList<E>
|
||||
* 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 @@ public class CopyOnWriteArrayList<E>
|
||||
* 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 @@ public class CopyOnWriteArrayList<E>
|
||||
len - index - 1);
|
||||
setArray(newElements);
|
||||
return true;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@ -579,9 +557,7 @@ public class CopyOnWriteArrayList<E>
|
||||
* ({@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 @@ public class CopyOnWriteArrayList<E>
|
||||
fromIndex, numMoved);
|
||||
setArray(newElements);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@ -620,16 +594,15 @@ public class CopyOnWriteArrayList<E>
|
||||
* 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 @@ public class CopyOnWriteArrayList<E>
|
||||
newElements[len] = e;
|
||||
setArray(newElements);
|
||||
return true;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@ -672,18 +643,16 @@ public class CopyOnWriteArrayList<E>
|
||||
* @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 @@ public class CopyOnWriteArrayList<E>
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@ -715,18 +682,16 @@ public class CopyOnWriteArrayList<E>
|
||||
* @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 @@ public class CopyOnWriteArrayList<E>
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@ -764,9 +727,7 @@ public class CopyOnWriteArrayList<E>
|
||||
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 @@ public class CopyOnWriteArrayList<E>
|
||||
setArray(newElements);
|
||||
}
|
||||
return added;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@ -793,12 +752,8 @@ public class CopyOnWriteArrayList<E>
|
||||
* 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 @@ public class CopyOnWriteArrayList<E>
|
||||
((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 @@ public class CopyOnWriteArrayList<E>
|
||||
setArray(newElements);
|
||||
}
|
||||
return true;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@ -853,14 +804,11 @@ public class CopyOnWriteArrayList<E>
|
||||
*/
|
||||
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 @@ public class CopyOnWriteArrayList<E>
|
||||
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 @@ public class CopyOnWriteArrayList<E>
|
||||
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 @@ public class CopyOnWriteArrayList<E>
|
||||
* 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 @@ public class CopyOnWriteArrayList<E>
|
||||
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 class CopyOnWriteArrayList<E>
|
||||
*/
|
||||
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 @@ public class CopyOnWriteArrayList<E>
|
||||
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 @@ public class CopyOnWriteArrayList<E>
|
||||
/** 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 @@ public class CopyOnWriteArrayList<E>
|
||||
}
|
||||
|
||||
@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 @@ public class CopyOnWriteArrayList<E>
|
||||
* @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 @@ public class CopyOnWriteArrayList<E>
|
||||
// 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 @@ public class CopyOnWriteArrayList<E>
|
||||
|
||||
// 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 class CopyOnWriteArrayList<E>
|
||||
}
|
||||
|
||||
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 class CopyOnWriteArrayList<E>
|
||||
|
||||
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 @@ public class CopyOnWriteArrayList<E>
|
||||
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 @@ public class CopyOnWriteArrayList<E>
|
||||
@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 @@ public class CopyOnWriteArrayList<E>
|
||||
l.setArray(expectedArray = newElements);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
@ -1513,9 +1395,7 @@ public class CopyOnWriteArrayList<E>
|
||||
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 @@ public class CopyOnWriteArrayList<E>
|
||||
l.setArray(expectedArray = newElements);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
@ -1553,9 +1431,7 @@ public class CopyOnWriteArrayList<E>
|
||||
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 @@ public class CopyOnWriteArrayList<E>
|
||||
l.setArray(expectedArray = newElements);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
@ -1658,29 +1532,26 @@ public class CopyOnWriteArrayList<E>
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,14 +34,16 @@
|
||||
*/
|
||||
|
||||
package java.util.concurrent;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import java.util.AbstractSet;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.Spliterator;
|
||||
import java.util.Spliterators;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* A {@link java.util.Set} that uses an internal {@link CopyOnWriteArrayList}
|
||||
@ -66,12 +68,12 @@ import java.util.function.Consumer;
|
||||
* 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 @@ import java.util.function.Consumer;
|
||||
* @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 @@ public class CopyOnWriteArraySet<E> extends AbstractSet<E>
|
||||
/**
|
||||
* 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 @@ public class CopyOnWriteArraySet<E> extends AbstractSet<E>
|
||||
* 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 @@ public class CopyOnWriteArraySet<E> extends AbstractSet<E>
|
||||
/**
|
||||
* 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 @@ public class CopyOnWriteArraySet<E> extends AbstractSet<E>
|
||||
* 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 @@ public class CopyOnWriteArraySet<E> extends AbstractSet<E>
|
||||
* @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 @@ public class CopyOnWriteArraySet<E> extends AbstractSet<E>
|
||||
* @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 @@ public class CopyOnWriteArraySet<E> extends AbstractSet<E>
|
||||
* @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 @@ public class CopyOnWriteArraySet<E> extends AbstractSet<E>
|
||||
* 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 @@ public class CopyOnWriteArraySet<E> extends AbstractSet<E>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,6 +34,7 @@
|
||||
*/
|
||||
|
||||
package java.util.concurrent;
|
||||
|
||||
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
|
||||
|
||||
/**
|
||||
@ -72,7 +73,7 @@ import java.util.concurrent.locks.AbstractQueuedSynchronizer;
|
||||
* 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 @@ import java.util.concurrent.locks.AbstractQueuedSynchronizer;
|
||||
* 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 @@ public class CountDownLatch {
|
||||
int c = getState();
|
||||
if (c == 0)
|
||||
return false;
|
||||
int nextc = c-1;
|
||||
int nextc = c - 1;
|
||||
if (compareAndSetState(c, nextc))
|
||||
return nextc == 0;
|
||||
}
|
||||
|
||||
@ -168,7 +168,8 @@ package java.util.concurrent;
|
||||
* {@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 @@ package java.util.concurrent;
|
||||
* 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 @@ package java.util.concurrent;
|
||||
* {@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 @@ package java.util.concurrent;
|
||||
* 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 @@ package java.util.concurrent;
|
||||
* }
|
||||
* 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 @@ package java.util.concurrent;
|
||||
* 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 @@ package java.util.concurrent;
|
||||
* 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 @@ package java.util.concurrent;
|
||||
* // 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 @@ public abstract class CountedCompleter<T> extends ForkJoinTask<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public abstract class CountedCompleter<T> extends ForkJoinTask<T> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,6 +34,7 @@
|
||||
*/
|
||||
|
||||
package java.util.concurrent;
|
||||
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
@ -54,7 +55,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
* <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 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
* 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 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
* {@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 @@ public class CyclicBarrier {
|
||||
* 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 @@ public class CyclicBarrier {
|
||||
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();
|
||||
|
||||
@ -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 @@ import java.util.*;
|
||||
*
|
||||
* @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 @@ public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
|
||||
* 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 @@ public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
|
||||
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 @@ public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
|
||||
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 @@ public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
|
||||
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 @@ public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
@ -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 @@ import java.util.concurrent.locks.LockSupport;
|
||||
* 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 @@ public class Exchanger<V> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Per-thread state
|
||||
* Per-thread state.
|
||||
*/
|
||||
private final Participant participant;
|
||||
|
||||
@ -628,37 +625,33 @@ public class Exchanger<V> {
|
||||
}
|
||||
|
||||
// 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"));
|
||||
MATCH = U.objectFieldOffset
|
||||
(nk.getDeclaredField("match"));
|
||||
BLOCKER = U.objectFieldOffset
|
||||
(tk.getDeclaredField("parkBlocker"));
|
||||
s = U.arrayIndexScale(ak);
|
||||
// ABASE absorbs padding in front of element 0
|
||||
ABASE = U.arrayBaseOffset(ak) + (1 << ASHIFT);
|
||||
(Exchanger.class.getDeclaredField("slot"));
|
||||
|
||||
} catch (Exception e) {
|
||||
MATCH = U.objectFieldOffset
|
||||
(Node.class.getDeclaredField("match"));
|
||||
|
||||
BLOCKER = U.objectFieldOffset
|
||||
(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(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");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -41,33 +41,31 @@ package java.util.concurrent;
|
||||
* 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 @@ package java.util.concurrent;
|
||||
* 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 @@ package java.util.concurrent;
|
||||
* }
|
||||
*
|
||||
* public synchronized void execute(final Runnable r) {
|
||||
* tasks.offer(new Runnable() {
|
||||
* tasks.add(new Runnable() {
|
||||
* public void run() {
|
||||
* try {
|
||||
* r.run();
|
||||
|
||||
@ -56,16 +56,16 @@ package java.util.concurrent;
|
||||
* 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 @@ package java.util.concurrent;
|
||||
* 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 @@ public class ExecutorCompletionService<V> implements CompletionService<V> {
|
||||
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;
|
||||
}
|
||||
protected void done() { completionQueue.add(task); }
|
||||
private final Future<V> task;
|
||||
private final BlockingQueue<Future<V>> completionQueue;
|
||||
protected void done() { completionQueue.add(task); }
|
||||
}
|
||||
|
||||
private RunnableFuture<V> newTaskFor(Callable<V> task) {
|
||||
@ -178,14 +180,14 @@ public class ExecutorCompletionService<V> implements CompletionService<V> {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@ -34,8 +34,9 @@
|
||||
*/
|
||||
|
||||
package java.util.concurrent;
|
||||
import java.util.List;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An {@link Executor} that provides methods to manage termination and
|
||||
@ -71,7 +72,7 @@ import java.util.Collection;
|
||||
* 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 @@ import java.util.Collection;
|
||||
* 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 {
|
||||
|
||||
@ -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.PrivilegedExceptionAction;
|
||||
import java.security.PrivilegedActionException;
|
||||
import java.security.AccessControlException;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import sun.security.util.SecurityConstants;
|
||||
|
||||
/**
|
||||
@ -51,18 +53,18 @@ import sun.security.util.SecurityConstants;
|
||||
* 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 @@ public class Executors {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public class Executors {
|
||||
// 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 @@ public class Executors {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public class Executors {
|
||||
|
||||
/**
|
||||
* 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 @@ public class Executors {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public class Executors {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public class Executors {
|
||||
* 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 @@ public class Executors {
|
||||
}
|
||||
}
|
||||
|
||||
static class FinalizableDelegatedExecutorService
|
||||
extends DelegatedExecutorService {
|
||||
private static class FinalizableDelegatedExecutorService
|
||||
extends DelegatedExecutorService {
|
||||
FinalizableDelegatedExecutorService(ExecutorService executor) {
|
||||
super(executor);
|
||||
}
|
||||
@ -717,7 +722,7 @@ public class Executors {
|
||||
* 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;
|
||||
|
||||
319
jdk/src/java.base/share/classes/java/util/concurrent/Flow.java
Normal file
319
jdk/src/java.base/share/classes/java/util/concurrent/Flow.java
Normal file
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -36,21 +36,13 @@
|
||||
package java.util.concurrent;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.RandomAccess;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.RunnableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
/**
|
||||
* Abstract base class for tasks that run within a {@link ForkJoinPool}.
|
||||
@ -442,7 +434,8 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
ExceptionNode next;
|
||||
final long thrower; // use id not ref to avoid weak cycles
|
||||
final int hashCode; // store task hashCode before weak ref disappears
|
||||
ExceptionNode(ForkJoinTask<?> task, Throwable ex, ExceptionNode next) {
|
||||
ExceptionNode(ForkJoinTask<?> task, Throwable ex, ExceptionNode next,
|
||||
ReferenceQueue<Object> exceptionTableRefQueue) {
|
||||
super(task, exceptionTableRefQueue);
|
||||
this.ex = ex;
|
||||
this.next = next;
|
||||
@ -468,7 +461,8 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
int i = h & (t.length - 1);
|
||||
for (ExceptionNode e = t[i]; ; e = e.next) {
|
||||
if (e == null) {
|
||||
t[i] = new ExceptionNode(this, ex, t[i]);
|
||||
t[i] = new ExceptionNode(this, ex, t[i],
|
||||
exceptionTableRefQueue);
|
||||
break;
|
||||
}
|
||||
if (e.get() == this) // already present
|
||||
@ -561,8 +555,6 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
* @return the exception, or null if none
|
||||
*/
|
||||
private Throwable getThrowableException() {
|
||||
if ((status & DONE_MASK) != EXCEPTIONAL)
|
||||
return null;
|
||||
int h = System.identityHashCode(this);
|
||||
ExceptionNode e;
|
||||
final ReentrantLock lock = exceptionTableLock;
|
||||
@ -608,7 +600,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Poll stale refs and remove them. Call only while holding lock.
|
||||
* Polls stale refs and removes them. Call only while holding lock.
|
||||
*/
|
||||
private static void expungeStaleExceptions() {
|
||||
for (Object x; (x = exceptionTableRefQueue.poll()) != null;) {
|
||||
@ -635,7 +627,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* If lock is available, poll stale refs and remove them.
|
||||
* If lock is available, polls stale refs and removes them.
|
||||
* Called from ForkJoinPool when pools become quiescent.
|
||||
*/
|
||||
static final void helpExpungeStaleExceptions() {
|
||||
@ -650,21 +642,23 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* A version of "sneaky throw" to relay exceptions
|
||||
* A version of "sneaky throw" to relay exceptions.
|
||||
*/
|
||||
static void rethrow(Throwable ex) {
|
||||
if (ex != null)
|
||||
ForkJoinTask.<RuntimeException>uncheckedThrow(ex);
|
||||
ForkJoinTask.<RuntimeException>uncheckedThrow(ex);
|
||||
}
|
||||
|
||||
/**
|
||||
* The sneaky part of sneaky throw, relying on generics
|
||||
* limitations to evade compiler complaints about rethrowing
|
||||
* unchecked exceptions
|
||||
* unchecked exceptions.
|
||||
*/
|
||||
@SuppressWarnings("unchecked") static <T extends Throwable>
|
||||
void uncheckedThrow(Throwable t) throws T {
|
||||
throw (T)t; // rely on vacuous cast
|
||||
void uncheckedThrow(Throwable t) throws T {
|
||||
if (t != null)
|
||||
throw (T)t; // rely on vacuous cast
|
||||
else
|
||||
throw new Error("Unknown Exception");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -999,11 +993,10 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
public final V get() throws InterruptedException, ExecutionException {
|
||||
int s = (Thread.currentThread() instanceof ForkJoinWorkerThread) ?
|
||||
doJoin() : externalInterruptibleAwaitDone();
|
||||
Throwable ex;
|
||||
if ((s &= DONE_MASK) == CANCELLED)
|
||||
throw new CancellationException();
|
||||
if (s == EXCEPTIONAL && (ex = getThrowableException()) != null)
|
||||
throw new ExecutionException(ex);
|
||||
if (s == EXCEPTIONAL)
|
||||
throw new ExecutionException(getThrowableException());
|
||||
return getRawResult();
|
||||
}
|
||||
|
||||
@ -1058,13 +1051,11 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
if (s >= 0)
|
||||
s = status;
|
||||
if ((s &= DONE_MASK) != NORMAL) {
|
||||
Throwable ex;
|
||||
if (s == CANCELLED)
|
||||
throw new CancellationException();
|
||||
if (s != EXCEPTIONAL)
|
||||
throw new TimeoutException();
|
||||
if ((ex = getThrowableException()) != null)
|
||||
throw new ExecutionException(ex);
|
||||
throw new ExecutionException(getThrowableException());
|
||||
}
|
||||
return getRawResult();
|
||||
}
|
||||
@ -1090,10 +1081,10 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
|
||||
/**
|
||||
* Possibly executes tasks until the pool hosting the current task
|
||||
* {@link ForkJoinPool#isQuiescent is quiescent}. This method may
|
||||
* be of use in designs in which many tasks are forked, but none
|
||||
* are explicitly joined, instead executing them until all are
|
||||
* processed.
|
||||
* {@linkplain ForkJoinPool#isQuiescent is quiescent}. This
|
||||
* method may be of use in designs in which many tasks are forked,
|
||||
* but none are explicitly joined, instead executing them until
|
||||
* all are processed.
|
||||
*/
|
||||
public static void helpQuiesce() {
|
||||
Thread t;
|
||||
@ -1129,10 +1120,12 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the pool hosting the current task execution, or null
|
||||
* if this task is executing outside of any ForkJoinPool.
|
||||
* Returns the pool hosting the current thread, or {@code null}
|
||||
* if the current thread is executing outside of any ForkJoinPool.
|
||||
*
|
||||
* <p>This method returns {@code null} if and only if {@link
|
||||
* #inForkJoinPool} returns {@code false}.
|
||||
*
|
||||
* @see #inForkJoinPool
|
||||
* @return the pool, or {@code null} if none
|
||||
*/
|
||||
public static ForkJoinPool getPool() {
|
||||
@ -1299,6 +1292,23 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
null;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the current thread is operating in a ForkJoinPool,
|
||||
* unschedules and returns, without executing, a task externally
|
||||
* submitted to the pool, if one is available. Availability may be
|
||||
* transient, so a {@code null} result does not necessarily imply
|
||||
* quiescence of the pool. This method is designed primarily to
|
||||
* support extensions, and is unlikely to be useful otherwise.
|
||||
*
|
||||
* @return a task, or {@code null} if none are available
|
||||
* @since 1.9
|
||||
*/
|
||||
protected static ForkJoinTask<?> pollSubmission() {
|
||||
Thread t;
|
||||
return ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
|
||||
((ForkJoinWorkerThread)t).pool.pollSubmission() : null;
|
||||
}
|
||||
|
||||
// tag operations
|
||||
|
||||
/**
|
||||
@ -1312,16 +1322,16 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Atomically sets the tag value for this task.
|
||||
* Atomically sets the tag value for this task and returns the old value.
|
||||
*
|
||||
* @param tag the tag value
|
||||
* @param newValue the new tag value
|
||||
* @return the previous value of the tag
|
||||
* @since 1.8
|
||||
*/
|
||||
public final short setForkJoinTaskTag(short tag) {
|
||||
public final short setForkJoinTaskTag(short newValue) {
|
||||
for (int s;;) {
|
||||
if (U.compareAndSwapInt(this, STATUS, s = status,
|
||||
(s & ~SMASK) | (tag & SMASK)))
|
||||
(s & ~SMASK) | (newValue & SMASK)))
|
||||
return (short)s;
|
||||
}
|
||||
}
|
||||
@ -1334,24 +1344,24 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
* before processing, otherwise exiting because the node has
|
||||
* already been visited.
|
||||
*
|
||||
* @param e the expected tag value
|
||||
* @param tag the new tag value
|
||||
* @param expect the expected tag value
|
||||
* @param update the new tag value
|
||||
* @return {@code true} if successful; i.e., the current value was
|
||||
* equal to e and is now tag.
|
||||
* equal to {@code expect} and was changed to {@code update}.
|
||||
* @since 1.8
|
||||
*/
|
||||
public final boolean compareAndSetForkJoinTaskTag(short e, short tag) {
|
||||
public final boolean compareAndSetForkJoinTaskTag(short expect, short update) {
|
||||
for (int s;;) {
|
||||
if ((short)(s = status) != e)
|
||||
if ((short)(s = status) != expect)
|
||||
return false;
|
||||
if (U.compareAndSwapInt(this, STATUS, s,
|
||||
(s & ~SMASK) | (tag & SMASK)))
|
||||
(s & ~SMASK) | (update & SMASK)))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adaptor for Runnables. This implements RunnableFuture
|
||||
* Adapter for Runnables. This implements RunnableFuture
|
||||
* to be compliant with AbstractExecutorService constraints
|
||||
* when used in ForkJoinPool.
|
||||
*/
|
||||
@ -1372,7 +1382,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adaptor for Runnables without results
|
||||
* Adapter for Runnables without results.
|
||||
*/
|
||||
static final class AdaptedRunnableAction extends ForkJoinTask<Void>
|
||||
implements RunnableFuture<Void> {
|
||||
@ -1389,7 +1399,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adaptor for Runnables in which failure forces worker exception
|
||||
* Adapter for Runnables in which failure forces worker exception.
|
||||
*/
|
||||
static final class RunnableExecuteAction extends ForkJoinTask<Void> {
|
||||
final Runnable runnable;
|
||||
@ -1407,7 +1417,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adaptor for Callables
|
||||
* Adapter for Callables.
|
||||
*/
|
||||
static final class AdaptedCallable<T> extends ForkJoinTask<T>
|
||||
implements RunnableFuture<T> {
|
||||
@ -1423,8 +1433,6 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
try {
|
||||
result = callable.call();
|
||||
return true;
|
||||
} catch (Error err) {
|
||||
throw err;
|
||||
} catch (RuntimeException rex) {
|
||||
throw rex;
|
||||
} catch (Exception ex) {
|
||||
@ -1509,7 +1517,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
}
|
||||
|
||||
// Unsafe mechanics
|
||||
private static final sun.misc.Unsafe U;
|
||||
private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
|
||||
private static final long STATUS;
|
||||
|
||||
static {
|
||||
@ -1517,11 +1525,9 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
exceptionTableRefQueue = new ReferenceQueue<Object>();
|
||||
exceptionTable = new ExceptionNode[EXCEPTION_MAP_CAPACITY];
|
||||
try {
|
||||
U = sun.misc.Unsafe.getUnsafe();
|
||||
Class<?> k = ForkJoinTask.class;
|
||||
STATUS = U.objectFieldOffset
|
||||
(k.getDeclaredField("status"));
|
||||
} catch (Exception e) {
|
||||
(ForkJoinTask.class.getDeclaredField("status"));
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,7 +87,7 @@ public class ForkJoinWorkerThread extends Thread {
|
||||
}
|
||||
|
||||
/**
|
||||
* Version for InnocuousForkJoinWorkerThread
|
||||
* Version for InnocuousForkJoinWorkerThread.
|
||||
*/
|
||||
ForkJoinWorkerThread(ForkJoinPool pool, ThreadGroup threadGroup,
|
||||
AccessControlContext acc) {
|
||||
@ -179,28 +179,25 @@ public class ForkJoinWorkerThread extends Thread {
|
||||
}
|
||||
|
||||
/**
|
||||
* Non-public hook method for InnocuousForkJoinWorkerThread
|
||||
* Non-public hook method for InnocuousForkJoinWorkerThread.
|
||||
*/
|
||||
void afterTopLevelExec() {
|
||||
}
|
||||
|
||||
// Set up to allow setting thread fields in constructor
|
||||
private static final sun.misc.Unsafe U;
|
||||
private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
|
||||
private static final long THREADLOCALS;
|
||||
private static final long INHERITABLETHREADLOCALS;
|
||||
private static final long INHERITEDACCESSCONTROLCONTEXT;
|
||||
static {
|
||||
try {
|
||||
U = sun.misc.Unsafe.getUnsafe();
|
||||
Class<?> tk = Thread.class;
|
||||
THREADLOCALS = U.objectFieldOffset
|
||||
(tk.getDeclaredField("threadLocals"));
|
||||
(Thread.class.getDeclaredField("threadLocals"));
|
||||
INHERITABLETHREADLOCALS = U.objectFieldOffset
|
||||
(tk.getDeclaredField("inheritableThreadLocals"));
|
||||
(Thread.class.getDeclaredField("inheritableThreadLocals"));
|
||||
INHERITEDACCESSCONTROLCONTEXT = U.objectFieldOffset
|
||||
(tk.getDeclaredField("inheritedAccessControlContext"));
|
||||
|
||||
} catch (Exception e) {
|
||||
(Thread.class.getDeclaredField("inheritedAccessControlContext"));
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
@ -252,10 +249,10 @@ public class ForkJoinWorkerThread extends Thread {
|
||||
private static ThreadGroup createThreadGroup() {
|
||||
try {
|
||||
sun.misc.Unsafe u = sun.misc.Unsafe.getUnsafe();
|
||||
Class<?> tk = Thread.class;
|
||||
Class<?> gk = ThreadGroup.class;
|
||||
long tg = u.objectFieldOffset(tk.getDeclaredField("group"));
|
||||
long gp = u.objectFieldOffset(gk.getDeclaredField("parent"));
|
||||
long tg = u.objectFieldOffset
|
||||
(Thread.class.getDeclaredField("group"));
|
||||
long gp = u.objectFieldOffset
|
||||
(ThreadGroup.class.getDeclaredField("parent"));
|
||||
ThreadGroup group = (ThreadGroup)
|
||||
u.getObject(Thread.currentThread(), tg);
|
||||
while (group != null) {
|
||||
@ -265,7 +262,7 @@ public class ForkJoinWorkerThread extends Thread {
|
||||
"InnocuousForkJoinWorkerThreadGroup");
|
||||
group = parent;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
// fall through if null as cannot-happen safeguard
|
||||
|
||||
@ -53,6 +53,7 @@ package java.util.concurrent;
|
||||
* <p>
|
||||
* <b>Sample Usage</b> (Note that the following classes are all
|
||||
* made-up.)
|
||||
*
|
||||
* <pre> {@code
|
||||
* interface ArchiveSearcher { String search(String target); }
|
||||
* class App {
|
||||
@ -75,9 +76,9 @@ package java.util.concurrent;
|
||||
* The {@link FutureTask} class is an implementation of {@code Future} that
|
||||
* implements {@code Runnable}, and so may be executed by an {@code Executor}.
|
||||
* For example, the above construction with {@code submit} could be replaced by:
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* FutureTask<String> future =
|
||||
* new FutureTask<String>(new Callable<String>() {
|
||||
* new FutureTask<>(new Callable<String>() {
|
||||
* public String call() {
|
||||
* return searcher.search(target);
|
||||
* }});
|
||||
|
||||
@ -34,6 +34,7 @@
|
||||
*/
|
||||
|
||||
package java.util.concurrent;
|
||||
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
|
||||
/**
|
||||
@ -395,7 +396,7 @@ public class FutureTask<V> implements RunnableFuture<V> {
|
||||
throws InterruptedException {
|
||||
// The code below is very delicate, to achieve these goals:
|
||||
// - call nanoTime exactly once for each call to park
|
||||
// - if nanos <= 0, return promptly without allocation or nanoTime
|
||||
// - if nanos <= 0L, return promptly without allocation or nanoTime
|
||||
// - if nanos == Long.MIN_VALUE, don't underflow
|
||||
// - if nanos == Long.MAX_VALUE, and nanoTime is non-monotonic
|
||||
// and we suffer a spurious wakeup, we will do no worse than
|
||||
@ -404,19 +405,20 @@ public class FutureTask<V> implements RunnableFuture<V> {
|
||||
WaitNode q = null;
|
||||
boolean queued = false;
|
||||
for (;;) {
|
||||
if (Thread.interrupted()) {
|
||||
removeWaiter(q);
|
||||
throw new InterruptedException();
|
||||
}
|
||||
|
||||
int s = state;
|
||||
if (s > COMPLETING) {
|
||||
if (q != null)
|
||||
q.thread = null;
|
||||
return s;
|
||||
}
|
||||
else if (s == COMPLETING) // cannot time out yet
|
||||
else if (s == COMPLETING)
|
||||
// We may have already promised (via isDone) that we are done
|
||||
// so never return empty-handed or throw InterruptedException
|
||||
Thread.yield();
|
||||
else if (Thread.interrupted()) {
|
||||
removeWaiter(q);
|
||||
throw new InterruptedException();
|
||||
}
|
||||
else if (q == null) {
|
||||
if (timed && nanos <= 0L)
|
||||
return s;
|
||||
@ -440,7 +442,9 @@ public class FutureTask<V> implements RunnableFuture<V> {
|
||||
}
|
||||
parkNanos = nanos - elapsed;
|
||||
}
|
||||
LockSupport.parkNanos(this, parkNanos);
|
||||
// nanoTime may be slow; recheck before parking
|
||||
if (state < COMPLETING)
|
||||
LockSupport.parkNanos(this, parkNanos);
|
||||
}
|
||||
else
|
||||
LockSupport.park(this);
|
||||
@ -480,20 +484,25 @@ public class FutureTask<V> implements RunnableFuture<V> {
|
||||
}
|
||||
|
||||
// Unsafe mechanics
|
||||
private static final sun.misc.Unsafe U;
|
||||
private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
|
||||
private static final long STATE;
|
||||
private static final long RUNNER;
|
||||
private static final long WAITERS;
|
||||
static {
|
||||
try {
|
||||
U = sun.misc.Unsafe.getUnsafe();
|
||||
Class<?> k = FutureTask.class;
|
||||
STATE = U.objectFieldOffset(k.getDeclaredField("state"));
|
||||
RUNNER = U.objectFieldOffset(k.getDeclaredField("runner"));
|
||||
WAITERS = U.objectFieldOffset(k.getDeclaredField("waiters"));
|
||||
} catch (Exception e) {
|
||||
STATE = U.objectFieldOffset
|
||||
(FutureTask.class.getDeclaredField("state"));
|
||||
RUNNER = U.objectFieldOffset
|
||||
(FutureTask.class.getDeclaredField("runner"));
|
||||
WAITERS = U.objectFieldOffset
|
||||
(FutureTask.class.getDeclaredField("waiters"));
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
|
||||
// Reduce the risk of rare disastrous classloading in first call to
|
||||
// LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
|
||||
Class<?> ensureLoaded = LockSupport.class;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* Written by Martin Buchholz with assistance from members of JCP
|
||||
* JSR-166 Expert Group and released to the public domain, as
|
||||
* explained at http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
package java.util.concurrent;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/** Shared implementation code for java.util.concurrent. */
|
||||
class Helpers {
|
||||
private Helpers() {} // non-instantiable
|
||||
|
||||
/**
|
||||
* An implementation of Collection.toString() suitable for classes
|
||||
* with locks. Instead of holding a lock for the entire duration of
|
||||
* toString(), or acquiring a lock for each call to Iterator.next(),
|
||||
* we hold the lock only during the call to toArray() (less
|
||||
* disruptive to other threads accessing the collection) and follows
|
||||
* the maxim "Never call foreign code while holding a lock".
|
||||
*/
|
||||
static String collectionToString(Collection<?> c) {
|
||||
final Object[] a = c.toArray();
|
||||
final int size = a.length;
|
||||
if (size == 0)
|
||||
return "[]";
|
||||
int charLength = 0;
|
||||
|
||||
// Replace every array element with its string representation
|
||||
for (int i = 0; i < size; i++) {
|
||||
Object e = a[i];
|
||||
// Extreme compatibility with AbstractCollection.toString()
|
||||
String s = (e == c) ? "(this Collection)" : objectToString(e);
|
||||
a[i] = s;
|
||||
charLength += s.length();
|
||||
}
|
||||
|
||||
return toString(a, size, charLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like Arrays.toString(), but caller guarantees that size > 0,
|
||||
* each element with index 0 <= i < size is a non-null String,
|
||||
* and charLength is the sum of the lengths of the input Strings.
|
||||
*/
|
||||
static String toString(Object[] a, int size, int charLength) {
|
||||
// assert a != null;
|
||||
// assert size > 0;
|
||||
|
||||
// Copy each string into a perfectly sized char[]
|
||||
// Length of [ , , , ] == 2 * size
|
||||
final char[] chars = new char[charLength + 2 * size];
|
||||
chars[0] = '[';
|
||||
int j = 1;
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (i > 0) {
|
||||
chars[j++] = ',';
|
||||
chars[j++] = ' ';
|
||||
}
|
||||
String s = (String) a[i];
|
||||
int len = s.length();
|
||||
s.getChars(0, len, chars, j);
|
||||
j += len;
|
||||
}
|
||||
chars[j] = ']';
|
||||
// assert j == chars.length - 1;
|
||||
return new String(chars);
|
||||
}
|
||||
|
||||
/** Optimized form of: key + "=" + val */
|
||||
static String mapEntryToString(Object key, Object val) {
|
||||
final String k, v;
|
||||
final int klen, vlen;
|
||||
final char[] chars =
|
||||
new char[(klen = (k = objectToString(key)).length()) +
|
||||
(vlen = (v = objectToString(val)).length()) + 1];
|
||||
k.getChars(0, klen, chars, 0);
|
||||
chars[klen] = '=';
|
||||
v.getChars(0, vlen, chars, klen + 1);
|
||||
return new String(chars);
|
||||
}
|
||||
|
||||
private static String objectToString(Object x) {
|
||||
// Extreme compatibility with StringBuilder.append(null)
|
||||
String s;
|
||||
return (x == null || (s = x.toString()) == null) ? "null" : s;
|
||||
}
|
||||
}
|
||||
@ -39,10 +39,10 @@ import java.util.AbstractQueue;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.Spliterator;
|
||||
import java.util.Spliterators;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
@ -72,7 +72,7 @@ import java.util.function.Consumer;
|
||||
*
|
||||
* @since 1.6
|
||||
* @author Doug Lea
|
||||
* @param <E> the type of elements held in this collection
|
||||
* @param <E> the type of elements held in this deque
|
||||
*/
|
||||
public class LinkedBlockingDeque<E>
|
||||
extends AbstractQueue<E>
|
||||
@ -412,7 +412,7 @@ public class LinkedBlockingDeque<E>
|
||||
lock.lockInterruptibly();
|
||||
try {
|
||||
while (!linkFirst(node)) {
|
||||
if (nanos <= 0)
|
||||
if (nanos <= 0L)
|
||||
return false;
|
||||
nanos = notFull.awaitNanos(nanos);
|
||||
}
|
||||
@ -435,7 +435,7 @@ public class LinkedBlockingDeque<E>
|
||||
lock.lockInterruptibly();
|
||||
try {
|
||||
while (!linkLast(node)) {
|
||||
if (nanos <= 0)
|
||||
if (nanos <= 0L)
|
||||
return false;
|
||||
nanos = notFull.awaitNanos(nanos);
|
||||
}
|
||||
@ -517,7 +517,7 @@ public class LinkedBlockingDeque<E>
|
||||
try {
|
||||
E x;
|
||||
while ( (x = unlinkFirst()) == null) {
|
||||
if (nanos <= 0)
|
||||
if (nanos <= 0L)
|
||||
return null;
|
||||
nanos = notEmpty.awaitNanos(nanos);
|
||||
}
|
||||
@ -535,7 +535,7 @@ public class LinkedBlockingDeque<E>
|
||||
try {
|
||||
E x;
|
||||
while ( (x = unlinkLast()) == null) {
|
||||
if (nanos <= 0)
|
||||
if (nanos <= 0L)
|
||||
return null;
|
||||
nanos = notEmpty.awaitNanos(nanos);
|
||||
}
|
||||
@ -924,7 +924,7 @@ public class LinkedBlockingDeque<E>
|
||||
* The following code can be used to dump the deque into a newly
|
||||
* allocated array of {@code String}:
|
||||
*
|
||||
* <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
|
||||
* <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
|
||||
*
|
||||
* Note that {@code toArray(new Object[0])} is identical in function to
|
||||
* {@code toArray()}.
|
||||
@ -959,26 +959,7 @@ public class LinkedBlockingDeque<E>
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
Node<E> p = first;
|
||||
if (p == null)
|
||||
return "[]";
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append('[');
|
||||
for (;;) {
|
||||
E e = p.item;
|
||||
sb.append(e == this ? "(this Collection)" : e);
|
||||
p = p.next;
|
||||
if (p == null)
|
||||
return sb.append(']').toString();
|
||||
sb.append(',').append(' ');
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return Helpers.collectionToString(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1032,11 +1013,11 @@ public class LinkedBlockingDeque<E>
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for Iterators for LinkedBlockingDeque
|
||||
* Base class for LinkedBlockingDeque iterators.
|
||||
*/
|
||||
private abstract class AbstractItr implements Iterator<E> {
|
||||
/**
|
||||
* The next node to return in next()
|
||||
* The next node to return in next().
|
||||
*/
|
||||
Node<E> next;
|
||||
|
||||
@ -1192,8 +1173,9 @@ public class LinkedBlockingDeque<E>
|
||||
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;
|
||||
|
||||
@ -35,15 +35,15 @@
|
||||
|
||||
package java.util.concurrent;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.AbstractQueue;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Spliterator;
|
||||
import java.util.Spliterators;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
@ -75,7 +75,7 @@ import java.util.function.Consumer;
|
||||
*
|
||||
* @since 1.5
|
||||
* @author Doug Lea
|
||||
* @param <E> the type of elements held in this collection
|
||||
* @param <E> the type of elements held in this queue
|
||||
*/
|
||||
public class LinkedBlockingQueue<E> extends AbstractQueue<E>
|
||||
implements BlockingQueue<E>, java.io.Serializable {
|
||||
@ -117,7 +117,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
|
||||
*/
|
||||
|
||||
/**
|
||||
* Linked list node class
|
||||
* Linked list node class.
|
||||
*/
|
||||
static class Node<E> {
|
||||
E item;
|
||||
@ -380,7 +380,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
|
||||
putLock.lockInterruptibly();
|
||||
try {
|
||||
while (count.get() == capacity) {
|
||||
if (nanos <= 0)
|
||||
if (nanos <= 0L)
|
||||
return false;
|
||||
nanos = notFull.awaitNanos(nanos);
|
||||
}
|
||||
@ -462,7 +462,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
|
||||
takeLock.lockInterruptibly();
|
||||
try {
|
||||
while (count.get() == 0) {
|
||||
if (nanos <= 0)
|
||||
if (nanos <= 0L)
|
||||
return null;
|
||||
nanos = notEmpty.awaitNanos(nanos);
|
||||
}
|
||||
@ -507,11 +507,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
|
||||
final ReentrantLock takeLock = this.takeLock;
|
||||
takeLock.lock();
|
||||
try {
|
||||
Node<E> first = head.next;
|
||||
if (first == null)
|
||||
return null;
|
||||
else
|
||||
return first.item;
|
||||
return (count.get() > 0) ? head.next.item : null;
|
||||
} finally {
|
||||
takeLock.unlock();
|
||||
}
|
||||
@ -630,7 +626,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
|
||||
* The following code can be used to dump the queue into a newly
|
||||
* allocated array of {@code String}:
|
||||
*
|
||||
* <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
|
||||
* <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
|
||||
*
|
||||
* Note that {@code toArray(new Object[0])} is identical in function to
|
||||
* {@code toArray()}.
|
||||
@ -665,25 +661,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
fullyLock();
|
||||
try {
|
||||
Node<E> p = head.next;
|
||||
if (p == null)
|
||||
return "[]";
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append('[');
|
||||
for (;;) {
|
||||
E e = p.item;
|
||||
sb.append(e == this ? "(this Collection)" : e);
|
||||
p = p.next;
|
||||
if (p == null)
|
||||
return sb.append(']').toString();
|
||||
sb.append(',').append(' ');
|
||||
}
|
||||
} finally {
|
||||
fullyUnlock();
|
||||
}
|
||||
return Helpers.collectionToString(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -801,34 +779,26 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
|
||||
return current != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next live successor of p, or null if no such.
|
||||
*
|
||||
* Unlike other traversal methods, iterators need to handle both:
|
||||
* - dequeued nodes (p.next == p)
|
||||
* - (possibly multiple) interior removed nodes (p.item == null)
|
||||
*/
|
||||
private Node<E> nextNode(Node<E> p) {
|
||||
for (;;) {
|
||||
Node<E> s = p.next;
|
||||
if (s == p)
|
||||
return head.next;
|
||||
if (s == null || s.item != null)
|
||||
return s;
|
||||
p = s;
|
||||
}
|
||||
}
|
||||
|
||||
public E next() {
|
||||
fullyLock();
|
||||
try {
|
||||
if (current == null)
|
||||
throw new NoSuchElementException();
|
||||
E x = currentElement;
|
||||
lastRet = current;
|
||||
current = nextNode(current);
|
||||
currentElement = (current == null) ? null : current.item;
|
||||
return x;
|
||||
E item = null;
|
||||
// Unlike other traversal methods, iterators must handle both:
|
||||
// - dequeued nodes (p.next == p)
|
||||
// - (possibly multiple) interior removed nodes (p.item == null)
|
||||
for (Node<E> p = current, q;; p = q) {
|
||||
if ((q = p.next) == p)
|
||||
q = head.next;
|
||||
if (q == null || (item = q.item) != null) {
|
||||
current = q;
|
||||
E x = currentElement;
|
||||
currentElement = item;
|
||||
return x;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
fullyUnlock();
|
||||
}
|
||||
@ -901,8 +871,9 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
|
||||
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;
|
||||
|
||||
@ -36,14 +36,14 @@
|
||||
package java.util.concurrent;
|
||||
|
||||
import java.util.AbstractQueue;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
import java.util.Spliterator;
|
||||
import java.util.Spliterators;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
@ -83,7 +83,7 @@ import java.util.function.Consumer;
|
||||
*
|
||||
* @since 1.7
|
||||
* @author Doug Lea
|
||||
* @param <E> the type of elements held in this collection
|
||||
* @param <E> the type of elements held in this queue
|
||||
*/
|
||||
public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
implements TransferQueue<E>, java.io.Serializable {
|
||||
@ -108,7 +108,7 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
*
|
||||
* A FIFO dual queue may be implemented using a variation of the
|
||||
* Michael & Scott (M&S) lock-free queue algorithm
|
||||
* (http://www.cs.rochester.edu/u/scott/papers/1996_PODC_queues.pdf).
|
||||
* (http://www.cs.rochester.edu/~scott/papers/1996_PODC_queues.pdf).
|
||||
* It maintains two pointer fields, "head", pointing to a
|
||||
* (matched) node that in turn points to the first actual
|
||||
* (unmatched) queue node (or null if empty); and "tail" that
|
||||
@ -215,7 +215,7 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
* of costly-to-reclaim garbage caused by the sequential "next"
|
||||
* links of nodes starting at old forgotten head nodes: As first
|
||||
* described in detail by Boehm
|
||||
* (http://portal.acm.org/citation.cfm?doid=503272.503282) if a GC
|
||||
* (http://portal.acm.org/citation.cfm?doid=503272.503282), if a GC
|
||||
* delays noticing that any arbitrarily old node has become
|
||||
* garbage, all newer dead nodes will also be unreclaimed.
|
||||
* (Similar issues arise in non-GC environments.) To cope with
|
||||
@ -456,12 +456,12 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
|
||||
// CAS methods for fields
|
||||
final boolean casNext(Node cmp, Node val) {
|
||||
return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
|
||||
return U.compareAndSwapObject(this, NEXT, cmp, val);
|
||||
}
|
||||
|
||||
final boolean casItem(Object cmp, Object val) {
|
||||
// assert cmp == null || cmp.getClass() != Node.class;
|
||||
return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);
|
||||
return U.compareAndSwapObject(this, ITEM, cmp, val);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -469,7 +469,7 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
* only be seen after publication via casNext.
|
||||
*/
|
||||
Node(Object item, boolean isData) {
|
||||
UNSAFE.putObject(this, itemOffset, item); // relaxed write
|
||||
U.putObject(this, ITEM, item); // relaxed write
|
||||
this.isData = isData;
|
||||
}
|
||||
|
||||
@ -478,7 +478,7 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
* only after CASing head field, so uses relaxed write.
|
||||
*/
|
||||
final void forgetNext() {
|
||||
UNSAFE.putObject(this, nextOffset, this);
|
||||
U.putObject(this, NEXT, this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -491,8 +491,8 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
* else we don't care).
|
||||
*/
|
||||
final void forgetContents() {
|
||||
UNSAFE.putObject(this, itemOffset, this);
|
||||
UNSAFE.putObject(this, waiterOffset, null);
|
||||
U.putObject(this, ITEM, this);
|
||||
U.putObject(this, WAITER, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -538,21 +538,19 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
private static final long serialVersionUID = -3375979862319811754L;
|
||||
|
||||
// Unsafe mechanics
|
||||
private static final sun.misc.Unsafe UNSAFE;
|
||||
private static final long itemOffset;
|
||||
private static final long nextOffset;
|
||||
private static final long waiterOffset;
|
||||
private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
|
||||
private static final long ITEM;
|
||||
private static final long NEXT;
|
||||
private static final long WAITER;
|
||||
static {
|
||||
try {
|
||||
UNSAFE = sun.misc.Unsafe.getUnsafe();
|
||||
Class<?> k = Node.class;
|
||||
itemOffset = UNSAFE.objectFieldOffset
|
||||
(k.getDeclaredField("item"));
|
||||
nextOffset = UNSAFE.objectFieldOffset
|
||||
(k.getDeclaredField("next"));
|
||||
waiterOffset = UNSAFE.objectFieldOffset
|
||||
(k.getDeclaredField("waiter"));
|
||||
} catch (Exception e) {
|
||||
ITEM = U.objectFieldOffset
|
||||
(Node.class.getDeclaredField("item"));
|
||||
NEXT = U.objectFieldOffset
|
||||
(Node.class.getDeclaredField("next"));
|
||||
WAITER = U.objectFieldOffset
|
||||
(Node.class.getDeclaredField("waiter"));
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
@ -569,15 +567,15 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
|
||||
// CAS methods for fields
|
||||
private boolean casTail(Node cmp, Node val) {
|
||||
return UNSAFE.compareAndSwapObject(this, tailOffset, cmp, val);
|
||||
return U.compareAndSwapObject(this, TAIL, cmp, val);
|
||||
}
|
||||
|
||||
private boolean casHead(Node cmp, Node val) {
|
||||
return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val);
|
||||
return U.compareAndSwapObject(this, HEAD, cmp, val);
|
||||
}
|
||||
|
||||
private boolean casSweepVotes(int cmp, int val) {
|
||||
return UNSAFE.compareAndSwapInt(this, sweepVotesOffset, cmp, val);
|
||||
return U.compareAndSwapInt(this, SWEEPVOTES, cmp, val);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -588,12 +586,6 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
private static final int SYNC = 2; // for transfer, take
|
||||
private static final int TIMED = 3; // for timed poll, tryTransfer
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static <E> E cast(Object item) {
|
||||
// assert item == null || item.getClass() != Node.class;
|
||||
return (E) item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements all queuing methods. See above for explanation.
|
||||
*
|
||||
@ -630,7 +622,8 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
break; // unless slack < 2
|
||||
}
|
||||
LockSupport.unpark(p.waiter);
|
||||
return LinkedTransferQueue.<E>cast(item);
|
||||
@SuppressWarnings("unchecked") E itemE = (E) item;
|
||||
return itemE;
|
||||
}
|
||||
}
|
||||
Node n = p.next;
|
||||
@ -708,15 +701,15 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
if (item != e) { // matched
|
||||
// assert item != s;
|
||||
s.forgetContents(); // avoid garbage
|
||||
return LinkedTransferQueue.<E>cast(item);
|
||||
@SuppressWarnings("unchecked") E itemE = (E) item;
|
||||
return itemE;
|
||||
}
|
||||
if ((w.isInterrupted() || (timed && nanos <= 0)) &&
|
||||
s.casItem(e, s)) { // cancel
|
||||
unsplice(pred, s);
|
||||
return e;
|
||||
else if (w.isInterrupted() || (timed && nanos <= 0L)) {
|
||||
unsplice(pred, s); // try to unlink and cancel
|
||||
if (s.casItem(e, s)) // return normally if lost CAS
|
||||
return e;
|
||||
}
|
||||
|
||||
if (spins < 0) { // establish spins at/near front
|
||||
else if (spins < 0) { // establish spins at/near front
|
||||
if ((spins = spinsFor(pred, s.isData)) > 0)
|
||||
randomYields = ThreadLocalRandom.current();
|
||||
}
|
||||
@ -768,52 +761,25 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first unmatched node of the given mode, or null if
|
||||
* none. Used by methods isEmpty, hasWaitingConsumer.
|
||||
*/
|
||||
private Node firstOfMode(boolean isData) {
|
||||
for (Node p = head; p != null; p = succ(p)) {
|
||||
if (!p.isMatched())
|
||||
return (p.isData == isData) ? p : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Version of firstOfMode used by Spliterator. Callers must
|
||||
* recheck if the returned node's item field is null or
|
||||
* self-linked before using.
|
||||
* Returns the first unmatched data node, or null if none.
|
||||
* Callers must recheck if the returned node's item field is null
|
||||
* or self-linked before using.
|
||||
*/
|
||||
final Node firstDataNode() {
|
||||
for (Node p = head; p != null;) {
|
||||
Object item = p.item;
|
||||
if (p.isData) {
|
||||
if (item != null && item != p)
|
||||
return p;
|
||||
restartFromHead: for (;;) {
|
||||
for (Node p = head; p != null;) {
|
||||
Object item = p.item;
|
||||
if (p.isData) {
|
||||
if (item != null && item != p)
|
||||
return p;
|
||||
}
|
||||
else if (item == null)
|
||||
break;
|
||||
if (p == (p = p.next))
|
||||
continue restartFromHead;
|
||||
}
|
||||
else if (item == null)
|
||||
break;
|
||||
if (p == (p = p.next))
|
||||
p = head;
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the item in the first unmatched node with isData; or
|
||||
* null if none. Used by peek.
|
||||
*/
|
||||
private E firstDataItem() {
|
||||
for (Node p = head; p != null; p = succ(p)) {
|
||||
Object item = p.item;
|
||||
if (p.isData) {
|
||||
if (item != null && item != p)
|
||||
return LinkedTransferQueue.<E>cast(item);
|
||||
}
|
||||
else if (item == null)
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -821,23 +787,140 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
* Used by methods size and getWaitingConsumerCount.
|
||||
*/
|
||||
private int countOfMode(boolean data) {
|
||||
int count = 0;
|
||||
for (Node p = head; p != null; ) {
|
||||
if (!p.isMatched()) {
|
||||
if (p.isData != data)
|
||||
return 0;
|
||||
if (++count == Integer.MAX_VALUE) // saturated
|
||||
break;
|
||||
}
|
||||
Node n = p.next;
|
||||
if (n != p)
|
||||
p = n;
|
||||
else {
|
||||
count = 0;
|
||||
p = head;
|
||||
restartFromHead: for (;;) {
|
||||
int count = 0;
|
||||
for (Node p = head; p != null;) {
|
||||
if (!p.isMatched()) {
|
||||
if (p.isData != data)
|
||||
return 0;
|
||||
if (++count == Integer.MAX_VALUE)
|
||||
break; // @see Collection.size()
|
||||
}
|
||||
if (p == (p = p.next))
|
||||
continue restartFromHead;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
String[] a = null;
|
||||
restartFromHead: for (;;) {
|
||||
int charLength = 0;
|
||||
int size = 0;
|
||||
for (Node p = head; p != null;) {
|
||||
Object item = p.item;
|
||||
if (p.isData) {
|
||||
if (item != null && item != p) {
|
||||
if (a == null)
|
||||
a = new String[4];
|
||||
else if (size == a.length)
|
||||
a = Arrays.copyOf(a, 2 * size);
|
||||
String s = item.toString();
|
||||
a[size++] = s;
|
||||
charLength += s.length();
|
||||
}
|
||||
} else if (item == null)
|
||||
break;
|
||||
if (p == (p = p.next))
|
||||
continue restartFromHead;
|
||||
}
|
||||
|
||||
if (size == 0)
|
||||
return "[]";
|
||||
|
||||
return Helpers.toString(a, size, charLength);
|
||||
}
|
||||
}
|
||||
|
||||
private Object[] toArrayInternal(Object[] a) {
|
||||
Object[] x = a;
|
||||
restartFromHead: for (;;) {
|
||||
int size = 0;
|
||||
for (Node p = head; p != null;) {
|
||||
Object item = p.item;
|
||||
if (p.isData) {
|
||||
if (item != null && item != p) {
|
||||
if (x == null)
|
||||
x = new Object[4];
|
||||
else if (size == x.length)
|
||||
x = Arrays.copyOf(x, 2 * (size + 4));
|
||||
x[size++] = item;
|
||||
}
|
||||
} else if (item == null)
|
||||
break;
|
||||
if (p == (p = p.next))
|
||||
continue restartFromHead;
|
||||
}
|
||||
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.
|
||||
*
|
||||
* <p>The returned array will be "safe" in that no references to it are
|
||||
* maintained by this queue. (In other words, this method must allocate
|
||||
* a new array). The caller is thus free to modify the returned array.
|
||||
*
|
||||
* <p>This method acts as bridge between array-based and collection-based
|
||||
* APIs.
|
||||
*
|
||||
* @return an array containing all of the elements in this queue
|
||||
*/
|
||||
public Object[] toArray() {
|
||||
return toArrayInternal(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array containing all of the elements in this queue, in
|
||||
* proper sequence; the runtime type of the returned array is that of
|
||||
* the specified array. If the queue fits in the specified array, it
|
||||
* is returned therein. Otherwise, a new array is allocated with the
|
||||
* runtime type of the specified array and the size of this queue.
|
||||
*
|
||||
* <p>If this queue fits in the specified array with room to spare
|
||||
* (i.e., the array has more elements than this queue), the element in
|
||||
* the array immediately following the end of the queue is set to
|
||||
* {@code null}.
|
||||
*
|
||||
* <p>Like the {@link #toArray()} method, this method acts as bridge between
|
||||
* array-based and collection-based APIs. Further, this method allows
|
||||
* precise control over the runtime type of the output array, and may,
|
||||
* under certain circumstances, be used to save allocation costs.
|
||||
*
|
||||
* <p>Suppose {@code x} is a queue known to contain only strings.
|
||||
* The following code can be used to dump the queue into a newly
|
||||
* allocated array of {@code String}:
|
||||
*
|
||||
* <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
|
||||
*
|
||||
* Note that {@code toArray(new Object[0])} is identical in function to
|
||||
* {@code toArray()}.
|
||||
*
|
||||
* @param a the array into which the elements of the queue are to
|
||||
* be stored, if it is big enough; otherwise, a new array of the
|
||||
* same runtime type is allocated for this purpose
|
||||
* @return an array containing all of the elements in this queue
|
||||
* @throws ArrayStoreException if the runtime type of the specified array
|
||||
* is not a supertype of the runtime type of every element in
|
||||
* this queue
|
||||
* @throws NullPointerException if the specified array is null
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T[] toArray(T[] a) {
|
||||
if (a == null) throw new NullPointerException();
|
||||
return (T[]) toArrayInternal(a);
|
||||
}
|
||||
|
||||
final class Itr implements Iterator<E> {
|
||||
@ -886,7 +969,8 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
Object item = s.item;
|
||||
if (s.isData) {
|
||||
if (item != null && item != s) {
|
||||
nextItem = LinkedTransferQueue.<E>cast(item);
|
||||
@SuppressWarnings("unchecked") E itemE = (E) item;
|
||||
nextItem = itemE;
|
||||
nextNode = s;
|
||||
return;
|
||||
}
|
||||
@ -934,23 +1018,19 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
}
|
||||
|
||||
/** A customized variant of Spliterators.IteratorSpliterator */
|
||||
static final class LTQSpliterator<E> implements Spliterator<E> {
|
||||
final class LTQSpliterator<E> implements Spliterator<E> {
|
||||
static final int MAX_BATCH = 1 << 25; // max batch array size;
|
||||
final LinkedTransferQueue<E> queue;
|
||||
Node current; // current node; null until initialized
|
||||
Node current; // current node; null until initialized
|
||||
int batch; // batch size for splits
|
||||
boolean exhausted; // true when no more nodes
|
||||
LTQSpliterator(LinkedTransferQueue<E> queue) {
|
||||
this.queue = queue;
|
||||
}
|
||||
LTQSpliterator() {}
|
||||
|
||||
public Spliterator<E> trySplit() {
|
||||
Node p;
|
||||
final LinkedTransferQueue<E> q = this.queue;
|
||||
int b = batch;
|
||||
int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
|
||||
if (!exhausted &&
|
||||
((p = current) != null || (p = q.firstDataNode()) != null) &&
|
||||
((p = current) != null || (p = firstDataNode()) != null) &&
|
||||
p.next != null) {
|
||||
Object[] a = new Object[n];
|
||||
int i = 0;
|
||||
@ -959,15 +1039,16 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
if (e != p && (a[i] = e) != null)
|
||||
++i;
|
||||
if (p == (p = p.next))
|
||||
p = q.firstDataNode();
|
||||
p = firstDataNode();
|
||||
} while (p != null && i < n && p.isData);
|
||||
if ((current = p) == null)
|
||||
exhausted = true;
|
||||
if (i > 0) {
|
||||
batch = i;
|
||||
return Spliterators.spliterator
|
||||
(a, 0, i, Spliterator.ORDERED | Spliterator.NONNULL |
|
||||
Spliterator.CONCURRENT);
|
||||
(a, 0, i, (Spliterator.ORDERED |
|
||||
Spliterator.NONNULL |
|
||||
Spliterator.CONCURRENT));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@ -977,16 +1058,15 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
public void forEachRemaining(Consumer<? super E> action) {
|
||||
Node p;
|
||||
if (action == null) throw new NullPointerException();
|
||||
final LinkedTransferQueue<E> q = this.queue;
|
||||
if (!exhausted &&
|
||||
((p = current) != null || (p = q.firstDataNode()) != null)) {
|
||||
((p = current) != null || (p = firstDataNode()) != null)) {
|
||||
exhausted = true;
|
||||
do {
|
||||
Object e = p.item;
|
||||
if (e != null && e != p)
|
||||
action.accept((E)e);
|
||||
if (p == (p = p.next))
|
||||
p = q.firstDataNode();
|
||||
p = firstDataNode();
|
||||
} while (p != null && p.isData);
|
||||
}
|
||||
}
|
||||
@ -995,15 +1075,14 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
public boolean tryAdvance(Consumer<? super E> action) {
|
||||
Node p;
|
||||
if (action == null) throw new NullPointerException();
|
||||
final LinkedTransferQueue<E> q = this.queue;
|
||||
if (!exhausted &&
|
||||
((p = current) != null || (p = q.firstDataNode()) != null)) {
|
||||
((p = current) != null || (p = firstDataNode()) != null)) {
|
||||
Object e;
|
||||
do {
|
||||
if ((e = p.item) == p)
|
||||
e = null;
|
||||
if (p == (p = p.next))
|
||||
p = q.firstDataNode();
|
||||
p = firstDataNode();
|
||||
} while (e == null && p != null && p.isData);
|
||||
if ((current = p) == null)
|
||||
exhausted = true;
|
||||
@ -1040,7 +1119,7 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
* @since 1.8
|
||||
*/
|
||||
public Spliterator<E> spliterator() {
|
||||
return new LTQSpliterator<E>(this);
|
||||
return new LTQSpliterator<E>();
|
||||
}
|
||||
|
||||
/* -------------- Removal methods -------------- */
|
||||
@ -1054,7 +1133,7 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
* @param s the node to be unspliced
|
||||
*/
|
||||
final void unsplice(Node pred, Node s) {
|
||||
s.forgetContents(); // forget unneeded fields
|
||||
s.waiter = null; // disable signals
|
||||
/*
|
||||
* See above for rationale. Briefly: if pred still points to
|
||||
* s, try to unlink s. If s cannot be unlinked, because it is
|
||||
@ -1332,7 +1411,22 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
}
|
||||
|
||||
public E peek() {
|
||||
return firstDataItem();
|
||||
restartFromHead: for (;;) {
|
||||
for (Node p = head; p != null;) {
|
||||
Object item = p.item;
|
||||
if (p.isData) {
|
||||
if (item != null && item != p) {
|
||||
@SuppressWarnings("unchecked") E e = (E) item;
|
||||
return e;
|
||||
}
|
||||
}
|
||||
else if (item == null)
|
||||
break;
|
||||
if (p == (p = p.next))
|
||||
continue restartFromHead;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1341,15 +1435,24 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
* @return {@code true} if this queue contains no elements
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
for (Node p = head; p != null; p = succ(p)) {
|
||||
if (!p.isMatched())
|
||||
return !p.isData;
|
||||
}
|
||||
return true;
|
||||
return firstDataNode() == null;
|
||||
}
|
||||
|
||||
public boolean hasWaitingConsumer() {
|
||||
return firstOfMode(false) != null;
|
||||
restartFromHead: for (;;) {
|
||||
for (Node p = head; p != null;) {
|
||||
Object item = p.item;
|
||||
if (p.isData) {
|
||||
if (item != null && item != p)
|
||||
break;
|
||||
}
|
||||
else if (item == null)
|
||||
return true;
|
||||
if (p == (p = p.next))
|
||||
continue restartFromHead;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1396,15 +1499,16 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
* @return {@code true} if this queue contains the specified element
|
||||
*/
|
||||
public boolean contains(Object o) {
|
||||
if (o == null) return false;
|
||||
for (Node p = head; p != null; p = succ(p)) {
|
||||
Object item = p.item;
|
||||
if (p.isData) {
|
||||
if (item != null && item != p && o.equals(item))
|
||||
return true;
|
||||
if (o != null) {
|
||||
for (Node p = head; p != null; p = succ(p)) {
|
||||
Object item = p.item;
|
||||
if (p.isData) {
|
||||
if (item != null && item != p && o.equals(item))
|
||||
return true;
|
||||
}
|
||||
else if (item == null)
|
||||
break;
|
||||
}
|
||||
else if (item == null)
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -1460,22 +1564,24 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
|
||||
// Unsafe mechanics
|
||||
|
||||
private static final sun.misc.Unsafe UNSAFE;
|
||||
private static final long headOffset;
|
||||
private static final long tailOffset;
|
||||
private static final long sweepVotesOffset;
|
||||
private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
|
||||
private static final long HEAD;
|
||||
private static final long TAIL;
|
||||
private static final long SWEEPVOTES;
|
||||
static {
|
||||
try {
|
||||
UNSAFE = sun.misc.Unsafe.getUnsafe();
|
||||
Class<?> k = LinkedTransferQueue.class;
|
||||
headOffset = UNSAFE.objectFieldOffset
|
||||
(k.getDeclaredField("head"));
|
||||
tailOffset = UNSAFE.objectFieldOffset
|
||||
(k.getDeclaredField("tail"));
|
||||
sweepVotesOffset = UNSAFE.objectFieldOffset
|
||||
(k.getDeclaredField("sweepVotes"));
|
||||
} catch (Exception e) {
|
||||
HEAD = U.objectFieldOffset
|
||||
(LinkedTransferQueue.class.getDeclaredField("head"));
|
||||
TAIL = U.objectFieldOffset
|
||||
(LinkedTransferQueue.class.getDeclaredField("tail"));
|
||||
SWEEPVOTES = U.objectFieldOffset
|
||||
(LinkedTransferQueue.class.getDeclaredField("sweepVotes"));
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
|
||||
// Reduce the risk of rare disastrous classloading in first call to
|
||||
// LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
|
||||
Class<?> ensureLoaded = LockSupport.class;
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,8 +35,6 @@
|
||||
|
||||
package java.util.concurrent;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
|
||||
@ -73,7 +71,7 @@ import java.util.concurrent.locks.LockSupport;
|
||||
*
|
||||
* <ul>
|
||||
*
|
||||
* <li> <b>Arrival.</b> Methods {@link #arrive} and
|
||||
* <li><b>Arrival.</b> Methods {@link #arrive} and
|
||||
* {@link #arriveAndDeregister} record arrival. These methods
|
||||
* do not block, but return an associated <em>arrival phase
|
||||
* number</em>; that is, the phase number of the phaser to which
|
||||
@ -86,7 +84,7 @@ import java.util.concurrent.locks.LockSupport;
|
||||
* flexible than, providing a barrier action to a {@code
|
||||
* CyclicBarrier}.
|
||||
*
|
||||
* <li> <b>Waiting.</b> Method {@link #awaitAdvance} requires an
|
||||
* <li><b>Waiting.</b> Method {@link #awaitAdvance} requires an
|
||||
* argument indicating an arrival phase number, and returns when
|
||||
* the phaser advances to (or is already at) a different phase.
|
||||
* Unlike similar constructions using {@code CyclicBarrier},
|
||||
@ -97,9 +95,10 @@ import java.util.concurrent.locks.LockSupport;
|
||||
* state of the phaser. If necessary, you can perform any
|
||||
* associated recovery within handlers of those exceptions,
|
||||
* often after invoking {@code forceTermination}. Phasers may
|
||||
* also be used by tasks executing in a {@link ForkJoinPool},
|
||||
* which will ensure sufficient parallelism to execute tasks
|
||||
* when others are blocked waiting for a phase to advance.
|
||||
* also be used by tasks executing in a {@link ForkJoinPool}.
|
||||
* Progress is ensured if the pool's parallelismLevel can
|
||||
* accommodate the maximum number of simultaneously blocked
|
||||
* parties.
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
@ -155,7 +154,7 @@ import java.util.concurrent.locks.LockSupport;
|
||||
* The typical idiom is for the method setting this up to first
|
||||
* register, then start the actions, then deregister, as in:
|
||||
*
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* void runTasks(List<Runnable> tasks) {
|
||||
* final Phaser phaser = new Phaser(1); // "1" to register self
|
||||
* // create and start threads
|
||||
@ -176,7 +175,7 @@ import java.util.concurrent.locks.LockSupport;
|
||||
* <p>One way to cause a set of threads to repeatedly perform actions
|
||||
* for a given number of iterations is to override {@code onAdvance}:
|
||||
*
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* void startTasks(List<Runnable> tasks, final int iterations) {
|
||||
* final Phaser phaser = new Phaser() {
|
||||
* protected boolean onAdvance(int phase, int registeredParties) {
|
||||
@ -200,7 +199,7 @@ import java.util.concurrent.locks.LockSupport;
|
||||
*
|
||||
* If the main task must later await termination, it
|
||||
* may re-register and then execute a similar loop:
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* // ...
|
||||
* phaser.register();
|
||||
* while (!phaser.isTerminated())
|
||||
@ -210,7 +209,7 @@ import java.util.concurrent.locks.LockSupport;
|
||||
* in contexts where you are sure that the phase will never wrap around
|
||||
* {@code Integer.MAX_VALUE}. For example:
|
||||
*
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* void awaitPhase(Phaser phaser, int phase) {
|
||||
* int p = phaser.register(); // assumes caller not already registered
|
||||
* while (p < phase) {
|
||||
@ -230,7 +229,7 @@ import java.util.concurrent.locks.LockSupport;
|
||||
* new Phaser())}, these tasks could then be started, for example by
|
||||
* submitting to a pool:
|
||||
*
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* void build(Task[] tasks, int lo, int hi, Phaser ph) {
|
||||
* if (hi - lo > TASKS_PER_PHASER) {
|
||||
* for (int i = lo; i < hi; i += TASKS_PER_PHASER) {
|
||||
@ -331,7 +330,7 @@ public class Phaser {
|
||||
}
|
||||
|
||||
/**
|
||||
* The parent of this phaser, or null if none
|
||||
* The parent of this phaser, or null if none.
|
||||
*/
|
||||
private final Phaser parent;
|
||||
|
||||
@ -389,7 +388,7 @@ public class Phaser {
|
||||
int unarrived = (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);
|
||||
if (unarrived <= 0)
|
||||
throw new IllegalStateException(badArrive(s));
|
||||
if (UNSAFE.compareAndSwapLong(this, stateOffset, s, s-=adjust)) {
|
||||
if (U.compareAndSwapLong(this, STATE, s, s-=adjust)) {
|
||||
if (unarrived == 1) {
|
||||
long n = s & PARTIES_MASK; // base of next state
|
||||
int nextUnarrived = (int)n >>> PARTIES_SHIFT;
|
||||
@ -402,13 +401,12 @@ public class Phaser {
|
||||
n |= nextUnarrived;
|
||||
int nextPhase = (phase + 1) & MAX_PHASE;
|
||||
n |= (long)nextPhase << PHASE_SHIFT;
|
||||
UNSAFE.compareAndSwapLong(this, stateOffset, s, n);
|
||||
U.compareAndSwapLong(this, STATE, s, n);
|
||||
releaseWaiters(phase);
|
||||
}
|
||||
else if (nextUnarrived == 0) { // propagate deregistration
|
||||
phase = parent.doArrive(ONE_DEREGISTER);
|
||||
UNSAFE.compareAndSwapLong(this, stateOffset,
|
||||
s, s | EMPTY);
|
||||
U.compareAndSwapLong(this, STATE, s, s | EMPTY);
|
||||
}
|
||||
else
|
||||
phase = parent.doArrive(ONE_ARRIVAL);
|
||||
@ -419,7 +417,7 @@ public class Phaser {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of register, bulkRegister
|
||||
* Implementation of register, bulkRegister.
|
||||
*
|
||||
* @param registrations number to add to both parties and
|
||||
* unarrived fields. Must be greater than zero.
|
||||
@ -443,14 +441,13 @@ public class Phaser {
|
||||
if (parent == null || reconcileState() == s) {
|
||||
if (unarrived == 0) // wait out advance
|
||||
root.internalAwaitAdvance(phase, null);
|
||||
else if (UNSAFE.compareAndSwapLong(this, stateOffset,
|
||||
s, s + adjust))
|
||||
else if (U.compareAndSwapLong(this, STATE, s, s + adjust))
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (parent == null) { // 1st root registration
|
||||
long next = ((long)phase << PHASE_SHIFT) | adjust;
|
||||
if (UNSAFE.compareAndSwapLong(this, stateOffset, s, next))
|
||||
if (U.compareAndSwapLong(this, STATE, s, next))
|
||||
break;
|
||||
}
|
||||
else {
|
||||
@ -462,8 +459,8 @@ public class Phaser {
|
||||
// finish registration whenever parent registration
|
||||
// succeeded, even when racing with termination,
|
||||
// since these are part of the same "transaction".
|
||||
while (!UNSAFE.compareAndSwapLong
|
||||
(this, stateOffset, s,
|
||||
while (!U.compareAndSwapLong
|
||||
(this, STATE, s,
|
||||
((long)phase << PHASE_SHIFT) | adjust)) {
|
||||
s = state;
|
||||
phase = (int)(root.state >>> PHASE_SHIFT);
|
||||
@ -494,8 +491,8 @@ public class Phaser {
|
||||
// CAS to root phase with current parties, tripping unarrived
|
||||
while ((phase = (int)(root.state >>> PHASE_SHIFT)) !=
|
||||
(int)(s >>> PHASE_SHIFT) &&
|
||||
!UNSAFE.compareAndSwapLong
|
||||
(this, stateOffset, s,
|
||||
!U.compareAndSwapLong
|
||||
(this, STATE, s,
|
||||
s = (((long)phase << PHASE_SHIFT) |
|
||||
((phase < 0) ? (s & COUNTS_MASK) :
|
||||
(((p = (int)s >>> PARTIES_SHIFT) == 0) ? EMPTY :
|
||||
@ -684,8 +681,7 @@ public class Phaser {
|
||||
int unarrived = (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);
|
||||
if (unarrived <= 0)
|
||||
throw new IllegalStateException(badArrive(s));
|
||||
if (UNSAFE.compareAndSwapLong(this, stateOffset, s,
|
||||
s -= ONE_ARRIVAL)) {
|
||||
if (U.compareAndSwapLong(this, STATE, s, s -= ONE_ARRIVAL)) {
|
||||
if (unarrived > 1)
|
||||
return root.internalAwaitAdvance(phase, null);
|
||||
if (root != this)
|
||||
@ -700,7 +696,7 @@ public class Phaser {
|
||||
n |= nextUnarrived;
|
||||
int nextPhase = (phase + 1) & MAX_PHASE;
|
||||
n |= (long)nextPhase << PHASE_SHIFT;
|
||||
if (!UNSAFE.compareAndSwapLong(this, stateOffset, s, n))
|
||||
if (!U.compareAndSwapLong(this, STATE, s, n))
|
||||
return (int)(state >>> PHASE_SHIFT); // terminated
|
||||
releaseWaiters(phase);
|
||||
return nextPhase;
|
||||
@ -816,8 +812,7 @@ public class Phaser {
|
||||
final Phaser root = this.root;
|
||||
long s;
|
||||
while ((s = root.state) >= 0) {
|
||||
if (UNSAFE.compareAndSwapLong(root, stateOffset,
|
||||
s, s | TERMINATION_BIT)) {
|
||||
if (U.compareAndSwapLong(root, STATE, s, s | TERMINATION_BIT)) {
|
||||
// signal all threads
|
||||
releaseWaiters(0); // Waiters on evenQ
|
||||
releaseWaiters(1); // Waiters on oddQ
|
||||
@ -956,7 +951,7 @@ public class Phaser {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of toString and string-based error messages
|
||||
* Implementation of toString and string-based error messages.
|
||||
*/
|
||||
private String stateToString(long s) {
|
||||
return super.toString() +
|
||||
@ -1065,7 +1060,7 @@ public class Phaser {
|
||||
else {
|
||||
try {
|
||||
ForkJoinPool.managedBlock(node);
|
||||
} catch (InterruptedException ie) {
|
||||
} catch (InterruptedException cantHappen) {
|
||||
node.wasInterrupted = true;
|
||||
}
|
||||
}
|
||||
@ -1084,7 +1079,7 @@ public class Phaser {
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait nodes for Treiber stack representing wait queue
|
||||
* Wait nodes for Treiber stack representing wait queue.
|
||||
*/
|
||||
static final class QNode implements ForkJoinPool.ManagedBlocker {
|
||||
final Phaser phaser;
|
||||
@ -1121,41 +1116,39 @@ public class Phaser {
|
||||
thread = null;
|
||||
return true;
|
||||
}
|
||||
if (timed) {
|
||||
if (nanos > 0L) {
|
||||
nanos = deadline - System.nanoTime();
|
||||
}
|
||||
if (nanos <= 0L) {
|
||||
thread = null;
|
||||
return true;
|
||||
}
|
||||
if (timed &&
|
||||
(nanos <= 0L || (nanos = deadline - System.nanoTime()) <= 0L)) {
|
||||
thread = null;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean block() {
|
||||
if (isReleasable())
|
||||
return true;
|
||||
else if (!timed)
|
||||
LockSupport.park(this);
|
||||
else if (nanos > 0L)
|
||||
LockSupport.parkNanos(this, nanos);
|
||||
return isReleasable();
|
||||
while (!isReleasable()) {
|
||||
if (timed)
|
||||
LockSupport.parkNanos(this, nanos);
|
||||
else
|
||||
LockSupport.park(this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Unsafe mechanics
|
||||
|
||||
private static final sun.misc.Unsafe UNSAFE;
|
||||
private static final long stateOffset;
|
||||
private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
|
||||
private static final long STATE;
|
||||
static {
|
||||
try {
|
||||
UNSAFE = sun.misc.Unsafe.getUnsafe();
|
||||
Class<?> k = Phaser.class;
|
||||
stateOffset = UNSAFE.objectFieldOffset
|
||||
(k.getDeclaredField("state"));
|
||||
} catch (Exception e) {
|
||||
STATE = U.objectFieldOffset
|
||||
(Phaser.class.getDeclaredField("state"));
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
|
||||
// Reduce the risk of rare disastrous classloading in first call to
|
||||
// LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
|
||||
Class<?> ensureLoaded = LockSupport.class;
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,8 +35,6 @@
|
||||
|
||||
package java.util.concurrent;
|
||||
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.AbstractQueue;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@ -47,6 +45,8 @@ import java.util.PriorityQueue;
|
||||
import java.util.Queue;
|
||||
import java.util.SortedSet;
|
||||
import java.util.Spliterator;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
@ -78,7 +78,7 @@ import java.util.function.Consumer;
|
||||
* tie-breaking to comparable elements. To use it, you would insert a
|
||||
* {@code new FIFOEntry(anEntry)} instead of a plain entry object.
|
||||
*
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* class FIFOEntry<E extends Comparable<? super E>>
|
||||
* implements Comparable<FIFOEntry<E>> {
|
||||
* static final AtomicLong seq = new AtomicLong(0);
|
||||
@ -103,7 +103,7 @@ import java.util.function.Consumer;
|
||||
*
|
||||
* @since 1.5
|
||||
* @author Doug Lea
|
||||
* @param <E> the type of elements held in this collection
|
||||
* @param <E> the type of elements held in this queue
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class PriorityBlockingQueue<E> extends AbstractQueue<E>
|
||||
@ -161,12 +161,12 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
|
||||
private transient Comparator<? super E> comparator;
|
||||
|
||||
/**
|
||||
* Lock used for all public operations
|
||||
* Lock used for all public operations.
|
||||
*/
|
||||
private final ReentrantLock lock;
|
||||
|
||||
/**
|
||||
* Condition for blocking when empty
|
||||
* Condition for blocking when empty.
|
||||
*/
|
||||
private final Condition notEmpty;
|
||||
|
||||
@ -289,8 +289,7 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
|
||||
lock.unlock(); // must release and then re-acquire main lock
|
||||
Object[] newArray = null;
|
||||
if (allocationSpinLock == 0 &&
|
||||
UNSAFE.compareAndSwapInt(this, allocationSpinLockOffset,
|
||||
0, 1)) {
|
||||
U.compareAndSwapInt(this, ALLOCATIONSPINLOCK, 0, 1)) {
|
||||
try {
|
||||
int newCap = oldCap + ((oldCap < 64) ?
|
||||
(oldCap + 2) : // grow faster if small
|
||||
@ -672,7 +671,7 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
|
||||
}
|
||||
|
||||
/**
|
||||
* Identity-based version for use in Itr.remove
|
||||
* Identity-based version for use in Itr.remove.
|
||||
*/
|
||||
void removeEQ(Object o) {
|
||||
final ReentrantLock lock = this.lock;
|
||||
@ -708,48 +707,8 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array containing all of the elements in this queue.
|
||||
* The returned array elements are in no particular order.
|
||||
*
|
||||
* <p>The returned array will be "safe" in that no references to it are
|
||||
* maintained by this queue. (In other words, this method must allocate
|
||||
* a new array). The caller is thus free to modify the returned array.
|
||||
*
|
||||
* <p>This method acts as bridge between array-based and collection-based
|
||||
* APIs.
|
||||
*
|
||||
* @return an array containing all of the elements in this queue
|
||||
*/
|
||||
public Object[] toArray() {
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
return Arrays.copyOf(queue, size);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
int n = size;
|
||||
if (n == 0)
|
||||
return "[]";
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append('[');
|
||||
for (int i = 0; i < n; ++i) {
|
||||
Object e = queue[i];
|
||||
sb.append(e == this ? "(this Collection)" : e);
|
||||
if (i != n - 1)
|
||||
sb.append(',').append(' ');
|
||||
}
|
||||
return sb.append(']').toString();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return Helpers.collectionToString(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -807,6 +766,29 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array containing all of the elements in this queue.
|
||||
* The returned array elements are in no particular order.
|
||||
*
|
||||
* <p>The returned array will be "safe" in that no references to it are
|
||||
* maintained by this queue. (In other words, this method must allocate
|
||||
* a new array). The caller is thus free to modify the returned array.
|
||||
*
|
||||
* <p>This method acts as bridge between array-based and collection-based
|
||||
* APIs.
|
||||
*
|
||||
* @return an array containing all of the elements in this queue
|
||||
*/
|
||||
public Object[] toArray() {
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
return Arrays.copyOf(queue, size);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array containing all of the elements in this queue; the
|
||||
* runtime type of the returned array is that of the specified array.
|
||||
@ -829,7 +811,7 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
|
||||
* The following code can be used to dump the queue into a newly
|
||||
* allocated array of {@code String}:
|
||||
*
|
||||
* <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
|
||||
* <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
|
||||
*
|
||||
* Note that {@code toArray(new Object[0])} is identical in function to
|
||||
* {@code toArray()}.
|
||||
@ -971,7 +953,7 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
|
||||
return hi;
|
||||
}
|
||||
|
||||
public Spliterator<E> trySplit() {
|
||||
public PBQSpliterator<E> trySplit() {
|
||||
int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
|
||||
return (lo >= mid) ? null :
|
||||
new PBQSpliterator<E>(queue, array, lo, index = mid);
|
||||
@ -1028,15 +1010,13 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
|
||||
}
|
||||
|
||||
// Unsafe mechanics
|
||||
private static final sun.misc.Unsafe UNSAFE;
|
||||
private static final long allocationSpinLockOffset;
|
||||
private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
|
||||
private static final long ALLOCATIONSPINLOCK;
|
||||
static {
|
||||
try {
|
||||
UNSAFE = sun.misc.Unsafe.getUnsafe();
|
||||
Class<?> k = PriorityBlockingQueue.class;
|
||||
allocationSpinLockOffset = UNSAFE.objectFieldOffset
|
||||
(k.getDeclaredField("allocationSpinLock"));
|
||||
} catch (Exception e) {
|
||||
ALLOCATIONSPINLOCK = U.objectFieldOffset
|
||||
(PriorityBlockingQueue.class.getDeclaredField("allocationSpinLock"));
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@ package java.util.concurrent;
|
||||
* <p><b>Sample Usages.</b> Here is a simple but complete ForkJoin
|
||||
* sort that sorts a given {@code long[]} array:
|
||||
*
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* static class SortTask extends RecursiveAction {
|
||||
* final long[] array; final int lo, hi;
|
||||
* SortTask(long[] array, int lo, int hi) {
|
||||
@ -79,7 +79,7 @@ package java.util.concurrent;
|
||||
* SortTask(anArray)} and invoking it in a ForkJoinPool. As a more
|
||||
* concrete simple example, the following task increments each element
|
||||
* of an array:
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* class IncrementTask extends RecursiveAction {
|
||||
* final long[] array; final int lo, hi;
|
||||
* IncrementTask(long[] array, int lo, int hi) {
|
||||
@ -110,7 +110,7 @@ package java.util.concurrent;
|
||||
* performing leaf actions on unstolen tasks rather than further
|
||||
* subdividing.
|
||||
*
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* double sumOfSquares(ForkJoinPool pool, double[] array) {
|
||||
* int n = array.length;
|
||||
* Applyer a = new Applyer(array, 0, n, null);
|
||||
|
||||
@ -40,11 +40,11 @@ package java.util.concurrent;
|
||||
*
|
||||
* <p>For a classic example, here is a task computing Fibonacci numbers:
|
||||
*
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* class Fibonacci extends RecursiveTask<Integer> {
|
||||
* final int n;
|
||||
* Fibonacci(int n) { this.n = n; }
|
||||
* Integer compute() {
|
||||
* protected Integer compute() {
|
||||
* if (n <= 1)
|
||||
* return n;
|
||||
* Fibonacci f1 = new Fibonacci(n - 1);
|
||||
|
||||
@ -70,7 +70,7 @@ package java.util.concurrent;
|
||||
* Here is a class with a method that sets up a ScheduledExecutorService
|
||||
* to beep every ten seconds for an hour:
|
||||
*
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* import static java.util.concurrent.TimeUnit.*;
|
||||
* class BeeperControl {
|
||||
* private final ScheduledExecutorService scheduler =
|
||||
@ -129,23 +129,37 @@ public interface ScheduledExecutorService extends ExecutorService {
|
||||
/**
|
||||
* Creates and executes a periodic action that becomes enabled first
|
||||
* after the given initial delay, and subsequently with the given
|
||||
* period; that is executions will commence after
|
||||
* {@code initialDelay} then {@code initialDelay+period}, then
|
||||
* period; that is, executions will commence after
|
||||
* {@code initialDelay}, then {@code initialDelay + period}, then
|
||||
* {@code initialDelay + 2 * period}, and so on.
|
||||
* If any execution of the task
|
||||
* encounters an exception, subsequent executions are suppressed.
|
||||
* Otherwise, the task will only terminate via cancellation or
|
||||
* termination of the executor. If any execution of this task
|
||||
* takes longer than its period, then subsequent executions
|
||||
* may start late, but will not concurrently execute.
|
||||
*
|
||||
* <p>The sequence of task executions continues indefinitely until
|
||||
* one of the following exceptional completions occur:
|
||||
* <ul>
|
||||
* <li>The task is {@linkplain Future#cancel explicitly cancelled}
|
||||
* via the returned future.
|
||||
* <li>The executor terminates, also resulting in task cancellation.
|
||||
* <li>An execution of the task throws an exception. In this case
|
||||
* calling {@link Future#get() get} on the returned future will
|
||||
* throw {@link ExecutionException}.
|
||||
* </ul>
|
||||
* Subsequent executions are suppressed. Subsequent calls to
|
||||
* {@link Future#isDone isDone()} on the returned future will
|
||||
* return {@code true}.
|
||||
*
|
||||
* <p>If any execution of this task takes longer than its period, then
|
||||
* subsequent executions may start late, but will not concurrently
|
||||
* execute.
|
||||
*
|
||||
* @param command the task to execute
|
||||
* @param initialDelay the time to delay first execution
|
||||
* @param period the period between successive executions
|
||||
* @param unit the time unit of the initialDelay and period parameters
|
||||
* @return a ScheduledFuture representing pending completion of
|
||||
* the task, and whose {@code get()} method will throw an
|
||||
* exception upon cancellation
|
||||
* the series of repeated tasks. The future's {@link
|
||||
* Future#get() get()} method will never return normally,
|
||||
* and will throw an exception upon task cancellation or
|
||||
* abnormal termination of a task execution.
|
||||
* @throws RejectedExecutionException if the task cannot be
|
||||
* scheduled for execution
|
||||
* @throws NullPointerException if command is null
|
||||
@ -160,10 +174,21 @@ public interface ScheduledExecutorService extends ExecutorService {
|
||||
* Creates and executes a periodic action that becomes enabled first
|
||||
* after the given initial delay, and subsequently with the
|
||||
* given delay between the termination of one execution and the
|
||||
* commencement of the next. If any execution of the task
|
||||
* encounters an exception, subsequent executions are suppressed.
|
||||
* Otherwise, the task will only terminate via cancellation or
|
||||
* termination of the executor.
|
||||
* commencement of the next.
|
||||
*
|
||||
* <p>The sequence of task executions continues indefinitely until
|
||||
* one of the following exceptional completions occur:
|
||||
* <ul>
|
||||
* <li>The task is {@linkplain Future#cancel explicitly cancelled}
|
||||
* via the returned future.
|
||||
* <li>The executor terminates, also resulting in task cancellation.
|
||||
* <li>An execution of the task throws an exception. In this case
|
||||
* calling {@link Future#get() get} on the returned future will
|
||||
* throw {@link ExecutionException}.
|
||||
* </ul>
|
||||
* Subsequent executions are suppressed. Subsequent calls to
|
||||
* {@link Future#isDone isDone()} on the returned future will
|
||||
* return {@code true}.
|
||||
*
|
||||
* @param command the task to execute
|
||||
* @param initialDelay the time to delay first execution
|
||||
@ -171,8 +196,10 @@ public interface ScheduledExecutorService extends ExecutorService {
|
||||
* execution and the commencement of the next
|
||||
* @param unit the time unit of the initialDelay and delay parameters
|
||||
* @return a ScheduledFuture representing pending completion of
|
||||
* the task, and whose {@code get()} method will throw an
|
||||
* exception upon cancellation
|
||||
* the series of repeated tasks. The future's {@link
|
||||
* Future#get() get()} method will never return normally,
|
||||
* and will throw an exception upon task cancellation or
|
||||
* abnormal termination of a task execution.
|
||||
* @throws RejectedExecutionException if the task cannot be
|
||||
* scheduled for execution
|
||||
* @throws NullPointerException if command is null
|
||||
|
||||
@ -34,19 +34,27 @@
|
||||
*/
|
||||
|
||||
package java.util.concurrent;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static java.util.concurrent.TimeUnit.NANOSECONDS;
|
||||
|
||||
import java.util.AbstractQueue;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A {@link ThreadPoolExecutor} that can additionally schedule
|
||||
* commands to run after a given delay, or to execute
|
||||
* periodically. This class is preferable to {@link java.util.Timer}
|
||||
* when multiple worker threads are needed, or when the additional
|
||||
* flexibility or capabilities of {@link ThreadPoolExecutor} (which
|
||||
* this class extends) are required.
|
||||
* commands to run after a given delay, or to execute periodically.
|
||||
* This class is preferable to {@link java.util.Timer} when multiple
|
||||
* worker threads are needed, or when the additional flexibility or
|
||||
* capabilities of {@link ThreadPoolExecutor} (which this class
|
||||
* extends) are required.
|
||||
*
|
||||
* <p>Delayed tasks execute no sooner than they are enabled, but
|
||||
* without any real-time guarantees about when, after they are
|
||||
@ -55,20 +63,19 @@ import java.util.*;
|
||||
* submission.
|
||||
*
|
||||
* <p>When a submitted task is cancelled before it is run, execution
|
||||
* is suppressed. By default, such a cancelled task is not
|
||||
* automatically removed from the work queue until its delay
|
||||
* elapses. While this enables further inspection and monitoring, it
|
||||
* may also cause unbounded retention of cancelled tasks. To avoid
|
||||
* this, set {@link #setRemoveOnCancelPolicy} to {@code true}, which
|
||||
* causes tasks to be immediately removed from the work queue at
|
||||
* time of cancellation.
|
||||
* is suppressed. By default, such a cancelled task is not
|
||||
* automatically removed from the work queue until its delay elapses.
|
||||
* While this enables further inspection and monitoring, it may also
|
||||
* cause unbounded retention of cancelled tasks. To avoid this, use
|
||||
* {@link #setRemoveOnCancelPolicy} to cause tasks to be immediately
|
||||
* removed from the work queue at time of cancellation.
|
||||
*
|
||||
* <p>Successive executions of a task scheduled via
|
||||
* {@code scheduleAtFixedRate} or
|
||||
* {@code scheduleWithFixedDelay} do not overlap. While different
|
||||
* executions may be performed by different threads, the effects of
|
||||
* prior executions <a
|
||||
* href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
|
||||
* <p>Successive executions of a periodic task scheduled via
|
||||
* {@link #scheduleAtFixedRate scheduleAtFixedRate} or
|
||||
* {@link #scheduleWithFixedDelay scheduleWithFixedDelay}
|
||||
* do not overlap. While different executions may be performed by
|
||||
* different threads, the effects of prior executions
|
||||
* <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
|
||||
* those of subsequent ones.
|
||||
*
|
||||
* <p>While this class inherits from {@link ThreadPoolExecutor}, a few
|
||||
@ -98,7 +105,7 @@ import java.util.*;
|
||||
* {@link FutureTask}. However, this may be modified or replaced using
|
||||
* subclasses of the form:
|
||||
*
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* public class CustomScheduledExecutor extends ScheduledThreadPoolExecutor {
|
||||
*
|
||||
* static class CustomTask<V> implements RunnableScheduledFuture<V> { ... }
|
||||
@ -160,9 +167,9 @@ public class ScheduledThreadPoolExecutor
|
||||
private volatile boolean executeExistingDelayedTasksAfterShutdown = true;
|
||||
|
||||
/**
|
||||
* True if ScheduledFutureTask.cancel should remove from queue
|
||||
* True if ScheduledFutureTask.cancel should remove from queue.
|
||||
*/
|
||||
private volatile boolean removeOnCancel = false;
|
||||
volatile boolean removeOnCancel;
|
||||
|
||||
/**
|
||||
* Sequence number to break scheduling ties, and in turn to
|
||||
@ -173,7 +180,7 @@ public class ScheduledThreadPoolExecutor
|
||||
/**
|
||||
* Returns current nanosecond time.
|
||||
*/
|
||||
final long now() {
|
||||
static final long now() {
|
||||
return System.nanoTime();
|
||||
}
|
||||
|
||||
@ -184,13 +191,13 @@ public class ScheduledThreadPoolExecutor
|
||||
private final long sequenceNumber;
|
||||
|
||||
/** The time the task is enabled to execute in nanoTime units */
|
||||
private long time;
|
||||
private volatile long time;
|
||||
|
||||
/**
|
||||
* Period in nanoseconds for repeating tasks. A positive
|
||||
* value indicates fixed-rate execution. A negative value
|
||||
* indicates fixed-delay execution. A value of 0 indicates a
|
||||
* non-repeating task.
|
||||
* Period in nanoseconds for repeating tasks.
|
||||
* A positive value indicates fixed-rate execution.
|
||||
* A negative value indicates fixed-delay execution.
|
||||
* A value of 0 indicates a non-repeating (one-shot) task.
|
||||
*/
|
||||
private final long period;
|
||||
|
||||
@ -205,31 +212,35 @@ public class ScheduledThreadPoolExecutor
|
||||
/**
|
||||
* Creates a one-shot action with given nanoTime-based trigger time.
|
||||
*/
|
||||
ScheduledFutureTask(Runnable r, V result, long ns) {
|
||||
ScheduledFutureTask(Runnable r, V result, long triggerTime,
|
||||
long sequenceNumber) {
|
||||
super(r, result);
|
||||
this.time = ns;
|
||||
this.time = triggerTime;
|
||||
this.period = 0;
|
||||
this.sequenceNumber = sequencer.getAndIncrement();
|
||||
this.sequenceNumber = sequenceNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a periodic action with given nano time and period.
|
||||
* Creates a periodic action with given nanoTime-based initial
|
||||
* trigger time and period.
|
||||
*/
|
||||
ScheduledFutureTask(Runnable r, V result, long ns, long period) {
|
||||
ScheduledFutureTask(Runnable r, V result, long triggerTime,
|
||||
long period, long sequenceNumber) {
|
||||
super(r, result);
|
||||
this.time = ns;
|
||||
this.time = triggerTime;
|
||||
this.period = period;
|
||||
this.sequenceNumber = sequencer.getAndIncrement();
|
||||
this.sequenceNumber = sequenceNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a one-shot action with given nanoTime-based trigger time.
|
||||
*/
|
||||
ScheduledFutureTask(Callable<V> callable, long ns) {
|
||||
ScheduledFutureTask(Callable<V> callable, long triggerTime,
|
||||
long sequenceNumber) {
|
||||
super(callable);
|
||||
this.time = ns;
|
||||
this.time = triggerTime;
|
||||
this.period = 0;
|
||||
this.sequenceNumber = sequencer.getAndIncrement();
|
||||
this.sequenceNumber = sequenceNumber;
|
||||
}
|
||||
|
||||
public long getDelay(TimeUnit unit) {
|
||||
@ -290,8 +301,8 @@ public class ScheduledThreadPoolExecutor
|
||||
if (!canRunInCurrentRunState(periodic))
|
||||
cancel(false);
|
||||
else if (!periodic)
|
||||
ScheduledFutureTask.super.run();
|
||||
else if (ScheduledFutureTask.super.runAndReset()) {
|
||||
super.run();
|
||||
else if (super.runAndReset()) {
|
||||
setNextRunTime();
|
||||
reExecutePeriodic(outerTask);
|
||||
}
|
||||
@ -418,6 +429,22 @@ public class ScheduledThreadPoolExecutor
|
||||
return task;
|
||||
}
|
||||
|
||||
/**
|
||||
* The default keep-alive time for pool threads.
|
||||
*
|
||||
* Normally, this value is unused because all pool threads will be
|
||||
* core threads, but if a user creates a pool with a corePoolSize
|
||||
* of zero (against our advice), we keep a thread alive as long as
|
||||
* there are queued tasks. If the keep alive time is zero (the
|
||||
* historic value), we end up hot-spinning in getTask, wasting a
|
||||
* CPU. But on the other hand, if we set the value too high, and
|
||||
* users create a one-shot pool which they don't cleanly shutdown,
|
||||
* the pool's non-daemon threads will prevent JVM termination. A
|
||||
* small but non-zero value (relative to a JVM's lifetime) seems
|
||||
* best.
|
||||
*/
|
||||
private static final long DEFAULT_KEEPALIVE_MILLIS = 10L;
|
||||
|
||||
/**
|
||||
* Creates a new {@code ScheduledThreadPoolExecutor} with the
|
||||
* given core pool size.
|
||||
@ -427,7 +454,8 @@ public class ScheduledThreadPoolExecutor
|
||||
* @throws IllegalArgumentException if {@code corePoolSize < 0}
|
||||
*/
|
||||
public ScheduledThreadPoolExecutor(int corePoolSize) {
|
||||
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
|
||||
super(corePoolSize, Integer.MAX_VALUE,
|
||||
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
|
||||
new DelayedWorkQueue());
|
||||
}
|
||||
|
||||
@ -444,13 +472,14 @@ public class ScheduledThreadPoolExecutor
|
||||
*/
|
||||
public ScheduledThreadPoolExecutor(int corePoolSize,
|
||||
ThreadFactory threadFactory) {
|
||||
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
|
||||
super(corePoolSize, Integer.MAX_VALUE,
|
||||
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
|
||||
new DelayedWorkQueue(), threadFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ScheduledThreadPoolExecutor with the given
|
||||
* initial parameters.
|
||||
* Creates a new {@code ScheduledThreadPoolExecutor} with the
|
||||
* given initial parameters.
|
||||
*
|
||||
* @param corePoolSize the number of threads to keep in the pool, even
|
||||
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
|
||||
@ -461,13 +490,14 @@ public class ScheduledThreadPoolExecutor
|
||||
*/
|
||||
public ScheduledThreadPoolExecutor(int corePoolSize,
|
||||
RejectedExecutionHandler handler) {
|
||||
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
|
||||
super(corePoolSize, Integer.MAX_VALUE,
|
||||
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
|
||||
new DelayedWorkQueue(), handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ScheduledThreadPoolExecutor with the given
|
||||
* initial parameters.
|
||||
* Creates a new {@code ScheduledThreadPoolExecutor} with the
|
||||
* given initial parameters.
|
||||
*
|
||||
* @param corePoolSize the number of threads to keep in the pool, even
|
||||
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
|
||||
@ -482,19 +512,20 @@ public class ScheduledThreadPoolExecutor
|
||||
public ScheduledThreadPoolExecutor(int corePoolSize,
|
||||
ThreadFactory threadFactory,
|
||||
RejectedExecutionHandler handler) {
|
||||
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
|
||||
super(corePoolSize, Integer.MAX_VALUE,
|
||||
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
|
||||
new DelayedWorkQueue(), threadFactory, handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the trigger time of a delayed action.
|
||||
* Returns the nanoTime-based trigger time of a delayed action.
|
||||
*/
|
||||
private long triggerTime(long delay, TimeUnit unit) {
|
||||
return triggerTime(unit.toNanos((delay < 0) ? 0 : delay));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the trigger time of a delayed action.
|
||||
* Returns the nanoTime-based trigger time of a delayed action.
|
||||
*/
|
||||
long triggerTime(long delay) {
|
||||
return now() +
|
||||
@ -527,9 +558,10 @@ public class ScheduledThreadPoolExecutor
|
||||
TimeUnit unit) {
|
||||
if (command == null || unit == null)
|
||||
throw new NullPointerException();
|
||||
RunnableScheduledFuture<?> t = decorateTask(command,
|
||||
RunnableScheduledFuture<Void> t = decorateTask(command,
|
||||
new ScheduledFutureTask<Void>(command, null,
|
||||
triggerTime(delay, unit)));
|
||||
triggerTime(delay, unit),
|
||||
sequencer.getAndIncrement()));
|
||||
delayedExecute(t);
|
||||
return t;
|
||||
}
|
||||
@ -545,7 +577,8 @@ public class ScheduledThreadPoolExecutor
|
||||
throw new NullPointerException();
|
||||
RunnableScheduledFuture<V> t = decorateTask(callable,
|
||||
new ScheduledFutureTask<V>(callable,
|
||||
triggerTime(delay, unit)));
|
||||
triggerTime(delay, unit),
|
||||
sequencer.getAndIncrement()));
|
||||
delayedExecute(t);
|
||||
return t;
|
||||
}
|
||||
@ -561,13 +594,14 @@ public class ScheduledThreadPoolExecutor
|
||||
TimeUnit unit) {
|
||||
if (command == null || unit == null)
|
||||
throw new NullPointerException();
|
||||
if (period <= 0)
|
||||
if (period <= 0L)
|
||||
throw new IllegalArgumentException();
|
||||
ScheduledFutureTask<Void> sft =
|
||||
new ScheduledFutureTask<Void>(command,
|
||||
null,
|
||||
triggerTime(initialDelay, unit),
|
||||
unit.toNanos(period));
|
||||
unit.toNanos(period),
|
||||
sequencer.getAndIncrement());
|
||||
RunnableScheduledFuture<Void> t = decorateTask(command, sft);
|
||||
sft.outerTask = t;
|
||||
delayedExecute(t);
|
||||
@ -585,13 +619,14 @@ public class ScheduledThreadPoolExecutor
|
||||
TimeUnit unit) {
|
||||
if (command == null || unit == null)
|
||||
throw new NullPointerException();
|
||||
if (delay <= 0)
|
||||
if (delay <= 0L)
|
||||
throw new IllegalArgumentException();
|
||||
ScheduledFutureTask<Void> sft =
|
||||
new ScheduledFutureTask<Void>(command,
|
||||
null,
|
||||
triggerTime(initialDelay, unit),
|
||||
unit.toNanos(-delay));
|
||||
-unit.toNanos(delay),
|
||||
sequencer.getAndIncrement());
|
||||
RunnableScheduledFuture<Void> t = decorateTask(command, sft);
|
||||
sft.outerTask = t;
|
||||
delayedExecute(t);
|
||||
@ -764,7 +799,8 @@ public class ScheduledThreadPoolExecutor
|
||||
/**
|
||||
* Attempts to stop all actively executing tasks, halts the
|
||||
* processing of waiting tasks, and returns a list of the tasks
|
||||
* that were awaiting execution.
|
||||
* that were awaiting execution. These tasks are drained (removed)
|
||||
* from the task queue upon return from this method.
|
||||
*
|
||||
* <p>This method does not wait for actively executing tasks to
|
||||
* terminate. Use {@link #awaitTermination awaitTermination} to
|
||||
@ -772,13 +808,15 @@ public class ScheduledThreadPoolExecutor
|
||||
*
|
||||
* <p>There are no guarantees beyond best-effort attempts to stop
|
||||
* processing actively executing tasks. This implementation
|
||||
* cancels tasks via {@link Thread#interrupt}, so any task that
|
||||
* interrupts tasks via {@link Thread#interrupt}; any task that
|
||||
* fails to respond to interrupts may never terminate.
|
||||
*
|
||||
* @return list of tasks that never commenced execution.
|
||||
* Each element of this list is a {@link ScheduledFuture},
|
||||
* including those tasks submitted using {@code execute},
|
||||
* which are for scheduling purposes used as the basis of a
|
||||
* Each element of this list is a {@link ScheduledFuture}.
|
||||
* For tasks submitted via one of the {@code schedule}
|
||||
* methods, the element will be identical to the returned
|
||||
* {@code ScheduledFuture}. For tasks submitted using
|
||||
* {@link #execute execute}, the element will be a
|
||||
* zero-delay {@code ScheduledFuture}.
|
||||
* @throws SecurityException {@inheritDoc}
|
||||
*/
|
||||
@ -787,13 +825,19 @@ public class ScheduledThreadPoolExecutor
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the task queue used by this executor. Each element of
|
||||
* this queue is a {@link ScheduledFuture}, including those
|
||||
* tasks submitted using {@code execute} which are for scheduling
|
||||
* purposes used as the basis of a zero-delay
|
||||
* {@code ScheduledFuture}. Iteration over this queue is
|
||||
* <em>not</em> guaranteed to traverse tasks in the order in
|
||||
* which they will execute.
|
||||
* Returns the task queue used by this executor. Access to the
|
||||
* task queue is intended primarily for debugging and monitoring.
|
||||
* This queue may be in active use. Retrieving the task queue
|
||||
* does not prevent queued tasks from executing.
|
||||
*
|
||||
* <p>Each element of this queue is a {@link ScheduledFuture}.
|
||||
* For tasks submitted via one of the {@code schedule} methods, the
|
||||
* element will be identical to the returned {@code ScheduledFuture}.
|
||||
* For tasks submitted using {@link #execute execute}, the element
|
||||
* will be a zero-delay {@code ScheduledFuture}.
|
||||
*
|
||||
* <p>Iteration over this queue is <em>not</em> guaranteed to traverse
|
||||
* tasks in the order in which they will execute.
|
||||
*
|
||||
* @return the task queue
|
||||
*/
|
||||
@ -836,7 +880,7 @@ public class ScheduledThreadPoolExecutor
|
||||
private RunnableScheduledFuture<?>[] queue =
|
||||
new RunnableScheduledFuture<?>[INITIAL_CAPACITY];
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
private int size = 0;
|
||||
private int size;
|
||||
|
||||
/**
|
||||
* Thread designated to wait for the task at the head of the
|
||||
@ -854,7 +898,7 @@ public class ScheduledThreadPoolExecutor
|
||||
* signalled. So waiting threads must be prepared to acquire
|
||||
* and lose leadership while waiting.
|
||||
*/
|
||||
private Thread leader = null;
|
||||
private Thread leader;
|
||||
|
||||
/**
|
||||
* Condition signalled when a newer task becomes available at the
|
||||
@ -1062,10 +1106,9 @@ public class ScheduledThreadPoolExecutor
|
||||
lock.lock();
|
||||
try {
|
||||
RunnableScheduledFuture<?> first = queue[0];
|
||||
if (first == null || first.getDelay(NANOSECONDS) > 0)
|
||||
return null;
|
||||
else
|
||||
return finishPoll(first);
|
||||
return (first == null || first.getDelay(NANOSECONDS) > 0)
|
||||
? null
|
||||
: finishPoll(first);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
@ -1081,7 +1124,7 @@ public class ScheduledThreadPoolExecutor
|
||||
available.await();
|
||||
else {
|
||||
long delay = first.getDelay(NANOSECONDS);
|
||||
if (delay <= 0)
|
||||
if (delay <= 0L)
|
||||
return finishPoll(first);
|
||||
first = null; // don't retain ref while waiting
|
||||
if (leader != null)
|
||||
@ -1114,15 +1157,15 @@ public class ScheduledThreadPoolExecutor
|
||||
for (;;) {
|
||||
RunnableScheduledFuture<?> first = queue[0];
|
||||
if (first == null) {
|
||||
if (nanos <= 0)
|
||||
if (nanos <= 0L)
|
||||
return null;
|
||||
else
|
||||
nanos = available.awaitNanos(nanos);
|
||||
} else {
|
||||
long delay = first.getDelay(NANOSECONDS);
|
||||
if (delay <= 0)
|
||||
if (delay <= 0L)
|
||||
return finishPoll(first);
|
||||
if (nanos <= 0)
|
||||
if (nanos <= 0L)
|
||||
return null;
|
||||
first = null; // don't retain ref while waiting
|
||||
if (nanos < delay || leader != null)
|
||||
@ -1254,8 +1297,8 @@ public class ScheduledThreadPoolExecutor
|
||||
*/
|
||||
private class Itr implements Iterator<Runnable> {
|
||||
final RunnableScheduledFuture<?>[] array;
|
||||
int cursor = 0; // index of next element to return
|
||||
int lastRet = -1; // index of last element, or -1 if no such
|
||||
int cursor; // index of next element to return; initially 0
|
||||
int lastRet = -1; // index of last element returned; -1 if no such
|
||||
|
||||
Itr(RunnableScheduledFuture<?>[] array) {
|
||||
this.array = array;
|
||||
|
||||
@ -34,6 +34,7 @@
|
||||
*/
|
||||
|
||||
package java.util.concurrent;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
|
||||
|
||||
@ -48,7 +49,7 @@ import java.util.concurrent.locks.AbstractQueuedSynchronizer;
|
||||
* <p>Semaphores are often used to restrict the number of threads than can
|
||||
* access some (physical or logical) resource. For example, here is
|
||||
* a class that uses a semaphore to control access to a pool of items:
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* class Pool {
|
||||
* private static final int MAX_AVAILABLE = 100;
|
||||
* private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);
|
||||
@ -114,7 +115,7 @@ import java.util.concurrent.locks.AbstractQueuedSynchronizer;
|
||||
* ownership). This can be useful in some specialized contexts, such
|
||||
* as deadlock recovery.
|
||||
*
|
||||
* <p> The constructor for this class optionally accepts a
|
||||
* <p>The constructor for this class optionally accepts a
|
||||
* <em>fairness</em> parameter. When set false, this class makes no
|
||||
* guarantees about the order in which threads acquire permits. In
|
||||
* particular, <em>barging</em> is permitted, that is, a thread
|
||||
@ -141,8 +142,13 @@ import java.util.concurrent.locks.AbstractQueuedSynchronizer;
|
||||
*
|
||||
* <p>This class also provides convenience methods to {@link
|
||||
* #acquire(int) acquire} and {@link #release(int) release} multiple
|
||||
* permits at a time. Beware of the increased risk of indefinite
|
||||
* postponement when these methods are used without fairness set true.
|
||||
* permits at a time. These methods are generally more efficient and
|
||||
* effective than loops. However, they do not establish any preference
|
||||
* order. For example, if thread A invokes {@code s.acquire(3}) and
|
||||
* thread B invokes {@code s.acquire(2)}, and two permits become
|
||||
* available, then there is no guarantee that thread B will obtain
|
||||
* them unless its acquire came first and Semaphore {@code s} is in
|
||||
* fair mode.
|
||||
*
|
||||
* <p>Memory consistency effects: Actions in a thread prior to calling
|
||||
* a "release" method such as {@code release()}
|
||||
@ -433,14 +439,16 @@ public class Semaphore implements java.io.Serializable {
|
||||
*
|
||||
* <p>Acquires the given number of permits, if they are available,
|
||||
* and returns immediately, reducing the number of available permits
|
||||
* by the given amount.
|
||||
* by the given amount. This method has the same effect as the
|
||||
* loop {@code for (int i = 0; i < permits; ++i) acquire();} except
|
||||
* that it atomically acquires the permits all at once:
|
||||
*
|
||||
* <p>If insufficient permits are available then the current thread becomes
|
||||
* disabled for thread scheduling purposes and lies dormant until
|
||||
* one of two things happens:
|
||||
* <ul>
|
||||
* <li>Some other thread invokes one of the {@link #release() release}
|
||||
* methods for this semaphore, the current thread is next to be assigned
|
||||
* methods for this semaphore and the current thread is next to be assigned
|
||||
* permits and the number of available permits satisfies this request; or
|
||||
* <li>Some other thread {@linkplain Thread#interrupt interrupts}
|
||||
* the current thread.
|
||||
@ -473,12 +481,14 @@ public class Semaphore implements java.io.Serializable {
|
||||
*
|
||||
* <p>Acquires the given number of permits, if they are available,
|
||||
* and returns immediately, reducing the number of available permits
|
||||
* by the given amount.
|
||||
* by the given amount. This method has the same effect as the
|
||||
* loop {@code for (int i = 0; i < permits; ++i) acquireUninterruptibly();}
|
||||
* except that it atomically acquires the permits all at once:
|
||||
*
|
||||
* <p>If insufficient permits are available then the current thread becomes
|
||||
* disabled for thread scheduling purposes and lies dormant until
|
||||
* some other thread invokes one of the {@link #release() release}
|
||||
* methods for this semaphore, the current thread is next to be assigned
|
||||
* methods for this semaphore and the current thread is next to be assigned
|
||||
* permits and the number of available permits satisfies this request.
|
||||
*
|
||||
* <p>If the current thread is {@linkplain Thread#interrupt interrupted}
|
||||
@ -540,7 +550,7 @@ public class Semaphore implements java.io.Serializable {
|
||||
* purposes and lies dormant until one of three things happens:
|
||||
* <ul>
|
||||
* <li>Some other thread invokes one of the {@link #release() release}
|
||||
* methods for this semaphore, the current thread is next to be assigned
|
||||
* methods for this semaphore and the current thread is next to be assigned
|
||||
* permits and the number of available permits satisfies this request; or
|
||||
* <li>Some other thread {@linkplain Thread#interrupt interrupts}
|
||||
* the current thread; or
|
||||
@ -587,7 +597,7 @@ public class Semaphore implements java.io.Serializable {
|
||||
*
|
||||
* <p>Releases the given number of permits, increasing the number of
|
||||
* available permits by that amount.
|
||||
* If any threads are trying to acquire permits, then one
|
||||
* If any threads are trying to acquire permits, then one thread
|
||||
* is selected and given the permits that were just released.
|
||||
* If the number of available permits satisfies that thread's request
|
||||
* then that thread is (re)enabled for thread scheduling purposes;
|
||||
@ -671,7 +681,7 @@ public class Semaphore implements java.io.Serializable {
|
||||
* Returns an estimate of the number of threads waiting to acquire.
|
||||
* The value is only an estimate because the number of threads may
|
||||
* change dynamically while this method traverses internal data
|
||||
* structures. This method is designed for use in monitoring of the
|
||||
* structures. This method is designed for use in monitoring
|
||||
* system state, not for synchronization control.
|
||||
*
|
||||
* @return the estimated number of threads waiting for this lock
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -35,11 +35,15 @@
|
||||
*/
|
||||
|
||||
package java.util.concurrent;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.*;
|
||||
|
||||
import java.util.AbstractQueue;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.Spliterator;
|
||||
import java.util.Spliterators;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* A {@linkplain BlockingQueue blocking queue} in which each insert
|
||||
@ -79,7 +83,7 @@ import java.util.Spliterators;
|
||||
*
|
||||
* @since 1.5
|
||||
* @author Doug Lea and Bill Scherer and Michael Scott
|
||||
* @param <E> the type of elements held in this collection
|
||||
* @param <E> the type of elements held in this queue
|
||||
*/
|
||||
public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
implements BlockingQueue<E>, java.io.Serializable {
|
||||
@ -182,9 +186,6 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
abstract E transfer(E e, boolean timed, long nanos);
|
||||
}
|
||||
|
||||
/** The number of CPUs, for spin control */
|
||||
static final int NCPUS = Runtime.getRuntime().availableProcessors();
|
||||
|
||||
/**
|
||||
* The number of times to spin before blocking in timed waits.
|
||||
* The value is empirically derived -- it works well across a
|
||||
@ -192,20 +193,21 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
* seems not to vary with number of CPUs (beyond 2) so is just
|
||||
* a constant.
|
||||
*/
|
||||
static final int maxTimedSpins = (NCPUS < 2) ? 0 : 32;
|
||||
static final int MAX_TIMED_SPINS =
|
||||
(Runtime.getRuntime().availableProcessors() < 2) ? 0 : 32;
|
||||
|
||||
/**
|
||||
* The number of times to spin before blocking in untimed waits.
|
||||
* This is greater than timed value because untimed waits spin
|
||||
* faster since they don't need to check times on each spin.
|
||||
*/
|
||||
static final int maxUntimedSpins = maxTimedSpins * 16;
|
||||
static final int MAX_UNTIMED_SPINS = MAX_TIMED_SPINS * 16;
|
||||
|
||||
/**
|
||||
* The number of nanoseconds for which it is faster to spin
|
||||
* rather than to use timed park. A rough estimate suffices.
|
||||
*/
|
||||
static final long spinForTimeoutThreshold = 1000L;
|
||||
static final long SPIN_FOR_TIMEOUT_THRESHOLD = 1000L;
|
||||
|
||||
/** Dual stack */
|
||||
static final class TransferStack<E> extends Transferer<E> {
|
||||
@ -245,7 +247,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
|
||||
boolean casNext(SNode cmp, SNode val) {
|
||||
return cmp == next &&
|
||||
UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
|
||||
U.compareAndSwapObject(this, NEXT, cmp, val);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -258,7 +260,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
*/
|
||||
boolean tryMatch(SNode s) {
|
||||
if (match == null &&
|
||||
UNSAFE.compareAndSwapObject(this, matchOffset, null, s)) {
|
||||
U.compareAndSwapObject(this, MATCH, null, s)) {
|
||||
Thread w = waiter;
|
||||
if (w != null) { // waiters need at most one unpark
|
||||
waiter = null;
|
||||
@ -273,7 +275,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
* Tries to cancel a wait by matching node to itself.
|
||||
*/
|
||||
void tryCancel() {
|
||||
UNSAFE.compareAndSwapObject(this, matchOffset, null, this);
|
||||
U.compareAndSwapObject(this, MATCH, null, this);
|
||||
}
|
||||
|
||||
boolean isCancelled() {
|
||||
@ -281,19 +283,17 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
}
|
||||
|
||||
// Unsafe mechanics
|
||||
private static final sun.misc.Unsafe UNSAFE;
|
||||
private static final long matchOffset;
|
||||
private static final long nextOffset;
|
||||
private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
|
||||
private static final long MATCH;
|
||||
private static final long NEXT;
|
||||
|
||||
static {
|
||||
try {
|
||||
UNSAFE = sun.misc.Unsafe.getUnsafe();
|
||||
Class<?> k = SNode.class;
|
||||
matchOffset = UNSAFE.objectFieldOffset
|
||||
(k.getDeclaredField("match"));
|
||||
nextOffset = UNSAFE.objectFieldOffset
|
||||
(k.getDeclaredField("next"));
|
||||
} catch (Exception e) {
|
||||
MATCH = U.objectFieldOffset
|
||||
(SNode.class.getDeclaredField("match"));
|
||||
NEXT = U.objectFieldOffset
|
||||
(SNode.class.getDeclaredField("next"));
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
@ -304,7 +304,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
|
||||
boolean casHead(SNode h, SNode nh) {
|
||||
return h == head &&
|
||||
UNSAFE.compareAndSwapObject(this, headOffset, h, nh);
|
||||
U.compareAndSwapObject(this, HEAD, h, nh);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -353,7 +353,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
for (;;) {
|
||||
SNode h = head;
|
||||
if (h == null || h.mode == mode) { // empty or same-mode
|
||||
if (timed && nanos <= 0) { // can't wait
|
||||
if (timed && nanos <= 0L) { // can't wait
|
||||
if (h != null && h.isCancelled())
|
||||
casHead(h, h.next); // pop cancelled node
|
||||
else
|
||||
@ -435,8 +435,9 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
*/
|
||||
final long deadline = timed ? System.nanoTime() + nanos : 0L;
|
||||
Thread w = Thread.currentThread();
|
||||
int spins = (shouldSpin(s) ?
|
||||
(timed ? maxTimedSpins : maxUntimedSpins) : 0);
|
||||
int spins = shouldSpin(s)
|
||||
? (timed ? MAX_TIMED_SPINS : MAX_UNTIMED_SPINS)
|
||||
: 0;
|
||||
for (;;) {
|
||||
if (w.isInterrupted())
|
||||
s.tryCancel();
|
||||
@ -451,12 +452,12 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
}
|
||||
}
|
||||
if (spins > 0)
|
||||
spins = shouldSpin(s) ? (spins-1) : 0;
|
||||
spins = shouldSpin(s) ? (spins - 1) : 0;
|
||||
else if (s.waiter == null)
|
||||
s.waiter = w; // establish waiter so can park next iter
|
||||
else if (!timed)
|
||||
LockSupport.park(this);
|
||||
else if (nanos > spinForTimeoutThreshold)
|
||||
else if (nanos > SPIN_FOR_TIMEOUT_THRESHOLD)
|
||||
LockSupport.parkNanos(this, nanos);
|
||||
}
|
||||
}
|
||||
@ -508,15 +509,13 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
}
|
||||
|
||||
// Unsafe mechanics
|
||||
private static final sun.misc.Unsafe UNSAFE;
|
||||
private static final long headOffset;
|
||||
private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
|
||||
private static final long HEAD;
|
||||
static {
|
||||
try {
|
||||
UNSAFE = sun.misc.Unsafe.getUnsafe();
|
||||
Class<?> k = TransferStack.class;
|
||||
headOffset = UNSAFE.objectFieldOffset
|
||||
(k.getDeclaredField("head"));
|
||||
} catch (Exception e) {
|
||||
HEAD = U.objectFieldOffset
|
||||
(TransferStack.class.getDeclaredField("head"));
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
@ -547,19 +546,19 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
|
||||
boolean casNext(QNode cmp, QNode val) {
|
||||
return next == cmp &&
|
||||
UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
|
||||
U.compareAndSwapObject(this, NEXT, cmp, val);
|
||||
}
|
||||
|
||||
boolean casItem(Object cmp, Object val) {
|
||||
return item == cmp &&
|
||||
UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);
|
||||
U.compareAndSwapObject(this, ITEM, cmp, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to cancel by CAS'ing ref to this as item.
|
||||
*/
|
||||
void tryCancel(Object cmp) {
|
||||
UNSAFE.compareAndSwapObject(this, itemOffset, cmp, this);
|
||||
U.compareAndSwapObject(this, ITEM, cmp, this);
|
||||
}
|
||||
|
||||
boolean isCancelled() {
|
||||
@ -576,19 +575,17 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
}
|
||||
|
||||
// Unsafe mechanics
|
||||
private static final sun.misc.Unsafe UNSAFE;
|
||||
private static final long itemOffset;
|
||||
private static final long nextOffset;
|
||||
private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
|
||||
private static final long ITEM;
|
||||
private static final long NEXT;
|
||||
|
||||
static {
|
||||
try {
|
||||
UNSAFE = sun.misc.Unsafe.getUnsafe();
|
||||
Class<?> k = QNode.class;
|
||||
itemOffset = UNSAFE.objectFieldOffset
|
||||
(k.getDeclaredField("item"));
|
||||
nextOffset = UNSAFE.objectFieldOffset
|
||||
(k.getDeclaredField("next"));
|
||||
} catch (Exception e) {
|
||||
ITEM = U.objectFieldOffset
|
||||
(QNode.class.getDeclaredField("item"));
|
||||
NEXT = U.objectFieldOffset
|
||||
(QNode.class.getDeclaredField("next"));
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
@ -617,7 +614,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
*/
|
||||
void advanceHead(QNode h, QNode nh) {
|
||||
if (h == head &&
|
||||
UNSAFE.compareAndSwapObject(this, headOffset, h, nh))
|
||||
U.compareAndSwapObject(this, HEAD, h, nh))
|
||||
h.next = h; // forget old next
|
||||
}
|
||||
|
||||
@ -626,7 +623,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
*/
|
||||
void advanceTail(QNode t, QNode nt) {
|
||||
if (tail == t)
|
||||
UNSAFE.compareAndSwapObject(this, tailOffset, t, nt);
|
||||
U.compareAndSwapObject(this, TAIL, t, nt);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -634,7 +631,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
*/
|
||||
boolean casCleanMe(QNode cmp, QNode val) {
|
||||
return cleanMe == cmp &&
|
||||
UNSAFE.compareAndSwapObject(this, cleanMeOffset, cmp, val);
|
||||
U.compareAndSwapObject(this, CLEANME, cmp, val);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -684,7 +681,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
advanceTail(t, tn);
|
||||
continue;
|
||||
}
|
||||
if (timed && nanos <= 0) // can't wait
|
||||
if (timed && nanos <= 0L) // can't wait
|
||||
return null;
|
||||
if (s == null)
|
||||
s = new QNode(e, isData);
|
||||
@ -739,8 +736,9 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
/* Same idea as TransferStack.awaitFulfill */
|
||||
final long deadline = timed ? System.nanoTime() + nanos : 0L;
|
||||
Thread w = Thread.currentThread();
|
||||
int spins = ((head.next == s) ?
|
||||
(timed ? maxTimedSpins : maxUntimedSpins) : 0);
|
||||
int spins = (head.next == s)
|
||||
? (timed ? MAX_TIMED_SPINS : MAX_UNTIMED_SPINS)
|
||||
: 0;
|
||||
for (;;) {
|
||||
if (w.isInterrupted())
|
||||
s.tryCancel(e);
|
||||
@ -760,7 +758,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
s.waiter = w;
|
||||
else if (!timed)
|
||||
LockSupport.park(this);
|
||||
else if (nanos > spinForTimeoutThreshold)
|
||||
else if (nanos > SPIN_FOR_TIMEOUT_THRESHOLD)
|
||||
LockSupport.parkNanos(this, nanos);
|
||||
}
|
||||
}
|
||||
@ -819,21 +817,19 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
}
|
||||
}
|
||||
|
||||
private static final sun.misc.Unsafe UNSAFE;
|
||||
private static final long headOffset;
|
||||
private static final long tailOffset;
|
||||
private static final long cleanMeOffset;
|
||||
private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
|
||||
private static final long HEAD;
|
||||
private static final long TAIL;
|
||||
private static final long CLEANME;
|
||||
static {
|
||||
try {
|
||||
UNSAFE = sun.misc.Unsafe.getUnsafe();
|
||||
Class<?> k = TransferQueue.class;
|
||||
headOffset = UNSAFE.objectFieldOffset
|
||||
(k.getDeclaredField("head"));
|
||||
tailOffset = UNSAFE.objectFieldOffset
|
||||
(k.getDeclaredField("tail"));
|
||||
cleanMeOffset = UNSAFE.objectFieldOffset
|
||||
(k.getDeclaredField("cleanMe"));
|
||||
} catch (Exception e) {
|
||||
HEAD = U.objectFieldOffset
|
||||
(TransferQueue.class.getDeclaredField("head"));
|
||||
TAIL = U.objectFieldOffset
|
||||
(TransferQueue.class.getDeclaredField("tail"));
|
||||
CLEANME = U.objectFieldOffset
|
||||
(TransferQueue.class.getDeclaredField("cleanMe"));
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
@ -1088,7 +1084,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the zeroeth element of the specified array to {@code null}
|
||||
* Sets the zeroth element of the specified array to {@code null}
|
||||
* (if the array has non-zero length) and returns it.
|
||||
*
|
||||
* @param a the array
|
||||
@ -1101,6 +1097,14 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns {@code "[]"}.
|
||||
* @return {@code "[]"}
|
||||
*/
|
||||
public String toString() {
|
||||
return "[]";
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws UnsupportedOperationException {@inheritDoc}
|
||||
* @throws ClassCastException {@inheritDoc}
|
||||
@ -1196,17 +1200,9 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
transferer = new TransferStack<E>();
|
||||
}
|
||||
|
||||
// Unsafe mechanics
|
||||
static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
|
||||
String field, Class<?> klazz) {
|
||||
try {
|
||||
return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
|
||||
} catch (NoSuchFieldException e) {
|
||||
// Convert Exception to corresponding Error
|
||||
NoSuchFieldError error = new NoSuchFieldError(field);
|
||||
error.initCause(e);
|
||||
throw error;
|
||||
}
|
||||
static {
|
||||
// Reduce the risk of rare disastrous classloading in first call to
|
||||
// LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
|
||||
Class<?> ensureLoaded = LockSupport.class;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -42,7 +42,7 @@ package java.util.concurrent;
|
||||
*
|
||||
* <p>
|
||||
* The simplest implementation of this interface is just:
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* class SimpleThreadFactory implements ThreadFactory {
|
||||
* public Thread newThread(Runnable r) {
|
||||
* return new Thread(r);
|
||||
|
||||
@ -126,8 +126,7 @@ public class ThreadLocalRandom extends Random {
|
||||
*/
|
||||
|
||||
/** Generates per-thread initialization/probe field */
|
||||
private static final AtomicInteger probeGenerator =
|
||||
new AtomicInteger();
|
||||
private static final AtomicInteger probeGenerator = new AtomicInteger();
|
||||
|
||||
/**
|
||||
* The next seed for default constructors.
|
||||
@ -150,17 +149,17 @@ public class ThreadLocalRandom extends Random {
|
||||
}
|
||||
|
||||
/**
|
||||
* The seed increment
|
||||
* The seed increment.
|
||||
*/
|
||||
private static final long GAMMA = 0x9e3779b97f4a7c15L;
|
||||
|
||||
/**
|
||||
* The increment for generating probe values
|
||||
* The increment for generating probe values.
|
||||
*/
|
||||
private static final int PROBE_INCREMENT = 0x9e3779b9;
|
||||
|
||||
/**
|
||||
* The increment of seeder per new instance
|
||||
* The increment of seeder per new instance.
|
||||
*/
|
||||
private static final long SEEDER_INCREMENT = 0xbb67ae8584caa73bL;
|
||||
|
||||
@ -170,7 +169,7 @@ public class ThreadLocalRandom extends Random {
|
||||
|
||||
/** Rarely-used holder for the second of a pair of Gaussians */
|
||||
private static final ThreadLocal<Double> nextLocalGaussian =
|
||||
new ThreadLocal<Double>();
|
||||
new ThreadLocal<>();
|
||||
|
||||
private static long mix64(long z) {
|
||||
z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL;
|
||||
@ -209,8 +208,8 @@ public class ThreadLocalRandom extends Random {
|
||||
int probe = (p == 0) ? 1 : p; // skip 0
|
||||
long seed = mix64(seeder.getAndAdd(SEEDER_INCREMENT));
|
||||
Thread t = Thread.currentThread();
|
||||
UNSAFE.putLong(t, SEED, seed);
|
||||
UNSAFE.putInt(t, PROBE, probe);
|
||||
U.putLong(t, SEED, seed);
|
||||
U.putInt(t, PROBE, probe);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -219,7 +218,7 @@ public class ThreadLocalRandom extends Random {
|
||||
* @return the current thread's {@code ThreadLocalRandom}
|
||||
*/
|
||||
public static ThreadLocalRandom current() {
|
||||
if (UNSAFE.getInt(Thread.currentThread(), PROBE) == 0)
|
||||
if (U.getInt(Thread.currentThread(), PROBE) == 0)
|
||||
localInit();
|
||||
return instance;
|
||||
}
|
||||
@ -238,8 +237,8 @@ public class ThreadLocalRandom extends Random {
|
||||
|
||||
final long nextSeed() {
|
||||
Thread t; long r; // read and update per-thread seed
|
||||
UNSAFE.putLong(t = Thread.currentThread(), SEED,
|
||||
r = UNSAFE.getLong(t, SEED) + GAMMA);
|
||||
U.putLong(t = Thread.currentThread(), SEED,
|
||||
r = U.getLong(t, SEED) + GAMMA);
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -249,9 +248,9 @@ public class ThreadLocalRandom extends Random {
|
||||
}
|
||||
|
||||
// IllegalArgumentException messages
|
||||
static final String BadBound = "bound must be positive";
|
||||
static final String BadRange = "bound must be greater than origin";
|
||||
static final String BadSize = "size must be non-negative";
|
||||
static final String BAD_BOUND = "bound must be positive";
|
||||
static final String BAD_RANGE = "bound must be greater than origin";
|
||||
static final String BAD_SIZE = "size must be non-negative";
|
||||
|
||||
/**
|
||||
* The form of nextLong used by LongStream Spliterators. If
|
||||
@ -349,7 +348,7 @@ public class ThreadLocalRandom extends Random {
|
||||
*/
|
||||
public int nextInt(int bound) {
|
||||
if (bound <= 0)
|
||||
throw new IllegalArgumentException(BadBound);
|
||||
throw new IllegalArgumentException(BAD_BOUND);
|
||||
int r = mix32(nextSeed());
|
||||
int m = bound - 1;
|
||||
if ((bound & m) == 0) // power of two
|
||||
@ -376,7 +375,7 @@ public class ThreadLocalRandom extends Random {
|
||||
*/
|
||||
public int nextInt(int origin, int bound) {
|
||||
if (origin >= bound)
|
||||
throw new IllegalArgumentException(BadRange);
|
||||
throw new IllegalArgumentException(BAD_RANGE);
|
||||
return internalNextInt(origin, bound);
|
||||
}
|
||||
|
||||
@ -400,7 +399,7 @@ public class ThreadLocalRandom extends Random {
|
||||
*/
|
||||
public long nextLong(long bound) {
|
||||
if (bound <= 0)
|
||||
throw new IllegalArgumentException(BadBound);
|
||||
throw new IllegalArgumentException(BAD_BOUND);
|
||||
long r = mix64(nextSeed());
|
||||
long m = bound - 1;
|
||||
if ((bound & m) == 0L) // power of two
|
||||
@ -427,7 +426,7 @@ public class ThreadLocalRandom extends Random {
|
||||
*/
|
||||
public long nextLong(long origin, long bound) {
|
||||
if (origin >= bound)
|
||||
throw new IllegalArgumentException(BadRange);
|
||||
throw new IllegalArgumentException(BAD_RANGE);
|
||||
return internalNextLong(origin, bound);
|
||||
}
|
||||
|
||||
@ -453,9 +452,9 @@ public class ThreadLocalRandom extends Random {
|
||||
*/
|
||||
public double nextDouble(double bound) {
|
||||
if (!(bound > 0.0))
|
||||
throw new IllegalArgumentException(BadBound);
|
||||
throw new IllegalArgumentException(BAD_BOUND);
|
||||
double result = (mix64(nextSeed()) >>> 11) * DOUBLE_UNIT * bound;
|
||||
return (result < bound) ? result : // correct for rounding
|
||||
return (result < bound) ? result : // correct for rounding
|
||||
Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1);
|
||||
}
|
||||
|
||||
@ -472,7 +471,7 @@ public class ThreadLocalRandom extends Random {
|
||||
*/
|
||||
public double nextDouble(double origin, double bound) {
|
||||
if (!(origin < bound))
|
||||
throw new IllegalArgumentException(BadRange);
|
||||
throw new IllegalArgumentException(BAD_RANGE);
|
||||
return internalNextDouble(origin, bound);
|
||||
}
|
||||
|
||||
@ -529,7 +528,7 @@ public class ThreadLocalRandom extends Random {
|
||||
*/
|
||||
public IntStream ints(long streamSize) {
|
||||
if (streamSize < 0L)
|
||||
throw new IllegalArgumentException(BadSize);
|
||||
throw new IllegalArgumentException(BAD_SIZE);
|
||||
return StreamSupport.intStream
|
||||
(new RandomIntsSpliterator
|
||||
(0L, streamSize, Integer.MAX_VALUE, 0),
|
||||
@ -571,9 +570,9 @@ public class ThreadLocalRandom extends Random {
|
||||
public IntStream ints(long streamSize, int randomNumberOrigin,
|
||||
int randomNumberBound) {
|
||||
if (streamSize < 0L)
|
||||
throw new IllegalArgumentException(BadSize);
|
||||
throw new IllegalArgumentException(BAD_SIZE);
|
||||
if (randomNumberOrigin >= randomNumberBound)
|
||||
throw new IllegalArgumentException(BadRange);
|
||||
throw new IllegalArgumentException(BAD_RANGE);
|
||||
return StreamSupport.intStream
|
||||
(new RandomIntsSpliterator
|
||||
(0L, streamSize, randomNumberOrigin, randomNumberBound),
|
||||
@ -598,7 +597,7 @@ public class ThreadLocalRandom extends Random {
|
||||
*/
|
||||
public IntStream ints(int randomNumberOrigin, int randomNumberBound) {
|
||||
if (randomNumberOrigin >= randomNumberBound)
|
||||
throw new IllegalArgumentException(BadRange);
|
||||
throw new IllegalArgumentException(BAD_RANGE);
|
||||
return StreamSupport.intStream
|
||||
(new RandomIntsSpliterator
|
||||
(0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
|
||||
@ -617,7 +616,7 @@ public class ThreadLocalRandom extends Random {
|
||||
*/
|
||||
public LongStream longs(long streamSize) {
|
||||
if (streamSize < 0L)
|
||||
throw new IllegalArgumentException(BadSize);
|
||||
throw new IllegalArgumentException(BAD_SIZE);
|
||||
return StreamSupport.longStream
|
||||
(new RandomLongsSpliterator
|
||||
(0L, streamSize, Long.MAX_VALUE, 0L),
|
||||
@ -659,9 +658,9 @@ public class ThreadLocalRandom extends Random {
|
||||
public LongStream longs(long streamSize, long randomNumberOrigin,
|
||||
long randomNumberBound) {
|
||||
if (streamSize < 0L)
|
||||
throw new IllegalArgumentException(BadSize);
|
||||
throw new IllegalArgumentException(BAD_SIZE);
|
||||
if (randomNumberOrigin >= randomNumberBound)
|
||||
throw new IllegalArgumentException(BadRange);
|
||||
throw new IllegalArgumentException(BAD_RANGE);
|
||||
return StreamSupport.longStream
|
||||
(new RandomLongsSpliterator
|
||||
(0L, streamSize, randomNumberOrigin, randomNumberBound),
|
||||
@ -686,7 +685,7 @@ public class ThreadLocalRandom extends Random {
|
||||
*/
|
||||
public LongStream longs(long randomNumberOrigin, long randomNumberBound) {
|
||||
if (randomNumberOrigin >= randomNumberBound)
|
||||
throw new IllegalArgumentException(BadRange);
|
||||
throw new IllegalArgumentException(BAD_RANGE);
|
||||
return StreamSupport.longStream
|
||||
(new RandomLongsSpliterator
|
||||
(0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
|
||||
@ -706,7 +705,7 @@ public class ThreadLocalRandom extends Random {
|
||||
*/
|
||||
public DoubleStream doubles(long streamSize) {
|
||||
if (streamSize < 0L)
|
||||
throw new IllegalArgumentException(BadSize);
|
||||
throw new IllegalArgumentException(BAD_SIZE);
|
||||
return StreamSupport.doubleStream
|
||||
(new RandomDoublesSpliterator
|
||||
(0L, streamSize, Double.MAX_VALUE, 0.0),
|
||||
@ -750,9 +749,9 @@ public class ThreadLocalRandom extends Random {
|
||||
public DoubleStream doubles(long streamSize, double randomNumberOrigin,
|
||||
double randomNumberBound) {
|
||||
if (streamSize < 0L)
|
||||
throw new IllegalArgumentException(BadSize);
|
||||
throw new IllegalArgumentException(BAD_SIZE);
|
||||
if (!(randomNumberOrigin < randomNumberBound))
|
||||
throw new IllegalArgumentException(BadRange);
|
||||
throw new IllegalArgumentException(BAD_RANGE);
|
||||
return StreamSupport.doubleStream
|
||||
(new RandomDoublesSpliterator
|
||||
(0L, streamSize, randomNumberOrigin, randomNumberBound),
|
||||
@ -777,7 +776,7 @@ public class ThreadLocalRandom extends Random {
|
||||
*/
|
||||
public DoubleStream doubles(double randomNumberOrigin, double randomNumberBound) {
|
||||
if (!(randomNumberOrigin < randomNumberBound))
|
||||
throw new IllegalArgumentException(BadRange);
|
||||
throw new IllegalArgumentException(BAD_RANGE);
|
||||
return StreamSupport.doubleStream
|
||||
(new RandomDoublesSpliterator
|
||||
(0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
|
||||
@ -792,7 +791,8 @@ public class ThreadLocalRandom extends Random {
|
||||
* approach. The long and double versions of this class are
|
||||
* identical except for types.
|
||||
*/
|
||||
static final class RandomIntsSpliterator implements Spliterator.OfInt {
|
||||
private static final class RandomIntsSpliterator
|
||||
implements Spliterator.OfInt {
|
||||
long index;
|
||||
final long fence;
|
||||
final int origin;
|
||||
@ -846,7 +846,8 @@ public class ThreadLocalRandom extends Random {
|
||||
/**
|
||||
* Spliterator for long streams.
|
||||
*/
|
||||
static final class RandomLongsSpliterator implements Spliterator.OfLong {
|
||||
private static final class RandomLongsSpliterator
|
||||
implements Spliterator.OfLong {
|
||||
long index;
|
||||
final long fence;
|
||||
final long origin;
|
||||
@ -901,7 +902,8 @@ public class ThreadLocalRandom extends Random {
|
||||
/**
|
||||
* Spliterator for double streams.
|
||||
*/
|
||||
static final class RandomDoublesSpliterator implements Spliterator.OfDouble {
|
||||
private static final class RandomDoublesSpliterator
|
||||
implements Spliterator.OfDouble {
|
||||
long index;
|
||||
final long fence;
|
||||
final double origin;
|
||||
@ -978,7 +980,7 @@ public class ThreadLocalRandom extends Random {
|
||||
* can be used to force initialization on zero return.
|
||||
*/
|
||||
static final int getProbe() {
|
||||
return UNSAFE.getInt(Thread.currentThread(), PROBE);
|
||||
return U.getInt(Thread.currentThread(), PROBE);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -989,7 +991,7 @@ public class ThreadLocalRandom extends Random {
|
||||
probe ^= probe << 13; // xorshift
|
||||
probe ^= probe >>> 17;
|
||||
probe ^= probe << 5;
|
||||
UNSAFE.putInt(Thread.currentThread(), PROBE, probe);
|
||||
U.putInt(Thread.currentThread(), PROBE, probe);
|
||||
return probe;
|
||||
}
|
||||
|
||||
@ -999,17 +1001,14 @@ public class ThreadLocalRandom extends Random {
|
||||
static final int nextSecondarySeed() {
|
||||
int r;
|
||||
Thread t = Thread.currentThread();
|
||||
if ((r = UNSAFE.getInt(t, SECONDARY)) != 0) {
|
||||
if ((r = U.getInt(t, SECONDARY)) != 0) {
|
||||
r ^= r << 13; // xorshift
|
||||
r ^= r >>> 17;
|
||||
r ^= r << 5;
|
||||
}
|
||||
else {
|
||||
localInit();
|
||||
if ((r = (int)UNSAFE.getLong(t, SEED)) == 0)
|
||||
r = 1; // avoid zero
|
||||
}
|
||||
UNSAFE.putInt(t, SECONDARY, r);
|
||||
else if ((r = mix32(seeder.getAndAdd(SEEDER_INCREMENT))) == 0)
|
||||
r = 1; // avoid zero
|
||||
U.putInt(t, SECONDARY, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -1024,8 +1023,8 @@ public class ThreadLocalRandom extends Random {
|
||||
* always true
|
||||
*/
|
||||
private static final ObjectStreamField[] serialPersistentFields = {
|
||||
new ObjectStreamField("rnd", long.class),
|
||||
new ObjectStreamField("initialized", boolean.class),
|
||||
new ObjectStreamField("rnd", long.class),
|
||||
new ObjectStreamField("initialized", boolean.class),
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1037,7 +1036,7 @@ public class ThreadLocalRandom extends Random {
|
||||
throws java.io.IOException {
|
||||
|
||||
java.io.ObjectOutputStream.PutField fields = s.putFields();
|
||||
fields.put("rnd", UNSAFE.getLong(Thread.currentThread(), SEED));
|
||||
fields.put("rnd", U.getLong(Thread.currentThread(), SEED));
|
||||
fields.put("initialized", true);
|
||||
s.writeFields();
|
||||
}
|
||||
@ -1051,21 +1050,19 @@ public class ThreadLocalRandom extends Random {
|
||||
}
|
||||
|
||||
// Unsafe mechanics
|
||||
private static final sun.misc.Unsafe UNSAFE;
|
||||
private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
|
||||
private static final long SEED;
|
||||
private static final long PROBE;
|
||||
private static final long SECONDARY;
|
||||
static {
|
||||
try {
|
||||
UNSAFE = sun.misc.Unsafe.getUnsafe();
|
||||
Class<?> tk = Thread.class;
|
||||
SEED = UNSAFE.objectFieldOffset
|
||||
(tk.getDeclaredField("threadLocalRandomSeed"));
|
||||
PROBE = UNSAFE.objectFieldOffset
|
||||
(tk.getDeclaredField("threadLocalRandomProbe"));
|
||||
SECONDARY = UNSAFE.objectFieldOffset
|
||||
(tk.getDeclaredField("threadLocalRandomSecondarySeed"));
|
||||
} catch (Exception e) {
|
||||
SEED = U.objectFieldOffset
|
||||
(Thread.class.getDeclaredField("threadLocalRandomSeed"));
|
||||
PROBE = U.objectFieldOffset
|
||||
(Thread.class.getDeclaredField("threadLocalRandomProbe"));
|
||||
SECONDARY = U.objectFieldOffset
|
||||
(Thread.class.getDeclaredField("threadLocalRandomSecondarySeed"));
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,11 +34,16 @@
|
||||
*/
|
||||
|
||||
package java.util.concurrent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* An {@link ExecutorService} that executes each submitted task using
|
||||
@ -69,7 +74,8 @@ import java.util.*;
|
||||
*
|
||||
* <dt>Core and maximum pool sizes</dt>
|
||||
*
|
||||
* <dd>A {@code ThreadPoolExecutor} will automatically adjust the
|
||||
* <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
|
||||
* A {@code ThreadPoolExecutor} will automatically adjust the
|
||||
* pool size (see {@link #getPoolSize})
|
||||
* according to the bounds set by
|
||||
* corePoolSize (see {@link #getCorePoolSize}) and
|
||||
@ -91,7 +97,8 @@ import java.util.*;
|
||||
*
|
||||
* <dt>On-demand construction</dt>
|
||||
*
|
||||
* <dd>By default, even core threads are initially created and
|
||||
* <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
|
||||
* By default, even core threads are initially created and
|
||||
* started only when new tasks arrive, but this can be overridden
|
||||
* dynamically using method {@link #prestartCoreThread} or {@link
|
||||
* #prestartAllCoreThreads}. You probably want to prestart threads if
|
||||
@ -99,7 +106,8 @@ import java.util.*;
|
||||
*
|
||||
* <dt>Creating new threads</dt>
|
||||
*
|
||||
* <dd>New threads are created using a {@link ThreadFactory}. If not
|
||||
* <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
|
||||
* New threads are created using a {@link ThreadFactory}. If not
|
||||
* otherwise specified, a {@link Executors#defaultThreadFactory} is
|
||||
* used, that creates threads to all be in the same {@link
|
||||
* ThreadGroup} and with the same {@code NORM_PRIORITY} priority and
|
||||
@ -116,7 +124,8 @@ import java.util.*;
|
||||
*
|
||||
* <dt>Keep-alive times</dt>
|
||||
*
|
||||
* <dd>If the pool currently has more than corePoolSize threads,
|
||||
* <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
|
||||
* If the pool currently has more than corePoolSize threads,
|
||||
* excess threads will be terminated if they have been idle for more
|
||||
* than the keepAliveTime (see {@link #getKeepAliveTime(TimeUnit)}).
|
||||
* This provides a means of reducing resource consumption when the
|
||||
@ -126,36 +135,37 @@ import java.util.*;
|
||||
* TimeUnit)}. Using a value of {@code Long.MAX_VALUE} {@link
|
||||
* TimeUnit#NANOSECONDS} effectively disables idle threads from ever
|
||||
* terminating prior to shut down. By default, the keep-alive policy
|
||||
* applies only when there are more than corePoolSize threads. But
|
||||
* applies only when there are more than corePoolSize threads, but
|
||||
* method {@link #allowCoreThreadTimeOut(boolean)} can be used to
|
||||
* apply this time-out policy to core threads as well, so long as the
|
||||
* keepAliveTime value is non-zero. </dd>
|
||||
*
|
||||
* <dt>Queuing</dt>
|
||||
*
|
||||
* <dd>Any {@link BlockingQueue} may be used to transfer and hold
|
||||
* <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
|
||||
* Any {@link BlockingQueue} may be used to transfer and hold
|
||||
* submitted tasks. The use of this queue interacts with pool sizing:
|
||||
*
|
||||
* <ul>
|
||||
*
|
||||
* <li> If fewer than corePoolSize threads are running, the Executor
|
||||
* <li>If fewer than corePoolSize threads are running, the Executor
|
||||
* always prefers adding a new thread
|
||||
* rather than queuing.</li>
|
||||
* rather than queuing.
|
||||
*
|
||||
* <li> If corePoolSize or more threads are running, the Executor
|
||||
* <li>If corePoolSize or more threads are running, the Executor
|
||||
* always prefers queuing a request rather than adding a new
|
||||
* thread.</li>
|
||||
* thread.
|
||||
*
|
||||
* <li> If a request cannot be queued, a new thread is created unless
|
||||
* <li>If a request cannot be queued, a new thread is created unless
|
||||
* this would exceed maximumPoolSize, in which case, the task will be
|
||||
* rejected.</li>
|
||||
* rejected.
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* There are three general strategies for queuing:
|
||||
* <ol>
|
||||
*
|
||||
* <li> <em> Direct handoffs.</em> A good default choice for a work
|
||||
* <li><em> Direct handoffs.</em> A good default choice for a work
|
||||
* queue is a {@link SynchronousQueue} that hands off tasks to threads
|
||||
* without otherwise holding them. Here, an attempt to queue a task
|
||||
* will fail if no threads are immediately available to run it, so a
|
||||
@ -164,7 +174,7 @@ import java.util.*;
|
||||
* Direct handoffs generally require unbounded maximumPoolSizes to
|
||||
* avoid rejection of new submitted tasks. This in turn admits the
|
||||
* possibility of unbounded thread growth when commands continue to
|
||||
* arrive on average faster than they can be processed. </li>
|
||||
* arrive on average faster than they can be processed.
|
||||
*
|
||||
* <li><em> Unbounded queues.</em> Using an unbounded queue (for
|
||||
* example a {@link LinkedBlockingQueue} without a predefined
|
||||
@ -177,7 +187,7 @@ import java.util.*;
|
||||
* While this style of queuing can be useful in smoothing out
|
||||
* transient bursts of requests, it admits the possibility of
|
||||
* unbounded work queue growth when commands continue to arrive on
|
||||
* average faster than they can be processed. </li>
|
||||
* average faster than they can be processed.
|
||||
*
|
||||
* <li><em>Bounded queues.</em> A bounded queue (for example, an
|
||||
* {@link ArrayBlockingQueue}) helps prevent resource exhaustion when
|
||||
@ -190,7 +200,7 @@ import java.util.*;
|
||||
* time for more threads than you otherwise allow. Use of small queues
|
||||
* generally requires larger pool sizes, which keeps CPUs busier but
|
||||
* may encounter unacceptable scheduling overhead, which also
|
||||
* decreases throughput. </li>
|
||||
* decreases throughput.
|
||||
*
|
||||
* </ol>
|
||||
*
|
||||
@ -198,7 +208,8 @@ import java.util.*;
|
||||
*
|
||||
* <dt>Rejected tasks</dt>
|
||||
*
|
||||
* <dd>New tasks submitted in method {@link #execute(Runnable)} will be
|
||||
* <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
|
||||
* New tasks submitted in method {@link #execute(Runnable)} will be
|
||||
* <em>rejected</em> when the Executor has been shut down, and also when
|
||||
* the Executor uses finite bounds for both maximum threads and work queue
|
||||
* capacity, and is saturated. In either case, the {@code execute} method
|
||||
@ -209,22 +220,22 @@ import java.util.*;
|
||||
*
|
||||
* <ol>
|
||||
*
|
||||
* <li> In the default {@link ThreadPoolExecutor.AbortPolicy}, the
|
||||
* <li>In the default {@link ThreadPoolExecutor.AbortPolicy}, the
|
||||
* handler throws a runtime {@link RejectedExecutionException} upon
|
||||
* rejection. </li>
|
||||
* rejection.
|
||||
*
|
||||
* <li> In {@link ThreadPoolExecutor.CallerRunsPolicy}, the thread
|
||||
* <li>In {@link ThreadPoolExecutor.CallerRunsPolicy}, the thread
|
||||
* that invokes {@code execute} itself runs the task. This provides a
|
||||
* simple feedback control mechanism that will slow down the rate that
|
||||
* new tasks are submitted. </li>
|
||||
* new tasks are submitted.
|
||||
*
|
||||
* <li> In {@link ThreadPoolExecutor.DiscardPolicy}, a task that
|
||||
* cannot be executed is simply dropped. </li>
|
||||
* <li>In {@link ThreadPoolExecutor.DiscardPolicy}, a task that
|
||||
* cannot be executed is simply dropped.
|
||||
*
|
||||
* <li>In {@link ThreadPoolExecutor.DiscardOldestPolicy}, if the
|
||||
* executor is not shut down, the task at the head of the work queue
|
||||
* is dropped, and then execution is retried (which can fail again,
|
||||
* causing this to be repeated.) </li>
|
||||
* causing this to be repeated.)
|
||||
*
|
||||
* </ol>
|
||||
*
|
||||
@ -235,7 +246,8 @@ import java.util.*;
|
||||
*
|
||||
* <dt>Hook methods</dt>
|
||||
*
|
||||
* <dd>This class provides {@code protected} overridable
|
||||
* <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
|
||||
* This class provides {@code protected} overridable
|
||||
* {@link #beforeExecute(Thread, Runnable)} and
|
||||
* {@link #afterExecute(Runnable, Throwable)} methods that are called
|
||||
* before and after execution of each task. These can be used to
|
||||
@ -245,12 +257,14 @@ import java.util.*;
|
||||
* any special processing that needs to be done once the Executor has
|
||||
* fully terminated.
|
||||
*
|
||||
* <p>If hook or callback methods throw exceptions, internal worker
|
||||
* threads may in turn fail and abruptly terminate.</dd>
|
||||
* <p>If hook, callback, or BlockingQueue methods throw exceptions,
|
||||
* internal worker threads may in turn fail, abruptly terminate, and
|
||||
* possibly be replaced.</dd>
|
||||
*
|
||||
* <dt>Queue maintenance</dt>
|
||||
*
|
||||
* <dd>Method {@link #getQueue()} allows access to the work queue
|
||||
* <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
|
||||
* Method {@link #getQueue()} allows access to the work queue
|
||||
* for purposes of monitoring and debugging. Use of this method for
|
||||
* any other purpose is strongly discouraged. Two supplied methods,
|
||||
* {@link #remove(Runnable)} and {@link #purge} are available to
|
||||
@ -259,7 +273,8 @@ import java.util.*;
|
||||
*
|
||||
* <dt>Finalization</dt>
|
||||
*
|
||||
* <dd>A pool that is no longer referenced in a program <em>AND</em>
|
||||
* <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
|
||||
* A pool that is no longer referenced in a program <em>AND</em>
|
||||
* has no remaining threads will be {@code shutdown} automatically. If
|
||||
* you would like to ensure that unreferenced pools are reclaimed even
|
||||
* if users forget to call {@link #shutdown}, then you must arrange
|
||||
@ -273,7 +288,7 @@ import java.util.*;
|
||||
* override one or more of the protected hook methods. For example,
|
||||
* here is a subclass that adds a simple pause/resume feature:
|
||||
*
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* class PausableThreadPoolExecutor extends ThreadPoolExecutor {
|
||||
* private boolean isPaused;
|
||||
* private ReentrantLock pauseLock = new ReentrantLock();
|
||||
@ -462,10 +477,10 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
||||
* Set containing all worker threads in pool. Accessed only when
|
||||
* holding mainLock.
|
||||
*/
|
||||
private final HashSet<Worker> workers = new HashSet<Worker>();
|
||||
private final HashSet<Worker> workers = new HashSet<>();
|
||||
|
||||
/**
|
||||
* Wait condition to support awaitTermination
|
||||
* Wait condition to support awaitTermination.
|
||||
*/
|
||||
private final Condition termination = mainLock.newCondition();
|
||||
|
||||
@ -541,7 +556,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
||||
private volatile int maximumPoolSize;
|
||||
|
||||
/**
|
||||
* The default rejected execution handler
|
||||
* The default rejected execution handler.
|
||||
*/
|
||||
private static final RejectedExecutionHandler defaultHandler =
|
||||
new AbortPolicy();
|
||||
@ -612,7 +627,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
||||
this.thread = getThreadFactory().newThread(this);
|
||||
}
|
||||
|
||||
/** Delegates main run loop to outer runWorker */
|
||||
/** Delegates main run loop to outer runWorker. */
|
||||
public void run() {
|
||||
runWorker(this);
|
||||
}
|
||||
@ -668,6 +683,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
||||
* (but not TIDYING or TERMINATED -- use tryTerminate for that)
|
||||
*/
|
||||
private void advanceRunState(int targetState) {
|
||||
// assert targetState == SHUTDOWN || targetState == STOP;
|
||||
for (;;) {
|
||||
int c = ctl.get();
|
||||
if (runStateAtLeast(c, targetState) ||
|
||||
@ -850,7 +866,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
||||
*/
|
||||
private List<Runnable> drainQueue() {
|
||||
BlockingQueue<Runnable> q = workQueue;
|
||||
ArrayList<Runnable> taskList = new ArrayList<Runnable>();
|
||||
ArrayList<Runnable> taskList = new ArrayList<>();
|
||||
q.drainTo(taskList);
|
||||
if (!q.isEmpty()) {
|
||||
for (Runnable r : q.toArray(new Runnable[0])) {
|
||||
@ -1406,7 +1422,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
||||
*
|
||||
* <p>There are no guarantees beyond best-effort attempts to stop
|
||||
* processing actively executing tasks. This implementation
|
||||
* cancels tasks via {@link Thread#interrupt}, so any task that
|
||||
* interrupts tasks via {@link Thread#interrupt}; any task that
|
||||
* fails to respond to interrupts may never terminate.
|
||||
*
|
||||
* @throws SecurityException {@inheritDoc}
|
||||
@ -1457,13 +1473,12 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
||||
final ReentrantLock mainLock = this.mainLock;
|
||||
mainLock.lock();
|
||||
try {
|
||||
for (;;) {
|
||||
if (runStateAtLeast(ctl.get(), TERMINATED))
|
||||
return true;
|
||||
if (nanos <= 0)
|
||||
while (!runStateAtLeast(ctl.get(), TERMINATED)) {
|
||||
if (nanos <= 0L)
|
||||
return false;
|
||||
nanos = termination.awaitNanos(nanos);
|
||||
}
|
||||
return true;
|
||||
} finally {
|
||||
mainLock.unlock();
|
||||
}
|
||||
@ -1680,11 +1695,13 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the time limit for which threads may remain idle before
|
||||
* being terminated. If there are more than the core number of
|
||||
* threads currently in the pool, after waiting this amount of
|
||||
* time without processing a task, excess threads will be
|
||||
* terminated. This overrides any value set in the constructor.
|
||||
* Sets the thread keep-alive time, which is the amount of time
|
||||
* that threads may remain idle before being terminated.
|
||||
* Threads that wait this amount of time without processing a
|
||||
* task will be terminated if there are more than the core
|
||||
* number of threads currently in the pool, or if this pool
|
||||
* {@linkplain #allowsCoreThreadTimeOut() allows core thread timeout}.
|
||||
* This overrides any value set in the constructor.
|
||||
*
|
||||
* @param time the time to wait. A time value of zero will cause
|
||||
* excess threads to terminate immediately after executing tasks.
|
||||
@ -1707,8 +1724,11 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
||||
|
||||
/**
|
||||
* Returns the thread keep-alive time, which is the amount of time
|
||||
* that threads in excess of the core pool size may remain
|
||||
* idle before being terminated.
|
||||
* that threads may remain idle before being terminated.
|
||||
* Threads that wait this amount of time without processing a
|
||||
* task will be terminated if there are more than the core
|
||||
* number of threads currently in the pool, or if this pool
|
||||
* {@linkplain #allowsCoreThreadTimeOut() allows core thread timeout}.
|
||||
*
|
||||
* @param unit the desired time unit of the result
|
||||
* @return the time limit
|
||||
@ -1739,8 +1759,8 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
||||
*
|
||||
* <p>This method may be useful as one part of a cancellation
|
||||
* scheme. It may fail to remove tasks that have been converted
|
||||
* into other forms before being placed on the internal queue. For
|
||||
* example, a task entered using {@code submit} might be
|
||||
* into other forms before being placed on the internal queue.
|
||||
* For example, a task entered using {@code submit} might be
|
||||
* converted into a form that maintains {@code Future} status.
|
||||
* However, in such cases, method {@link #purge} may be used to
|
||||
* remove those Futures that have been cancelled.
|
||||
@ -1912,11 +1932,12 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
||||
mainLock.unlock();
|
||||
}
|
||||
int c = ctl.get();
|
||||
String rs = (runStateLessThan(c, SHUTDOWN) ? "Running" :
|
||||
(runStateAtLeast(c, TERMINATED) ? "Terminated" :
|
||||
"Shutting down"));
|
||||
String runState =
|
||||
runStateLessThan(c, SHUTDOWN) ? "Running" :
|
||||
runStateAtLeast(c, TERMINATED) ? "Terminated" :
|
||||
"Shutting down";
|
||||
return super.toString() +
|
||||
"[" + rs +
|
||||
"[" + runState +
|
||||
", pool size = " + nworkers +
|
||||
", active threads = " + nactive +
|
||||
", queued tasks = " + workQueue.size() +
|
||||
@ -1963,20 +1984,23 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
||||
* as in this sample subclass that prints either the direct cause
|
||||
* or the underlying exception if a task has been aborted:
|
||||
*
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* class ExtendedExecutor extends ThreadPoolExecutor {
|
||||
* // ...
|
||||
* protected void afterExecute(Runnable r, Throwable t) {
|
||||
* super.afterExecute(r, t);
|
||||
* if (t == null && r instanceof Future<?>) {
|
||||
* if (t == null
|
||||
* && r instanceof Future<?>
|
||||
* && ((Future<?>)r).isDone()) {
|
||||
* try {
|
||||
* Object result = ((Future<?>) r).get();
|
||||
* } catch (CancellationException ce) {
|
||||
* t = ce;
|
||||
* t = ce;
|
||||
* } catch (ExecutionException ee) {
|
||||
* t = ee.getCause();
|
||||
* t = ee.getCause();
|
||||
* } catch (InterruptedException ie) {
|
||||
* Thread.currentThread().interrupt(); // ignore/reset
|
||||
* // ignore/reset
|
||||
* Thread.currentThread().interrupt();
|
||||
* }
|
||||
* }
|
||||
* if (t != null)
|
||||
|
||||
@ -52,12 +52,12 @@ package java.util.concurrent;
|
||||
* the following code will timeout in 50 milliseconds if the {@link
|
||||
* java.util.concurrent.locks.Lock lock} is not available:
|
||||
*
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* Lock lock = ...;
|
||||
* if (lock.tryLock(50L, TimeUnit.MILLISECONDS)) ...}</pre>
|
||||
*
|
||||
* while this code will timeout in 50 seconds:
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* Lock lock = ...;
|
||||
* if (lock.tryLock(50L, TimeUnit.SECONDS)) ...}</pre>
|
||||
*
|
||||
@ -70,7 +70,7 @@ package java.util.concurrent;
|
||||
*/
|
||||
public enum TimeUnit {
|
||||
/**
|
||||
* Time unit representing one thousandth of a microsecond
|
||||
* Time unit representing one thousandth of a microsecond.
|
||||
*/
|
||||
NANOSECONDS {
|
||||
public long toNanos(long d) { return d; }
|
||||
@ -85,7 +85,7 @@ public enum TimeUnit {
|
||||
},
|
||||
|
||||
/**
|
||||
* Time unit representing one thousandth of a millisecond
|
||||
* Time unit representing one thousandth of a millisecond.
|
||||
*/
|
||||
MICROSECONDS {
|
||||
public long toNanos(long d) { return x(d, C1/C0, MAX/(C1/C0)); }
|
||||
@ -100,7 +100,7 @@ public enum TimeUnit {
|
||||
},
|
||||
|
||||
/**
|
||||
* Time unit representing one thousandth of a second
|
||||
* Time unit representing one thousandth of a second.
|
||||
*/
|
||||
MILLISECONDS {
|
||||
public long toNanos(long d) { return x(d, C2/C0, MAX/(C2/C0)); }
|
||||
@ -115,7 +115,7 @@ public enum TimeUnit {
|
||||
},
|
||||
|
||||
/**
|
||||
* Time unit representing one second
|
||||
* Time unit representing one second.
|
||||
*/
|
||||
SECONDS {
|
||||
public long toNanos(long d) { return x(d, C3/C0, MAX/(C3/C0)); }
|
||||
@ -130,7 +130,7 @@ public enum TimeUnit {
|
||||
},
|
||||
|
||||
/**
|
||||
* Time unit representing sixty seconds
|
||||
* Time unit representing sixty seconds.
|
||||
* @since 1.6
|
||||
*/
|
||||
MINUTES {
|
||||
@ -146,7 +146,7 @@ public enum TimeUnit {
|
||||
},
|
||||
|
||||
/**
|
||||
* Time unit representing sixty minutes
|
||||
* Time unit representing sixty minutes.
|
||||
* @since 1.6
|
||||
*/
|
||||
HOURS {
|
||||
@ -162,7 +162,7 @@ public enum TimeUnit {
|
||||
},
|
||||
|
||||
/**
|
||||
* Time unit representing twenty four hours
|
||||
* Time unit representing twenty four hours.
|
||||
* @since 1.6
|
||||
*/
|
||||
DAYS {
|
||||
@ -193,7 +193,7 @@ public enum TimeUnit {
|
||||
* This has a short name to make above code more readable.
|
||||
*/
|
||||
static long x(long d, long m, long over) {
|
||||
if (d > over) return Long.MAX_VALUE;
|
||||
if (d > +over) return Long.MAX_VALUE;
|
||||
if (d < -over) return Long.MIN_VALUE;
|
||||
return d * m;
|
||||
}
|
||||
@ -329,7 +329,7 @@ public enum TimeUnit {
|
||||
* method (see {@link BlockingQueue#poll BlockingQueue.poll})
|
||||
* using:
|
||||
*
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* public synchronized Object poll(long timeout, TimeUnit unit)
|
||||
* throws InterruptedException {
|
||||
* while (empty) {
|
||||
|
||||
@ -63,7 +63,7 @@ package java.util.concurrent;
|
||||
*
|
||||
* @since 1.7
|
||||
* @author Doug Lea
|
||||
* @param <E> the type of elements held in this collection
|
||||
* @param <E> the type of elements held in this queue
|
||||
*/
|
||||
public interface TransferQueue<E> extends BlockingQueue<E> {
|
||||
/**
|
||||
|
||||
@ -53,9 +53,9 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
|
||||
private static final long serialVersionUID = -6209656149925076980L;
|
||||
|
||||
private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
|
||||
private static final long ARRAY;
|
||||
private static final int ABASE;
|
||||
private static final int ASHIFT;
|
||||
private static final long ARRAY;
|
||||
private final Object[] array; // must have exact type Object[]
|
||||
|
||||
static {
|
||||
|
||||
@ -34,11 +34,12 @@
|
||||
*/
|
||||
|
||||
package java.util.concurrent.locks;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import sun.misc.Unsafe;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.AbstractQueuedSynchronizer.Node;
|
||||
|
||||
/**
|
||||
* A version of {@link AbstractQueuedSynchronizer} in
|
||||
@ -76,221 +77,6 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
*/
|
||||
protected AbstractQueuedLongSynchronizer() { }
|
||||
|
||||
/**
|
||||
* Wait queue node class.
|
||||
*
|
||||
* <p>The wait queue is a variant of a "CLH" (Craig, Landin, and
|
||||
* Hagersten) lock queue. CLH locks are normally used for
|
||||
* spinlocks. We instead use them for blocking synchronizers, but
|
||||
* use the same basic tactic of holding some of the control
|
||||
* information about a thread in the predecessor of its node. A
|
||||
* "status" field in each node keeps track of whether a thread
|
||||
* should block. A node is signalled when its predecessor
|
||||
* releases. Each node of the queue otherwise serves as a
|
||||
* specific-notification-style monitor holding a single waiting
|
||||
* thread. The status field does NOT control whether threads are
|
||||
* granted locks etc though. A thread may try to acquire if it is
|
||||
* first in the queue. But being first does not guarantee success;
|
||||
* it only gives the right to contend. So the currently released
|
||||
* contender thread may need to rewait.
|
||||
*
|
||||
* <p>To enqueue into a CLH lock, you atomically splice it in as new
|
||||
* tail. To dequeue, you just set the head field.
|
||||
* <pre>
|
||||
* +------+ prev +-----+ +-----+
|
||||
* head | | <---- | | <---- | | tail
|
||||
* +------+ +-----+ +-----+
|
||||
* </pre>
|
||||
*
|
||||
* <p>Insertion into a CLH queue requires only a single atomic
|
||||
* operation on "tail", so there is a simple atomic point of
|
||||
* demarcation from unqueued to queued. Similarly, dequeuing
|
||||
* involves only updating the "head". However, it takes a bit
|
||||
* more work for nodes to determine who their successors are,
|
||||
* in part to deal with possible cancellation due to timeouts
|
||||
* and interrupts.
|
||||
*
|
||||
* <p>The "prev" links (not used in original CLH locks), are mainly
|
||||
* needed to handle cancellation. If a node is cancelled, its
|
||||
* successor is (normally) relinked to a non-cancelled
|
||||
* predecessor. For explanation of similar mechanics in the case
|
||||
* of spin locks, see the papers by Scott and Scherer at
|
||||
* http://www.cs.rochester.edu/u/scott/synchronization/
|
||||
*
|
||||
* <p>We also use "next" links to implement blocking mechanics.
|
||||
* The thread id for each node is kept in its own node, so a
|
||||
* predecessor signals the next node to wake up by traversing
|
||||
* next link to determine which thread it is. Determination of
|
||||
* successor must avoid races with newly queued nodes to set
|
||||
* the "next" fields of their predecessors. This is solved
|
||||
* when necessary by checking backwards from the atomically
|
||||
* updated "tail" when a node's successor appears to be null.
|
||||
* (Or, said differently, the next-links are an optimization
|
||||
* so that we don't usually need a backward scan.)
|
||||
*
|
||||
* <p>Cancellation introduces some conservatism to the basic
|
||||
* algorithms. Since we must poll for cancellation of other
|
||||
* nodes, we can miss noticing whether a cancelled node is
|
||||
* ahead or behind us. This is dealt with by always unparking
|
||||
* successors upon cancellation, allowing them to stabilize on
|
||||
* a new predecessor, unless we can identify an uncancelled
|
||||
* predecessor who will carry this responsibility.
|
||||
*
|
||||
* <p>CLH queues need a dummy header node to get started. But
|
||||
* we don't create them on construction, because it would be wasted
|
||||
* effort if there is never contention. Instead, the node
|
||||
* is constructed and head and tail pointers are set upon first
|
||||
* contention.
|
||||
*
|
||||
* <p>Threads waiting on Conditions use the same nodes, but
|
||||
* use an additional link. Conditions only need to link nodes
|
||||
* in simple (non-concurrent) linked queues because they are
|
||||
* only accessed when exclusively held. Upon await, a node is
|
||||
* inserted into a condition queue. Upon signal, the node is
|
||||
* transferred to the main queue. A special value of status
|
||||
* field is used to mark which queue a node is on.
|
||||
*
|
||||
* <p>Thanks go to Dave Dice, Mark Moir, Victor Luchangco, Bill
|
||||
* Scherer and Michael Scott, along with members of JSR-166
|
||||
* expert group, for helpful ideas, discussions, and critiques
|
||||
* on the design of this class.
|
||||
*/
|
||||
static final class Node {
|
||||
/** Marker to indicate a node is waiting in shared mode */
|
||||
static final Node SHARED = new Node();
|
||||
/** Marker to indicate a node is waiting in exclusive mode */
|
||||
static final Node EXCLUSIVE = null;
|
||||
|
||||
/** waitStatus value to indicate thread has cancelled */
|
||||
static final int CANCELLED = 1;
|
||||
/** waitStatus value to indicate successor's thread needs unparking */
|
||||
static final int SIGNAL = -1;
|
||||
/** waitStatus value to indicate thread is waiting on condition */
|
||||
static final int CONDITION = -2;
|
||||
/**
|
||||
* waitStatus value to indicate the next acquireShared should
|
||||
* unconditionally propagate
|
||||
*/
|
||||
static final int PROPAGATE = -3;
|
||||
|
||||
/**
|
||||
* Status field, taking on only the values:
|
||||
* SIGNAL: The successor of this node is (or will soon be)
|
||||
* blocked (via park), so the current node must
|
||||
* unpark its successor when it releases or
|
||||
* cancels. To avoid races, acquire methods must
|
||||
* first indicate they need a signal,
|
||||
* then retry the atomic acquire, and then,
|
||||
* on failure, block.
|
||||
* CANCELLED: This node is cancelled due to timeout or interrupt.
|
||||
* Nodes never leave this state. In particular,
|
||||
* a thread with cancelled node never again blocks.
|
||||
* CONDITION: This node is currently on a condition queue.
|
||||
* It will not be used as a sync queue node
|
||||
* until transferred, at which time the status
|
||||
* will be set to 0. (Use of this value here has
|
||||
* nothing to do with the other uses of the
|
||||
* field, but simplifies mechanics.)
|
||||
* PROPAGATE: A releaseShared should be propagated to other
|
||||
* nodes. This is set (for head node only) in
|
||||
* doReleaseShared to ensure propagation
|
||||
* continues, even if other operations have
|
||||
* since intervened.
|
||||
* 0: None of the above
|
||||
*
|
||||
* The values are arranged numerically to simplify use.
|
||||
* Non-negative values mean that a node doesn't need to
|
||||
* signal. So, most code doesn't need to check for particular
|
||||
* values, just for sign.
|
||||
*
|
||||
* The field is initialized to 0 for normal sync nodes, and
|
||||
* CONDITION for condition nodes. It is modified using CAS
|
||||
* (or when possible, unconditional volatile writes).
|
||||
*/
|
||||
volatile int waitStatus;
|
||||
|
||||
/**
|
||||
* Link to predecessor node that current node/thread relies on
|
||||
* for checking waitStatus. Assigned during enqueuing, and nulled
|
||||
* out (for sake of GC) only upon dequeuing. Also, upon
|
||||
* cancellation of a predecessor, we short-circuit while
|
||||
* finding a non-cancelled one, which will always exist
|
||||
* because the head node is never cancelled: A node becomes
|
||||
* head only as a result of successful acquire. A
|
||||
* cancelled thread never succeeds in acquiring, and a thread only
|
||||
* cancels itself, not any other node.
|
||||
*/
|
||||
volatile Node prev;
|
||||
|
||||
/**
|
||||
* Link to the successor node that the current node/thread
|
||||
* unparks upon release. Assigned during enqueuing, adjusted
|
||||
* when bypassing cancelled predecessors, and nulled out (for
|
||||
* sake of GC) when dequeued. The enq operation does not
|
||||
* assign next field of a predecessor until after attachment,
|
||||
* so seeing a null next field does not necessarily mean that
|
||||
* node is at end of queue. However, if a next field appears
|
||||
* to be null, we can scan prev's from the tail to
|
||||
* double-check. The next field of cancelled nodes is set to
|
||||
* point to the node itself instead of null, to make life
|
||||
* easier for isOnSyncQueue.
|
||||
*/
|
||||
volatile Node next;
|
||||
|
||||
/**
|
||||
* The thread that enqueued this node. Initialized on
|
||||
* construction and nulled out after use.
|
||||
*/
|
||||
volatile Thread thread;
|
||||
|
||||
/**
|
||||
* Link to next node waiting on condition, or the special
|
||||
* value SHARED. Because condition queues are accessed only
|
||||
* when holding in exclusive mode, we just need a simple
|
||||
* linked queue to hold nodes while they are waiting on
|
||||
* conditions. They are then transferred to the queue to
|
||||
* re-acquire. And because conditions can only be exclusive,
|
||||
* we save a field by using special value to indicate shared
|
||||
* mode.
|
||||
*/
|
||||
Node nextWaiter;
|
||||
|
||||
/**
|
||||
* Returns true if node is waiting in shared mode.
|
||||
*/
|
||||
final boolean isShared() {
|
||||
return nextWaiter == SHARED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns previous node, or throws NullPointerException if null.
|
||||
* Use when predecessor cannot be null. The null check could
|
||||
* be elided, but is present to help the VM.
|
||||
*
|
||||
* @return the predecessor of this node
|
||||
*/
|
||||
final Node predecessor() throws NullPointerException {
|
||||
Node p = prev;
|
||||
if (p == null)
|
||||
throw new NullPointerException();
|
||||
else
|
||||
return p;
|
||||
}
|
||||
|
||||
Node() { // Used to establish initial head or SHARED marker
|
||||
}
|
||||
|
||||
Node(Thread thread, Node mode) { // Used by addWaiter
|
||||
this.nextWaiter = mode;
|
||||
this.thread = thread;
|
||||
}
|
||||
|
||||
Node(Thread thread, int waitStatus) { // Used by Condition
|
||||
this.waitStatus = waitStatus;
|
||||
this.thread = thread;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Head of the wait queue, lazily initialized. Except for
|
||||
* initialization, it is modified only via method setHead. Note:
|
||||
@ -325,7 +111,9 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
* @param newState the new state value
|
||||
*/
|
||||
protected final void setState(long newState) {
|
||||
state = newState;
|
||||
// Use putLongVolatile instead of ordinary volatile store when
|
||||
// using compareAndSwapLong, for sake of some 32bit systems.
|
||||
U.putLongVolatile(this, STATE, newState);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -340,8 +128,7 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
* value was not equal to the expected value.
|
||||
*/
|
||||
protected final boolean compareAndSetState(long expect, long update) {
|
||||
// See below for intrinsics setup to support this
|
||||
return unsafe.compareAndSwapLong(this, stateOffset, expect, update);
|
||||
return U.compareAndSwapLong(this, STATE, expect, update);
|
||||
}
|
||||
|
||||
// Queuing utilities
|
||||
@ -351,25 +138,24 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
* rather than to use timed park. A rough estimate suffices
|
||||
* to improve responsiveness with very short timeouts.
|
||||
*/
|
||||
static final long spinForTimeoutThreshold = 1000L;
|
||||
static final long SPIN_FOR_TIMEOUT_THRESHOLD = 1000L;
|
||||
|
||||
/**
|
||||
* Inserts node into queue, initializing if necessary. See picture above.
|
||||
* @param node the node to insert
|
||||
* @return node's predecessor
|
||||
*/
|
||||
private Node enq(final Node node) {
|
||||
private Node enq(Node node) {
|
||||
for (;;) {
|
||||
Node t = tail;
|
||||
if (t == null) { // Must initialize
|
||||
if (compareAndSetHead(new Node()))
|
||||
tail = head;
|
||||
} else {
|
||||
node.prev = t;
|
||||
if (compareAndSetTail(t, node)) {
|
||||
t.next = node;
|
||||
return t;
|
||||
Node oldTail = tail;
|
||||
if (oldTail != null) {
|
||||
U.putObject(node, Node.PREV, oldTail);
|
||||
if (compareAndSetTail(oldTail, node)) {
|
||||
oldTail.next = node;
|
||||
return oldTail;
|
||||
}
|
||||
} else {
|
||||
initializeSyncQueue();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -381,18 +167,20 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
* @return the new node
|
||||
*/
|
||||
private Node addWaiter(Node mode) {
|
||||
Node node = new Node(Thread.currentThread(), mode);
|
||||
// Try the fast path of enq; backup to full enq on failure
|
||||
Node pred = tail;
|
||||
if (pred != null) {
|
||||
node.prev = pred;
|
||||
if (compareAndSetTail(pred, node)) {
|
||||
pred.next = node;
|
||||
return node;
|
||||
Node node = new Node(mode);
|
||||
|
||||
for (;;) {
|
||||
Node oldTail = tail;
|
||||
if (oldTail != null) {
|
||||
U.putObject(node, Node.PREV, oldTail);
|
||||
if (compareAndSetTail(oldTail, node)) {
|
||||
oldTail.next = node;
|
||||
return node;
|
||||
}
|
||||
} else {
|
||||
initializeSyncQueue();
|
||||
}
|
||||
}
|
||||
enq(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -421,7 +209,7 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
*/
|
||||
int ws = node.waitStatus;
|
||||
if (ws < 0)
|
||||
compareAndSetWaitStatus(node, ws, 0);
|
||||
node.compareAndSetWaitStatus(ws, 0);
|
||||
|
||||
/*
|
||||
* Thread to unpark is held in successor, which is normally
|
||||
@ -432,9 +220,9 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
Node s = node.next;
|
||||
if (s == null || s.waitStatus > 0) {
|
||||
s = null;
|
||||
for (Node t = tail; t != null && t != node; t = t.prev)
|
||||
if (t.waitStatus <= 0)
|
||||
s = t;
|
||||
for (Node p = tail; p != node && p != null; p = p.prev)
|
||||
if (p.waitStatus <= 0)
|
||||
s = p;
|
||||
}
|
||||
if (s != null)
|
||||
LockSupport.unpark(s.thread);
|
||||
@ -462,12 +250,12 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
if (h != null && h != tail) {
|
||||
int ws = h.waitStatus;
|
||||
if (ws == Node.SIGNAL) {
|
||||
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
|
||||
if (!h.compareAndSetWaitStatus(Node.SIGNAL, 0))
|
||||
continue; // loop to recheck cases
|
||||
unparkSuccessor(h);
|
||||
}
|
||||
else if (ws == 0 &&
|
||||
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
|
||||
!h.compareAndSetWaitStatus(0, Node.PROPAGATE))
|
||||
continue; // loop on failed CAS
|
||||
}
|
||||
if (h == head) // loop if head changed
|
||||
@ -541,18 +329,18 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
|
||||
// If we are the tail, remove ourselves.
|
||||
if (node == tail && compareAndSetTail(node, pred)) {
|
||||
compareAndSetNext(pred, predNext, null);
|
||||
pred.compareAndSetNext(predNext, null);
|
||||
} else {
|
||||
// If successor needs signal, try to set pred's next-link
|
||||
// so it will get one. Otherwise wake it up to propagate.
|
||||
int ws;
|
||||
if (pred != head &&
|
||||
((ws = pred.waitStatus) == Node.SIGNAL ||
|
||||
(ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
|
||||
(ws <= 0 && pred.compareAndSetWaitStatus(ws, Node.SIGNAL))) &&
|
||||
pred.thread != null) {
|
||||
Node next = node.next;
|
||||
if (next != null && next.waitStatus <= 0)
|
||||
compareAndSetNext(pred, predNext, next);
|
||||
pred.compareAndSetNext(predNext, next);
|
||||
} else {
|
||||
unparkSuccessor(node);
|
||||
}
|
||||
@ -593,7 +381,7 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
* need a signal, but don't park yet. Caller will need to
|
||||
* retry to make sure it cannot acquire before parking.
|
||||
*/
|
||||
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
|
||||
pred.compareAndSetWaitStatus(ws, Node.SIGNAL);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -606,7 +394,7 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to park and then check if interrupted
|
||||
* Convenience method to park and then check if interrupted.
|
||||
*
|
||||
* @return {@code true} if interrupted
|
||||
*/
|
||||
@ -633,7 +421,6 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
* @return {@code true} if interrupted while waiting
|
||||
*/
|
||||
final boolean acquireQueued(final Node node, long arg) {
|
||||
boolean failed = true;
|
||||
try {
|
||||
boolean interrupted = false;
|
||||
for (;;) {
|
||||
@ -641,16 +428,15 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
if (p == head && tryAcquire(arg)) {
|
||||
setHead(node);
|
||||
p.next = null; // help GC
|
||||
failed = false;
|
||||
return interrupted;
|
||||
}
|
||||
if (shouldParkAfterFailedAcquire(p, node) &&
|
||||
parkAndCheckInterrupt())
|
||||
interrupted = true;
|
||||
}
|
||||
} finally {
|
||||
if (failed)
|
||||
cancelAcquire(node);
|
||||
} catch (Throwable t) {
|
||||
cancelAcquire(node);
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
@ -661,23 +447,21 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
private void doAcquireInterruptibly(long arg)
|
||||
throws InterruptedException {
|
||||
final Node node = addWaiter(Node.EXCLUSIVE);
|
||||
boolean failed = true;
|
||||
try {
|
||||
for (;;) {
|
||||
final Node p = node.predecessor();
|
||||
if (p == head && tryAcquire(arg)) {
|
||||
setHead(node);
|
||||
p.next = null; // help GC
|
||||
failed = false;
|
||||
return;
|
||||
}
|
||||
if (shouldParkAfterFailedAcquire(p, node) &&
|
||||
parkAndCheckInterrupt())
|
||||
throw new InterruptedException();
|
||||
}
|
||||
} finally {
|
||||
if (failed)
|
||||
cancelAcquire(node);
|
||||
} catch (Throwable t) {
|
||||
cancelAcquire(node);
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
@ -694,28 +478,28 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
return false;
|
||||
final long deadline = System.nanoTime() + nanosTimeout;
|
||||
final Node node = addWaiter(Node.EXCLUSIVE);
|
||||
boolean failed = true;
|
||||
try {
|
||||
for (;;) {
|
||||
final Node p = node.predecessor();
|
||||
if (p == head && tryAcquire(arg)) {
|
||||
setHead(node);
|
||||
p.next = null; // help GC
|
||||
failed = false;
|
||||
return true;
|
||||
}
|
||||
nanosTimeout = deadline - System.nanoTime();
|
||||
if (nanosTimeout <= 0L)
|
||||
if (nanosTimeout <= 0L) {
|
||||
cancelAcquire(node);
|
||||
return false;
|
||||
}
|
||||
if (shouldParkAfterFailedAcquire(p, node) &&
|
||||
nanosTimeout > spinForTimeoutThreshold)
|
||||
nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
|
||||
LockSupport.parkNanos(this, nanosTimeout);
|
||||
if (Thread.interrupted())
|
||||
throw new InterruptedException();
|
||||
}
|
||||
} finally {
|
||||
if (failed)
|
||||
cancelAcquire(node);
|
||||
} catch (Throwable t) {
|
||||
cancelAcquire(node);
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
@ -725,7 +509,6 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
*/
|
||||
private void doAcquireShared(long arg) {
|
||||
final Node node = addWaiter(Node.SHARED);
|
||||
boolean failed = true;
|
||||
try {
|
||||
boolean interrupted = false;
|
||||
for (;;) {
|
||||
@ -737,7 +520,6 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
p.next = null; // help GC
|
||||
if (interrupted)
|
||||
selfInterrupt();
|
||||
failed = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -745,9 +527,9 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
parkAndCheckInterrupt())
|
||||
interrupted = true;
|
||||
}
|
||||
} finally {
|
||||
if (failed)
|
||||
cancelAcquire(node);
|
||||
} catch (Throwable t) {
|
||||
cancelAcquire(node);
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
@ -758,7 +540,6 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
private void doAcquireSharedInterruptibly(long arg)
|
||||
throws InterruptedException {
|
||||
final Node node = addWaiter(Node.SHARED);
|
||||
boolean failed = true;
|
||||
try {
|
||||
for (;;) {
|
||||
final Node p = node.predecessor();
|
||||
@ -767,7 +548,6 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
if (r >= 0) {
|
||||
setHeadAndPropagate(node, r);
|
||||
p.next = null; // help GC
|
||||
failed = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -775,9 +555,9 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
parkAndCheckInterrupt())
|
||||
throw new InterruptedException();
|
||||
}
|
||||
} finally {
|
||||
if (failed)
|
||||
cancelAcquire(node);
|
||||
} catch (Throwable t) {
|
||||
cancelAcquire(node);
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
@ -794,7 +574,6 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
return false;
|
||||
final long deadline = System.nanoTime() + nanosTimeout;
|
||||
final Node node = addWaiter(Node.SHARED);
|
||||
boolean failed = true;
|
||||
try {
|
||||
for (;;) {
|
||||
final Node p = node.predecessor();
|
||||
@ -803,22 +582,23 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
if (r >= 0) {
|
||||
setHeadAndPropagate(node, r);
|
||||
p.next = null; // help GC
|
||||
failed = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
nanosTimeout = deadline - System.nanoTime();
|
||||
if (nanosTimeout <= 0L)
|
||||
if (nanosTimeout <= 0L) {
|
||||
cancelAcquire(node);
|
||||
return false;
|
||||
}
|
||||
if (shouldParkAfterFailedAcquire(p, node) &&
|
||||
nanosTimeout > spinForTimeoutThreshold)
|
||||
nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
|
||||
LockSupport.parkNanos(this, nanosTimeout);
|
||||
if (Thread.interrupted())
|
||||
throw new InterruptedException();
|
||||
}
|
||||
} finally {
|
||||
if (failed)
|
||||
cancelAcquire(node);
|
||||
} catch (Throwable t) {
|
||||
cancelAcquire(node);
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1170,7 +950,7 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
}
|
||||
|
||||
/**
|
||||
* Version of getFirstQueuedThread called when fastpath fails
|
||||
* Version of getFirstQueuedThread called when fastpath fails.
|
||||
*/
|
||||
private Thread fullGetFirstQueuedThread() {
|
||||
/*
|
||||
@ -1250,7 +1030,7 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
*
|
||||
* <p>An invocation of this method is equivalent to (but may be
|
||||
* more efficient than):
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* getFirstQueuedThread() != Thread.currentThread() &&
|
||||
* hasQueuedThreads()}</pre>
|
||||
*
|
||||
@ -1270,7 +1050,7 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
* tryAcquire} method for a fair, reentrant, exclusive mode
|
||||
* synchronizer might look like this:
|
||||
*
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* protected boolean tryAcquire(int arg) {
|
||||
* if (isHeldExclusively()) {
|
||||
* // A reentrant acquire; increment hold count
|
||||
@ -1306,8 +1086,7 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
* acquire. The value is only an estimate because the number of
|
||||
* threads may change dynamically while this method traverses
|
||||
* internal data structures. This method is designed for use in
|
||||
* monitoring system state, not for synchronization
|
||||
* control.
|
||||
* monitoring system state, not for synchronization control.
|
||||
*
|
||||
* @return the estimated number of threads waiting to acquire
|
||||
*/
|
||||
@ -1332,7 +1111,7 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
* @return the collection of threads
|
||||
*/
|
||||
public final Collection<Thread> getQueuedThreads() {
|
||||
ArrayList<Thread> list = new ArrayList<Thread>();
|
||||
ArrayList<Thread> list = new ArrayList<>();
|
||||
for (Node p = tail; p != null; p = p.prev) {
|
||||
Thread t = p.thread;
|
||||
if (t != null)
|
||||
@ -1350,7 +1129,7 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
* @return the collection of threads
|
||||
*/
|
||||
public final Collection<Thread> getExclusiveQueuedThreads() {
|
||||
ArrayList<Thread> list = new ArrayList<Thread>();
|
||||
ArrayList<Thread> list = new ArrayList<>();
|
||||
for (Node p = tail; p != null; p = p.prev) {
|
||||
if (!p.isShared()) {
|
||||
Thread t = p.thread;
|
||||
@ -1370,7 +1149,7 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
* @return the collection of threads
|
||||
*/
|
||||
public final Collection<Thread> getSharedQueuedThreads() {
|
||||
ArrayList<Thread> list = new ArrayList<Thread>();
|
||||
ArrayList<Thread> list = new ArrayList<>();
|
||||
for (Node p = tail; p != null; p = p.prev) {
|
||||
if (p.isShared()) {
|
||||
Thread t = p.thread;
|
||||
@ -1391,10 +1170,9 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
* @return a string identifying this synchronizer, as well as its state
|
||||
*/
|
||||
public String toString() {
|
||||
long s = getState();
|
||||
String q = hasQueuedThreads() ? "non" : "";
|
||||
return super.toString() +
|
||||
"[State = " + s + ", " + q + "empty queue]";
|
||||
return super.toString()
|
||||
+ "[State = " + getState() + ", "
|
||||
+ (hasQueuedThreads() ? "non" : "") + "empty queue]";
|
||||
}
|
||||
|
||||
|
||||
@ -1428,13 +1206,15 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
* @return true if present
|
||||
*/
|
||||
private boolean findNodeFromTail(Node node) {
|
||||
Node t = tail;
|
||||
for (;;) {
|
||||
if (t == node)
|
||||
// We check for node first, since it's likely to be at or near tail.
|
||||
// tail is known to be non-null, so we could re-order to "save"
|
||||
// one null check, but we leave it this way to help the VM.
|
||||
for (Node p = tail;;) {
|
||||
if (p == node)
|
||||
return true;
|
||||
if (t == null)
|
||||
if (p == null)
|
||||
return false;
|
||||
t = t.prev;
|
||||
p = p.prev;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1449,7 +1229,7 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
/*
|
||||
* If cannot change waitStatus, the node has been cancelled.
|
||||
*/
|
||||
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
|
||||
if (!node.compareAndSetWaitStatus(Node.CONDITION, 0))
|
||||
return false;
|
||||
|
||||
/*
|
||||
@ -1460,7 +1240,7 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
*/
|
||||
Node p = enq(node);
|
||||
int ws = p.waitStatus;
|
||||
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
|
||||
if (ws > 0 || !p.compareAndSetWaitStatus(ws, Node.SIGNAL))
|
||||
LockSupport.unpark(node.thread);
|
||||
return true;
|
||||
}
|
||||
@ -1473,7 +1253,7 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
* @return true if cancelled before the node was signalled
|
||||
*/
|
||||
final boolean transferAfterCancelledWait(Node node) {
|
||||
if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) {
|
||||
if (node.compareAndSetWaitStatus(Node.CONDITION, 0)) {
|
||||
enq(node);
|
||||
return true;
|
||||
}
|
||||
@ -1495,18 +1275,14 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
* @return previous sync state
|
||||
*/
|
||||
final long fullyRelease(Node node) {
|
||||
boolean failed = true;
|
||||
try {
|
||||
long savedState = getState();
|
||||
if (release(savedState)) {
|
||||
failed = false;
|
||||
if (release(savedState))
|
||||
return savedState;
|
||||
} else {
|
||||
throw new IllegalMonitorStateException();
|
||||
}
|
||||
} finally {
|
||||
if (failed)
|
||||
node.waitStatus = Node.CANCELLED;
|
||||
throw new IllegalMonitorStateException();
|
||||
} catch (Throwable t) {
|
||||
node.waitStatus = Node.CANCELLED;
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1551,8 +1327,8 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
* given condition associated with this synchronizer. Note that
|
||||
* because timeouts and interrupts may occur at any time, the
|
||||
* estimate serves only as an upper bound on the actual number of
|
||||
* waiters. This method is designed for use in monitoring of the
|
||||
* system state, not for synchronization control.
|
||||
* waiters. This method is designed for use in monitoring system
|
||||
* state, not for synchronization control.
|
||||
*
|
||||
* @param condition the condition
|
||||
* @return the estimated number of waiting threads
|
||||
@ -1632,7 +1408,9 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
unlinkCancelledWaiters();
|
||||
t = lastWaiter;
|
||||
}
|
||||
Node node = new Node(Thread.currentThread(), Node.CONDITION);
|
||||
|
||||
Node node = new Node(Node.CONDITION);
|
||||
|
||||
if (t == null)
|
||||
firstWaiter = node;
|
||||
else
|
||||
@ -1740,12 +1518,12 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
/**
|
||||
* Implements uninterruptible condition wait.
|
||||
* <ol>
|
||||
* <li> Save lock state returned by {@link #getState}.
|
||||
* <li> Invoke {@link #release} with saved state as argument,
|
||||
* throwing IllegalMonitorStateException if it fails.
|
||||
* <li> Block until signalled.
|
||||
* <li> Reacquire by invoking specialized version of
|
||||
* {@link #acquire} with saved state as argument.
|
||||
* <li>Save lock state returned by {@link #getState}.
|
||||
* <li>Invoke {@link #release} with saved state as argument,
|
||||
* throwing IllegalMonitorStateException if it fails.
|
||||
* <li>Block until signalled.
|
||||
* <li>Reacquire by invoking specialized version of
|
||||
* {@link #acquire} with saved state as argument.
|
||||
* </ol>
|
||||
*/
|
||||
public final void awaitUninterruptibly() {
|
||||
@ -1799,14 +1577,14 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
/**
|
||||
* Implements interruptible condition wait.
|
||||
* <ol>
|
||||
* <li> If current thread is interrupted, throw InterruptedException.
|
||||
* <li> Save lock state returned by {@link #getState}.
|
||||
* <li> Invoke {@link #release} with saved state as argument,
|
||||
* throwing IllegalMonitorStateException if it fails.
|
||||
* <li> Block until signalled or interrupted.
|
||||
* <li> Reacquire by invoking specialized version of
|
||||
* {@link #acquire} with saved state as argument.
|
||||
* <li> If interrupted while blocked in step 4, throw InterruptedException.
|
||||
* <li>If current thread is interrupted, throw InterruptedException.
|
||||
* <li>Save lock state returned by {@link #getState}.
|
||||
* <li>Invoke {@link #release} with saved state as argument,
|
||||
* throwing IllegalMonitorStateException if it fails.
|
||||
* <li>Block until signalled or interrupted.
|
||||
* <li>Reacquire by invoking specialized version of
|
||||
* {@link #acquire} with saved state as argument.
|
||||
* <li>If interrupted while blocked in step 4, throw InterruptedException.
|
||||
* </ol>
|
||||
*/
|
||||
public final void await() throws InterruptedException {
|
||||
@ -1831,30 +1609,33 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
/**
|
||||
* Implements timed condition wait.
|
||||
* <ol>
|
||||
* <li> If current thread is interrupted, throw InterruptedException.
|
||||
* <li> Save lock state returned by {@link #getState}.
|
||||
* <li> Invoke {@link #release} with saved state as argument,
|
||||
* throwing IllegalMonitorStateException if it fails.
|
||||
* <li> Block until signalled, interrupted, or timed out.
|
||||
* <li> Reacquire by invoking specialized version of
|
||||
* {@link #acquire} with saved state as argument.
|
||||
* <li> If interrupted while blocked in step 4, throw InterruptedException.
|
||||
* <li>If current thread is interrupted, throw InterruptedException.
|
||||
* <li>Save lock state returned by {@link #getState}.
|
||||
* <li>Invoke {@link #release} with saved state as argument,
|
||||
* throwing IllegalMonitorStateException if it fails.
|
||||
* <li>Block until signalled, interrupted, or timed out.
|
||||
* <li>Reacquire by invoking specialized version of
|
||||
* {@link #acquire} with saved state as argument.
|
||||
* <li>If interrupted while blocked in step 4, throw InterruptedException.
|
||||
* </ol>
|
||||
*/
|
||||
public final long awaitNanos(long nanosTimeout)
|
||||
throws InterruptedException {
|
||||
if (Thread.interrupted())
|
||||
throw new InterruptedException();
|
||||
// We don't check for nanosTimeout <= 0L here, to allow
|
||||
// awaitNanos(0) as a way to "yield the lock".
|
||||
final long deadline = System.nanoTime() + nanosTimeout;
|
||||
long initialNanos = nanosTimeout;
|
||||
Node node = addConditionWaiter();
|
||||
long savedState = fullyRelease(node);
|
||||
final long deadline = System.nanoTime() + nanosTimeout;
|
||||
int interruptMode = 0;
|
||||
while (!isOnSyncQueue(node)) {
|
||||
if (nanosTimeout <= 0L) {
|
||||
transferAfterCancelledWait(node);
|
||||
break;
|
||||
}
|
||||
if (nanosTimeout >= spinForTimeoutThreshold)
|
||||
if (nanosTimeout >= SPIN_FOR_TIMEOUT_THRESHOLD)
|
||||
LockSupport.parkNanos(this, nanosTimeout);
|
||||
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
|
||||
break;
|
||||
@ -1866,21 +1647,22 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
unlinkCancelledWaiters();
|
||||
if (interruptMode != 0)
|
||||
reportInterruptAfterWait(interruptMode);
|
||||
return deadline - System.nanoTime();
|
||||
long remaining = deadline - System.nanoTime(); // avoid overflow
|
||||
return (remaining <= initialNanos) ? remaining : Long.MIN_VALUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements absolute timed condition wait.
|
||||
* <ol>
|
||||
* <li> If current thread is interrupted, throw InterruptedException.
|
||||
* <li> Save lock state returned by {@link #getState}.
|
||||
* <li> Invoke {@link #release} with saved state as argument,
|
||||
* throwing IllegalMonitorStateException if it fails.
|
||||
* <li> Block until signalled, interrupted, or timed out.
|
||||
* <li> Reacquire by invoking specialized version of
|
||||
* {@link #acquire} with saved state as argument.
|
||||
* <li> If interrupted while blocked in step 4, throw InterruptedException.
|
||||
* <li> If timed out while blocked in step 4, return false, else true.
|
||||
* <li>If current thread is interrupted, throw InterruptedException.
|
||||
* <li>Save lock state returned by {@link #getState}.
|
||||
* <li>Invoke {@link #release} with saved state as argument,
|
||||
* throwing IllegalMonitorStateException if it fails.
|
||||
* <li>Block until signalled, interrupted, or timed out.
|
||||
* <li>Reacquire by invoking specialized version of
|
||||
* {@link #acquire} with saved state as argument.
|
||||
* <li>If interrupted while blocked in step 4, throw InterruptedException.
|
||||
* <li>If timed out while blocked in step 4, return false, else true.
|
||||
* </ol>
|
||||
*/
|
||||
public final boolean awaitUntil(Date deadline)
|
||||
@ -1893,7 +1675,7 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
boolean timedout = false;
|
||||
int interruptMode = 0;
|
||||
while (!isOnSyncQueue(node)) {
|
||||
if (System.currentTimeMillis() > abstime) {
|
||||
if (System.currentTimeMillis() >= abstime) {
|
||||
timedout = transferAfterCancelledWait(node);
|
||||
break;
|
||||
}
|
||||
@ -1913,15 +1695,15 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
/**
|
||||
* Implements timed condition wait.
|
||||
* <ol>
|
||||
* <li> If current thread is interrupted, throw InterruptedException.
|
||||
* <li> Save lock state returned by {@link #getState}.
|
||||
* <li> Invoke {@link #release} with saved state as argument,
|
||||
* throwing IllegalMonitorStateException if it fails.
|
||||
* <li> Block until signalled, interrupted, or timed out.
|
||||
* <li> Reacquire by invoking specialized version of
|
||||
* {@link #acquire} with saved state as argument.
|
||||
* <li> If interrupted while blocked in step 4, throw InterruptedException.
|
||||
* <li> If timed out while blocked in step 4, return false, else true.
|
||||
* <li>If current thread is interrupted, throw InterruptedException.
|
||||
* <li>Save lock state returned by {@link #getState}.
|
||||
* <li>Invoke {@link #release} with saved state as argument,
|
||||
* throwing IllegalMonitorStateException if it fails.
|
||||
* <li>Block until signalled, interrupted, or timed out.
|
||||
* <li>Reacquire by invoking specialized version of
|
||||
* {@link #acquire} with saved state as argument.
|
||||
* <li>If interrupted while blocked in step 4, throw InterruptedException.
|
||||
* <li>If timed out while blocked in step 4, return false, else true.
|
||||
* </ol>
|
||||
*/
|
||||
public final boolean await(long time, TimeUnit unit)
|
||||
@ -1929,9 +1711,11 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
long nanosTimeout = unit.toNanos(time);
|
||||
if (Thread.interrupted())
|
||||
throw new InterruptedException();
|
||||
// We don't check for nanosTimeout <= 0L here, to allow
|
||||
// await(0, unit) as a way to "yield the lock".
|
||||
final long deadline = System.nanoTime() + nanosTimeout;
|
||||
Node node = addConditionWaiter();
|
||||
long savedState = fullyRelease(node);
|
||||
final long deadline = System.nanoTime() + nanosTimeout;
|
||||
boolean timedout = false;
|
||||
int interruptMode = 0;
|
||||
while (!isOnSyncQueue(node)) {
|
||||
@ -1939,7 +1723,7 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
timedout = transferAfterCancelledWait(node);
|
||||
break;
|
||||
}
|
||||
if (nanosTimeout >= spinForTimeoutThreshold)
|
||||
if (nanosTimeout >= SPIN_FOR_TIMEOUT_THRESHOLD)
|
||||
LockSupport.parkNanos(this, nanosTimeout);
|
||||
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
|
||||
break;
|
||||
@ -2016,7 +1800,7 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
protected final Collection<Thread> getWaitingThreads() {
|
||||
if (!isHeldExclusively())
|
||||
throw new IllegalMonitorStateException();
|
||||
ArrayList<Thread> list = new ArrayList<Thread>();
|
||||
ArrayList<Thread> list = new ArrayList<>();
|
||||
for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
|
||||
if (w.waitStatus == Node.CONDITION) {
|
||||
Thread t = w.thread;
|
||||
@ -2037,59 +1821,40 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
* are at it, we do the same for other CASable fields (which could
|
||||
* otherwise be done with atomic field updaters).
|
||||
*/
|
||||
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||
private static final long stateOffset;
|
||||
private static final long headOffset;
|
||||
private static final long tailOffset;
|
||||
private static final long waitStatusOffset;
|
||||
private static final long nextOffset;
|
||||
private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
|
||||
private static final long STATE;
|
||||
private static final long HEAD;
|
||||
private static final long TAIL;
|
||||
|
||||
static {
|
||||
try {
|
||||
stateOffset = unsafe.objectFieldOffset
|
||||
STATE = U.objectFieldOffset
|
||||
(AbstractQueuedLongSynchronizer.class.getDeclaredField("state"));
|
||||
headOffset = unsafe.objectFieldOffset
|
||||
HEAD = U.objectFieldOffset
|
||||
(AbstractQueuedLongSynchronizer.class.getDeclaredField("head"));
|
||||
tailOffset = unsafe.objectFieldOffset
|
||||
TAIL = U.objectFieldOffset
|
||||
(AbstractQueuedLongSynchronizer.class.getDeclaredField("tail"));
|
||||
waitStatusOffset = unsafe.objectFieldOffset
|
||||
(Node.class.getDeclaredField("waitStatus"));
|
||||
nextOffset = unsafe.objectFieldOffset
|
||||
(Node.class.getDeclaredField("next"));
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
|
||||
} catch (Exception ex) { throw new Error(ex); }
|
||||
// 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* CAS head field. Used only by enq.
|
||||
* Initializes head and tail fields on first contention.
|
||||
*/
|
||||
private final boolean compareAndSetHead(Node update) {
|
||||
return unsafe.compareAndSwapObject(this, headOffset, null, update);
|
||||
private final void initializeSyncQueue() {
|
||||
if (U.compareAndSwapObject(this, HEAD, null, new Node()))
|
||||
tail = head;
|
||||
}
|
||||
|
||||
/**
|
||||
* CAS tail field. Used only by enq.
|
||||
* CASes tail field.
|
||||
*/
|
||||
private final boolean compareAndSetTail(Node expect, Node update) {
|
||||
return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
|
||||
}
|
||||
|
||||
/**
|
||||
* CAS waitStatus field of a node.
|
||||
*/
|
||||
private static final boolean compareAndSetWaitStatus(Node node,
|
||||
int expect,
|
||||
int update) {
|
||||
return unsafe.compareAndSwapInt(node, waitStatusOffset,
|
||||
expect, update);
|
||||
}
|
||||
|
||||
/**
|
||||
* CAS next field of a node.
|
||||
*/
|
||||
private static final boolean compareAndSetNext(Node node,
|
||||
Node expect,
|
||||
Node update) {
|
||||
return unsafe.compareAndSwapObject(node, nextOffset, expect, update);
|
||||
return U.compareAndSwapObject(this, TAIL, expect, update);
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,11 +34,11 @@
|
||||
*/
|
||||
|
||||
package java.util.concurrent.locks;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import sun.misc.Unsafe;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Provides a framework for implementing blocking locks and related
|
||||
@ -110,11 +110,11 @@ import sun.misc.Unsafe;
|
||||
* #setState} and/or {@link #compareAndSetState}:
|
||||
*
|
||||
* <ul>
|
||||
* <li> {@link #tryAcquire}
|
||||
* <li> {@link #tryRelease}
|
||||
* <li> {@link #tryAcquireShared}
|
||||
* <li> {@link #tryReleaseShared}
|
||||
* <li> {@link #isHeldExclusively}
|
||||
* <li>{@link #tryAcquire}
|
||||
* <li>{@link #tryRelease}
|
||||
* <li>{@link #tryAcquireShared}
|
||||
* <li>{@link #tryReleaseShared}
|
||||
* <li>{@link #isHeldExclusively}
|
||||
* </ul>
|
||||
*
|
||||
* Each of these methods by default throws {@link
|
||||
@ -195,7 +195,7 @@ import sun.misc.Unsafe;
|
||||
* It also supports conditions and exposes
|
||||
* one of the instrumentation methods:
|
||||
*
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* class Mutex implements Lock, java.io.Serializable {
|
||||
*
|
||||
* // Our internal helper class
|
||||
@ -259,7 +259,7 @@ import sun.misc.Unsafe;
|
||||
* fire. Because a latch is non-exclusive, it uses the {@code shared}
|
||||
* acquire and release methods.
|
||||
*
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* class BooleanLatch {
|
||||
*
|
||||
* private static class Sync extends AbstractQueuedSynchronizer {
|
||||
@ -383,15 +383,15 @@ public abstract class AbstractQueuedSynchronizer
|
||||
/** Marker to indicate a node is waiting in exclusive mode */
|
||||
static final Node EXCLUSIVE = null;
|
||||
|
||||
/** waitStatus value to indicate thread has cancelled */
|
||||
/** waitStatus value to indicate thread has cancelled. */
|
||||
static final int CANCELLED = 1;
|
||||
/** waitStatus value to indicate successor's thread needs unparking */
|
||||
/** waitStatus value to indicate successor's thread needs unparking. */
|
||||
static final int SIGNAL = -1;
|
||||
/** waitStatus value to indicate thread is waiting on condition */
|
||||
/** waitStatus value to indicate thread is waiting on condition. */
|
||||
static final int CONDITION = -2;
|
||||
/**
|
||||
* waitStatus value to indicate the next acquireShared should
|
||||
* unconditionally propagate
|
||||
* unconditionally propagate.
|
||||
*/
|
||||
static final int PROPAGATE = -3;
|
||||
|
||||
@ -499,17 +499,49 @@ public abstract class AbstractQueuedSynchronizer
|
||||
return p;
|
||||
}
|
||||
|
||||
Node() { // Used to establish initial head or SHARED marker
|
||||
/** Establishes initial head or SHARED marker. */
|
||||
Node() {}
|
||||
|
||||
/** Constructor used by addWaiter. */
|
||||
Node(Node nextWaiter) {
|
||||
this.nextWaiter = nextWaiter;
|
||||
U.putObject(this, THREAD, Thread.currentThread());
|
||||
}
|
||||
|
||||
Node(Thread thread, Node mode) { // Used by addWaiter
|
||||
this.nextWaiter = mode;
|
||||
this.thread = thread;
|
||||
/** Constructor used by addConditionWaiter. */
|
||||
Node(int waitStatus) {
|
||||
U.putInt(this, WAITSTATUS, waitStatus);
|
||||
U.putObject(this, THREAD, Thread.currentThread());
|
||||
}
|
||||
|
||||
Node(Thread thread, int waitStatus) { // Used by Condition
|
||||
this.waitStatus = waitStatus;
|
||||
this.thread = thread;
|
||||
/** CASes waitStatus field. */
|
||||
final boolean compareAndSetWaitStatus(int expect, int update) {
|
||||
return U.compareAndSwapInt(this, WAITSTATUS, expect, update);
|
||||
}
|
||||
|
||||
/** CASes next field. */
|
||||
final boolean compareAndSetNext(Node expect, Node update) {
|
||||
return U.compareAndSwapObject(this, NEXT, expect, update);
|
||||
}
|
||||
|
||||
private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
|
||||
private static final long NEXT;
|
||||
static final long PREV;
|
||||
private static final long THREAD;
|
||||
private static final long WAITSTATUS;
|
||||
static {
|
||||
try {
|
||||
NEXT = U.objectFieldOffset
|
||||
(Node.class.getDeclaredField("next"));
|
||||
PREV = U.objectFieldOffset
|
||||
(Node.class.getDeclaredField("prev"));
|
||||
THREAD = U.objectFieldOffset
|
||||
(Node.class.getDeclaredField("thread"));
|
||||
WAITSTATUS = U.objectFieldOffset
|
||||
(Node.class.getDeclaredField("waitStatus"));
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -562,8 +594,7 @@ public abstract class AbstractQueuedSynchronizer
|
||||
* value was not equal to the expected value.
|
||||
*/
|
||||
protected final boolean compareAndSetState(int expect, int update) {
|
||||
// See below for intrinsics setup to support this
|
||||
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
|
||||
return U.compareAndSwapInt(this, STATE, expect, update);
|
||||
}
|
||||
|
||||
// Queuing utilities
|
||||
@ -573,25 +604,24 @@ public abstract class AbstractQueuedSynchronizer
|
||||
* rather than to use timed park. A rough estimate suffices
|
||||
* to improve responsiveness with very short timeouts.
|
||||
*/
|
||||
static final long spinForTimeoutThreshold = 1000L;
|
||||
static final long SPIN_FOR_TIMEOUT_THRESHOLD = 1000L;
|
||||
|
||||
/**
|
||||
* Inserts node into queue, initializing if necessary. See picture above.
|
||||
* @param node the node to insert
|
||||
* @return node's predecessor
|
||||
*/
|
||||
private Node enq(final Node node) {
|
||||
private Node enq(Node node) {
|
||||
for (;;) {
|
||||
Node t = tail;
|
||||
if (t == null) { // Must initialize
|
||||
if (compareAndSetHead(new Node()))
|
||||
tail = head;
|
||||
} else {
|
||||
node.prev = t;
|
||||
if (compareAndSetTail(t, node)) {
|
||||
t.next = node;
|
||||
return t;
|
||||
Node oldTail = tail;
|
||||
if (oldTail != null) {
|
||||
U.putObject(node, Node.PREV, oldTail);
|
||||
if (compareAndSetTail(oldTail, node)) {
|
||||
oldTail.next = node;
|
||||
return oldTail;
|
||||
}
|
||||
} else {
|
||||
initializeSyncQueue();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -603,18 +633,20 @@ public abstract class AbstractQueuedSynchronizer
|
||||
* @return the new node
|
||||
*/
|
||||
private Node addWaiter(Node mode) {
|
||||
Node node = new Node(Thread.currentThread(), mode);
|
||||
// Try the fast path of enq; backup to full enq on failure
|
||||
Node pred = tail;
|
||||
if (pred != null) {
|
||||
node.prev = pred;
|
||||
if (compareAndSetTail(pred, node)) {
|
||||
pred.next = node;
|
||||
return node;
|
||||
Node node = new Node(mode);
|
||||
|
||||
for (;;) {
|
||||
Node oldTail = tail;
|
||||
if (oldTail != null) {
|
||||
U.putObject(node, Node.PREV, oldTail);
|
||||
if (compareAndSetTail(oldTail, node)) {
|
||||
oldTail.next = node;
|
||||
return node;
|
||||
}
|
||||
} else {
|
||||
initializeSyncQueue();
|
||||
}
|
||||
}
|
||||
enq(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -643,7 +675,7 @@ public abstract class AbstractQueuedSynchronizer
|
||||
*/
|
||||
int ws = node.waitStatus;
|
||||
if (ws < 0)
|
||||
compareAndSetWaitStatus(node, ws, 0);
|
||||
node.compareAndSetWaitStatus(ws, 0);
|
||||
|
||||
/*
|
||||
* Thread to unpark is held in successor, which is normally
|
||||
@ -654,9 +686,9 @@ public abstract class AbstractQueuedSynchronizer
|
||||
Node s = node.next;
|
||||
if (s == null || s.waitStatus > 0) {
|
||||
s = null;
|
||||
for (Node t = tail; t != null && t != node; t = t.prev)
|
||||
if (t.waitStatus <= 0)
|
||||
s = t;
|
||||
for (Node p = tail; p != node && p != null; p = p.prev)
|
||||
if (p.waitStatus <= 0)
|
||||
s = p;
|
||||
}
|
||||
if (s != null)
|
||||
LockSupport.unpark(s.thread);
|
||||
@ -684,12 +716,12 @@ public abstract class AbstractQueuedSynchronizer
|
||||
if (h != null && h != tail) {
|
||||
int ws = h.waitStatus;
|
||||
if (ws == Node.SIGNAL) {
|
||||
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
|
||||
if (!h.compareAndSetWaitStatus(Node.SIGNAL, 0))
|
||||
continue; // loop to recheck cases
|
||||
unparkSuccessor(h);
|
||||
}
|
||||
else if (ws == 0 &&
|
||||
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
|
||||
!h.compareAndSetWaitStatus(0, Node.PROPAGATE))
|
||||
continue; // loop on failed CAS
|
||||
}
|
||||
if (h == head) // loop if head changed
|
||||
@ -763,18 +795,18 @@ public abstract class AbstractQueuedSynchronizer
|
||||
|
||||
// If we are the tail, remove ourselves.
|
||||
if (node == tail && compareAndSetTail(node, pred)) {
|
||||
compareAndSetNext(pred, predNext, null);
|
||||
pred.compareAndSetNext(predNext, null);
|
||||
} else {
|
||||
// If successor needs signal, try to set pred's next-link
|
||||
// so it will get one. Otherwise wake it up to propagate.
|
||||
int ws;
|
||||
if (pred != head &&
|
||||
((ws = pred.waitStatus) == Node.SIGNAL ||
|
||||
(ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
|
||||
(ws <= 0 && pred.compareAndSetWaitStatus(ws, Node.SIGNAL))) &&
|
||||
pred.thread != null) {
|
||||
Node next = node.next;
|
||||
if (next != null && next.waitStatus <= 0)
|
||||
compareAndSetNext(pred, predNext, next);
|
||||
pred.compareAndSetNext(predNext, next);
|
||||
} else {
|
||||
unparkSuccessor(node);
|
||||
}
|
||||
@ -815,7 +847,7 @@ public abstract class AbstractQueuedSynchronizer
|
||||
* need a signal, but don't park yet. Caller will need to
|
||||
* retry to make sure it cannot acquire before parking.
|
||||
*/
|
||||
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
|
||||
pred.compareAndSetWaitStatus(ws, Node.SIGNAL);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -828,7 +860,7 @@ public abstract class AbstractQueuedSynchronizer
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to park and then check if interrupted
|
||||
* Convenience method to park and then check if interrupted.
|
||||
*
|
||||
* @return {@code true} if interrupted
|
||||
*/
|
||||
@ -855,7 +887,6 @@ public abstract class AbstractQueuedSynchronizer
|
||||
* @return {@code true} if interrupted while waiting
|
||||
*/
|
||||
final boolean acquireQueued(final Node node, int arg) {
|
||||
boolean failed = true;
|
||||
try {
|
||||
boolean interrupted = false;
|
||||
for (;;) {
|
||||
@ -863,16 +894,15 @@ public abstract class AbstractQueuedSynchronizer
|
||||
if (p == head && tryAcquire(arg)) {
|
||||
setHead(node);
|
||||
p.next = null; // help GC
|
||||
failed = false;
|
||||
return interrupted;
|
||||
}
|
||||
if (shouldParkAfterFailedAcquire(p, node) &&
|
||||
parkAndCheckInterrupt())
|
||||
interrupted = true;
|
||||
}
|
||||
} finally {
|
||||
if (failed)
|
||||
cancelAcquire(node);
|
||||
} catch (Throwable t) {
|
||||
cancelAcquire(node);
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
@ -883,23 +913,21 @@ public abstract class AbstractQueuedSynchronizer
|
||||
private void doAcquireInterruptibly(int arg)
|
||||
throws InterruptedException {
|
||||
final Node node = addWaiter(Node.EXCLUSIVE);
|
||||
boolean failed = true;
|
||||
try {
|
||||
for (;;) {
|
||||
final Node p = node.predecessor();
|
||||
if (p == head && tryAcquire(arg)) {
|
||||
setHead(node);
|
||||
p.next = null; // help GC
|
||||
failed = false;
|
||||
return;
|
||||
}
|
||||
if (shouldParkAfterFailedAcquire(p, node) &&
|
||||
parkAndCheckInterrupt())
|
||||
throw new InterruptedException();
|
||||
}
|
||||
} finally {
|
||||
if (failed)
|
||||
cancelAcquire(node);
|
||||
} catch (Throwable t) {
|
||||
cancelAcquire(node);
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
@ -916,28 +944,28 @@ public abstract class AbstractQueuedSynchronizer
|
||||
return false;
|
||||
final long deadline = System.nanoTime() + nanosTimeout;
|
||||
final Node node = addWaiter(Node.EXCLUSIVE);
|
||||
boolean failed = true;
|
||||
try {
|
||||
for (;;) {
|
||||
final Node p = node.predecessor();
|
||||
if (p == head && tryAcquire(arg)) {
|
||||
setHead(node);
|
||||
p.next = null; // help GC
|
||||
failed = false;
|
||||
return true;
|
||||
}
|
||||
nanosTimeout = deadline - System.nanoTime();
|
||||
if (nanosTimeout <= 0L)
|
||||
if (nanosTimeout <= 0L) {
|
||||
cancelAcquire(node);
|
||||
return false;
|
||||
}
|
||||
if (shouldParkAfterFailedAcquire(p, node) &&
|
||||
nanosTimeout > spinForTimeoutThreshold)
|
||||
nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
|
||||
LockSupport.parkNanos(this, nanosTimeout);
|
||||
if (Thread.interrupted())
|
||||
throw new InterruptedException();
|
||||
}
|
||||
} finally {
|
||||
if (failed)
|
||||
cancelAcquire(node);
|
||||
} catch (Throwable t) {
|
||||
cancelAcquire(node);
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
@ -947,7 +975,6 @@ public abstract class AbstractQueuedSynchronizer
|
||||
*/
|
||||
private void doAcquireShared(int arg) {
|
||||
final Node node = addWaiter(Node.SHARED);
|
||||
boolean failed = true;
|
||||
try {
|
||||
boolean interrupted = false;
|
||||
for (;;) {
|
||||
@ -959,7 +986,6 @@ public abstract class AbstractQueuedSynchronizer
|
||||
p.next = null; // help GC
|
||||
if (interrupted)
|
||||
selfInterrupt();
|
||||
failed = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -967,9 +993,9 @@ public abstract class AbstractQueuedSynchronizer
|
||||
parkAndCheckInterrupt())
|
||||
interrupted = true;
|
||||
}
|
||||
} finally {
|
||||
if (failed)
|
||||
cancelAcquire(node);
|
||||
} catch (Throwable t) {
|
||||
cancelAcquire(node);
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
@ -980,7 +1006,6 @@ public abstract class AbstractQueuedSynchronizer
|
||||
private void doAcquireSharedInterruptibly(int arg)
|
||||
throws InterruptedException {
|
||||
final Node node = addWaiter(Node.SHARED);
|
||||
boolean failed = true;
|
||||
try {
|
||||
for (;;) {
|
||||
final Node p = node.predecessor();
|
||||
@ -989,7 +1014,6 @@ public abstract class AbstractQueuedSynchronizer
|
||||
if (r >= 0) {
|
||||
setHeadAndPropagate(node, r);
|
||||
p.next = null; // help GC
|
||||
failed = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -997,9 +1021,9 @@ public abstract class AbstractQueuedSynchronizer
|
||||
parkAndCheckInterrupt())
|
||||
throw new InterruptedException();
|
||||
}
|
||||
} finally {
|
||||
if (failed)
|
||||
cancelAcquire(node);
|
||||
} catch (Throwable t) {
|
||||
cancelAcquire(node);
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1016,7 +1040,6 @@ public abstract class AbstractQueuedSynchronizer
|
||||
return false;
|
||||
final long deadline = System.nanoTime() + nanosTimeout;
|
||||
final Node node = addWaiter(Node.SHARED);
|
||||
boolean failed = true;
|
||||
try {
|
||||
for (;;) {
|
||||
final Node p = node.predecessor();
|
||||
@ -1025,22 +1048,23 @@ public abstract class AbstractQueuedSynchronizer
|
||||
if (r >= 0) {
|
||||
setHeadAndPropagate(node, r);
|
||||
p.next = null; // help GC
|
||||
failed = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
nanosTimeout = deadline - System.nanoTime();
|
||||
if (nanosTimeout <= 0L)
|
||||
if (nanosTimeout <= 0L) {
|
||||
cancelAcquire(node);
|
||||
return false;
|
||||
}
|
||||
if (shouldParkAfterFailedAcquire(p, node) &&
|
||||
nanosTimeout > spinForTimeoutThreshold)
|
||||
nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
|
||||
LockSupport.parkNanos(this, nanosTimeout);
|
||||
if (Thread.interrupted())
|
||||
throw new InterruptedException();
|
||||
}
|
||||
} finally {
|
||||
if (failed)
|
||||
cancelAcquire(node);
|
||||
} catch (Throwable t) {
|
||||
cancelAcquire(node);
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1392,7 +1416,7 @@ public abstract class AbstractQueuedSynchronizer
|
||||
}
|
||||
|
||||
/**
|
||||
* Version of getFirstQueuedThread called when fastpath fails
|
||||
* Version of getFirstQueuedThread called when fastpath fails.
|
||||
*/
|
||||
private Thread fullGetFirstQueuedThread() {
|
||||
/*
|
||||
@ -1472,7 +1496,7 @@ public abstract class AbstractQueuedSynchronizer
|
||||
*
|
||||
* <p>An invocation of this method is equivalent to (but may be
|
||||
* more efficient than):
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* getFirstQueuedThread() != Thread.currentThread() &&
|
||||
* hasQueuedThreads()}</pre>
|
||||
*
|
||||
@ -1492,7 +1516,7 @@ public abstract class AbstractQueuedSynchronizer
|
||||
* tryAcquire} method for a fair, reentrant, exclusive mode
|
||||
* synchronizer might look like this:
|
||||
*
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* protected boolean tryAcquire(int arg) {
|
||||
* if (isHeldExclusively()) {
|
||||
* // A reentrant acquire; increment hold count
|
||||
@ -1528,8 +1552,7 @@ public abstract class AbstractQueuedSynchronizer
|
||||
* acquire. The value is only an estimate because the number of
|
||||
* threads may change dynamically while this method traverses
|
||||
* internal data structures. This method is designed for use in
|
||||
* monitoring system state, not for synchronization
|
||||
* control.
|
||||
* monitoring system state, not for synchronization control.
|
||||
*
|
||||
* @return the estimated number of threads waiting to acquire
|
||||
*/
|
||||
@ -1554,7 +1577,7 @@ public abstract class AbstractQueuedSynchronizer
|
||||
* @return the collection of threads
|
||||
*/
|
||||
public final Collection<Thread> getQueuedThreads() {
|
||||
ArrayList<Thread> list = new ArrayList<Thread>();
|
||||
ArrayList<Thread> list = new ArrayList<>();
|
||||
for (Node p = tail; p != null; p = p.prev) {
|
||||
Thread t = p.thread;
|
||||
if (t != null)
|
||||
@ -1572,7 +1595,7 @@ public abstract class AbstractQueuedSynchronizer
|
||||
* @return the collection of threads
|
||||
*/
|
||||
public final Collection<Thread> getExclusiveQueuedThreads() {
|
||||
ArrayList<Thread> list = new ArrayList<Thread>();
|
||||
ArrayList<Thread> list = new ArrayList<>();
|
||||
for (Node p = tail; p != null; p = p.prev) {
|
||||
if (!p.isShared()) {
|
||||
Thread t = p.thread;
|
||||
@ -1592,7 +1615,7 @@ public abstract class AbstractQueuedSynchronizer
|
||||
* @return the collection of threads
|
||||
*/
|
||||
public final Collection<Thread> getSharedQueuedThreads() {
|
||||
ArrayList<Thread> list = new ArrayList<Thread>();
|
||||
ArrayList<Thread> list = new ArrayList<>();
|
||||
for (Node p = tail; p != null; p = p.prev) {
|
||||
if (p.isShared()) {
|
||||
Thread t = p.thread;
|
||||
@ -1613,10 +1636,9 @@ public abstract class AbstractQueuedSynchronizer
|
||||
* @return a string identifying this synchronizer, as well as its state
|
||||
*/
|
||||
public String toString() {
|
||||
int s = getState();
|
||||
String q = hasQueuedThreads() ? "non" : "";
|
||||
return super.toString() +
|
||||
"[State = " + s + ", " + q + "empty queue]";
|
||||
return super.toString()
|
||||
+ "[State = " + getState() + ", "
|
||||
+ (hasQueuedThreads() ? "non" : "") + "empty queue]";
|
||||
}
|
||||
|
||||
|
||||
@ -1650,13 +1672,15 @@ public abstract class AbstractQueuedSynchronizer
|
||||
* @return true if present
|
||||
*/
|
||||
private boolean findNodeFromTail(Node node) {
|
||||
Node t = tail;
|
||||
for (;;) {
|
||||
if (t == node)
|
||||
// We check for node first, since it's likely to be at or near tail.
|
||||
// tail is known to be non-null, so we could re-order to "save"
|
||||
// one null check, but we leave it this way to help the VM.
|
||||
for (Node p = tail;;) {
|
||||
if (p == node)
|
||||
return true;
|
||||
if (t == null)
|
||||
if (p == null)
|
||||
return false;
|
||||
t = t.prev;
|
||||
p = p.prev;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1671,7 +1695,7 @@ public abstract class AbstractQueuedSynchronizer
|
||||
/*
|
||||
* If cannot change waitStatus, the node has been cancelled.
|
||||
*/
|
||||
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
|
||||
if (!node.compareAndSetWaitStatus(Node.CONDITION, 0))
|
||||
return false;
|
||||
|
||||
/*
|
||||
@ -1682,7 +1706,7 @@ public abstract class AbstractQueuedSynchronizer
|
||||
*/
|
||||
Node p = enq(node);
|
||||
int ws = p.waitStatus;
|
||||
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
|
||||
if (ws > 0 || !p.compareAndSetWaitStatus(ws, Node.SIGNAL))
|
||||
LockSupport.unpark(node.thread);
|
||||
return true;
|
||||
}
|
||||
@ -1695,7 +1719,7 @@ public abstract class AbstractQueuedSynchronizer
|
||||
* @return true if cancelled before the node was signalled
|
||||
*/
|
||||
final boolean transferAfterCancelledWait(Node node) {
|
||||
if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) {
|
||||
if (node.compareAndSetWaitStatus(Node.CONDITION, 0)) {
|
||||
enq(node);
|
||||
return true;
|
||||
}
|
||||
@ -1717,18 +1741,14 @@ public abstract class AbstractQueuedSynchronizer
|
||||
* @return previous sync state
|
||||
*/
|
||||
final int fullyRelease(Node node) {
|
||||
boolean failed = true;
|
||||
try {
|
||||
int savedState = getState();
|
||||
if (release(savedState)) {
|
||||
failed = false;
|
||||
if (release(savedState))
|
||||
return savedState;
|
||||
} else {
|
||||
throw new IllegalMonitorStateException();
|
||||
}
|
||||
} finally {
|
||||
if (failed)
|
||||
node.waitStatus = Node.CANCELLED;
|
||||
throw new IllegalMonitorStateException();
|
||||
} catch (Throwable t) {
|
||||
node.waitStatus = Node.CANCELLED;
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1773,8 +1793,8 @@ public abstract class AbstractQueuedSynchronizer
|
||||
* given condition associated with this synchronizer. Note that
|
||||
* because timeouts and interrupts may occur at any time, the
|
||||
* estimate serves only as an upper bound on the actual number of
|
||||
* waiters. This method is designed for use in monitoring of the
|
||||
* system state, not for synchronization control.
|
||||
* waiters. This method is designed for use in monitoring system
|
||||
* state, not for synchronization control.
|
||||
*
|
||||
* @param condition the condition
|
||||
* @return the estimated number of waiting threads
|
||||
@ -1852,7 +1872,9 @@ public abstract class AbstractQueuedSynchronizer
|
||||
unlinkCancelledWaiters();
|
||||
t = lastWaiter;
|
||||
}
|
||||
Node node = new Node(Thread.currentThread(), Node.CONDITION);
|
||||
|
||||
Node node = new Node(Node.CONDITION);
|
||||
|
||||
if (t == null)
|
||||
firstWaiter = node;
|
||||
else
|
||||
@ -1960,12 +1982,12 @@ public abstract class AbstractQueuedSynchronizer
|
||||
/**
|
||||
* Implements uninterruptible condition wait.
|
||||
* <ol>
|
||||
* <li> Save lock state returned by {@link #getState}.
|
||||
* <li> Invoke {@link #release} with saved state as argument,
|
||||
* throwing IllegalMonitorStateException if it fails.
|
||||
* <li> Block until signalled.
|
||||
* <li> Reacquire by invoking specialized version of
|
||||
* {@link #acquire} with saved state as argument.
|
||||
* <li>Save lock state returned by {@link #getState}.
|
||||
* <li>Invoke {@link #release} with saved state as argument,
|
||||
* throwing IllegalMonitorStateException if it fails.
|
||||
* <li>Block until signalled.
|
||||
* <li>Reacquire by invoking specialized version of
|
||||
* {@link #acquire} with saved state as argument.
|
||||
* </ol>
|
||||
*/
|
||||
public final void awaitUninterruptibly() {
|
||||
@ -2019,14 +2041,14 @@ public abstract class AbstractQueuedSynchronizer
|
||||
/**
|
||||
* Implements interruptible condition wait.
|
||||
* <ol>
|
||||
* <li> If current thread is interrupted, throw InterruptedException.
|
||||
* <li> Save lock state returned by {@link #getState}.
|
||||
* <li> Invoke {@link #release} with saved state as argument,
|
||||
* throwing IllegalMonitorStateException if it fails.
|
||||
* <li> Block until signalled or interrupted.
|
||||
* <li> Reacquire by invoking specialized version of
|
||||
* {@link #acquire} with saved state as argument.
|
||||
* <li> If interrupted while blocked in step 4, throw InterruptedException.
|
||||
* <li>If current thread is interrupted, throw InterruptedException.
|
||||
* <li>Save lock state returned by {@link #getState}.
|
||||
* <li>Invoke {@link #release} with saved state as argument,
|
||||
* throwing IllegalMonitorStateException if it fails.
|
||||
* <li>Block until signalled or interrupted.
|
||||
* <li>Reacquire by invoking specialized version of
|
||||
* {@link #acquire} with saved state as argument.
|
||||
* <li>If interrupted while blocked in step 4, throw InterruptedException.
|
||||
* </ol>
|
||||
*/
|
||||
public final void await() throws InterruptedException {
|
||||
@ -2051,30 +2073,33 @@ public abstract class AbstractQueuedSynchronizer
|
||||
/**
|
||||
* Implements timed condition wait.
|
||||
* <ol>
|
||||
* <li> If current thread is interrupted, throw InterruptedException.
|
||||
* <li> Save lock state returned by {@link #getState}.
|
||||
* <li> Invoke {@link #release} with saved state as argument,
|
||||
* throwing IllegalMonitorStateException if it fails.
|
||||
* <li> Block until signalled, interrupted, or timed out.
|
||||
* <li> Reacquire by invoking specialized version of
|
||||
* {@link #acquire} with saved state as argument.
|
||||
* <li> If interrupted while blocked in step 4, throw InterruptedException.
|
||||
* <li>If current thread is interrupted, throw InterruptedException.
|
||||
* <li>Save lock state returned by {@link #getState}.
|
||||
* <li>Invoke {@link #release} with saved state as argument,
|
||||
* throwing IllegalMonitorStateException if it fails.
|
||||
* <li>Block until signalled, interrupted, or timed out.
|
||||
* <li>Reacquire by invoking specialized version of
|
||||
* {@link #acquire} with saved state as argument.
|
||||
* <li>If interrupted while blocked in step 4, throw InterruptedException.
|
||||
* </ol>
|
||||
*/
|
||||
public final long awaitNanos(long nanosTimeout)
|
||||
throws InterruptedException {
|
||||
if (Thread.interrupted())
|
||||
throw new InterruptedException();
|
||||
// We don't check for nanosTimeout <= 0L here, to allow
|
||||
// awaitNanos(0) as a way to "yield the lock".
|
||||
final long deadline = System.nanoTime() + nanosTimeout;
|
||||
long initialNanos = nanosTimeout;
|
||||
Node node = addConditionWaiter();
|
||||
int savedState = fullyRelease(node);
|
||||
final long deadline = System.nanoTime() + nanosTimeout;
|
||||
int interruptMode = 0;
|
||||
while (!isOnSyncQueue(node)) {
|
||||
if (nanosTimeout <= 0L) {
|
||||
transferAfterCancelledWait(node);
|
||||
break;
|
||||
}
|
||||
if (nanosTimeout >= spinForTimeoutThreshold)
|
||||
if (nanosTimeout >= SPIN_FOR_TIMEOUT_THRESHOLD)
|
||||
LockSupport.parkNanos(this, nanosTimeout);
|
||||
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
|
||||
break;
|
||||
@ -2086,21 +2111,22 @@ public abstract class AbstractQueuedSynchronizer
|
||||
unlinkCancelledWaiters();
|
||||
if (interruptMode != 0)
|
||||
reportInterruptAfterWait(interruptMode);
|
||||
return deadline - System.nanoTime();
|
||||
long remaining = deadline - System.nanoTime(); // avoid overflow
|
||||
return (remaining <= initialNanos) ? remaining : Long.MIN_VALUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements absolute timed condition wait.
|
||||
* <ol>
|
||||
* <li> If current thread is interrupted, throw InterruptedException.
|
||||
* <li> Save lock state returned by {@link #getState}.
|
||||
* <li> Invoke {@link #release} with saved state as argument,
|
||||
* throwing IllegalMonitorStateException if it fails.
|
||||
* <li> Block until signalled, interrupted, or timed out.
|
||||
* <li> Reacquire by invoking specialized version of
|
||||
* {@link #acquire} with saved state as argument.
|
||||
* <li> If interrupted while blocked in step 4, throw InterruptedException.
|
||||
* <li> If timed out while blocked in step 4, return false, else true.
|
||||
* <li>If current thread is interrupted, throw InterruptedException.
|
||||
* <li>Save lock state returned by {@link #getState}.
|
||||
* <li>Invoke {@link #release} with saved state as argument,
|
||||
* throwing IllegalMonitorStateException if it fails.
|
||||
* <li>Block until signalled, interrupted, or timed out.
|
||||
* <li>Reacquire by invoking specialized version of
|
||||
* {@link #acquire} with saved state as argument.
|
||||
* <li>If interrupted while blocked in step 4, throw InterruptedException.
|
||||
* <li>If timed out while blocked in step 4, return false, else true.
|
||||
* </ol>
|
||||
*/
|
||||
public final boolean awaitUntil(Date deadline)
|
||||
@ -2113,7 +2139,7 @@ public abstract class AbstractQueuedSynchronizer
|
||||
boolean timedout = false;
|
||||
int interruptMode = 0;
|
||||
while (!isOnSyncQueue(node)) {
|
||||
if (System.currentTimeMillis() > abstime) {
|
||||
if (System.currentTimeMillis() >= abstime) {
|
||||
timedout = transferAfterCancelledWait(node);
|
||||
break;
|
||||
}
|
||||
@ -2133,15 +2159,15 @@ public abstract class AbstractQueuedSynchronizer
|
||||
/**
|
||||
* Implements timed condition wait.
|
||||
* <ol>
|
||||
* <li> If current thread is interrupted, throw InterruptedException.
|
||||
* <li> Save lock state returned by {@link #getState}.
|
||||
* <li> Invoke {@link #release} with saved state as argument,
|
||||
* throwing IllegalMonitorStateException if it fails.
|
||||
* <li> Block until signalled, interrupted, or timed out.
|
||||
* <li> Reacquire by invoking specialized version of
|
||||
* {@link #acquire} with saved state as argument.
|
||||
* <li> If interrupted while blocked in step 4, throw InterruptedException.
|
||||
* <li> If timed out while blocked in step 4, return false, else true.
|
||||
* <li>If current thread is interrupted, throw InterruptedException.
|
||||
* <li>Save lock state returned by {@link #getState}.
|
||||
* <li>Invoke {@link #release} with saved state as argument,
|
||||
* throwing IllegalMonitorStateException if it fails.
|
||||
* <li>Block until signalled, interrupted, or timed out.
|
||||
* <li>Reacquire by invoking specialized version of
|
||||
* {@link #acquire} with saved state as argument.
|
||||
* <li>If interrupted while blocked in step 4, throw InterruptedException.
|
||||
* <li>If timed out while blocked in step 4, return false, else true.
|
||||
* </ol>
|
||||
*/
|
||||
public final boolean await(long time, TimeUnit unit)
|
||||
@ -2149,9 +2175,11 @@ public abstract class AbstractQueuedSynchronizer
|
||||
long nanosTimeout = unit.toNanos(time);
|
||||
if (Thread.interrupted())
|
||||
throw new InterruptedException();
|
||||
// We don't check for nanosTimeout <= 0L here, to allow
|
||||
// await(0, unit) as a way to "yield the lock".
|
||||
final long deadline = System.nanoTime() + nanosTimeout;
|
||||
Node node = addConditionWaiter();
|
||||
int savedState = fullyRelease(node);
|
||||
final long deadline = System.nanoTime() + nanosTimeout;
|
||||
boolean timedout = false;
|
||||
int interruptMode = 0;
|
||||
while (!isOnSyncQueue(node)) {
|
||||
@ -2159,7 +2187,7 @@ public abstract class AbstractQueuedSynchronizer
|
||||
timedout = transferAfterCancelledWait(node);
|
||||
break;
|
||||
}
|
||||
if (nanosTimeout >= spinForTimeoutThreshold)
|
||||
if (nanosTimeout >= SPIN_FOR_TIMEOUT_THRESHOLD)
|
||||
LockSupport.parkNanos(this, nanosTimeout);
|
||||
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
|
||||
break;
|
||||
@ -2236,7 +2264,7 @@ public abstract class AbstractQueuedSynchronizer
|
||||
protected final Collection<Thread> getWaitingThreads() {
|
||||
if (!isHeldExclusively())
|
||||
throw new IllegalMonitorStateException();
|
||||
ArrayList<Thread> list = new ArrayList<Thread>();
|
||||
ArrayList<Thread> list = new ArrayList<>();
|
||||
for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
|
||||
if (w.waitStatus == Node.CONDITION) {
|
||||
Thread t = w.thread;
|
||||
@ -2257,59 +2285,40 @@ public abstract class AbstractQueuedSynchronizer
|
||||
* are at it, we do the same for other CASable fields (which could
|
||||
* otherwise be done with atomic field updaters).
|
||||
*/
|
||||
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||
private static final long stateOffset;
|
||||
private static final long headOffset;
|
||||
private static final long tailOffset;
|
||||
private static final long waitStatusOffset;
|
||||
private static final long nextOffset;
|
||||
private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
|
||||
private static final long STATE;
|
||||
private static final long HEAD;
|
||||
private static final long TAIL;
|
||||
|
||||
static {
|
||||
try {
|
||||
stateOffset = unsafe.objectFieldOffset
|
||||
STATE = U.objectFieldOffset
|
||||
(AbstractQueuedSynchronizer.class.getDeclaredField("state"));
|
||||
headOffset = unsafe.objectFieldOffset
|
||||
HEAD = U.objectFieldOffset
|
||||
(AbstractQueuedSynchronizer.class.getDeclaredField("head"));
|
||||
tailOffset = unsafe.objectFieldOffset
|
||||
TAIL = U.objectFieldOffset
|
||||
(AbstractQueuedSynchronizer.class.getDeclaredField("tail"));
|
||||
waitStatusOffset = unsafe.objectFieldOffset
|
||||
(Node.class.getDeclaredField("waitStatus"));
|
||||
nextOffset = unsafe.objectFieldOffset
|
||||
(Node.class.getDeclaredField("next"));
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
|
||||
} catch (Exception ex) { throw new Error(ex); }
|
||||
// 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* CAS head field. Used only by enq.
|
||||
* Initializes head and tail fields on first contention.
|
||||
*/
|
||||
private final boolean compareAndSetHead(Node update) {
|
||||
return unsafe.compareAndSwapObject(this, headOffset, null, update);
|
||||
private final void initializeSyncQueue() {
|
||||
if (U.compareAndSwapObject(this, HEAD, null, new Node()))
|
||||
tail = head;
|
||||
}
|
||||
|
||||
/**
|
||||
* CAS tail field. Used only by enq.
|
||||
* CASes tail field.
|
||||
*/
|
||||
private final boolean compareAndSetTail(Node expect, Node update) {
|
||||
return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
|
||||
}
|
||||
|
||||
/**
|
||||
* CAS waitStatus field of a node.
|
||||
*/
|
||||
private static final boolean compareAndSetWaitStatus(Node node,
|
||||
int expect,
|
||||
int update) {
|
||||
return unsafe.compareAndSwapInt(node, waitStatusOffset,
|
||||
expect, update);
|
||||
}
|
||||
|
||||
/**
|
||||
* CAS next field of a node.
|
||||
*/
|
||||
private static final boolean compareAndSetNext(Node node,
|
||||
Node expect,
|
||||
Node update) {
|
||||
return unsafe.compareAndSwapObject(node, nextOffset, expect, update);
|
||||
return U.compareAndSwapObject(this, TAIL, expect, update);
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,8 +34,9 @@
|
||||
*/
|
||||
|
||||
package java.util.concurrent.locks;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* {@code Condition} factors out the {@code Object} monitor
|
||||
@ -126,7 +127,7 @@ import java.util.Date;
|
||||
* <p>Note that {@code Condition} instances are just normal objects and can
|
||||
* themselves be used as the target in a {@code synchronized} statement,
|
||||
* and can have their own monitor {@link Object#wait wait} and
|
||||
* {@link Object#notify notification} methods invoked.
|
||||
* {@link Object#notify notify} methods invoked.
|
||||
* Acquiring the monitor lock of a {@code Condition} instance, or using its
|
||||
* monitor methods, has no specified relationship with acquiring the
|
||||
* {@link Lock} associated with that {@code Condition} or the use of its
|
||||
@ -308,7 +309,7 @@ public interface Condition {
|
||||
* condition still does not hold. Typical uses of this method take
|
||||
* the following form:
|
||||
*
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* boolean aMethod(long timeout, TimeUnit unit) {
|
||||
* long nanos = unit.toNanos(timeout);
|
||||
* lock.lock();
|
||||
@ -361,7 +362,7 @@ public interface Condition {
|
||||
* Causes the current thread to wait until it is signalled or interrupted,
|
||||
* or the specified waiting time elapses. This method is behaviorally
|
||||
* equivalent to:
|
||||
* <pre> {@code awaitNanos(unit.toNanos(time)) > 0}</pre>
|
||||
* <pre> {@code awaitNanos(unit.toNanos(time)) > 0}</pre>
|
||||
*
|
||||
* @param time the maximum time to wait
|
||||
* @param unit the time unit of the {@code time} argument
|
||||
@ -410,7 +411,7 @@ public interface Condition {
|
||||
*
|
||||
* <p>The return value indicates whether the deadline has elapsed,
|
||||
* which can be used as follows:
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* boolean aMethod(Date deadline) {
|
||||
* boolean stillWaiting = true;
|
||||
* lock.lock();
|
||||
|
||||
@ -34,6 +34,7 @@
|
||||
*/
|
||||
|
||||
package java.util.concurrent.locks;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
@ -77,7 +78,7 @@ import java.util.concurrent.TimeUnit;
|
||||
* methods and statements. In most cases, the following idiom
|
||||
* should be used:
|
||||
*
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* Lock l = ...;
|
||||
* l.lock();
|
||||
* try {
|
||||
@ -121,8 +122,9 @@ import java.util.concurrent.TimeUnit;
|
||||
* <p>All {@code Lock} implementations <em>must</em> enforce the same
|
||||
* memory synchronization semantics as provided by the built-in monitor
|
||||
* lock, as described in
|
||||
* <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4">
|
||||
* The Java Language Specification (17.4 Memory Model)</a>:
|
||||
* <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4">
|
||||
* Chapter 17 of
|
||||
* <cite>The Java™ Language Specification</cite></a>:
|
||||
* <ul>
|
||||
* <li>A successful {@code lock} operation has the same memory
|
||||
* synchronization effects as a successful <em>Lock</em> action.
|
||||
@ -240,7 +242,7 @@ public interface Lock {
|
||||
* immediately with the value {@code false}.
|
||||
*
|
||||
* <p>A typical usage idiom for this method would be:
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* Lock lock = ...;
|
||||
* if (lock.tryLock()) {
|
||||
* try {
|
||||
|
||||
@ -34,7 +34,6 @@
|
||||
*/
|
||||
|
||||
package java.util.concurrent.locks;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
/**
|
||||
* Basic thread blocking primitives for creating locks and other
|
||||
@ -47,6 +46,10 @@ import sun.misc.Unsafe;
|
||||
* it <em>may</em> block. A call to {@code unpark} makes the permit
|
||||
* available, if it was not already available. (Unlike with Semaphores
|
||||
* though, permits do not accumulate. There is at most one.)
|
||||
* Reliable usage requires the use of volatile (or atomic) variables
|
||||
* to control when to park or unpark. Orderings of calls to these
|
||||
* methods are maintained with respect to volatile variable accesses,
|
||||
* but not necessarily non-volatile variable accesses.
|
||||
*
|
||||
* <p>Methods {@code park} and {@code unpark} provide efficient
|
||||
* means of blocking and unblocking threads that do not encounter the
|
||||
@ -77,7 +80,7 @@ import sun.misc.Unsafe;
|
||||
* useful for most concurrency control applications. The {@code park}
|
||||
* method is designed for use only in constructions of the form:
|
||||
*
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* while (!canProceed()) { ... LockSupport.park(this); }}</pre>
|
||||
*
|
||||
* where neither {@code canProceed} nor any other actions prior to the
|
||||
@ -87,11 +90,11 @@ import sun.misc.Unsafe;
|
||||
*
|
||||
* <p><b>Sample Usage.</b> Here is a sketch of a first-in-first-out
|
||||
* non-reentrant lock class:
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* class FIFOMutex {
|
||||
* private final AtomicBoolean locked = new AtomicBoolean(false);
|
||||
* private final Queue<Thread> waiters
|
||||
* = new ConcurrentLinkedQueue<Thread>();
|
||||
* = new ConcurrentLinkedQueue<>();
|
||||
*
|
||||
* public void lock() {
|
||||
* boolean wasInterrupted = false;
|
||||
@ -122,7 +125,7 @@ public class LockSupport {
|
||||
|
||||
private static void setBlocker(Thread t, Object arg) {
|
||||
// Even though volatile, hotspot doesn't need a write barrier here.
|
||||
UNSAFE.putObject(t, parkBlockerOffset, arg);
|
||||
U.putObject(t, PARKBLOCKER, arg);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -138,7 +141,7 @@ public class LockSupport {
|
||||
*/
|
||||
public static void unpark(Thread thread) {
|
||||
if (thread != null)
|
||||
UNSAFE.unpark(thread);
|
||||
U.unpark(thread);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -172,7 +175,7 @@ public class LockSupport {
|
||||
public static void park(Object blocker) {
|
||||
Thread t = Thread.currentThread();
|
||||
setBlocker(t, blocker);
|
||||
UNSAFE.park(false, 0L);
|
||||
U.park(false, 0L);
|
||||
setBlocker(t, null);
|
||||
}
|
||||
|
||||
@ -212,7 +215,7 @@ public class LockSupport {
|
||||
if (nanos > 0) {
|
||||
Thread t = Thread.currentThread();
|
||||
setBlocker(t, blocker);
|
||||
UNSAFE.park(false, nanos);
|
||||
U.park(false, nanos);
|
||||
setBlocker(t, null);
|
||||
}
|
||||
}
|
||||
@ -253,7 +256,7 @@ public class LockSupport {
|
||||
public static void parkUntil(Object blocker, long deadline) {
|
||||
Thread t = Thread.currentThread();
|
||||
setBlocker(t, blocker);
|
||||
UNSAFE.park(true, deadline);
|
||||
U.park(true, deadline);
|
||||
setBlocker(t, null);
|
||||
}
|
||||
|
||||
@ -272,7 +275,7 @@ public class LockSupport {
|
||||
public static Object getBlocker(Thread t) {
|
||||
if (t == null)
|
||||
throw new NullPointerException();
|
||||
return UNSAFE.getObjectVolatile(t, parkBlockerOffset);
|
||||
return U.getObjectVolatile(t, PARKBLOCKER);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -301,7 +304,7 @@ public class LockSupport {
|
||||
* for example, the interrupt status of the thread upon return.
|
||||
*/
|
||||
public static void park() {
|
||||
UNSAFE.park(false, 0L);
|
||||
U.park(false, 0L);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -335,7 +338,7 @@ public class LockSupport {
|
||||
*/
|
||||
public static void parkNanos(long nanos) {
|
||||
if (nanos > 0)
|
||||
UNSAFE.park(false, nanos);
|
||||
U.park(false, nanos);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -369,7 +372,7 @@ public class LockSupport {
|
||||
* to wait until
|
||||
*/
|
||||
public static void parkUntil(long deadline) {
|
||||
UNSAFE.park(true, deadline);
|
||||
U.park(true, deadline);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -379,36 +382,30 @@ public class LockSupport {
|
||||
static final int nextSecondarySeed() {
|
||||
int r;
|
||||
Thread t = Thread.currentThread();
|
||||
if ((r = UNSAFE.getInt(t, SECONDARY)) != 0) {
|
||||
if ((r = U.getInt(t, SECONDARY)) != 0) {
|
||||
r ^= r << 13; // xorshift
|
||||
r ^= r >>> 17;
|
||||
r ^= r << 5;
|
||||
}
|
||||
else if ((r = java.util.concurrent.ThreadLocalRandom.current().nextInt()) == 0)
|
||||
r = 1; // avoid zero
|
||||
UNSAFE.putInt(t, SECONDARY, r);
|
||||
U.putInt(t, SECONDARY, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
// Hotspot implementation via intrinsics API
|
||||
private static final sun.misc.Unsafe UNSAFE;
|
||||
private static final long parkBlockerOffset;
|
||||
private static final long SEED;
|
||||
private static final long PROBE;
|
||||
private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
|
||||
private static final long PARKBLOCKER;
|
||||
private static final long SECONDARY;
|
||||
static {
|
||||
try {
|
||||
UNSAFE = sun.misc.Unsafe.getUnsafe();
|
||||
Class<?> tk = Thread.class;
|
||||
parkBlockerOffset = UNSAFE.objectFieldOffset
|
||||
(tk.getDeclaredField("parkBlocker"));
|
||||
SEED = UNSAFE.objectFieldOffset
|
||||
(tk.getDeclaredField("threadLocalRandomSeed"));
|
||||
PROBE = UNSAFE.objectFieldOffset
|
||||
(tk.getDeclaredField("threadLocalRandomProbe"));
|
||||
SECONDARY = UNSAFE.objectFieldOffset
|
||||
(tk.getDeclaredField("threadLocalRandomSecondarySeed"));
|
||||
} catch (Exception ex) { throw new Error(ex); }
|
||||
PARKBLOCKER = U.objectFieldOffset
|
||||
(Thread.class.getDeclaredField("parkBlocker"));
|
||||
SECONDARY = U.objectFieldOffset
|
||||
(Thread.class.getDeclaredField("threadLocalRandomSecondarySeed"));
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -38,9 +38,9 @@ package java.util.concurrent.locks;
|
||||
/**
|
||||
* A {@code ReadWriteLock} maintains a pair of associated {@link
|
||||
* Lock locks}, one for read-only operations and one for writing.
|
||||
* The {@link #readLock read lock} may be held simultaneously by
|
||||
* multiple reader threads, so long as there are no writers. The
|
||||
* {@link #writeLock write lock} is exclusive.
|
||||
* The {@linkplain #readLock read lock} may be held simultaneously
|
||||
* by multiple reader threads, so long as there are no writers.
|
||||
* The {@linkplain #writeLock write lock} is exclusive.
|
||||
*
|
||||
* <p>All {@code ReadWriteLock} implementations must guarantee that
|
||||
* the memory synchronization effects of {@code writeLock} operations
|
||||
|
||||
@ -34,8 +34,9 @@
|
||||
*/
|
||||
|
||||
package java.util.concurrent.locks;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* A reentrant mutual exclusion {@link Lock} with the same basic
|
||||
@ -72,7 +73,7 @@ import java.util.Collection;
|
||||
* follow a call to {@code lock} with a {@code try} block, most
|
||||
* typically in a before/after construction such as:
|
||||
*
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* class X {
|
||||
* private final ReentrantLock lock = new ReentrantLock();
|
||||
* // ...
|
||||
@ -378,7 +379,7 @@ public class ReentrantLock implements Lock, java.io.Serializable {
|
||||
* method. If you want a timed {@code tryLock} that does permit barging on
|
||||
* a fair lock then combine the timed and un-timed forms together:
|
||||
*
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* if (lock.tryLock() ||
|
||||
* lock.tryLock(timeout, unit)) {
|
||||
* ...
|
||||
@ -484,7 +485,7 @@ public class ReentrantLock implements Lock, java.io.Serializable {
|
||||
* InterruptedException} will be thrown, and the thread's
|
||||
* interrupted status will be cleared.
|
||||
*
|
||||
* <li> Waiting threads are signalled in FIFO order.
|
||||
* <li>Waiting threads are signalled in FIFO order.
|
||||
*
|
||||
* <li>The ordering of lock reacquisition for threads returning
|
||||
* from waiting methods is the same as for threads initially
|
||||
@ -511,7 +512,7 @@ public class ReentrantLock implements Lock, java.io.Serializable {
|
||||
* not be entered with the lock already held then we can assert that
|
||||
* fact:
|
||||
*
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* class X {
|
||||
* ReentrantLock lock = new ReentrantLock();
|
||||
* // ...
|
||||
@ -541,7 +542,7 @@ public class ReentrantLock implements Lock, java.io.Serializable {
|
||||
* debugging and testing. For example, a method that should only be
|
||||
* called while a lock is held can assert that this is the case:
|
||||
*
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* class X {
|
||||
* ReentrantLock lock = new ReentrantLock();
|
||||
* // ...
|
||||
@ -555,7 +556,7 @@ public class ReentrantLock implements Lock, java.io.Serializable {
|
||||
* <p>It can also be used to ensure that a reentrant lock is used
|
||||
* in a non-reentrant manner, for example:
|
||||
*
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* class X {
|
||||
* ReentrantLock lock = new ReentrantLock();
|
||||
* // ...
|
||||
@ -646,12 +647,11 @@ public class ReentrantLock implements Lock, java.io.Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an estimate of the number of threads waiting to
|
||||
* acquire this lock. The value is only an estimate because the number of
|
||||
* Returns an estimate of the number of threads waiting to acquire
|
||||
* this lock. The value is only an estimate because the number of
|
||||
* threads may change dynamically while this method traverses
|
||||
* internal data structures. This method is designed for use in
|
||||
* monitoring of the system state, not for synchronization
|
||||
* control.
|
||||
* monitoring system state, not for synchronization control.
|
||||
*
|
||||
* @return the estimated number of threads waiting for this lock
|
||||
*/
|
||||
|
||||
@ -34,8 +34,9 @@
|
||||
*/
|
||||
|
||||
package java.util.concurrent.locks;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* An implementation of {@link ReadWriteLock} supporting similar
|
||||
@ -51,14 +52,16 @@ import java.util.Collection;
|
||||
*
|
||||
* <dl>
|
||||
* <dt><b><i>Non-fair mode (default)</i></b>
|
||||
* <dd>When constructed as non-fair (the default), the order of entry
|
||||
* <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
|
||||
* When constructed as non-fair (the default), the order of entry
|
||||
* to the read and write lock is unspecified, subject to reentrancy
|
||||
* constraints. A nonfair lock that is continuously contended may
|
||||
* indefinitely postpone one or more reader or writer threads, but
|
||||
* will normally have higher throughput than a fair lock.
|
||||
*
|
||||
* <dt><b><i>Fair mode</i></b>
|
||||
* <dd>When constructed as fair, threads contend for entry using an
|
||||
* <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
|
||||
* When constructed as fair, threads contend for entry using an
|
||||
* approximately arrival-order policy. When the currently held lock
|
||||
* is released, either the longest-waiting single writer thread will
|
||||
* be assigned the write lock, or if there is a group of reader threads
|
||||
@ -173,9 +176,9 @@ import java.util.Collection;
|
||||
* is a class using a TreeMap that is expected to be large and
|
||||
* concurrently accessed.
|
||||
*
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* class RWDictionary {
|
||||
* private final Map<String, Data> m = new TreeMap<String, Data>();
|
||||
* private final Map<String, Data> m = new TreeMap<>();
|
||||
* private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
|
||||
* private final Lock r = rwl.readLock();
|
||||
* private final Lock w = rwl.writeLock();
|
||||
@ -263,17 +266,17 @@ public class ReentrantReadWriteLock
|
||||
static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1;
|
||||
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
|
||||
|
||||
/** Returns the number of shared holds represented in count */
|
||||
/** Returns the number of shared holds represented in count. */
|
||||
static int sharedCount(int c) { return c >>> SHARED_SHIFT; }
|
||||
/** Returns the number of exclusive holds represented in count */
|
||||
/** Returns the number of exclusive holds represented in count. */
|
||||
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
|
||||
|
||||
/**
|
||||
* A counter for per-thread read hold counts.
|
||||
* Maintained as a ThreadLocal; cached in cachedHoldCounter
|
||||
* Maintained as a ThreadLocal; cached in cachedHoldCounter.
|
||||
*/
|
||||
static final class HoldCounter {
|
||||
int count = 0;
|
||||
int count; // initially 0
|
||||
// Use id, not reference, to avoid garbage retention
|
||||
final long tid = getThreadId(Thread.currentThread());
|
||||
}
|
||||
@ -330,7 +333,7 @@ public class ReentrantReadWriteLock
|
||||
* <p>This allows tracking of read holds for uncontended read
|
||||
* locks to be very cheap.
|
||||
*/
|
||||
private transient Thread firstReader = null;
|
||||
private transient Thread firstReader;
|
||||
private transient int firstReaderHoldCount;
|
||||
|
||||
Sync() {
|
||||
@ -703,7 +706,7 @@ public class ReentrantReadWriteLock
|
||||
private final Sync sync;
|
||||
|
||||
/**
|
||||
* Constructor for use by subclasses
|
||||
* Constructor for use by subclasses.
|
||||
*
|
||||
* @param lock the outer lock object
|
||||
* @throws NullPointerException if the lock is null
|
||||
@ -814,7 +817,7 @@ public class ReentrantReadWriteLock
|
||||
* permit barging on a fair lock then combine the timed and
|
||||
* un-timed forms together:
|
||||
*
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* if (lock.tryLock() ||
|
||||
* lock.tryLock(timeout, unit)) {
|
||||
* ...
|
||||
@ -874,7 +877,12 @@ public class ReentrantReadWriteLock
|
||||
* Attempts to release this lock.
|
||||
*
|
||||
* <p>If the number of readers is now zero then the lock
|
||||
* is made available for write lock attempts.
|
||||
* is made available for write lock attempts. If the current
|
||||
* thread does not hold this lock then {@link
|
||||
* IllegalMonitorStateException} is thrown.
|
||||
*
|
||||
* @throws IllegalMonitorStateException if the current thread
|
||||
* does not hold this lock
|
||||
*/
|
||||
public void unlock() {
|
||||
sync.releaseShared(1);
|
||||
@ -912,7 +920,7 @@ public class ReentrantReadWriteLock
|
||||
private final Sync sync;
|
||||
|
||||
/**
|
||||
* Constructor for use by subclasses
|
||||
* Constructor for use by subclasses.
|
||||
*
|
||||
* @param lock the outer lock object
|
||||
* @throws NullPointerException if the lock is null
|
||||
@ -1026,7 +1034,7 @@ public class ReentrantReadWriteLock
|
||||
* by the current thread, or the write lock was already held
|
||||
* by the current thread; and {@code false} otherwise.
|
||||
*/
|
||||
public boolean tryLock( ) {
|
||||
public boolean tryLock() {
|
||||
return sync.tryWriteLock();
|
||||
}
|
||||
|
||||
@ -1046,7 +1054,7 @@ public class ReentrantReadWriteLock
|
||||
* that does permit barging on a fair lock then combine the
|
||||
* timed and un-timed forms together:
|
||||
*
|
||||
* <pre> {@code
|
||||
* <pre> {@code
|
||||
* if (lock.tryLock() ||
|
||||
* lock.tryLock(timeout, unit)) {
|
||||
* ...
|
||||
@ -1161,7 +1169,7 @@ public class ReentrantReadWriteLock
|
||||
* InterruptedException} will be thrown, and the thread's
|
||||
* interrupted status will be cleared.
|
||||
*
|
||||
* <li> Waiting threads are signalled in FIFO order.
|
||||
* <li>Waiting threads are signalled in FIFO order.
|
||||
*
|
||||
* <li>The ordering of lock reacquisition for threads returning
|
||||
* from waiting methods is the same as for threads initially
|
||||
@ -1369,7 +1377,7 @@ public class ReentrantReadWriteLock
|
||||
* either the read or write lock. The value is only an estimate
|
||||
* because the number of threads may change dynamically while this
|
||||
* method traverses internal data structures. This method is
|
||||
* designed for use in monitoring of the system state, not for
|
||||
* designed for use in monitoring system state, not for
|
||||
* synchronization control.
|
||||
*
|
||||
* @return the estimated number of threads waiting for this lock
|
||||
@ -1489,19 +1497,17 @@ public class ReentrantReadWriteLock
|
||||
* ways that do not preserve unique mappings.
|
||||
*/
|
||||
static final long getThreadId(Thread thread) {
|
||||
return UNSAFE.getLongVolatile(thread, TID_OFFSET);
|
||||
return U.getLongVolatile(thread, TID);
|
||||
}
|
||||
|
||||
// Unsafe mechanics
|
||||
private static final sun.misc.Unsafe UNSAFE;
|
||||
private static final long TID_OFFSET;
|
||||
private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
|
||||
private static final long TID;
|
||||
static {
|
||||
try {
|
||||
UNSAFE = sun.misc.Unsafe.getUnsafe();
|
||||
Class<?> tk = Thread.class;
|
||||
TID_OFFSET = UNSAFE.objectFieldOffset
|
||||
(tk.getDeclaredField("tid"));
|
||||
} catch (Exception e) {
|
||||
TID = U.objectFieldOffset
|
||||
(Thread.class.getDeclaredField("tid"));
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,10 +36,6 @@
|
||||
package java.util.concurrent.locks;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
|
||||
/**
|
||||
* A capability-based lock with three modes for controlling read/write
|
||||
@ -58,12 +54,12 @@ import java.util.concurrent.locks.LockSupport;
|
||||
* in method {@link #unlockWrite} to release the lock. Untimed and
|
||||
* timed versions of {@code tryWriteLock} are also provided. When
|
||||
* the lock is held in write mode, no read locks may be obtained,
|
||||
* and all optimistic read validations will fail. </li>
|
||||
* and all optimistic read validations will fail.
|
||||
*
|
||||
* <li><b>Reading.</b> Method {@link #readLock} possibly blocks
|
||||
* waiting for non-exclusive access, returning a stamp that can be
|
||||
* used in method {@link #unlockRead} to release the lock. Untimed
|
||||
* and timed versions of {@code tryReadLock} are also provided. </li>
|
||||
* and timed versions of {@code tryReadLock} are also provided.
|
||||
*
|
||||
* <li><b>Optimistic Reading.</b> Method {@link #tryOptimisticRead}
|
||||
* returns a non-zero stamp only if the lock is not currently held
|
||||
@ -81,7 +77,7 @@ import java.util.concurrent.locks.LockSupport;
|
||||
* invoke method {@code validate()}. For example, such steps are
|
||||
* typically required when first reading an object or array
|
||||
* reference, and then accessing one of its fields, elements or
|
||||
* methods. </li>
|
||||
* methods.
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
@ -132,7 +128,7 @@ import java.util.concurrent.locks.LockSupport;
|
||||
* not strictly needed here because no exceptions can occur in their
|
||||
* bodies.<br>
|
||||
*
|
||||
* <pre>{@code
|
||||
* <pre> {@code
|
||||
* class Point {
|
||||
* private double x, y;
|
||||
* private final StampedLock sl = new StampedLock();
|
||||
@ -542,7 +538,7 @@ public class StampedLock implements java.io.Serializable {
|
||||
WNode h;
|
||||
if (state != stamp || (stamp & WBIT) == 0L)
|
||||
throw new IllegalMonitorStateException();
|
||||
state = (stamp += WBIT) == 0L ? ORIGIN : stamp;
|
||||
U.putLongVolatile(this, STATE, (stamp += WBIT) == 0L ? ORIGIN : stamp);
|
||||
if ((h = whead) != null && h.status != 0)
|
||||
release(h);
|
||||
}
|
||||
@ -589,7 +585,7 @@ public class StampedLock implements java.io.Serializable {
|
||||
else if (m == WBIT) {
|
||||
if (a != m)
|
||||
break;
|
||||
state = (s += WBIT) == 0L ? ORIGIN : s;
|
||||
U.putLongVolatile(this, STATE, (s += WBIT) == 0L ? ORIGIN : s);
|
||||
if ((h = whead) != null && h.status != 0)
|
||||
release(h);
|
||||
return;
|
||||
@ -610,7 +606,7 @@ public class StampedLock implements java.io.Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* If the lock state matches the given stamp, performs one of
|
||||
* If the lock state matches the given stamp, atomically performs one of
|
||||
* the following actions. If the stamp represents holding a write
|
||||
* lock, returns it. Or, if a read lock, if the write lock is
|
||||
* available, releases the read lock and returns a write stamp.
|
||||
@ -647,7 +643,7 @@ public class StampedLock implements java.io.Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* If the lock state matches the given stamp, performs one of
|
||||
* If the lock state matches the given stamp, atomically performs one of
|
||||
* the following actions. If the stamp represents holding a write
|
||||
* lock, releases it and obtains a read lock. Or, if a read lock,
|
||||
* returns it. Or, if an optimistic read, acquires a read lock and
|
||||
@ -673,7 +669,7 @@ public class StampedLock implements java.io.Serializable {
|
||||
else if (m == WBIT) {
|
||||
if (a != m)
|
||||
break;
|
||||
state = next = s + (WBIT + RUNIT);
|
||||
U.putLongVolatile(this, STATE, next = s + (WBIT + RUNIT));
|
||||
if ((h = whead) != null && h.status != 0)
|
||||
release(h);
|
||||
return next;
|
||||
@ -687,7 +683,7 @@ public class StampedLock implements java.io.Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* If the lock state matches the given stamp then, if the stamp
|
||||
* If the lock state matches the given stamp then, atomically, if the stamp
|
||||
* represents holding a lock, releases it and returns an
|
||||
* observation stamp. Or, if an optimistic read, returns it if
|
||||
* validated. This method returns zero in all other cases, and so
|
||||
@ -710,7 +706,8 @@ public class StampedLock implements java.io.Serializable {
|
||||
else if (m == WBIT) {
|
||||
if (a != m)
|
||||
break;
|
||||
state = next = (s += WBIT) == 0L ? ORIGIN : s;
|
||||
U.putLongVolatile(this, STATE,
|
||||
next = (s += WBIT) == 0L ? ORIGIN : s);
|
||||
if ((h = whead) != null && h.status != 0)
|
||||
release(h);
|
||||
return next;
|
||||
@ -740,7 +737,7 @@ public class StampedLock implements java.io.Serializable {
|
||||
public boolean tryUnlockWrite() {
|
||||
long s; WNode h;
|
||||
if (((s = state) & WBIT) != 0L) {
|
||||
state = (s += WBIT) == 0L ? ORIGIN : s;
|
||||
U.putLongVolatile(this, STATE, (s += WBIT) == 0L ? ORIGIN : s);
|
||||
if ((h = whead) != null && h.status != 0)
|
||||
release(h);
|
||||
return true;
|
||||
@ -923,7 +920,7 @@ public class StampedLock implements java.io.Serializable {
|
||||
WNode h; long s;
|
||||
if (((s = state) & WBIT) == 0L)
|
||||
throw new IllegalMonitorStateException();
|
||||
state = (s += WBIT) == 0L ? ORIGIN : s;
|
||||
U.putLongVolatile(this, STATE, (s += WBIT) == 0L ? ORIGIN : s);
|
||||
if ((h = whead) != null && h.status != 0)
|
||||
release(h);
|
||||
}
|
||||
@ -948,7 +945,7 @@ public class StampedLock implements java.io.Serializable {
|
||||
private void readObject(java.io.ObjectInputStream s)
|
||||
throws java.io.IOException, ClassNotFoundException {
|
||||
s.defaultReadObject();
|
||||
state = ORIGIN; // reset to unlocked state
|
||||
U.putLongVolatile(this, STATE, ORIGIN); // reset to unlocked state
|
||||
}
|
||||
|
||||
// internals
|
||||
@ -966,7 +963,7 @@ public class StampedLock implements java.io.Serializable {
|
||||
if ((s & ABITS) == RFULL) {
|
||||
if (U.compareAndSwapLong(this, STATE, s, s | RBITS)) {
|
||||
++readerOverflow;
|
||||
state = s;
|
||||
U.putLongVolatile(this, STATE, s);
|
||||
return s;
|
||||
}
|
||||
}
|
||||
@ -993,8 +990,8 @@ public class StampedLock implements java.io.Serializable {
|
||||
}
|
||||
else
|
||||
next = s - RUNIT;
|
||||
state = next;
|
||||
return next;
|
||||
U.putLongVolatile(this, STATE, next);
|
||||
return next;
|
||||
}
|
||||
}
|
||||
else if ((LockSupport.nextSecondarySeed() &
|
||||
@ -1062,6 +1059,7 @@ public class StampedLock implements java.io.Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
boolean wasInterrupted = false;
|
||||
for (int spins = -1;;) {
|
||||
WNode h, np, pp; int ps;
|
||||
if ((h = whead) == p) {
|
||||
@ -1076,6 +1074,8 @@ public class StampedLock implements java.io.Serializable {
|
||||
ns = s + WBIT)) {
|
||||
whead = node;
|
||||
node.prev = null;
|
||||
if (wasInterrupted)
|
||||
Thread.currentThread().interrupt();
|
||||
return ns;
|
||||
}
|
||||
}
|
||||
@ -1119,8 +1119,11 @@ public class StampedLock implements java.io.Serializable {
|
||||
U.park(false, time); // emulate LockSupport.park
|
||||
node.thread = null;
|
||||
U.putObject(wt, PARKBLOCKER, null);
|
||||
if (interruptible && Thread.interrupted())
|
||||
return cancelWaiter(node, node, true);
|
||||
if (Thread.interrupted()) {
|
||||
if (interruptible)
|
||||
return cancelWaiter(node, node, true);
|
||||
wasInterrupted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1136,6 +1139,7 @@ public class StampedLock implements java.io.Serializable {
|
||||
* @return next state, or INTERRUPTED
|
||||
*/
|
||||
private long acquireRead(boolean interruptible, long deadline) {
|
||||
boolean wasInterrupted = false;
|
||||
WNode node = null, p;
|
||||
for (int spins = -1;;) {
|
||||
WNode h;
|
||||
@ -1143,8 +1147,11 @@ public class StampedLock implements java.io.Serializable {
|
||||
for (long m, s, ns;;) {
|
||||
if ((m = (s = state) & ABITS) < RFULL ?
|
||||
U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) :
|
||||
(m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L))
|
||||
(m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) {
|
||||
if (wasInterrupted)
|
||||
Thread.currentThread().interrupt();
|
||||
return ns;
|
||||
}
|
||||
else if (m >= WBIT) {
|
||||
if (spins > 0) {
|
||||
if (LockSupport.nextSecondarySeed() >= 0)
|
||||
@ -1193,8 +1200,11 @@ public class StampedLock implements java.io.Serializable {
|
||||
U.compareAndSwapLong(this, STATE, s,
|
||||
ns = s + RUNIT) :
|
||||
(m < WBIT &&
|
||||
(ns = tryIncReaderOverflow(s)) != 0L))
|
||||
(ns = tryIncReaderOverflow(s)) != 0L)) {
|
||||
if (wasInterrupted)
|
||||
Thread.currentThread().interrupt();
|
||||
return ns;
|
||||
}
|
||||
} while (m < WBIT);
|
||||
}
|
||||
if (whead == h && p.prev == pp) {
|
||||
@ -1205,8 +1215,11 @@ public class StampedLock implements java.io.Serializable {
|
||||
}
|
||||
if (deadline == 0L)
|
||||
time = 0L;
|
||||
else if ((time = deadline - System.nanoTime()) <= 0L)
|
||||
else if ((time = deadline - System.nanoTime()) <= 0L) {
|
||||
if (wasInterrupted)
|
||||
Thread.currentThread().interrupt();
|
||||
return cancelWaiter(node, p, false);
|
||||
}
|
||||
Thread wt = Thread.currentThread();
|
||||
U.putObject(wt, PARKBLOCKER, this);
|
||||
node.thread = wt;
|
||||
@ -1215,8 +1228,11 @@ public class StampedLock implements java.io.Serializable {
|
||||
U.park(false, time);
|
||||
node.thread = null;
|
||||
U.putObject(wt, PARKBLOCKER, null);
|
||||
if (interruptible && Thread.interrupted())
|
||||
return cancelWaiter(node, p, true);
|
||||
if (Thread.interrupted()) {
|
||||
if (interruptible)
|
||||
return cancelWaiter(node, p, true);
|
||||
wasInterrupted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1243,6 +1259,8 @@ public class StampedLock implements java.io.Serializable {
|
||||
(w = c.thread) != null)
|
||||
U.unpark(w);
|
||||
}
|
||||
if (wasInterrupted)
|
||||
Thread.currentThread().interrupt();
|
||||
return ns;
|
||||
}
|
||||
else if (m >= WBIT &&
|
||||
@ -1286,8 +1304,11 @@ public class StampedLock implements java.io.Serializable {
|
||||
U.park(false, time);
|
||||
node.thread = null;
|
||||
U.putObject(wt, PARKBLOCKER, null);
|
||||
if (interruptible && Thread.interrupted())
|
||||
return cancelWaiter(node, node, true);
|
||||
if (Thread.interrupted()) {
|
||||
if (interruptible)
|
||||
return cancelWaiter(node, node, true);
|
||||
wasInterrupted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1377,7 +1398,7 @@ public class StampedLock implements java.io.Serializable {
|
||||
}
|
||||
|
||||
// Unsafe mechanics
|
||||
private static final sun.misc.Unsafe U;
|
||||
private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
|
||||
private static final long STATE;
|
||||
private static final long WHEAD;
|
||||
private static final long WTAIL;
|
||||
@ -1388,26 +1409,23 @@ public class StampedLock implements java.io.Serializable {
|
||||
|
||||
static {
|
||||
try {
|
||||
U = sun.misc.Unsafe.getUnsafe();
|
||||
Class<?> k = StampedLock.class;
|
||||
Class<?> wk = WNode.class;
|
||||
STATE = U.objectFieldOffset
|
||||
(k.getDeclaredField("state"));
|
||||
(StampedLock.class.getDeclaredField("state"));
|
||||
WHEAD = U.objectFieldOffset
|
||||
(k.getDeclaredField("whead"));
|
||||
(StampedLock.class.getDeclaredField("whead"));
|
||||
WTAIL = U.objectFieldOffset
|
||||
(k.getDeclaredField("wtail"));
|
||||
WSTATUS = U.objectFieldOffset
|
||||
(wk.getDeclaredField("status"));
|
||||
WNEXT = U.objectFieldOffset
|
||||
(wk.getDeclaredField("next"));
|
||||
WCOWAIT = U.objectFieldOffset
|
||||
(wk.getDeclaredField("cowait"));
|
||||
Class<?> tk = Thread.class;
|
||||
PARKBLOCKER = U.objectFieldOffset
|
||||
(tk.getDeclaredField("parkBlocker"));
|
||||
(StampedLock.class.getDeclaredField("wtail"));
|
||||
|
||||
} catch (Exception e) {
|
||||
WSTATUS = U.objectFieldOffset
|
||||
(WNode.class.getDeclaredField("status"));
|
||||
WNEXT = U.objectFieldOffset
|
||||
(WNode.class.getDeclaredField("next"));
|
||||
WCOWAIT = U.objectFieldOffset
|
||||
(WNode.class.getDeclaredField("cowait"));
|
||||
|
||||
PARKBLOCKER = U.objectFieldOffset
|
||||
(Thread.class.getDeclaredField("parkBlocker"));
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -226,8 +226,9 @@
|
||||
*
|
||||
* <h2 id="MemoryVisibility">Memory Consistency Properties</h2>
|
||||
*
|
||||
* <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4.5">
|
||||
* Chapter 17 of the Java Language Specification</a> defines the
|
||||
* <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4.5">
|
||||
* Chapter 17 of
|
||||
* <cite>The Java™ Language Specification</cite></a> defines the
|
||||
* <i>happens-before</i> relation on memory operations such as reads and
|
||||
* writes of shared variables. The results of a write by one thread are
|
||||
* guaranteed to be visible to a read by another thread only if the write
|
||||
|
||||
@ -318,7 +318,9 @@ class Deflater {
|
||||
* should be called in order to provide more input
|
||||
*/
|
||||
public boolean needsInput() {
|
||||
return len <= 0;
|
||||
synchronized (zsRef) {
|
||||
return len <= 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -31,7 +31,7 @@ package java.util.zip;
|
||||
|
||||
class ZStreamRef {
|
||||
|
||||
private long address;
|
||||
private volatile long address;
|
||||
ZStreamRef (long address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
@ -60,7 +60,7 @@ import static java.util.zip.ZipConstants64.*;
|
||||
*/
|
||||
public
|
||||
class ZipFile implements ZipConstants, Closeable {
|
||||
private long jzfile; // address of jzfile data
|
||||
private long jzfile; // address of jzfile data
|
||||
private final String name; // zip file name
|
||||
private final int total; // total number of entries
|
||||
private final boolean locsig; // if zip file starts with LOCSIG (usually true)
|
||||
@ -691,7 +691,7 @@ class ZipFile implements ZipConstants, Closeable {
|
||||
* (possibly compressed) zip file entry.
|
||||
*/
|
||||
private class ZipFileInputStream extends InputStream {
|
||||
private volatile boolean closeRequested = false;
|
||||
private volatile boolean zfisCloseRequested = false;
|
||||
protected long jzentry; // address of jzentry data
|
||||
private long pos; // current position within entry data
|
||||
protected long rem; // number of remaining bytes within entry
|
||||
@ -718,6 +718,7 @@ class ZipFile implements ZipConstants, Closeable {
|
||||
len = (int) rem;
|
||||
}
|
||||
|
||||
// Check if ZipFile open
|
||||
ensureOpenOrZipException();
|
||||
len = ZipFile.read(ZipFile.this.jzfile, jzentry, pos, b,
|
||||
off, len);
|
||||
@ -761,9 +762,9 @@ class ZipFile implements ZipConstants, Closeable {
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (closeRequested)
|
||||
if (zfisCloseRequested)
|
||||
return;
|
||||
closeRequested = true;
|
||||
zfisCloseRequested = true;
|
||||
|
||||
rem = 0;
|
||||
synchronized (ZipFile.this) {
|
||||
|
||||
@ -58,7 +58,7 @@ public class BasicImageReader implements AutoCloseable {
|
||||
|
||||
try {
|
||||
substrate = ImageNativeSubstrate.openImage(imagePath, byteOrder);
|
||||
} catch (UnsatisfiedLinkError ex) {
|
||||
} catch (UnsatisfiedLinkError | NoClassDefFoundError ex) {
|
||||
substrate = ImageJavaSubstrate.openImage(imagePath, byteOrder);
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2011, 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
|
||||
@ -37,14 +37,20 @@ public class BytecodeDescriptor {
|
||||
|
||||
private BytecodeDescriptor() { } // cannot instantiate
|
||||
|
||||
/**
|
||||
* @param loader the class loader in which to look up the types (null means
|
||||
* bootstrap class loader)
|
||||
*/
|
||||
public static List<Class<?>> parseMethod(String bytecodeSignature, ClassLoader loader) {
|
||||
return parseMethod(bytecodeSignature, 0, bytecodeSignature.length(), loader);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param loader the class loader in which to look up the types (null means
|
||||
* bootstrap class loader)
|
||||
*/
|
||||
static List<Class<?>> parseMethod(String bytecodeSignature,
|
||||
int start, int end, ClassLoader loader) {
|
||||
if (loader == null)
|
||||
loader = ClassLoader.getSystemClassLoader();
|
||||
String str = bytecodeSignature;
|
||||
int[] i = {start};
|
||||
ArrayList<Class<?>> ptypes = new ArrayList<Class<?>>();
|
||||
@ -71,6 +77,10 @@ public class BytecodeDescriptor {
|
||||
throw new IllegalArgumentException("bad signature: "+str+": "+msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param loader the class loader in which to look up the types (null means
|
||||
* bootstrap class loader)
|
||||
*/
|
||||
private static Class<?> parseSig(String str, int[] i, int end, ClassLoader loader) {
|
||||
if (i[0] == end) return null;
|
||||
char c = str.charAt(i[0]++);
|
||||
@ -80,7 +90,9 @@ public class BytecodeDescriptor {
|
||||
i[0] = endc+1;
|
||||
String name = str.substring(begc, endc).replace('/', '.');
|
||||
try {
|
||||
return loader.loadClass(name);
|
||||
return (loader == null)
|
||||
? Class.forName(name, false, null)
|
||||
: loader.loadClass(name);
|
||||
} catch (ClassNotFoundException ex) {
|
||||
throw new TypeNotPresentException(name, ex);
|
||||
}
|
||||
|
||||
@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1994, 2005, 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
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package sun.misc;
|
||||
|
||||
/**
|
||||
* ConditionLock is a Lock with a built in state variable. This class
|
||||
* provides the ability to wait for the state variable to be set to a
|
||||
* desired value and then acquire the lock.<p>
|
||||
*
|
||||
* The lockWhen() and unlockWith() methods can be safely intermixed
|
||||
* with the lock() and unlock() methods. However if there is a thread
|
||||
* waiting for the state variable to become a particular value and you
|
||||
* simply call Unlock(), that thread will not be able to acquire the
|
||||
* lock until the state variable equals its desired value.
|
||||
*
|
||||
* @author Peter King
|
||||
*/
|
||||
public final
|
||||
class ConditionLock extends Lock {
|
||||
private int state = 0;
|
||||
|
||||
/**
|
||||
* Creates a ConditionLock.
|
||||
*/
|
||||
public ConditionLock () {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ConditionLock in an initialState.
|
||||
*/
|
||||
public ConditionLock (int initialState) {
|
||||
state = initialState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquires the lock when the state variable equals the desired state.
|
||||
*
|
||||
* @param desiredState the desired state
|
||||
* @exception java.lang.InterruptedException if any thread has
|
||||
* interrupted this thread.
|
||||
*/
|
||||
public synchronized void lockWhen(int desiredState)
|
||||
throws InterruptedException
|
||||
{
|
||||
while (state != desiredState) {
|
||||
wait();
|
||||
}
|
||||
lock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases the lock, and sets the state to a new value.
|
||||
* @param newState the new state
|
||||
*/
|
||||
public synchronized void unlockWith(int newState) {
|
||||
state = newState;
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
@ -1,93 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1994, 2005, 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
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package sun.misc;
|
||||
|
||||
/**
|
||||
* The Lock class provides a simple, useful interface to a lock.
|
||||
* Unlike monitors which synchronize access to an object, locks
|
||||
* synchronize access to an arbitrary set of resources (objects,
|
||||
* methods, variables, etc.). <p>
|
||||
*
|
||||
* The programmer using locks must be responsible for clearly defining
|
||||
* the semantics of their use and should handle deadlock avoidance in
|
||||
* the face of exceptions. <p>
|
||||
*
|
||||
* For example, if you want to protect a set of method invocations with
|
||||
* a lock, and one of the methods may throw an exception, you must be
|
||||
* prepared to release the lock similarly to the following example:
|
||||
* <pre>
|
||||
* class SomeClass {
|
||||
* Lock myLock = new Lock();
|
||||
|
||||
* void someMethod() {
|
||||
* myLock.lock();
|
||||
* try {
|
||||
* StartOperation();
|
||||
* ContinueOperation();
|
||||
* EndOperation();
|
||||
* } finally {
|
||||
* myLock.unlock();
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author Peter King
|
||||
*/
|
||||
public
|
||||
class Lock {
|
||||
private boolean locked = false;
|
||||
|
||||
/**
|
||||
* Create a lock, which is initially not locked.
|
||||
*/
|
||||
public Lock () {
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquire the lock. If someone else has the lock, wait until it
|
||||
* has been freed, and then try to acquire it again. This method
|
||||
* will not return until the lock has been acquired.
|
||||
*
|
||||
* @exception java.lang.InterruptedException if any thread has
|
||||
* interrupted this thread.
|
||||
*/
|
||||
public final synchronized void lock() throws InterruptedException {
|
||||
while (locked) {
|
||||
wait();
|
||||
}
|
||||
locked = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release the lock. If someone else is waiting for the lock, the
|
||||
* will be notitified so they can try to acquire the lock again.
|
||||
*/
|
||||
public final synchronized void unlock() {
|
||||
locked = false;
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
@ -1,99 +0,0 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998, 2001, 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
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "fdlibm.h"
|
||||
|
||||
/* cbrt(x)
|
||||
* Return cube root of x
|
||||
*/
|
||||
#ifdef __STDC__
|
||||
static const unsigned
|
||||
#else
|
||||
static unsigned
|
||||
#endif
|
||||
B1 = 715094163, /* B1 = (682-0.03306235651)*2**20 */
|
||||
B2 = 696219795; /* B2 = (664-0.03306235651)*2**20 */
|
||||
|
||||
#ifdef __STDC__
|
||||
static const double
|
||||
#else
|
||||
static double
|
||||
#endif
|
||||
C = 5.42857142857142815906e-01, /* 19/35 = 0x3FE15F15, 0xF15F15F1 */
|
||||
D = -7.05306122448979611050e-01, /* -864/1225 = 0xBFE691DE, 0x2532C834 */
|
||||
E = 1.41428571428571436819e+00, /* 99/70 = 0x3FF6A0EA, 0x0EA0EA0F */
|
||||
F = 1.60714285714285720630e+00, /* 45/28 = 0x3FF9B6DB, 0x6DB6DB6E */
|
||||
G = 3.57142857142857150787e-01; /* 5/14 = 0x3FD6DB6D, 0xB6DB6DB7 */
|
||||
|
||||
#ifdef __STDC__
|
||||
double cbrt(double x)
|
||||
#else
|
||||
double cbrt(x)
|
||||
double x;
|
||||
#endif
|
||||
{
|
||||
int hx;
|
||||
double r,s,t=0.0,w;
|
||||
unsigned sign;
|
||||
|
||||
|
||||
hx = __HI(x); /* high word of x */
|
||||
sign=hx&0x80000000; /* sign= sign(x) */
|
||||
hx ^=sign;
|
||||
if(hx>=0x7ff00000) return(x+x); /* cbrt(NaN,INF) is itself */
|
||||
if((hx|__LO(x))==0)
|
||||
return(x); /* cbrt(0) is itself */
|
||||
|
||||
__HI(x) = hx; /* x <- |x| */
|
||||
/* rough cbrt to 5 bits */
|
||||
if(hx<0x00100000) /* subnormal number */
|
||||
{__HI(t)=0x43500000; /* set t= 2**54 */
|
||||
t*=x; __HI(t)=__HI(t)/3+B2;
|
||||
}
|
||||
else
|
||||
__HI(t)=hx/3+B1;
|
||||
|
||||
|
||||
/* new cbrt to 23 bits, may be implemented in single precision */
|
||||
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) */
|
||||
__LO(t)=0; __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;
|
||||
|
||||
/* retore the sign bit */
|
||||
__HI(t) |= sign;
|
||||
return(t);
|
||||
}
|
||||
@ -88,12 +88,6 @@ Java_java_lang_StrictMath_sqrt(JNIEnv *env, jclass unused, jdouble d)
|
||||
return (jdouble) jsqrt((double)d);
|
||||
}
|
||||
|
||||
JNIEXPORT jdouble JNICALL
|
||||
Java_java_lang_StrictMath_cbrt(JNIEnv *env, jclass unused, jdouble d)
|
||||
{
|
||||
return (jdouble) jcbrt((double)d);
|
||||
}
|
||||
|
||||
JNIEXPORT jdouble JNICALL
|
||||
Java_java_lang_StrictMath_atan2(JNIEnv *env, jclass unused, jdouble d1, jdouble d2)
|
||||
{
|
||||
|
||||
@ -1302,12 +1302,23 @@ ZIP_GetEntryDataOffset(jzfile *zip, jzentry *entry)
|
||||
jint
|
||||
ZIP_Read(jzfile *zip, jzentry *entry, jlong pos, void *buf, jint len)
|
||||
{
|
||||
jlong entry_size = (entry->csize != 0) ? entry->csize : entry->size;
|
||||
jlong entry_size;
|
||||
jlong start;
|
||||
|
||||
if (zip == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Clear previous zip error */
|
||||
zip->msg = NULL;
|
||||
|
||||
if (entry == 0) {
|
||||
zip->msg = "ZIP_Read: jzentry is NULL";
|
||||
return -1;
|
||||
}
|
||||
|
||||
entry_size = (entry->csize != 0) ? entry->csize : entry->size;
|
||||
|
||||
/* Check specified position */
|
||||
if (pos < 0 || pos > entry_size - 1) {
|
||||
zip->msg = "ZIP_Read: specified offset out of range";
|
||||
@ -1440,6 +1451,11 @@ ZIP_ReadEntry(jzfile *zip, jzentry *entry, unsigned char *buf, char *entryname)
|
||||
char *msg;
|
||||
char tmpbuf[1024];
|
||||
|
||||
if (entry == 0) {
|
||||
jio_fprintf(stderr, "jzentry was invalid");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
strcpy(entryname, entry->name);
|
||||
if (entry->csize == 0) {
|
||||
/* Entry is stored */
|
||||
|
||||
@ -32,8 +32,14 @@ import java.security.*;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import jdk.internal.misc.JavaAWTAccess;
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
import sun.misc.ManagedLocalsThread;
|
||||
@ -57,37 +63,28 @@ import sun.misc.ManagedLocalsThread;
|
||||
* <p>
|
||||
* At startup the LogManager class is located using the
|
||||
* java.util.logging.manager system property.
|
||||
*
|
||||
* <h3>LogManager Configuration</h3>
|
||||
*
|
||||
* A LogManager initializes the logging configuration via
|
||||
* the {@link #readConfiguration()} method during LogManager initialization.
|
||||
* By default, LogManager default configuration is used.
|
||||
* The logging configuration read by LogManager must be in the
|
||||
* {@linkplain Properties properties file} format.
|
||||
* <p>
|
||||
* The LogManager defines two optional system properties that allow control over
|
||||
* the initial configuration:
|
||||
* the initial configuration, as specified in the {@link #readConfiguration()}
|
||||
* method:
|
||||
* <ul>
|
||||
* <li>"java.util.logging.config.class"
|
||||
* <li>"java.util.logging.config.file"
|
||||
* </ul>
|
||||
* These two properties may be specified on the command line to the "java"
|
||||
* <p>
|
||||
* These two system properties may be specified on the command line to the "java"
|
||||
* command, or as system property definitions passed to JNI_CreateJavaVM.
|
||||
* <p>
|
||||
* If the "java.util.logging.config.class" property is set, then the
|
||||
* property value is treated as a class name. The given class will be
|
||||
* loaded, an object will be instantiated, and that object's constructor
|
||||
* is responsible for reading in the initial configuration. (That object
|
||||
* may use other system properties to control its configuration.) The
|
||||
* alternate configuration class can use {@code readConfiguration(InputStream)}
|
||||
* to define properties in the LogManager.
|
||||
* <p>
|
||||
* If "java.util.logging.config.class" property is <b>not</b> set,
|
||||
* then the "java.util.logging.config.file" system property can be used
|
||||
* to specify a properties file (in java.util.Properties format). The
|
||||
* initial logging configuration will be read from this file.
|
||||
* <p>
|
||||
* If neither of these properties is defined then the LogManager uses its
|
||||
* default configuration. The default configuration is typically loaded from the
|
||||
* properties file "{@code conf/logging.properties}" in the Java installation
|
||||
* directory.
|
||||
* <p>
|
||||
* The properties for loggers and Handlers will have names starting
|
||||
* with the dot-separated name for the handler or logger.
|
||||
* <p>
|
||||
* The {@linkplain Properties properties} for loggers and Handlers will have
|
||||
* names starting with the dot-separated name for the handler or logger.<br>
|
||||
* The global logging properties may include:
|
||||
* <ul>
|
||||
* <li>A property "handlers". This defines a whitespace or comma separated
|
||||
@ -788,7 +785,7 @@ public class LogManager {
|
||||
// instantiation of the handler is done in the LogManager.addLogger
|
||||
// implementation as a handler class may be only visible to LogManager
|
||||
// subclass for the custom log manager case
|
||||
processParentHandlers(logger, name);
|
||||
processParentHandlers(logger, name, VisitedLoggers.NEVER);
|
||||
|
||||
// Find the new node and its parent.
|
||||
LogNode node = getNode(name);
|
||||
@ -836,7 +833,8 @@ public class LogManager {
|
||||
|
||||
// If logger.getUseParentHandlers() returns 'true' and any of the logger's
|
||||
// parents have levels or handlers defined, make sure they are instantiated.
|
||||
private void processParentHandlers(final Logger logger, final String name) {
|
||||
private void processParentHandlers(final Logger logger, final String name,
|
||||
Predicate<Logger> visited) {
|
||||
final LogManager owner = getOwner();
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
@Override
|
||||
@ -862,7 +860,9 @@ public class LogManager {
|
||||
owner.getProperty(pname + ".handlers") != null) {
|
||||
// This pname has a level/handlers definition.
|
||||
// Make sure it exists.
|
||||
demandLogger(pname, null, null);
|
||||
if (visited.test(demandLogger(pname, null, null))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
ix = ix2+1;
|
||||
}
|
||||
@ -942,48 +942,64 @@ public class LogManager {
|
||||
private void loadLoggerHandlers(final Logger logger, final String name,
|
||||
final String handlersPropertyName)
|
||||
{
|
||||
AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
@Override
|
||||
public Object run() {
|
||||
String names[] = parseClassNames(handlersPropertyName);
|
||||
final boolean ensureCloseOnReset = names.length > 0
|
||||
&& getBooleanProperty(handlersPropertyName + ".ensureCloseOnReset",true);
|
||||
|
||||
int count = 0;
|
||||
for (String type : names) {
|
||||
try {
|
||||
Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(type);
|
||||
Handler hdl = (Handler) clz.newInstance();
|
||||
// Check if there is a property defining the
|
||||
// this handler's level.
|
||||
String levs = getProperty(type + ".level");
|
||||
if (levs != null) {
|
||||
Level l = Level.findLevel(levs);
|
||||
if (l != null) {
|
||||
hdl.setLevel(l);
|
||||
} else {
|
||||
// Probably a bad level. Drop through.
|
||||
System.err.println("Can't set level for " + type);
|
||||
}
|
||||
}
|
||||
// Add this Handler to the logger
|
||||
logger.addHandler(hdl);
|
||||
if (++count == 1 && ensureCloseOnReset) {
|
||||
// add this logger to the closeOnResetLoggers list.
|
||||
closeOnResetLoggers.addIfAbsent(CloseOnReset.create(logger));
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
System.err.println("Can't load log handler \"" + type + "\"");
|
||||
System.err.println("" + ex);
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public Void run() {
|
||||
setLoggerHandlers(logger, name, handlersPropertyName,
|
||||
createLoggerHandlers(name, handlersPropertyName));
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setLoggerHandlers(final Logger logger, final String name,
|
||||
final String handlersPropertyName,
|
||||
List<Handler> handlers)
|
||||
{
|
||||
final boolean ensureCloseOnReset = ! handlers.isEmpty()
|
||||
&& getBooleanProperty(handlersPropertyName + ".ensureCloseOnReset",true);
|
||||
int count = 0;
|
||||
for (Handler hdl : handlers) {
|
||||
logger.addHandler(hdl);
|
||||
if (++count == 1 && ensureCloseOnReset) {
|
||||
// add this logger to the closeOnResetLoggers list.
|
||||
closeOnResetLoggers.addIfAbsent(CloseOnReset.create(logger));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<Handler> createLoggerHandlers(final String name, final String handlersPropertyName)
|
||||
{
|
||||
String names[] = parseClassNames(handlersPropertyName);
|
||||
List<Handler> handlers = new ArrayList<>(names.length);
|
||||
for (String type : names) {
|
||||
try {
|
||||
Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(type);
|
||||
Handler hdl = (Handler) clz.newInstance();
|
||||
// Check if there is a property defining the
|
||||
// this handler's level.
|
||||
String levs = getProperty(type + ".level");
|
||||
if (levs != null) {
|
||||
Level l = Level.findLevel(levs);
|
||||
if (l != null) {
|
||||
hdl.setLevel(l);
|
||||
} else {
|
||||
// Probably a bad level. Drop through.
|
||||
System.err.println("Can't set level for " + type);
|
||||
}
|
||||
}
|
||||
// Add this Handler to the logger
|
||||
handlers.add(hdl);
|
||||
} catch (Exception ex) {
|
||||
System.err.println("Can't load log handler \"" + type + "\"");
|
||||
System.err.println("" + ex);
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return handlers;
|
||||
}
|
||||
|
||||
|
||||
// loggerRefQueue holds LoggerWeakRef objects for Logger objects
|
||||
// that have been GC'ed.
|
||||
@ -1242,21 +1258,48 @@ public class LogManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Reinitialize the logging properties and reread the logging configuration.
|
||||
* Reads and initializes the logging configuration.
|
||||
* <p>
|
||||
* The same rules are used for locating the configuration properties
|
||||
* as are used at startup. So normally the logging properties will
|
||||
* be re-read from the same file that was used at startup.
|
||||
* <P>
|
||||
* Any log level definitions in the new configuration file will be
|
||||
* applied using Logger.setLevel(), if the target Logger exists.
|
||||
* If the "java.util.logging.config.class" system property is set, then the
|
||||
* property value is treated as a class name. The given class will be
|
||||
* loaded, an object will be instantiated, and that object's constructor
|
||||
* is responsible for reading in the initial configuration. (That object
|
||||
* may use other system properties to control its configuration.) The
|
||||
* alternate configuration class can use {@code readConfiguration(InputStream)}
|
||||
* to define properties in the LogManager.
|
||||
* <p>
|
||||
* If "java.util.logging.config.class" system property is <b>not</b> set,
|
||||
* then this method will read the initial configuration from a properties
|
||||
* file and calls the {@link #readConfiguration(InputStream)} method to initialize
|
||||
* the configuration. The "java.util.logging.config.file" system property can be used
|
||||
* to specify the properties file that will be read as the initial configuration;
|
||||
* if not set, then the LogManager default configuration is used.
|
||||
* The default configuration is typically loaded from the
|
||||
* properties file "{@code conf/logging.properties}" in the Java installation
|
||||
* directory.
|
||||
*
|
||||
* <p>
|
||||
* Any {@linkplain #addConfigurationListener registered configuration
|
||||
* listener} will be invoked after the properties are read.
|
||||
*
|
||||
* @exception SecurityException if a security manager exists and if
|
||||
* the caller does not have LoggingPermission("control").
|
||||
* @exception IOException if there are IO problems reading the configuration.
|
||||
* @apiNote This {@code readConfiguration} method should only be used for
|
||||
* initializing the configuration during LogManager initialization or
|
||||
* used with the "java.util.logging.config.class" property.
|
||||
* When this method is called after loggers have been created, and
|
||||
* the "java.util.logging.config.class" system property is not set, all
|
||||
* existing loggers will be {@linkplain #reset() reset}. Then any
|
||||
* existing loggers that have a level property specified in the new
|
||||
* configuration stream will be {@linkplain
|
||||
* Logger#setLevel(java.util.logging.Level) set} to the specified log level.
|
||||
* <p>
|
||||
* To properly update the logging configuration, use the
|
||||
* {@link #updateConfiguration(java.util.function.Function)} or
|
||||
* {@link #updateConfiguration(java.io.InputStream, java.util.function.Function)}
|
||||
* methods instead.
|
||||
*
|
||||
* @throws SecurityException if a security manager exists and if
|
||||
* the caller does not have LoggingPermission("control").
|
||||
* @throws IOException if there are IO problems reading the configuration.
|
||||
*/
|
||||
public void readConfiguration() throws IOException, SecurityException {
|
||||
checkPermission();
|
||||
@ -1284,20 +1327,24 @@ public class LogManager {
|
||||
}
|
||||
}
|
||||
|
||||
String fname = getConfigurationFileName();
|
||||
try (final InputStream in = new FileInputStream(fname)) {
|
||||
final BufferedInputStream bin = new BufferedInputStream(in);
|
||||
readConfiguration(bin);
|
||||
}
|
||||
}
|
||||
|
||||
String getConfigurationFileName() throws IOException {
|
||||
String fname = System.getProperty("java.util.logging.config.file");
|
||||
if (fname == null) {
|
||||
fname = System.getProperty("java.home");
|
||||
if (fname == null) {
|
||||
throw new Error("Can't find java.home ??");
|
||||
}
|
||||
File f = new File(fname, "conf");
|
||||
f = new File(f, "logging.properties");
|
||||
fname = f.getCanonicalPath();
|
||||
}
|
||||
try (final InputStream in = new FileInputStream(fname)) {
|
||||
final BufferedInputStream bin = new BufferedInputStream(in);
|
||||
readConfiguration(bin);
|
||||
fname = Paths.get(fname, "conf", "logging.properties")
|
||||
.toAbsolutePath().normalize().toString();
|
||||
}
|
||||
return fname;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1305,9 +1352,17 @@ public class LogManager {
|
||||
* <p>
|
||||
* For all named loggers, the reset operation removes and closes
|
||||
* all Handlers and (except for the root logger) sets the level
|
||||
* to null. The root logger's level is set to Level.INFO.
|
||||
* to {@code null}. The root logger's level is set to {@code Level.INFO}.
|
||||
*
|
||||
* @exception SecurityException if a security manager exists and if
|
||||
* @apiNote Calling this method also clears the LogManager {@linkplain
|
||||
* #getProperty(java.lang.String) properties}. The {@link
|
||||
* #updateConfiguration(java.util.function.Function)
|
||||
* updateConfiguration(Function)} or
|
||||
* {@link #updateConfiguration(java.io.InputStream, java.util.function.Function)
|
||||
* updateConfiguration(InputStream, Function)} method can be used to
|
||||
* properly update to a new configuration.
|
||||
*
|
||||
* @throws SecurityException if a security manager exists and if
|
||||
* the caller does not have LoggingPermission("control").
|
||||
*/
|
||||
|
||||
@ -1421,18 +1476,32 @@ public class LogManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Reinitialize the logging properties and reread the logging configuration
|
||||
* from the given stream, which should be in java.util.Properties format.
|
||||
* Reads and initializes the logging configuration from the given input stream.
|
||||
*
|
||||
* <p>
|
||||
* Any {@linkplain #addConfigurationListener registered configuration
|
||||
* listener} will be invoked after the properties are read.
|
||||
* <p>
|
||||
* Any log level definitions in the new configuration file will be
|
||||
* applied using Logger.setLevel(), if the target Logger exists.
|
||||
* @apiNote This {@code readConfiguration} method should only be used for
|
||||
* initializing the configuration during LogManager initialization or
|
||||
* used with the "java.util.logging.config.class" property.
|
||||
* When this method is called after loggers have been created, all
|
||||
* existing loggers will be {@linkplain #reset() reset}. Then any
|
||||
* existing loggers that have a level property specified in the
|
||||
* given input stream will be {@linkplain
|
||||
* Logger#setLevel(java.util.logging.Level) set} to the specified log level.
|
||||
* <p>
|
||||
* To properly update the logging configuration, use the
|
||||
* {@link #updateConfiguration(java.util.function.Function)} or
|
||||
* {@link #updateConfiguration(java.io.InputStream, java.util.function.Function)}
|
||||
* method instead.
|
||||
*
|
||||
* @param ins stream to read properties from
|
||||
* @exception SecurityException if a security manager exists and if
|
||||
* @param ins stream to read properties from
|
||||
* @throws SecurityException if a security manager exists and if
|
||||
* the caller does not have LoggingPermission("control").
|
||||
* @exception IOException if there are problems reading from the stream.
|
||||
* @throws IOException if there are problems reading from the stream,
|
||||
* or the given stream is not in the
|
||||
* {@linkplain java.util.Properties properties file} format.
|
||||
*/
|
||||
public void readConfiguration(InputStream ins) throws IOException, SecurityException {
|
||||
checkPermission();
|
||||
@ -1506,6 +1575,633 @@ public class LogManager {
|
||||
invokeConfigurationListeners();
|
||||
}
|
||||
|
||||
// This enum enumerate the configuration properties that will be
|
||||
// updated on existing loggers when the configuration is updated
|
||||
// with LogManager.updateConfiguration().
|
||||
//
|
||||
// Note that this works properly only for the global LogManager - as
|
||||
// Handler and its subclasses get their configuration from
|
||||
// LogManager.getLogManager().
|
||||
//
|
||||
static enum ConfigProperty {
|
||||
LEVEL(".level"), HANDLERS(".handlers"), USEPARENT(".useParentHandlers");
|
||||
final String suffix;
|
||||
final int length;
|
||||
private ConfigProperty(String suffix) {
|
||||
this.suffix = Objects.requireNonNull(suffix);
|
||||
length = suffix.length();
|
||||
}
|
||||
|
||||
public boolean handleKey(String key) {
|
||||
if (this == HANDLERS && suffix.substring(1).equals(key)) return true;
|
||||
if (this == HANDLERS && suffix.equals(key)) return false;
|
||||
return key.endsWith(suffix);
|
||||
}
|
||||
String key(String loggerName) {
|
||||
if (this == HANDLERS && (loggerName == null || loggerName.isEmpty())) {
|
||||
return suffix.substring(1);
|
||||
}
|
||||
return loggerName + suffix;
|
||||
}
|
||||
String loggerName(String key) {
|
||||
assert key.equals(suffix.substring(1)) && this == HANDLERS || key.endsWith(suffix);
|
||||
if (this == HANDLERS && suffix.substring(1).equals(key)) return "";
|
||||
return key.substring(0, key.length() - length);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the property is one that should be updated on existing loggers by
|
||||
* updateConfiguration, returns the name of the logger for which the
|
||||
* property is configured. Otherwise, returns null.
|
||||
* @param property a property key in 'props'
|
||||
* @return the name of the logger on which the property is to be set,
|
||||
* if the property is one that should be updated on existing
|
||||
* loggers, {@code null} otherwise.
|
||||
*/
|
||||
static String getLoggerName(String property) {
|
||||
for (ConfigProperty p : ConfigProperty.ALL) {
|
||||
if (p.handleKey(property)) {
|
||||
return p.loggerName(property);
|
||||
}
|
||||
}
|
||||
return null; // Not a property that should be updated.
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the ConfigProperty corresponding to the given
|
||||
* property key (may find none).
|
||||
* @param property a property key in 'props'
|
||||
* @return An optional containing a ConfigProperty object,
|
||||
* if the property is one that should be updated on existing
|
||||
* loggers, empty otherwise.
|
||||
*/
|
||||
static Optional<ConfigProperty> find(String property) {
|
||||
return ConfigProperty.ALL.stream()
|
||||
.filter(p -> p.handleKey(property))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given property is one that should be updated
|
||||
* on existing loggers.
|
||||
* Used to filter property name streams.
|
||||
* @param property a property key from the configuration.
|
||||
* @return true if this property is of interest for updateConfiguration.
|
||||
*/
|
||||
static boolean matches(String property) {
|
||||
return find(property).isPresent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the new property value is different from the old,
|
||||
* and therefore needs to be updated on existing loggers.
|
||||
* @param k a property key in the configuration
|
||||
* @param previous the old configuration
|
||||
* @param next the new configuration
|
||||
* @return true if the property is changing value between the two
|
||||
* configurations.
|
||||
*/
|
||||
static boolean needsUpdating(String k, Properties previous, Properties next) {
|
||||
final String p = trim(previous.getProperty(k, null));
|
||||
final String n = trim(next.getProperty(k, null));
|
||||
return ! Objects.equals(p,n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the mapping function for the given key to the next
|
||||
* configuration.
|
||||
* If the mapping function is null then this method does nothing.
|
||||
* Otherwise, it calls the mapping function to compute the value
|
||||
* that should be associated with {@code key} in the resulting
|
||||
* configuration, and applies it to {@code next}.
|
||||
* If the mapping function returns {@code null} the key is removed
|
||||
* from {@code next}.
|
||||
*
|
||||
* @param k a property key in the configuration
|
||||
* @param previous the old configuration
|
||||
* @param next the new configuration (modified by this function)
|
||||
* @param remappingFunction the mapping function.
|
||||
*/
|
||||
static void merge(String k, Properties previous, Properties next,
|
||||
BiFunction<String, String, String> mappingFunction) {
|
||||
String p = trim(previous.getProperty(k, null));
|
||||
String n = trim(next.getProperty(k, null));
|
||||
String mapped = trim(mappingFunction.apply(p,n));
|
||||
if (!Objects.equals(n, mapped)) {
|
||||
if (mapped == null) {
|
||||
next.remove(k);
|
||||
} else {
|
||||
next.setProperty(k, mapped);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final EnumSet<ConfigProperty> ALL =
|
||||
EnumSet.allOf(ConfigProperty.class);
|
||||
}
|
||||
|
||||
// trim the value if not null.
|
||||
private static String trim(String value) {
|
||||
return value == null ? null : value.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* An object that keep track of loggers we have already visited.
|
||||
* Used when updating configuration, to avoid processing the same logger
|
||||
* twice.
|
||||
*/
|
||||
static final class VisitedLoggers implements Predicate<Logger> {
|
||||
final IdentityHashMap<Logger,Boolean> visited;
|
||||
private VisitedLoggers(IdentityHashMap<Logger,Boolean> visited) {
|
||||
this.visited = visited;
|
||||
}
|
||||
VisitedLoggers() {
|
||||
this(new IdentityHashMap<>());
|
||||
}
|
||||
@Override
|
||||
public boolean test(Logger logger) {
|
||||
return visited != null && visited.put(logger, Boolean.TRUE) != null;
|
||||
}
|
||||
public void clear() {
|
||||
if (visited != null) visited.clear();
|
||||
}
|
||||
|
||||
// An object that considers that no logger has ever been visited.
|
||||
// This is used when processParentHandlers is called from
|
||||
// LoggerContext.addLocalLogger
|
||||
static final VisitedLoggers NEVER = new VisitedLoggers(null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Type of the modification for a given property. One of SAME, ADDED, CHANGED,
|
||||
* or REMOVED.
|
||||
*/
|
||||
static enum ModType {
|
||||
SAME, // property had no value in the old and new conf, or had the
|
||||
// same value in both.
|
||||
ADDED, // property had no value in the old conf, but has one in the new.
|
||||
CHANGED, // property has a different value in the old conf and the new conf.
|
||||
REMOVED; // property has no value in the new conf, but had one in the old.
|
||||
static ModType of(String previous, String next) {
|
||||
if (previous == null && next != null) {
|
||||
return ADDED;
|
||||
}
|
||||
if (next == null && previous != null) {
|
||||
return REMOVED;
|
||||
}
|
||||
if (!Objects.equals(trim(previous), trim(next))) {
|
||||
return CHANGED;
|
||||
}
|
||||
return SAME;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the logging configuration.
|
||||
* <p>
|
||||
* If the "java.util.logging.config.file" system property is set,
|
||||
* then the property value specifies the properties file to be read
|
||||
* as the new configuration. Otherwise, the LogManager default
|
||||
* configuration is used.
|
||||
* <br>The default configuration is typically loaded from the
|
||||
* properties file "{@code conf/logging.properties}" in the
|
||||
* Java installation directory.
|
||||
* <p>
|
||||
* This method reads the new configuration and calls the {@link
|
||||
* #updateConfiguration(java.io.InputStream, java.util.function.Function)
|
||||
* updateConfiguration(ins, mapper)} method to
|
||||
* update the configuration.
|
||||
*
|
||||
* @apiNote
|
||||
* This method updates the logging configuration from reading
|
||||
* a properties file and ignores the "java.util.logging.config.class"
|
||||
* system property. The "java.util.logging.config.class" property is
|
||||
* only used by the {@link #readConfiguration()} method to load a custom
|
||||
* configuration class as an initial configuration.
|
||||
*
|
||||
* @param mapper a functional interface that takes a configuration
|
||||
* key <i>k</i> and returns a function <i>f(o,n)</i> whose returned
|
||||
* value will be applied to the resulting configuration. The
|
||||
* function <i>f</i> may return {@code null} to indicate that the property
|
||||
* <i>k</i> will not be added to the resulting configuration.
|
||||
* <br>
|
||||
* If {@code mapper} is {@code null} then {@code (k) -> ((o, n) -> n)} is
|
||||
* assumed.
|
||||
* <br>
|
||||
* For each <i>k</i>, the mapped function <i>f</i> will
|
||||
* be invoked with the value associated with <i>k</i> in the old
|
||||
* configuration (i.e <i>o</i>) and the value associated with
|
||||
* <i>k</i> in the new configuration (i.e. <i>n</i>).
|
||||
* <br>A {@code null} value for <i>o</i> or <i>n</i> indicates that no
|
||||
* value was present for <i>k</i> in the corresponding configuration.
|
||||
*
|
||||
* @throws SecurityException if a security manager exists and if
|
||||
* the caller does not have LoggingPermission("control"), or
|
||||
* does not have the permissions required to set up the
|
||||
* configuration (e.g. open file specified for FileHandlers
|
||||
* etc...)
|
||||
*
|
||||
* @throws NullPointerException if {@code mapper} returns a {@code null}
|
||||
* function when invoked.
|
||||
*
|
||||
* @throws IOException if there are problems reading from the
|
||||
* logging configuration file.
|
||||
*
|
||||
* @see #updateConfiguration(java.io.InputStream, java.util.function.Function)
|
||||
*/
|
||||
public void updateConfiguration(Function<String, BiFunction<String,String,String>> mapper)
|
||||
throws IOException {
|
||||
checkPermission();
|
||||
ensureLogManagerInitialized();
|
||||
drainLoggerRefQueueBounded();
|
||||
|
||||
String fname = getConfigurationFileName();
|
||||
try (final InputStream in = new FileInputStream(fname)) {
|
||||
final BufferedInputStream bin = new BufferedInputStream(in);
|
||||
updateConfiguration(bin, mapper);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the logging configuration.
|
||||
* <p>
|
||||
* For each configuration key in the {@linkplain
|
||||
* #getProperty(java.lang.String) existing configuration} and
|
||||
* the given input stream configuration, the given {@code mapper} function
|
||||
* is invoked to map from the configuration key to a function,
|
||||
* <i>f(o,n)</i>, that takes the old value and new value and returns
|
||||
* the resulting value to be applied in the resulting configuration,
|
||||
* as specified in the table below.
|
||||
* <p>Let <i>k</i> be a configuration key in the old or new configuration,
|
||||
* <i>o</i> be the old value (i.e. the value associated
|
||||
* with <i>k</i> in the old configuration), <i>n</i> be the
|
||||
* new value (i.e. the value associated with <i>k</i> in the new
|
||||
* configuration), and <i>f</i> be the function returned
|
||||
* by {@code mapper.apply(}<i>k</i>{@code )}: then <i>v = f(o,n)</i> is the
|
||||
* resulting value. If <i>v</i> is not {@code null}, then a property
|
||||
* <i>k</i> with value <i>v</i> will be added to the resulting configuration.
|
||||
* Otherwise, it will be omitted.
|
||||
* <br>A {@code null} value may be passed to function
|
||||
* <i>f</i> to indicate that the corresponding configuration has no
|
||||
* configuration key <i>k</i>.
|
||||
* The function <i>f</i> may return {@code null} to indicate that
|
||||
* there will be no value associated with <i>k</i> in the resulting
|
||||
* configuration.
|
||||
* <p>
|
||||
* If {@code mapper} is {@code null}, then <i>v</i> will be set to
|
||||
* <i>n</i>.
|
||||
* <p>
|
||||
* LogManager {@linkplain #getProperty(java.lang.String) properties} are
|
||||
* updated with the resulting value in the resulting configuration.
|
||||
* <p>
|
||||
* The registered {@linkplain #addConfigurationListener configuration
|
||||
* listeners} will be invoked after the configuration is successfully updated.
|
||||
* <br><br>
|
||||
* <table summary="Updating configuration properties">
|
||||
* <tr>
|
||||
* <th>Property</th>
|
||||
* <th>Resulting Behavior</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td valign="top">{@code <logger>.level}</td>
|
||||
* <td>
|
||||
* <ul>
|
||||
* <li>If the resulting configuration defines a level for a logger and
|
||||
* if the resulting level is different than the level specified in the
|
||||
* the old configuration, or not specified in
|
||||
* the old configuration, then if the logger exists or if children for
|
||||
* that logger exist, the level for that logger will be updated,
|
||||
* and the change propagated to any existing logger children.
|
||||
* This may cause the logger to be created, if necessary.
|
||||
* </li>
|
||||
* <li>If the old configuration defined a level for a logger, and the
|
||||
* resulting configuration doesn't, then this change will not be
|
||||
* propagated to existing loggers, if any.
|
||||
* To completely replace a configuration - the caller should therefore
|
||||
* call {@link #reset() reset} to empty the current configuration,
|
||||
* before calling {@code updateConfiguration}.
|
||||
* </li>
|
||||
* </ul>
|
||||
* </td>
|
||||
* <tr>
|
||||
* <td valign="top">{@code <logger>.useParentHandlers}</td>
|
||||
* <td>
|
||||
* <ul>
|
||||
* <li>If either the resulting or the old value for the useParentHandlers
|
||||
* property is not null, then if the logger exists or if children for
|
||||
* that logger exist, that logger will be updated to the resulting
|
||||
* value.
|
||||
* The value of the useParentHandlers property is the value specified
|
||||
* in the configuration; if not specified, the default is true.
|
||||
* </li>
|
||||
* </ul>
|
||||
* </td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td valign="top">{@code <logger>.handlers}</td>
|
||||
* <td>
|
||||
* <ul>
|
||||
* <li>If the resulting configuration defines a list of handlers for a
|
||||
* logger, and if the resulting list is different than the list
|
||||
* specified in the old configuration for that logger (that could be
|
||||
* empty), then if the logger exists or its children exist, the
|
||||
* handlers associated with that logger are closed and removed and
|
||||
* the new handlers will be created per the resulting configuration
|
||||
* and added to that logger, creating that logger if necessary.
|
||||
* </li>
|
||||
* <li>If the old configuration defined some handlers for a logger, and
|
||||
* the resulting configuration doesn't, if that logger exists,
|
||||
* its handlers will be removed and closed.
|
||||
* </li>
|
||||
* <li>Changing the list of handlers on an existing logger will cause all
|
||||
* its previous handlers to be removed and closed, regardless of whether
|
||||
* they had been created from the configuration or programmatically.
|
||||
* The old handlers will be replaced by new handlers, if any.
|
||||
* </li>
|
||||
* </ul>
|
||||
* </td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td valign="top">{@code <handler-name>.*}</td>
|
||||
* <td>
|
||||
* <ul>
|
||||
* <li>Properties configured/changed on handler classes will only affect
|
||||
* newly created handlers. If a node is configured with the same list
|
||||
* of handlers in the old and the resulting configuration, then these
|
||||
* handlers will remain unchanged.
|
||||
* </li>
|
||||
* </ul>
|
||||
* </td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td valign="top">{@code config} and any other property</td>
|
||||
* <td>
|
||||
* <ul>
|
||||
* <li>The resulting value for these property will be stored in the
|
||||
* LogManager properties, but {@code updateConfiguration} will not parse
|
||||
* or process their values.
|
||||
* </li>
|
||||
* </ul>
|
||||
* </td>
|
||||
* </tr>
|
||||
* </table>
|
||||
* <p>
|
||||
* <em>Example mapper functions:</em>
|
||||
* <br><br>
|
||||
* <ul>
|
||||
* <li>Replace all logging properties with the new configuration:
|
||||
* <br><br>{@code (k) -> ((o, n) -> n)}:
|
||||
* <br><br>this is equivalent to passing a null {@code mapper} parameter.
|
||||
* </li>
|
||||
* <li>Merge the new configuration and old configuration and use the
|
||||
* new value if <i>k</i> exists in the new configuration:
|
||||
* <br><br>{@code (k) -> ((o, n) -> n == null ? o : n)}:
|
||||
* <br><br>as if merging two collections as follows:
|
||||
* {@code result.putAll(oldc); result.putAll(newc)}.<br></li>
|
||||
* <li>Merge the new configuration and old configuration and use the old
|
||||
* value if <i>k</i> exists in the old configuration:
|
||||
* <br><br>{@code (k) -> ((o, n) -> o == null ? n : o)}:
|
||||
* <br><br>as if merging two collections as follows:
|
||||
* {@code result.putAll(newc); result.putAll(oldc)}.<br></li>
|
||||
* <li>Replace all properties with the new configuration except the handler
|
||||
* property to configure Logger's handler that is not root logger:
|
||||
* <br>
|
||||
* <pre>{@code (k) -> k.endsWith(".handlers")}
|
||||
* {@code ? ((o, n) -> (o == null ? n : o))}
|
||||
* {@code : ((o, n) -> n)}</pre>
|
||||
* </li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* To completely reinitialize a configuration, an application can first call
|
||||
* {@link #reset() reset} to fully remove the old configuration, followed by
|
||||
* {@code updateConfiguration} to initialize the new configuration.
|
||||
*
|
||||
* @param ins a stream to read properties from
|
||||
* @param mapper a functional interface that takes a configuration
|
||||
* key <i>k</i> and returns a function <i>f(o,n)</i> whose returned
|
||||
* value will be applied to the resulting configuration. The
|
||||
* function <i>f</i> may return {@code null} to indicate that the property
|
||||
* <i>k</i> will not be added to the resulting configuration.
|
||||
* <br>
|
||||
* If {@code mapper} is {@code null} then {@code (k) -> ((o, n) -> n)} is
|
||||
* assumed.
|
||||
* <br>
|
||||
* For each <i>k</i>, the mapped function <i>f</i> will
|
||||
* be invoked with the value associated with <i>k</i> in the old
|
||||
* configuration (i.e <i>o</i>) and the value associated with
|
||||
* <i>k</i> in the new configuration (i.e. <i>n</i>).
|
||||
* <br>A {@code null} value for <i>o</i> or <i>n</i> indicates that no
|
||||
* value was present for <i>k</i> in the corresponding configuration.
|
||||
*
|
||||
* @throws SecurityException if a security manager exists and if
|
||||
* the caller does not have LoggingPermission("control"), or
|
||||
* does not have the permissions required to set up the
|
||||
* configuration (e.g. open files specified for FileHandlers)
|
||||
*
|
||||
* @throws NullPointerException if {@code ins} is null or if
|
||||
* {@code mapper} returns a null function when invoked.
|
||||
*
|
||||
* @throws IOException if there are problems reading from the stream,
|
||||
* or the given stream is not in the
|
||||
* {@linkplain java.util.Properties properties file} format.
|
||||
*/
|
||||
public void updateConfiguration(InputStream ins,
|
||||
Function<String, BiFunction<String,String,String>> mapper)
|
||||
throws IOException {
|
||||
checkPermission();
|
||||
ensureLogManagerInitialized();
|
||||
drainLoggerRefQueueBounded();
|
||||
|
||||
final Properties previous;
|
||||
final Set<String> updatePropertyNames;
|
||||
List<LoggerContext> cxs = Collections.emptyList();
|
||||
final VisitedLoggers visited = new VisitedLoggers();
|
||||
final Properties next = new Properties();
|
||||
|
||||
try {
|
||||
// Load the properties
|
||||
next.load(ins);
|
||||
} catch (IllegalArgumentException x) {
|
||||
// props.load may throw an IllegalArgumentException if the stream
|
||||
// contains malformed Unicode escape sequences.
|
||||
// We wrap that in an IOException as updateConfiguration is
|
||||
// specified to throw IOException if there are problems reading
|
||||
// from the stream.
|
||||
// Note: new IOException(x.getMessage(), x) allow us to get a more
|
||||
// concise error message than new IOException(x);
|
||||
throw new IOException(x.getMessage(), x);
|
||||
}
|
||||
|
||||
if (globalHandlersState == STATE_SHUTDOWN) return;
|
||||
|
||||
// exclusive lock: readConfiguration/reset/updateConfiguration can't
|
||||
// run concurrently.
|
||||
// configurationLock.writeLock().lock();
|
||||
configurationLock.lock();
|
||||
try {
|
||||
if (globalHandlersState == STATE_SHUTDOWN) return;
|
||||
previous = props;
|
||||
|
||||
// Builds a TreeSet of all (old and new) property names.
|
||||
updatePropertyNames =
|
||||
Stream.concat(previous.stringPropertyNames().stream(),
|
||||
next.stringPropertyNames().stream())
|
||||
.collect(Collectors.toCollection(TreeSet::new));
|
||||
|
||||
if (mapper != null) {
|
||||
// mapper will potentially modify the content of
|
||||
// 'next', so we need to call it before affecting props=next.
|
||||
// give a chance to the mapper to control all
|
||||
// properties - not just those we will reset.
|
||||
updatePropertyNames.stream()
|
||||
.forEachOrdered(k -> ConfigProperty
|
||||
.merge(k, previous, next,
|
||||
Objects.requireNonNull(mapper.apply(k))));
|
||||
}
|
||||
|
||||
props = next;
|
||||
|
||||
// allKeys will contain all keys:
|
||||
// - which correspond to a configuration property we are interested in
|
||||
// (first filter)
|
||||
// - whose value needs to be updated (because it's new, removed, or
|
||||
// different) in the resulting configuration (second filter)
|
||||
final Stream<String> allKeys = updatePropertyNames.stream()
|
||||
.filter(ConfigProperty::matches)
|
||||
.filter(k -> ConfigProperty.needsUpdating(k, previous, next));
|
||||
|
||||
// Group configuration properties by logger name
|
||||
// We use a TreeMap so that parent loggers will be visited before
|
||||
// child loggers.
|
||||
final Map<String, TreeSet<String>> loggerConfigs =
|
||||
allKeys.collect(Collectors.groupingBy(ConfigProperty::getLoggerName,
|
||||
TreeMap::new,
|
||||
Collectors.toCollection(TreeSet::new)));
|
||||
|
||||
if (!loggerConfigs.isEmpty()) {
|
||||
cxs = contexts();
|
||||
}
|
||||
final List<Logger> loggers = cxs.isEmpty()
|
||||
? Collections.emptyList() : new ArrayList<>(cxs.size());
|
||||
for (Map.Entry<String, TreeSet<String>> e : loggerConfigs.entrySet()) {
|
||||
// This can be a logger name, or something else...
|
||||
// The only thing we know is that we found a property
|
||||
// we are interested in.
|
||||
// For instance, if we found x.y.z.level, then x.y.z could be
|
||||
// a logger, but it could also be a handler class...
|
||||
// Anyway...
|
||||
final String name = e.getKey();
|
||||
final Set<String> properties = e.getValue();
|
||||
loggers.clear();
|
||||
for (LoggerContext cx : cxs) {
|
||||
Logger l = cx.findLogger(name);
|
||||
if (l != null && !visited.test(l)) {
|
||||
loggers.add(l);
|
||||
}
|
||||
}
|
||||
if (loggers.isEmpty()) continue;
|
||||
for (String pk : properties) {
|
||||
ConfigProperty cp = ConfigProperty.find(pk).get();
|
||||
String p = previous.getProperty(pk, null);
|
||||
String n = next.getProperty(pk, null);
|
||||
|
||||
// Determines the type of modification.
|
||||
ModType mod = ModType.of(p, n);
|
||||
|
||||
// mod == SAME means that the two values are equals, there
|
||||
// is nothing to do. Usually, this should not happen as such
|
||||
// properties should have been filtered above.
|
||||
// It could happen however if the properties had
|
||||
// trailing/leading whitespaces.
|
||||
if (mod == ModType.SAME) continue;
|
||||
|
||||
switch (cp) {
|
||||
case LEVEL:
|
||||
if (mod == ModType.REMOVED) continue;
|
||||
Level level = Level.findLevel(trim(n));
|
||||
if (level != null) {
|
||||
if (name.isEmpty()) {
|
||||
rootLogger.setLevel(level);
|
||||
}
|
||||
for (Logger l : loggers) {
|
||||
if (!name.isEmpty() || l != rootLogger) {
|
||||
l.setLevel(level);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case USEPARENT:
|
||||
if (!name.isEmpty()) {
|
||||
boolean useParent = getBooleanProperty(pk, true);
|
||||
if (n != null || p != null) {
|
||||
// reset the flag only if the previous value
|
||||
// or the new value are not null.
|
||||
for (Logger l : loggers) {
|
||||
l.setUseParentHandlers(useParent);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case HANDLERS:
|
||||
List<Handler> hdls = null;
|
||||
if (name.isEmpty()) {
|
||||
// special handling for the root logger.
|
||||
globalHandlersState = STATE_READING_CONFIG;
|
||||
try {
|
||||
closeHandlers(rootLogger);
|
||||
globalHandlersState = STATE_UNINITIALIZED;
|
||||
} catch (Throwable t) {
|
||||
globalHandlersState = STATE_INITIALIZED;
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
for (Logger l : loggers) {
|
||||
if (l == rootLogger) continue;
|
||||
closeHandlers(l);
|
||||
if (mod == ModType.REMOVED) {
|
||||
closeOnResetLoggers.removeIf(c -> c.logger == l);
|
||||
continue;
|
||||
}
|
||||
if (hdls == null) {
|
||||
hdls = name.isEmpty()
|
||||
? Arrays.asList(rootLogger.getHandlers())
|
||||
: createLoggerHandlers(name, pk);
|
||||
}
|
||||
setLoggerHandlers(l, name, pk, hdls);
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
configurationLock.unlock();
|
||||
visited.clear();
|
||||
}
|
||||
|
||||
// Now ensure that if an existing logger has acquired a new parent
|
||||
// in the configuration, this new parent will be created - if needed,
|
||||
// and added to the context of the existing child.
|
||||
//
|
||||
drainLoggerRefQueueBounded();
|
||||
for (LoggerContext cx : cxs) {
|
||||
for (Enumeration<String> names = cx.getLoggerNames() ; names.hasMoreElements();) {
|
||||
String name = names.nextElement();
|
||||
if (name.isEmpty()) continue; // don't need to process parents on root.
|
||||
Logger l = cx.findLogger(name);
|
||||
if (l != null && !visited.test(l)) {
|
||||
// should pass visited here to cut the processing when
|
||||
// reaching a logger already visited.
|
||||
cx.processParentHandlers(l, name, visited);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We changed the configuration: invoke configuration listeners
|
||||
invokeConfigurationListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of a logging property.
|
||||
* The method returns null if the property is not found.
|
||||
|
||||
@ -47,7 +47,8 @@ public final class TimeZoneNames_en_GB extends TimeZoneNamesBundle {
|
||||
protected final Object[][] getContents() {
|
||||
return new Object[][] {
|
||||
{"Europe/London", new String[] {"Greenwich Mean Time", "GMT",
|
||||
"British Summer Time", "BST"}},
|
||||
"British Summer Time", "BST",
|
||||
"British Time", "BT"}},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,7 +40,8 @@ public final class TimeZoneNames_hi extends TimeZoneNamesBundle {
|
||||
{"Asia/Calcutta",
|
||||
new String[] {
|
||||
"\u092d\u093e\u0930\u0924\u0940\u092f \u0938\u092e\u092f", "IST",
|
||||
"\u092d\u093e\u0930\u0924\u0940\u092f \u0938\u092e\u092f", "IST"
|
||||
"\u092d\u093e\u0930\u0924\u0940\u092f \u0938\u092e\u092f", "IST",
|
||||
"\u092d\u093e\u0930\u0924\u0940\u092f \u0938\u092e\u092f", "IT"
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
/*
|
||||
* @test
|
||||
* @library /lib/testlibrary/
|
||||
* @build jdk.testlibrary.*
|
||||
* @build jdk.testlibrary.RandomFactory
|
||||
* @run main CubeRootTests
|
||||
* @bug 4347132 4939441 8078672
|
||||
* @summary Tests for {Math, StrictMath}.cbrt (use -Dseed=X to set PRNG seed)
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
/*
|
||||
* @test
|
||||
* @library /lib/testlibrary/
|
||||
* @build jdk.testlibrary.*
|
||||
* @build jdk.testlibrary.RandomFactory
|
||||
* @run main HypotTests
|
||||
* @bug 4851638 4939441 8078672
|
||||
* @summary Tests for {Math, StrictMath}.hypot (use -Dseed=X to set PRNG seed)
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
/*
|
||||
* @test
|
||||
* @library /lib/testlibrary/
|
||||
* @build jdk.testlibrary.*
|
||||
* @build jdk.testlibrary.RandomFactory
|
||||
* @run main IeeeRecommendedTests
|
||||
* @bug 4860891 4826732 4780454 4939441 4826652 8078672
|
||||
* @summary Tests for IEEE 754[R] recommended functions and similar methods (use -Dseed=X to set PRNG seed)
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
/*
|
||||
* @test
|
||||
* @library /lib/testlibrary/
|
||||
* @build jdk.testlibrary.*
|
||||
* @build jdk.testlibrary.RandomFactory
|
||||
* @run main Log1pTests
|
||||
* @bug 4851638 4939441 8078672
|
||||
* @summary Tests for {Math, StrictMath}.log1p (use -Dseed=X to set PRNG seed)
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 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
|
||||
@ -23,11 +23,20 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 4347132
|
||||
* @bug 4347132 8136799
|
||||
* @key randomness
|
||||
* @library /lib/testlibrary/
|
||||
* @build jdk.testlibrary.RandomFactory
|
||||
* @build Tests
|
||||
* @build FdlibmTranslit
|
||||
* @build CubeRootTests
|
||||
* @run main CubeRootTests
|
||||
* @summary Tests specifically for StrictMath.cbrt
|
||||
* @author Joseph D. Darcy
|
||||
*/
|
||||
|
||||
import jdk.testlibrary.RandomFactory;
|
||||
|
||||
/**
|
||||
* The tests in ../Math/CubeRootTests.java test properties that should
|
||||
* hold for any cube root implementation, including the FDLIBM-based
|
||||
@ -42,6 +51,19 @@
|
||||
public class CubeRootTests {
|
||||
private CubeRootTests(){}
|
||||
|
||||
public static void main(String [] argv) {
|
||||
int failures = 0;
|
||||
|
||||
failures += testCubeRoot();
|
||||
failures += testAgainstTranslit();
|
||||
|
||||
if (failures > 0) {
|
||||
System.err.println("Testing the cube root incurred "
|
||||
+ failures + " failures.");
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
static int testCubeRootCase(double input, double expected) {
|
||||
int failures=0;
|
||||
|
||||
@ -458,16 +480,44 @@ public class CubeRootTests {
|
||||
return failures;
|
||||
}
|
||||
|
||||
// Initialize shared random number generator
|
||||
private static java.util.Random random = RandomFactory.getRandom();
|
||||
|
||||
public static void main(String [] argv) {
|
||||
/**
|
||||
* Test StrictMath.cbrt against transliteration port of cbrt.
|
||||
*/
|
||||
private static int testAgainstTranslit() {
|
||||
int failures = 0;
|
||||
double x;
|
||||
|
||||
failures += testCubeRoot();
|
||||
// Test just above subnormal threshold...
|
||||
x = Double.MIN_NORMAL;
|
||||
failures += testRange(x, Math.ulp(x), 1000);
|
||||
|
||||
if (failures > 0) {
|
||||
System.err.println("Testing the cube root incurred "
|
||||
+ failures + " failures.");
|
||||
throw new RuntimeException();
|
||||
// ... and just below subnormal threshold ...
|
||||
x = Math.nextDown(Double.MIN_NORMAL);
|
||||
failures += testRange(x, -Math.ulp(x), 1000);
|
||||
|
||||
// ... and near zero.
|
||||
failures += testRange(0.0, Double.MIN_VALUE, 1000);
|
||||
|
||||
x = Tests.createRandomDouble(random);
|
||||
|
||||
// Make the increment twice the ulp value in case the random
|
||||
// value is near an exponent threshold. Don't worry about test
|
||||
// elements overflowing to infinity if the starting value is
|
||||
// near Double.MAX_VALUE.
|
||||
failures += testRange(x, 2.0 * Math.ulp(x), 1000);
|
||||
|
||||
return failures;
|
||||
}
|
||||
|
||||
private static int testRange(double start, double increment, int count) {
|
||||
int failures = 0;
|
||||
double x = start;
|
||||
for (int i = 0; i < count; i++, x += increment) {
|
||||
failures += testCubeRootCase(x, FdlibmTranslit.Cbrt.compute(x));
|
||||
}
|
||||
return failures;
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,6 +72,67 @@ public class FdlibmTranslit {
|
||||
return Hypot.compute(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 = 5.42857142857142815906e-01; /* 19/35 = 0x3FE15F15, 0xF15F15F1 */
|
||||
private static final double D = -7.05306122448979611050e-01; /* -864/1225 = 0xBFE691DE, 0x2532C834 */
|
||||
private static final double E = 1.41428571428571436819e+00; /* 99/70 = 0x3FF6A0EA, 0x0EA0EA0F */
|
||||
private static final double F = 1.60714285714285720630e+00; /* 45/28 = 0x3FF9B6DB, 0x6DB6DB6E */
|
||||
private static final double G = 3.57142857142857150787e-01; /* 5/14 = 0x3FD6DB6D, 0xB6DB6DB7 */
|
||||
|
||||
public static strictfp double compute(double x) {
|
||||
int hx;
|
||||
double r, s, t=0.0, w;
|
||||
int sign; // unsigned
|
||||
|
||||
hx = __HI(x); // high word of x
|
||||
sign = hx & 0x80000000; // sign= sign(x)
|
||||
hx ^= sign;
|
||||
if (hx >= 0x7ff00000)
|
||||
return (x+x); // cbrt(NaN,INF) is itself
|
||||
if ((hx | __LO(x)) == 0)
|
||||
return(x); // cbrt(0) is itself
|
||||
|
||||
x = __HI(x, hx); // x <- |x|
|
||||
// rough cbrt to 5 bits
|
||||
if (hx < 0x00100000) { // subnormal number
|
||||
t = __HI(t, 0x43500000); // set t= 2**54
|
||||
t *= x;
|
||||
t = __HI(t, __HI(t)/3+B2);
|
||||
} else {
|
||||
t = __HI(t, hx/3+B1);
|
||||
}
|
||||
|
||||
// new cbrt to 23 bits, may be implemented in single precision
|
||||
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;
|
||||
|
||||
// retore the sign bit
|
||||
t = __HI(t, __HI(t) | sign);
|
||||
return(t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* hypot(x,y)
|
||||
*
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
* @key randomness
|
||||
* @summary Tests for StrictMath.hypot
|
||||
* @library /lib/testlibrary/
|
||||
* @build jdk.testlibrary.*
|
||||
* @build jdk.testlibrary.RandomFactory
|
||||
* @build Tests
|
||||
* @build FdlibmTranslit
|
||||
* @build HypotTests
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
# @build TestLibrary
|
||||
# @summary remove java.rmi.server.codebase property parsing from registyimpl
|
||||
# @run shell readTest.sh
|
||||
# @key intermittent
|
||||
|
||||
OS=`uname -s`
|
||||
VER=`uname -r`
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user