diff options
Diffstat (limited to 'libjava/classpath/external/jsr166/java/util')
70 files changed, 31674 insertions, 0 deletions
diff --git a/libjava/classpath/external/jsr166/java/util/AbstractQueue.java b/libjava/classpath/external/jsr166/java/util/AbstractQueue.java new file mode 100644 index 000000000..644df6c49 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/AbstractQueue.java @@ -0,0 +1,166 @@ +/* + * 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/licenses/publicdomain + */ + +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> + * 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. + * + * <p> A <tt>Queue</tt> 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 + * Queue#peek}, {@link Queue#poll}, {@link Collection#size}, and a + * {@link Collection#iterator} supporting {@link + * Iterator#remove}. Typically, additional methods will be overridden + * as well. If these requirements cannot be met, consider instead + * subclassing {@link AbstractCollection}. + * + * <p>This class is a member of the + * <a href="{@docRoot}/../technotes/guides/collections/index.html"> + * Java Collections Framework</a>. + * + * @since 1.5 + * @author Doug Lea + * @param <E> the type of elements held in this collection + */ +public abstract class AbstractQueue<E> + extends AbstractCollection<E> + implements Queue<E> { + + /** + * Constructor for use by subclasses. + */ + protected AbstractQueue() { + } + + /** + * 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> + * if no space is currently available. + * + * <p>This implementation returns <tt>true</tt> if <tt>offer</tt> succeeds, + * else throws an <tt>IllegalStateException</tt>. + * + * @param e the element to add + * @return <tt>true</tt> (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 + * prevents it from being added to this queue + * @throws NullPointerException if the specified element is null and + * this queue does not permit null elements + * @throws IllegalArgumentException if some property of this element + * prevents it from being added to this queue + */ + public boolean add(E e) { + if (offer(e)) + return true; + else + throw new IllegalStateException("Queue full"); + } + + /** + * Retrieves and removes the head of this queue. This method differs + * 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> + * unless the queue is empty. + * + * @return the head of this queue + * @throws NoSuchElementException if this queue is empty + */ + public E remove() { + E x = poll(); + if (x != null) + return x; + else + throw new NoSuchElementException(); + } + + /** + * Retrieves, but does not remove, the head of this queue. This method + * 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> + * unless the queue is empty. + * + * @return the head of this queue + * @throws NoSuchElementException if this queue is empty + */ + public E element() { + E x = peek(); + if (x != null) + return x; + else + throw new NoSuchElementException(); + } + + /** + * Removes all of the elements from this queue. + * The queue will be empty after this call returns. + * + * <p>This implementation repeatedly invokes {@link #poll poll} until it + * returns <tt>null</tt>. + */ + public void clear() { + while (poll() != null) + ; + } + + /** + * 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 + * this operation is undefined if the specified collection is + * modified while the operation is in progress. + * + * <p>This implementation iterates over the specified collection, + * 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 + * 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 + * @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 + * null element and this queue does not permit null elements, + * or if the specified collection is null + * @throws IllegalArgumentException if some property of an element of the + * specified collection prevents it from being added to this + * queue, or if the specified collection is this queue + * @throws IllegalStateException if not all the elements can be added at + * this time due to insertion restrictions + * @see #add(Object) + */ + public boolean addAll(Collection<? extends E> c) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + boolean modified = false; + Iterator<? extends E> e = c.iterator(); + while (e.hasNext()) { + if (add(e.next())) + modified = true; + } + return modified; + } + +} diff --git a/libjava/classpath/external/jsr166/java/util/ArrayDeque.java b/libjava/classpath/external/jsr166/java/util/ArrayDeque.java new file mode 100644 index 000000000..a4bc75c99 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/ArrayDeque.java @@ -0,0 +1,839 @@ +/* + * Written by Josh Bloch of Google Inc. and released to the public domain, + * as explained at http://creativecommons.org/licenses/publicdomain. + */ + +package java.util; +import java.io.*; + +/** + * Resizable-array implementation of the {@link Deque} interface. Array + * deques have no capacity restrictions; they grow as necessary to support + * usage. They are not thread-safe; in the absence of external + * synchronization, they do not support concurrent access by multiple threads. + * Null elements are prohibited. This class is likely to be faster than + * {@link Stack} when used as a stack, and faster than {@link LinkedList} + * when used as a queue. + * + * <p>Most <tt>ArrayDeque</tt> 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. + * + * <p>The iterators returned by this class's <tt>iterator</tt> 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 <tt>remove</tt> + * 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 + * future. + * + * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed + * as it is, generally speaking, impossible to make any hard guarantees in the + * presence of unsynchronized concurrent modification. Fail-fast iterators + * throw <tt>ConcurrentModificationException</tt> on a best-effort basis. + * Therefore, it would be wrong to write a program that depended on this + * exception for its correctness: <i>the fail-fast behavior of iterators + * should be used only to detect bugs.</i> + * + * <p>This class and its iterator implement all of the + * <em>optional</em> methods of the {@link Collection} and {@link + * Iterator} interfaces. + * + * <p>This class is a member of the + * <a href="{@docRoot}/../technotes/guides/collections/index.html"> + * Java Collections Framework</a>. + * + * @author Josh Bloch and Doug Lea + * @since 1.6 + * @param <E> the type of elements held in this collection + */ +public class ArrayDeque<E> extends AbstractCollection<E> + implements Deque<E>, Cloneable, Serializable +{ + /** + * The array in which the elements of the deque are stored. + * The capacity of the deque is the length of this array, which is + * always a power of two. The array is never allowed to become + * full, except transiently within an addX method where it is + * resized (see doubleCapacity) immediately upon becoming full, + * thus avoiding head and tail wrapping around to equal each + * other. We also guarantee that all array cells not holding + * deque elements are always null. + */ + private transient E[] elements; + + /** + * The index of the element at the head of the deque (which is the + * element that would be removed by remove() or pop()); or an + * arbitrary number equal to tail if the deque is empty. + */ + private transient int head; + + /** + * The index at which the next element would be added to the tail + * of the deque (via addLast(E), add(E), or push(E)). + */ + private transient int tail; + + /** + * The minimum capacity that we'll use for a newly created deque. + * Must be a power of 2. + */ + private static final int MIN_INITIAL_CAPACITY = 8; + + // ****** Array allocation and resizing utilities ****** + + /** + * Allocate empty array to hold the given number of elements. + * + * @param numElements the number of elements to hold + */ + private void allocateElements(int numElements) { + int initialCapacity = MIN_INITIAL_CAPACITY; + // Find the best power of two to hold elements. + // Tests "<=" because arrays aren't kept full. + if (numElements >= initialCapacity) { + initialCapacity = numElements; + initialCapacity |= (initialCapacity >>> 1); + initialCapacity |= (initialCapacity >>> 2); + initialCapacity |= (initialCapacity >>> 4); + initialCapacity |= (initialCapacity >>> 8); + initialCapacity |= (initialCapacity >>> 16); + initialCapacity++; + + if (initialCapacity < 0) // Too many elements, must back off + initialCapacity >>>= 1;// Good luck allocating 2 ^ 30 elements + } + elements = (E[]) new Object[initialCapacity]; + } + + /** + * Double the capacity of this deque. Call only when full, i.e., + * when head and tail have wrapped around to become equal. + */ + private void doubleCapacity() { + assert head == tail; + int p = head; + int n = elements.length; + int r = n - p; // number of elements to the right of p + int newCapacity = n << 1; + if (newCapacity < 0) + throw new IllegalStateException("Sorry, deque too big"); + Object[] a = new Object[newCapacity]; + System.arraycopy(elements, p, a, 0, r); + System.arraycopy(elements, 0, a, r, p); + elements = (E[])a; + head = 0; + 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. + */ + public ArrayDeque() { + elements = (E[]) new Object[16]; + } + + /** + * Constructs an empty array deque with an initial capacity + * sufficient to hold the specified number of elements. + * + * @param numElements lower bound on initial capacity of the deque + */ + public ArrayDeque(int numElements) { + allocateElements(numElements); + } + + /** + * Constructs a deque containing the elements of the specified + * collection, in the order they are returned by the collection's + * iterator. (The first element returned by the collection's + * iterator becomes the first element, or <i>front</i> of the + * deque.) + * + * @param c the collection whose elements are to be placed into the deque + * @throws NullPointerException if the specified collection is null + */ + public ArrayDeque(Collection<? extends E> c) { + allocateElements(c.size()); + addAll(c); + } + + // The main insertion and extraction methods are addFirst, + // addLast, pollFirst, pollLast. The other methods are defined in + // terms of these. + + /** + * Inserts the specified element at the front of this deque. + * + * @param e the element to add + * @throws NullPointerException if the specified element is null + */ + public void addFirst(E e) { + if (e == null) + throw new NullPointerException(); + elements[head = (head - 1) & (elements.length - 1)] = e; + if (head == tail) + doubleCapacity(); + } + + /** + * Inserts the specified element at the end of this deque. + * + * <p>This method is equivalent to {@link #add}. + * + * @param e the element to add + * @throws NullPointerException if the specified element is null + */ + public void addLast(E e) { + if (e == null) + throw new NullPointerException(); + elements[tail] = e; + if ( (tail = (tail + 1) & (elements.length - 1)) == head) + doubleCapacity(); + } + + /** + * Inserts the specified element at the front of this deque. + * + * @param e the element to add + * @return <tt>true</tt> (as specified by {@link Deque#offerFirst}) + * @throws NullPointerException if the specified element is null + */ + public boolean offerFirst(E e) { + addFirst(e); + return true; + } + + /** + * Inserts the specified element at the end of this deque. + * + * @param e the element to add + * @return <tt>true</tt> (as specified by {@link Deque#offerLast}) + * @throws NullPointerException if the specified element is null + */ + public boolean offerLast(E e) { + addLast(e); + return true; + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E removeFirst() { + E x = pollFirst(); + if (x == null) + throw new NoSuchElementException(); + return x; + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E removeLast() { + E x = pollLast(); + if (x == null) + throw new NoSuchElementException(); + return x; + } + + public E pollFirst() { + int h = head; + E result = 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); + return result; + } + + public E pollLast() { + int t = (tail - 1) & (elements.length - 1); + E result = elements[t]; + if (result == null) + return null; + elements[t] = null; + tail = t; + return result; + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E getFirst() { + E x = elements[head]; + if (x == null) + throw new NoSuchElementException(); + return x; + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E getLast() { + E x = elements[(tail - 1) & (elements.length - 1)]; + if (x == null) + throw new NoSuchElementException(); + return x; + } + + public E peekFirst() { + return elements[head]; // elements[head] is null if deque empty + } + + public E peekLast() { + return elements[(tail - 1) & (elements.length - 1)]; + } + + /** + * Removes the first occurrence of the specified element in this + * deque (when traversing the deque from head to tail). + * If the deque does not contain the element, it is unchanged. + * More formally, removes the first element <tt>e</tt> such that + * <tt>o.equals(e)</tt> (if such an element exists). + * Returns <tt>true</tt> 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 <tt>true</tt> 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; + E x; + while ( (x = elements[i]) != null) { + if (o.equals(x)) { + delete(i); + return true; + } + i = (i + 1) & mask; + } + return false; + } + + /** + * Removes the last occurrence of the specified element in this + * deque (when traversing the deque from head to tail). + * If the deque does not contain the element, it is unchanged. + * More formally, removes the last element <tt>e</tt> such that + * <tt>o.equals(e)</tt> (if such an element exists). + * Returns <tt>true</tt> 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 <tt>true</tt> 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; + E x; + while ( (x = elements[i]) != null) { + if (o.equals(x)) { + delete(i); + return true; + } + i = (i - 1) & mask; + } + return false; + } + + // *** Queue methods *** + + /** + * Inserts the specified element at the end of this deque. + * + * <p>This method is equivalent to {@link #addLast}. + * + * @param e the element to add + * @return <tt>true</tt> (as specified by {@link Collection#add}) + * @throws NullPointerException if the specified element is null + */ + public boolean add(E e) { + addLast(e); + return true; + } + + /** + * Inserts the specified element at the end of this deque. + * + * <p>This method is equivalent to {@link #offerLast}. + * + * @param e the element to add + * @return <tt>true</tt> (as specified by {@link Queue#offer}) + * @throws NullPointerException if the specified element is null + */ + public boolean offer(E e) { + return offerLast(e); + } + + /** + * Retrieves and removes the head of the queue represented by this deque. + * + * This method differs from {@link #poll poll} only in that it throws an + * exception if this deque is empty. + * + * <p>This method is equivalent to {@link #removeFirst}. + * + * @return the head of the queue represented by this deque + * @throws NoSuchElementException {@inheritDoc} + */ + public E remove() { + return removeFirst(); + } + + /** + * Retrieves and removes the head of the queue represented by this deque + * (in other words, the first element of this deque), or returns + * <tt>null</tt> if this deque is empty. + * + * <p>This method is equivalent to {@link #pollFirst}. + * + * @return the head of the queue represented by this deque, or + * <tt>null</tt> if this deque is empty + */ + public E poll() { + return pollFirst(); + } + + /** + * Retrieves, but does not remove, the head of the queue represented by + * this deque. This method differs from {@link #peek peek} only in + * that it throws an exception if this deque is empty. + * + * <p>This method is equivalent to {@link #getFirst}. + * + * @return the head of the queue represented by this deque + * @throws NoSuchElementException {@inheritDoc} + */ + public E element() { + return getFirst(); + } + + /** + * Retrieves, but does not remove, the head of the queue represented by + * this deque, or returns <tt>null</tt> if this deque is empty. + * + * <p>This method is equivalent to {@link #peekFirst}. + * + * @return the head of the queue represented by this deque, or + * <tt>null</tt> if this deque is empty + */ + public E peek() { + return peekFirst(); + } + + // *** Stack methods *** + + /** + * Pushes an element onto the stack represented by this deque. In other + * words, inserts the element at the front of this deque. + * + * <p>This method is equivalent to {@link #addFirst}. + * + * @param e the element to push + * @throws NullPointerException if the specified element is null + */ + public void push(E e) { + addFirst(e); + } + + /** + * Pops an element from the stack represented by this deque. In other + * words, removes and returns the first element of this deque. + * + * <p>This method is equivalent to {@link #removeFirst()}. + * + * @return the element at the front of this deque (which is the top + * of the stack represented by this deque) + * @throws NoSuchElementException {@inheritDoc} + */ + public E pop() { + return removeFirst(); + } + + private void checkInvariants() { + assert elements[tail] == null; + assert head == tail ? elements[head] == null : + (elements[head] != null && + elements[(tail - 1) & (elements.length - 1)] != null); + assert elements[(head - 1) & (elements.length - 1)] == null; + } + + /** + * Removes the element at the specified position in the elements array, + * adjusting head and tail as necessary. This can result in motion of + * elements backwards or forwards in the array. + * + * <p>This method is called delete rather than remove to emphasize + * that its semantics differ from those of {@link List#remove(int)}. + * + * @return true if elements moved backwards + */ + private boolean delete(int i) { + checkInvariants(); + final E[] elements = this.elements; + final int mask = elements.length - 1; + final int h = head; + final int t = tail; + final int front = (i - h) & mask; + final int back = (t - i) & mask; + + // Invariant: head <= i < tail mod circularity + if (front >= ((t - h) & mask)) + throw new ConcurrentModificationException(); + + // Optimize for least element motion + if (front < back) { + if (h <= i) { + System.arraycopy(elements, h, elements, h + 1, front); + } else { // Wrap around + System.arraycopy(elements, 0, elements, 1, i); + elements[0] = elements[mask]; + System.arraycopy(elements, h, elements, h + 1, mask - h); + } + elements[h] = null; + head = (h + 1) & mask; + return false; + } else { + if (i < t) { // Copy the null tail as well + System.arraycopy(elements, i + 1, elements, i, back); + tail = t - 1; + } else { // Wrap around + System.arraycopy(elements, i + 1, elements, i, mask - i); + elements[mask] = elements[0]; + System.arraycopy(elements, 1, elements, 0, t); + tail = (t - 1) & mask; + } + return true; + } + } + + // *** Collection Methods *** + + /** + * Returns the number of elements in this deque. + * + * @return the number of elements in this deque + */ + public int size() { + return (tail - head) & (elements.length - 1); + } + + /** + * Returns <tt>true</tt> if this deque contains no elements. + * + * @return <tt>true</tt> if this deque contains no elements + */ + public boolean isEmpty() { + return head == tail; + } + + /** + * Returns an iterator over the elements in this deque. The elements + * will be ordered from first (head) to last (tail). This is the same + * order that elements would be dequeued (via successive calls to + * {@link #remove} or popped (via successive calls to {@link #pop}). + * + * @return an iterator over the elements in this deque + */ + public Iterator<E> iterator() { + return new DeqIterator(); + } + + public Iterator<E> descendingIterator() { + return new DescendingIterator(); + } + + private class DeqIterator implements Iterator<E> { + /** + * Index of element to be returned by subsequent call to next. + */ + private int cursor = head; + + /** + * Tail recorded at construction (also in remove), to stop + * iterator and also to check for comodification. + */ + private int fence = tail; + + /** + * Index of element returned by most recent call to next. + * Reset to -1 if element is deleted by a call to remove. + */ + private int lastRet = -1; + + public boolean hasNext() { + return cursor != fence; + } + + public E next() { + if (cursor == fence) + throw new NoSuchElementException(); + E result = elements[cursor]; + // This check doesn't catch all possible comodifications, + // but does catch the ones that corrupt traversal + if (tail != fence || result == null) + throw new ConcurrentModificationException(); + lastRet = cursor; + cursor = (cursor + 1) & (elements.length - 1); + return result; + } + + public void remove() { + if (lastRet < 0) + throw new IllegalStateException(); + if (delete(lastRet)) { // if left-shifted, undo increment in next() + cursor = (cursor - 1) & (elements.length - 1); + fence = tail; + } + lastRet = -1; + } + } + + 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; + + public boolean hasNext() { + return cursor != fence; + } + + public E next() { + if (cursor == fence) + throw new NoSuchElementException(); + cursor = (cursor - 1) & (elements.length - 1); + E result = elements[cursor]; + if (head != fence || result == null) + throw new ConcurrentModificationException(); + lastRet = cursor; + return result; + } + + public void remove() { + if (lastRet < 0) + throw new IllegalStateException(); + if (!delete(lastRet)) { + cursor = (cursor + 1) & (elements.length - 1); + fence = head; + } + lastRet = -1; + } + } + + /** + * Returns <tt>true</tt> if this deque contains the specified element. + * More formally, returns <tt>true</tt> if and only if this deque contains + * at least one element <tt>e</tt> such that <tt>o.equals(e)</tt>. + * + * @param o object to be checked for containment in this deque + * @return <tt>true</tt> 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; + E x; + while ( (x = elements[i]) != null) { + if (o.equals(x)) + return true; + i = (i + 1) & mask; + } + return false; + } + + /** + * Removes a single instance of the specified element from this deque. + * If the deque does not contain the element, it is unchanged. + * More formally, removes the first element <tt>e</tt> such that + * <tt>o.equals(e)</tt> (if such an element exists). + * Returns <tt>true</tt> 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}. + * + * @param o element to be removed from this deque, if present + * @return <tt>true</tt> if this deque contained the specified element + */ + public boolean remove(Object o) { + return removeFirstOccurrence(o); + } + + /** + * Removes all of the elements from this deque. + * The deque will be empty after this call returns. + */ + public void clear() { + int h = head; + int t = tail; + if (h != t) { // clear all cells + head = tail = 0; + int i = h; + int mask = elements.length - 1; + do { + elements[i] = null; + i = (i + 1) & mask; + } while (i != t); + } + } + + /** + * Returns an array containing all of the elements in this deque + * in proper sequence (from first to last element). + * + * <p>The returned array will be "safe" in that no references to it are + * maintained by this deque. (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 deque + */ + public Object[] toArray() { + return copyElements(new Object[size()]); + } + + /** + * Returns an array containing all of the elements in this deque in + * proper sequence (from first to last element); the runtime type of the + * returned array is that of the specified array. If the deque 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 deque. + * + * <p>If this deque fits in the specified array with room to spare + * (i.e., the array has more elements than this deque), the element in + * the array immediately following the end of the deque is set to + * <tt>null</tt>. + * + * <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 <tt>x</tt> is a deque known to contain only strings. + * The following code can be used to dump the deque into a newly + * allocated array of <tt>String</tt>: + * + * <pre> + * String[] y = x.toArray(new String[0]);</pre> + * + * Note that <tt>toArray(new Object[0])</tt> is identical in function to + * <tt>toArray()</tt>. + * + * @param a the array into which the elements of the deque 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 deque + * @throws ArrayStoreException if the runtime type of the specified array + * is not a supertype of the runtime type of every element in + * this deque + * @throws NullPointerException if the specified array is null + */ + 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; + return a; + } + + // *** Object methods *** + + /** + * Returns a copy of this deque. + * + * @return a copy of this deque + */ + public ArrayDeque<E> clone() { + try { + ArrayDeque<E> result = (ArrayDeque<E>) super.clone(); + // Classpath local: we don't have Arrays.copyOf yet. + // result.elements = Arrays.copyOf(elements, elements.length); + result.elements = (E[]) elements.clone(); + return result; + + } catch (CloneNotSupportedException e) { + throw new AssertionError(); + } + } + + /** + * Appease the serialization gods. + */ + private static final long serialVersionUID = 2340985798034038923L; + + /** + * Serialize this deque. + * + * @serialData The current size (<tt>int</tt>) of the deque, + * followed by all of its elements (each an object reference) in + * first-to-last order. + */ + private void writeObject(ObjectOutputStream s) throws IOException { + s.defaultWriteObject(); + + // Write out size + s.writeInt(size()); + + // Write out elements in order. + int mask = elements.length - 1; + for (int i = head; i != tail; i = (i + 1) & mask) + s.writeObject(elements[i]); + } + + /** + * Deserialize this deque. + */ + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException { + s.defaultReadObject(); + + // Read in size and allocate array + int size = s.readInt(); + allocateElements(size); + head = 0; + tail = size; + + // Read in all elements in the proper order. + for (int i = 0; i < size; i++) + elements[i] = (E)s.readObject(); + } +} diff --git a/libjava/classpath/external/jsr166/java/util/Deque.java b/libjava/classpath/external/jsr166/java/util/Deque.java new file mode 100644 index 000000000..a769561dc --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/Deque.java @@ -0,0 +1,547 @@ +/* + * Written by Doug Lea and Josh Bloch with assistance from members of + * JCP JSR-166 Expert Group and released to the public domain, as explained + * at http://creativecommons.org/licenses/publicdomain + */ + +package java.util; + +/** + * A linear collection that supports element insertion and removal at + * both ends. The name <i>deque</i> is short for "double ended queue" + * and is usually pronounced "deck". Most <tt>Deque</tt> + * implementations place no fixed limits on the number of elements + * they may contain, but this interface supports capacity-restricted + * deques as well as those with no fixed size limit. + * + * <p>This interface defines methods to access the elements at both + * ends of the deque. Methods are provided to insert, remove, and + * examine the element. Each of these methods exists in two forms: + * one throws an exception if the operation fails, the other returns a + * special value (either <tt>null</tt> or <tt>false</tt>, depending on + * the operation). The latter form of the insert operation is + * designed specifically for use with capacity-restricted + * <tt>Deque</tt> implementations; in most implementations, insert + * operations cannot fail. + * + * <p>The twelve methods described above are summarized in the + * following table: + * + * <p> + * <table BORDER CELLPADDING=3 CELLSPACING=1> + * <tr> + * <td></td> + * <td ALIGN=CENTER COLSPAN = 2> <b>First Element (Head)</b></td> + * <td ALIGN=CENTER COLSPAN = 2> <b>Last Element (Tail)</b></td> + * </tr> + * <tr> + * <td></td> + * <td ALIGN=CENTER><em>Throws exception</em></td> + * <td ALIGN=CENTER><em>Special value</em></td> + * <td ALIGN=CENTER><em>Throws exception</em></td> + * <td ALIGN=CENTER><em>Special value</em></td> + * </tr> + * <tr> + * <td><b>Insert</b></td> + * <td>{@link #addFirst addFirst(e)}</td> + * <td>{@link #offerFirst offerFirst(e)}</td> + * <td>{@link #addLast addLast(e)}</td> + * <td>{@link #offerLast offerLast(e)}</td> + * </tr> + * <tr> + * <td><b>Remove</b></td> + * <td>{@link #removeFirst removeFirst()}</td> + * <td>{@link #pollFirst pollFirst()}</td> + * <td>{@link #removeLast removeLast()}</td> + * <td>{@link #pollLast pollLast()}</td> + * </tr> + * <tr> + * <td><b>Examine</b></td> + * <td>{@link #getFirst getFirst()}</td> + * <td>{@link #peekFirst peekFirst()}</td> + * <td>{@link #getLast getLast()}</td> + * <td>{@link #peekLast peekLast()}</td> + * </tr> + * </table> + * + * <p>This interface extends the {@link Queue} interface. When a deque is + * used as a queue, FIFO (First-In-First-Out) behavior results. Elements are + * added at the end of the deque and removed from the beginning. The methods + * inherited from the <tt>Queue</tt> interface are precisely equivalent to + * <tt>Deque</tt> methods as indicated in the following table: + * + * <p> + * <table BORDER CELLPADDING=3 CELLSPACING=1> + * <tr> + * <td ALIGN=CENTER> <b><tt>Queue</tt> Method</b></td> + * <td ALIGN=CENTER> <b>Equivalent <tt>Deque</tt> Method</b></td> + * </tr> + * <tr> + * <td>{@link java.util.Queue#add add(e)}</td> + * <td>{@link #addLast addLast(e)}</td> + * </tr> + * <tr> + * <td>{@link java.util.Queue#offer offer(e)}</td> + * <td>{@link #offerLast offerLast(e)}</td> + * </tr> + * <tr> + * <td>{@link java.util.Queue#remove remove()}</td> + * <td>{@link #removeFirst removeFirst()}</td> + * </tr> + * <tr> + * <td>{@link java.util.Queue#poll poll()}</td> + * <td>{@link #pollFirst pollFirst()}</td> + * </tr> + * <tr> + * <td>{@link java.util.Queue#element element()}</td> + * <td>{@link #getFirst getFirst()}</td> + * </tr> + * <tr> + * <td>{@link java.util.Queue#peek peek()}</td> + * <td>{@link #peek peekFirst()}</td> + * </tr> + * </table> + * + * <p>Deques can also be used as LIFO (Last-In-First-Out) stacks. This + * interface should be used in preference to the legacy {@link Stack} class. + * When a deque is used as a stack, elements are pushed and popped from the + * beginning of the deque. Stack methods are precisely equivalent to + * <tt>Deque</tt> methods as indicated in the table below: + * + * <p> + * <table BORDER CELLPADDING=3 CELLSPACING=1> + * <tr> + * <td ALIGN=CENTER> <b>Stack Method</b></td> + * <td ALIGN=CENTER> <b>Equivalent <tt>Deque</tt> Method</b></td> + * </tr> + * <tr> + * <td>{@link #push push(e)}</td> + * <td>{@link #addFirst addFirst(e)}</td> + * </tr> + * <tr> + * <td>{@link #pop pop()}</td> + * <td>{@link #removeFirst removeFirst()}</td> + * </tr> + * <tr> + * <td>{@link #peek peek()}</td> + * <td>{@link #peekFirst peekFirst()}</td> + * </tr> + * </table> + * + * <p>Note that the {@link #peek peek} method works equally well when + * a deque is used as a queue or a stack; in either case, elements are + * drawn from the beginning of the deque. + * + * <p>This interface provides two methods to remove interior + * elements, {@link #removeFirstOccurrence removeFirstOccurrence} and + * {@link #removeLastOccurrence removeLastOccurrence}. + * + * <p>Unlike the {@link List} interface, this interface does not + * provide support for indexed access to elements. + * + * <p>While <tt>Deque</tt> implementations are not strictly required + * to prohibit the insertion of null elements, they are strongly + * encouraged to do so. Users of any <tt>Deque</tt> implementations + * that do allow null elements are strongly encouraged <i>not</i> to + * take advantage of the ability to insert nulls. This is so because + * <tt>null</tt> is used as a special return value by various methods + * to indicated that the deque is empty. + * + * <p><tt>Deque</tt> implementations generally do not define + * element-based versions of the <tt>equals</tt> and <tt>hashCode</tt> + * methods, but instead inherit the identity-based versions from class + * <tt>Object</tt>. + * + * <p>This interface is a member of the <a + * href="{@docRoot}/../technotes/guides/collections/index.html"> Java Collections + * Framework</a>. + * + * @author Doug Lea + * @author Josh Bloch + * @since 1.6 + * @param <E> the type of elements held in this collection + */ + +public interface Deque<E> extends Queue<E> { + /** + * Inserts the specified element at the front of this deque if it is + * possible to do so immediately without violating capacity restrictions. + * When using a capacity-restricted deque, it is generally preferable to + * use method {@link #offerFirst}. + * + * @param e the element to 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 + * prevents it from being added to this deque + * @throws NullPointerException if the specified element is null and this + * deque does not permit null elements + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this deque + */ + void addFirst(E e); + + /** + * Inserts the specified element at the end of this deque if it is + * possible to do so immediately without violating capacity restrictions. + * When using a capacity-restricted deque, it is generally preferable to + * use method {@link #offerLast}. + * + * <p>This method is equivalent to {@link #add}. + * + * @param e the element to 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 + * prevents it from being added to this deque + * @throws NullPointerException if the specified element is null and this + * deque does not permit null elements + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this deque + */ + void addLast(E e); + + /** + * Inserts the specified element at the front of this deque unless it would + * violate capacity restrictions. When using a capacity-restricted deque, + * this method is generally preferable to the {@link #addFirst} method, + * which can fail to insert an element only by throwing an exception. + * + * @param e the element to add + * @return <tt>true</tt> if the element was added to this deque, else + * <tt>false</tt> + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this deque + * @throws NullPointerException if the specified element is null and this + * deque does not permit null elements + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this deque + */ + boolean offerFirst(E e); + + /** + * Inserts the specified element at the end of this deque unless it would + * violate capacity restrictions. When using a capacity-restricted deque, + * this method is generally preferable to the {@link #addLast} method, + * which can fail to insert an element only by throwing an exception. + * + * @param e the element to add + * @return <tt>true</tt> if the element was added to this deque, else + * <tt>false</tt> + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this deque + * @throws NullPointerException if the specified element is null and this + * deque does not permit null elements + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this deque + */ + boolean offerLast(E e); + + /** + * Retrieves and removes the first element of this deque. This method + * differs from {@link #pollFirst pollFirst} only in that it throws an + * exception if this deque is empty. + * + * @return the head of this deque + * @throws NoSuchElementException if this deque is empty + */ + E removeFirst(); + + /** + * Retrieves and removes the last element of this deque. This method + * differs from {@link #pollLast pollLast} only in that it throws an + * exception if this deque is empty. + * + * @return the tail of this deque + * @throws NoSuchElementException if this deque is empty + */ + E removeLast(); + + /** + * Retrieves and removes the first element of this deque, + * or returns <tt>null</tt> if this deque is empty. + * + * @return the head of this deque, or <tt>null</tt> if this deque is empty + */ + E pollFirst(); + + /** + * Retrieves and removes the last element of this deque, + * or returns <tt>null</tt> if this deque is empty. + * + * @return the tail of this deque, or <tt>null</tt> if this deque is empty + */ + E pollLast(); + + /** + * Retrieves, but does not remove, the first element of this deque. + * + * This method differs from {@link #peekFirst peekFirst} only in that it + * throws an exception if this deque is empty. + * + * @return the head of this deque + * @throws NoSuchElementException if this deque is empty + */ + E getFirst(); + + /** + * Retrieves, but does not remove, the last element of this deque. + * This method differs from {@link #peekLast peekLast} only in that it + * throws an exception if this deque is empty. + * + * @return the tail of this deque + * @throws NoSuchElementException if this deque is empty + */ + E getLast(); + + /** + * Retrieves, but does not remove, the first element of this deque, + * or returns <tt>null</tt> if this deque is empty. + * + * @return the head of this deque, or <tt>null</tt> if this deque is empty + */ + E peekFirst(); + + /** + * Retrieves, but does not remove, the last element of this deque, + * or returns <tt>null</tt> if this deque is empty. + * + * @return the tail of this deque, or <tt>null</tt> if this deque is empty + */ + E peekLast(); + + /** + * 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 <tt>e</tt> such that + * <tt>(o==null ? e==null : o.equals(e))</tt> + * (if such an element exists). + * Returns <tt>true</tt> 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 <tt>true</tt> 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 (optional) + * @throws NullPointerException if the specified element is null and this + * deque does not permit null elements (optional) + */ + boolean removeFirstOccurrence(Object o); + + /** + * 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 <tt>e</tt> such that + * <tt>(o==null ? e==null : o.equals(e))</tt> + * (if such an element exists). + * Returns <tt>true</tt> 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 <tt>true</tt> 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 (optional) + * @throws NullPointerException if the specified element is null and this + * deque does not permit null elements (optional) + */ + boolean removeLastOccurrence(Object o); + + // *** Queue methods *** + + /** + * Inserts the specified element into the queue represented by this deque + * (in other words, at the tail of this deque) if it is possible to do so + * immediately without violating capacity restrictions, returning + * <tt>true</tt> upon success and throwing an + * <tt>IllegalStateException</tt> if no space is currently available. + * When using a capacity-restricted deque, it is generally preferable to + * use {@link #offer(Object) offer}. + * + * <p>This method is equivalent to {@link #addLast}. + * + * @param e the element to add + * @return <tt>true</tt> (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 + * prevents it from being added to this deque + * @throws NullPointerException if the specified element is null and this + * deque does not permit null elements + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this deque + */ + boolean add(E e); + + /** + * Inserts the specified element into the queue represented by this deque + * (in other words, at the tail of this deque) if it is possible to do so + * immediately without violating capacity restrictions, returning + * <tt>true</tt> upon success and <tt>false</tt> if no space is currently + * available. When using a capacity-restricted deque, this method is + * generally preferable to the {@link #add} method, which can fail to + * insert an element only by throwing an exception. + * + * <p>This method is equivalent to {@link #offerLast}. + * + * @param e the element to add + * @return <tt>true</tt> if the element was added to this deque, else + * <tt>false</tt> + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this deque + * @throws NullPointerException if the specified element is null and this + * deque does not permit null elements + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this deque + */ + boolean offer(E e); + + /** + * Retrieves and removes the head of the queue represented by this deque + * (in other words, the first element of this deque). + * This method differs from {@link #poll poll} only in that it throws an + * exception if this deque is empty. + * + * <p>This method is equivalent to {@link #removeFirst()}. + * + * @return the head of the queue represented by this deque + * @throws NoSuchElementException if this deque is empty + */ + E remove(); + + /** + * Retrieves and removes the head of the queue represented by this deque + * (in other words, the first element of this deque), or returns + * <tt>null</tt> if this deque is empty. + * + * <p>This method is equivalent to {@link #pollFirst()}. + * + * @return the first element of this deque, or <tt>null</tt> if + * this deque is empty + */ + E poll(); + + /** + * Retrieves, but does not remove, the head of the queue represented by + * this deque (in other words, the first element of this deque). + * This method differs from {@link #peek peek} only in that it throws an + * exception if this deque is empty. + * + * <p>This method is equivalent to {@link #getFirst()}. + * + * @return the head of the queue represented by this deque + * @throws NoSuchElementException if this deque is empty + */ + E element(); + + /** + * Retrieves, but does not remove, the head of the queue represented by + * this deque (in other words, the first element of this deque), or + * returns <tt>null</tt> if this deque is empty. + * + * <p>This method is equivalent to {@link #peekFirst()}. + * + * @return the head of the queue represented by this deque, or + * <tt>null</tt> if this deque is empty + */ + E peek(); + + + // *** Stack methods *** + + /** + * Pushes an element onto the stack represented by this deque (in other + * words, at the head of this deque) if it is possible to do so + * immediately without violating capacity restrictions, returning + * <tt>true</tt> upon success and throwing an + * <tt>IllegalStateException</tt> if no space is currently available. + * + * <p>This method is equivalent to {@link #addFirst}. + * + * @param e the element to push + * @throws IllegalStateException if the element cannot be added at this + * time due to capacity restrictions + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this deque + * @throws NullPointerException if the specified element is null and this + * deque does not permit null elements + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this deque + */ + void push(E e); + + /** + * Pops an element from the stack represented by this deque. In other + * words, removes and returns the first element of this deque. + * + * <p>This method is equivalent to {@link #removeFirst()}. + * + * @return the element at the front of this deque (which is the top + * of the stack represented by this deque) + * @throws NoSuchElementException if this deque is empty + */ + E pop(); + + + // *** Collection methods *** + + /** + * 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 <tt>e</tt> such that + * <tt>(o==null ? e==null : o.equals(e))</tt> + * (if such an element exists). + * Returns <tt>true</tt> 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}. + * + * @param o element to be removed from this deque, if present + * @return <tt>true</tt> 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 (optional) + * @throws NullPointerException if the specified element is null and this + * deque does not permit null elements (optional) + */ + boolean remove(Object o); + + /** + * Returns <tt>true</tt> if this deque contains the specified element. + * More formally, returns <tt>true</tt> if and only if this deque contains + * at least one element <tt>e</tt> such that + * <tt>(o==null ? e==null : o.equals(e))</tt>. + * + * @param o element whose presence in this deque is to be tested + * @return <tt>true</tt> if this deque contains the specified element + * @throws ClassCastException if the type of the specified element + * is incompatible with this deque (optional) + * @throws NullPointerException if the specified element is null and this + * deque does not permit null elements (optional) + */ + boolean contains(Object o); + + /** + * Returns the number of elements in this deque. + * + * @return the number of elements in this deque + */ + public int size(); + + /** + * Returns an iterator over the elements in this deque in proper sequence. + * The elements will be returned in order from first (head) to last (tail). + * + * @return an iterator over the elements in this deque in proper sequence + */ + Iterator<E> iterator(); + + /** + * Returns an iterator over the elements in this deque in reverse + * sequential order. The elements will be returned in order from + * last (tail) to first (head). + * + * @return an iterator over the elements in this deque in reverse + * sequence + */ + Iterator<E> descendingIterator(); + +} diff --git a/libjava/classpath/external/jsr166/java/util/NavigableMap.java b/libjava/classpath/external/jsr166/java/util/NavigableMap.java new file mode 100644 index 000000000..a55f84bdd --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/NavigableMap.java @@ -0,0 +1,395 @@ +/* + * Written by Doug Lea and Josh Bloch with assistance from members of JCP + * JSR-166 Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +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 + * 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 + * 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} + * 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. + * + * <p>This interface additionally defines methods {@code firstEntry}, + * {@code pollFirstEntry}, {@code lastEntry}, and + * {@code 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 + * return {@code Map.Entry} pairs representing snapshots of mappings + * at the time they were produced, and thus generally do <em>not</em> + * support the optional {@code Entry.setValue} method. Note however + * that it is possible to change mappings in the associated map using + * method {@code put}. + * + * <p>Methods + * {@link #subMap(Object, Object) subMap(K, K)}, + * {@link #headMap(Object) headMap(K)}, and + * {@link #tailMap(Object) tailMap(K)} + * are specified to return {@code SortedMap} to allow existing + * implementations of {@code SortedMap} to be compatibly retrofitted to + * 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}. + * + * <p>This interface is a member of the + * <a href="{@docRoot}/../technotes/guides/collections/index.html"> + * Java Collections Framework</a>. + * + * @author Doug Lea + * @author Josh Bloch + * @param <K> the type of keys maintained by this map + * @param <V> the type of mapped values + * @since 1.6 + */ +public interface NavigableMap<K,V> extends SortedMap<K,V> { + /** + * Returns a key-value mapping associated with the greatest key + * strictly less than the given key, or {@code null} if there is + * no such key. + * + * @param key the key + * @return an entry with the greatest key less than {@code key}, + * or {@code null} if there is no such key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + * and this map does not permit null keys + */ + Map.Entry<K,V> lowerEntry(K key); + + /** + * Returns the greatest key strictly less than the given key, or + * {@code null} if there is no such key. + * + * @param key the key + * @return the greatest key less than {@code key}, + * or {@code null} if there is no such key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + * and this map does not permit null keys + */ + K lowerKey(K key); + + /** + * Returns a key-value mapping associated with the greatest key + * less than or equal to the given key, or {@code null} if there + * is no such key. + * + * @param key the key + * @return an entry with the greatest key less than or equal to + * {@code key}, or {@code null} if there is no such key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + * and this map does not permit null keys + */ + Map.Entry<K,V> floorEntry(K key); + + /** + * Returns the greatest key less than or equal to the given key, + * or {@code null} if there is no such key. + * + * @param key the key + * @return the greatest key less than or equal to {@code key}, + * or {@code null} if there is no such key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + * and this map does not permit null keys + */ + K floorKey(K key); + + /** + * Returns a key-value mapping associated with the least key + * greater than or equal to the given key, or {@code null} if + * there is no such key. + * + * @param key the key + * @return an entry with the least key greater than or equal to + * {@code key}, or {@code null} if there is no such key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + * and this map does not permit null keys + */ + Map.Entry<K,V> ceilingEntry(K key); + + /** + * Returns the least key greater than or equal to the given key, + * or {@code null} if there is no such key. + * + * @param key the key + * @return the least key greater than or equal to {@code key}, + * or {@code null} if there is no such key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + * and this map does not permit null keys + */ + K ceilingKey(K key); + + /** + * Returns a key-value mapping associated with the least key + * strictly greater than the given key, or {@code null} if there + * is no such key. + * + * @param key the key + * @return an entry with the least key greater than {@code key}, + * or {@code null} if there is no such key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + * and this map does not permit null keys + */ + Map.Entry<K,V> higherEntry(K key); + + /** + * Returns the least key strictly greater than the given key, or + * {@code null} if there is no such key. + * + * @param key the key + * @return the least key greater than {@code key}, + * or {@code null} if there is no such key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + * and this map does not permit null keys + */ + K higherKey(K key); + + /** + * Returns a key-value mapping associated with the least + * key in this map, or {@code null} if the map is empty. + * + * @return an entry with the least key, + * or {@code null} if this map is empty + */ + Map.Entry<K,V> firstEntry(); + + /** + * Returns a key-value mapping associated with the greatest + * key in this map, or {@code null} if the map is empty. + * + * @return an entry with the greatest key, + * or {@code null} if this map is empty + */ + Map.Entry<K,V> lastEntry(); + + /** + * Removes and returns a key-value mapping associated with + * the least key in this map, or {@code null} if the map is empty. + * + * @return the removed first entry of this map, + * or {@code null} if this map is empty + */ + Map.Entry<K,V> pollFirstEntry(); + + /** + * Removes and returns a key-value mapping associated with + * the greatest key in this map, or {@code null} if the map is empty. + * + * @return the removed last entry of this map, + * or {@code null} if this map is empty + */ + Map.Entry<K,V> pollLastEntry(); + + /** + * Returns a reverse order view of the mappings contained in this map. + * The descending map is backed by this map, so changes to the map are + * reflected in the descending map, and vice-versa. If either map is + * modified while an iteration over a collection view of either map + * is in progress (except through the iterator's own {@code remove} + * 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>. + * The expression {@code m.descendingMap().descendingMap()} returns a + * view of {@code m} essentially equivalent to {@code m}. + * + * @return a reverse order view of this map + */ + NavigableMap<K,V> descendingMap(); + + /** + * Returns a {@link NavigableSet} view of the keys contained in this map. + * The set's iterator returns the keys in ascending order. + * The set is backed by the map, so changes to the map are reflected in + * the set, and vice-versa. If the map is modified while an iteration + * over the set is in progress (except through the iterator's own {@code + * remove} operation), the results of the iteration are undefined. The + * set supports element removal, which removes the corresponding mapping + * from the map, via the {@code Iterator.remove}, {@code Set.remove}, + * {@code removeAll}, {@code retainAll}, and {@code clear} operations. + * It does not support the {@code add} or {@code addAll} operations. + * + * @return a navigable set view of the keys in this map + */ + NavigableSet<K> navigableKeySet(); + + /** + * Returns a reverse order {@link NavigableSet} view of the keys contained in this map. + * The set's iterator returns the keys in descending order. + * The set is backed by the map, so changes to the map are reflected in + * the set, and vice-versa. If the map is modified while an iteration + * over the set is in progress (except through the iterator's own {@code + * remove} operation), the results of the iteration are undefined. The + * set supports element removal, which removes the corresponding mapping + * from the map, via the {@code Iterator.remove}, {@code Set.remove}, + * {@code removeAll}, {@code retainAll}, and {@code clear} operations. + * It does not support the {@code add} or {@code addAll} operations. + * + * @return a reverse order navigable set view of the keys in this map + */ + NavigableSet<K> descendingKeySet(); + + /** + * Returns a view of the portion of this map whose keys range from + * {@code fromKey} to {@code toKey}. If {@code fromKey} and + * {@code toKey} are equal, the returned map is empty unless + * {@code fromExclusive} and {@code toExclusive} are both true. The + * returned map is backed by this map, so changes in the returned map are + * reflected in this map, and vice-versa. The returned map supports all + * optional map operations that this map supports. + * + * <p>The returned map will throw an {@code IllegalArgumentException} + * on an attempt to insert a key outside of its range, or to construct a + * submap either of whose endpoints lie outside its range. + * + * @param fromKey low endpoint of the keys in the returned map + * @param fromInclusive {@code true} if the low endpoint + * is to be included in the returned view + * @param toKey high endpoint of the keys in the returned map + * @param toInclusive {@code true} if the high endpoint + * is to be included in the returned view + * @return a view of the portion of this map whose keys range from + * {@code fromKey} to {@code toKey} + * @throws ClassCastException if {@code fromKey} and {@code toKey} + * cannot be compared to one another using this map's comparator + * (or, if the map has no comparator, using natural ordering). + * Implementations may, but are not required to, throw this + * exception if {@code fromKey} or {@code toKey} + * cannot be compared to keys currently in the map. + * @throws NullPointerException if {@code fromKey} or {@code toKey} + * is null and this map does not permit null keys + * @throws IllegalArgumentException if {@code fromKey} is greater than + * {@code toKey}; or if this map itself has a restricted + * range, and {@code fromKey} or {@code toKey} lies + * outside the bounds of the range + */ + NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive, + K toKey, boolean toInclusive); + + /** + * Returns a view of the portion of this map whose keys are less than (or + * equal to, if {@code inclusive} is true) {@code toKey}. The returned + * map is backed by this map, so changes in the returned map are reflected + * in this map, and vice-versa. The returned map supports all optional + * map operations that this map supports. + * + * <p>The returned map will throw an {@code IllegalArgumentException} + * on an attempt to insert a key outside its range. + * + * @param toKey high endpoint of the keys in the returned map + * @param inclusive {@code true} if the high endpoint + * is to be included in the returned view + * @return a view of the portion of this map whose keys are less than + * (or equal to, if {@code inclusive} is true) {@code toKey} + * @throws ClassCastException if {@code toKey} is not compatible + * with this map's comparator (or, if the map has no comparator, + * if {@code toKey} does not implement {@link Comparable}). + * Implementations may, but are not required to, throw this + * exception if {@code toKey} cannot be compared to keys + * currently in the map. + * @throws NullPointerException if {@code toKey} is null + * and this map does not permit null keys + * @throws IllegalArgumentException if this map itself has a + * restricted range, and {@code toKey} lies outside the + * bounds of the range + */ + NavigableMap<K,V> headMap(K toKey, boolean inclusive); + + /** + * Returns a view of the portion of this map whose keys are greater than (or + * equal to, if {@code inclusive} is true) {@code fromKey}. The returned + * map is backed by this map, so changes in the returned map are reflected + * in this map, and vice-versa. The returned map supports all optional + * map operations that this map supports. + * + * <p>The returned map will throw an {@code IllegalArgumentException} + * on an attempt to insert a key outside its range. + * + * @param fromKey low endpoint of the keys in the returned map + * @param inclusive {@code true} if the low endpoint + * is to be included in the returned view + * @return a view of the portion of this map whose keys are greater than + * (or equal to, if {@code inclusive} is true) {@code fromKey} + * @throws ClassCastException if {@code fromKey} is not compatible + * with this map's comparator (or, if the map has no comparator, + * if {@code fromKey} does not implement {@link Comparable}). + * Implementations may, but are not required to, throw this + * exception if {@code fromKey} cannot be compared to keys + * currently in the map. + * @throws NullPointerException if {@code fromKey} is null + * and this map does not permit null keys + * @throws IllegalArgumentException if this map itself has a + * restricted range, and {@code fromKey} lies outside the + * bounds of the range + */ + NavigableMap<K,V> tailMap(K fromKey, boolean inclusive); + + /** + * {@inheritDoc} + * + * <p>Equivalent to {@code subMap(fromKey, true, toKey, false)}. + * + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + SortedMap<K,V> subMap(K fromKey, K toKey); + + /** + * {@inheritDoc} + * + * <p>Equivalent to {@code headMap(toKey, false)}. + * + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + SortedMap<K,V> headMap(K toKey); + + /** + * {@inheritDoc} + * + * <p>Equivalent to {@code tailMap(fromKey, true)}. + * + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + SortedMap<K,V> tailMap(K fromKey); +} diff --git a/libjava/classpath/external/jsr166/java/util/NavigableSet.java b/libjava/classpath/external/jsr166/java/util/NavigableSet.java new file mode 100644 index 000000000..e14fe347d --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/NavigableSet.java @@ -0,0 +1,290 @@ +/* + * Written by Doug Lea and Josh Bloch with assistance from members of JCP + * JSR-166 Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +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 + * 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. + * + * <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 + * this interface are encouraged to <em>not</em> permit insertion of + * {@code null} elements. (Note that sorted sets of {@link + * Comparable} elements intrinsically do not permit {@code null}.) + * + * <p>Methods + * {@link #subSet(Object, Object) subSet(E, E)}, + * {@link #headSet(Object) headSet(E)}, and + * {@link #tailSet(Object) tailSet(E)} + * are specified to return {@code SortedSet} to allow existing + * implementations of {@code SortedSet} to be compatibly retrofitted to + * implement {@code NavigableSet}, but extensions and implementations + * of this interface are encouraged to override these methods to return + * {@code NavigableSet}. + * + * <p>This interface is a member of the + * <a href="{@docRoot}/../technotes/guides/collections/index.html"> + * Java Collections Framework</a>. + * + * @author Doug Lea + * @author Josh Bloch + * @param <E> the type of elements maintained by this set + * @since 1.6 + */ +public interface NavigableSet<E> extends SortedSet<E> { + /** + * Returns the greatest element in this set strictly less than the + * given element, or {@code null} if there is no such element. + * + * @param e the value to match + * @return the greatest element less than {@code e}, + * or {@code null} if there is no such element + * @throws ClassCastException if the specified element cannot be + * compared with the elements currently in the set + * @throws NullPointerException if the specified element is null + * and this set does not permit null elements + */ + E lower(E e); + + /** + * Returns the greatest element in this set less than or equal to + * the given element, or {@code null} if there is no such element. + * + * @param e the value to match + * @return the greatest element less than or equal to {@code e}, + * or {@code null} if there is no such element + * @throws ClassCastException if the specified element cannot be + * compared with the elements currently in the set + * @throws NullPointerException if the specified element is null + * and this set does not permit null elements + */ + E floor(E e); + + /** + * Returns the least element in this set greater than or equal to + * the given element, or {@code null} if there is no such element. + * + * @param e the value to match + * @return the least element greater than or equal to {@code e}, + * or {@code null} if there is no such element + * @throws ClassCastException if the specified element cannot be + * compared with the elements currently in the set + * @throws NullPointerException if the specified element is null + * and this set does not permit null elements + */ + E ceiling(E e); + + /** + * Returns the least element in this set strictly greater than the + * given element, or {@code null} if there is no such element. + * + * @param e the value to match + * @return the least element greater than {@code e}, + * or {@code null} if there is no such element + * @throws ClassCastException if the specified element cannot be + * compared with the elements currently in the set + * @throws NullPointerException if the specified element is null + * and this set does not permit null elements + */ + E higher(E e); + + /** + * Retrieves and removes the first (lowest) element, + * or returns {@code null} if this set is empty. + * + * @return the first element, or {@code null} if this set is empty + */ + E pollFirst(); + + /** + * Retrieves and removes the last (highest) element, + * or returns {@code null} if this set is empty. + * + * @return the last element, or {@code null} if this set is empty + */ + E pollLast(); + + /** + * Returns an iterator over the elements in this set, in ascending order. + * + * @return an iterator over the elements in this set, in ascending order + */ + Iterator<E> iterator(); + + /** + * Returns a reverse order view of the elements contained in this set. + * The descending set is backed by this set, so changes to the set are + * reflected in the descending set, and vice-versa. If either set is + * modified while an iteration over either set is in progress (except + * through the iterator's own {@code remove} operation), the results of + * the iteration are undefined. + * + * <p>The returned set has an ordering equivalent to + * <tt>{@link Collections#reverseOrder(Comparator) Collections.reverseOrder}(comparator())</tt>. + * The expression {@code s.descendingSet().descendingSet()} returns a + * view of {@code s} essentially equivalent to {@code s}. + * + * @return a reverse order view of this set + */ + NavigableSet<E> descendingSet(); + + /** + * Returns an iterator over the elements in this set, in descending order. + * Equivalent in effect to {@code descendingSet().iterator()}. + * + * @return an iterator over the elements in this set, in descending order + */ + Iterator<E> descendingIterator(); + + /** + * Returns a view of the portion of this set whose elements range from + * {@code fromElement} to {@code toElement}. If {@code fromElement} and + * {@code toElement} are equal, the returned set is empty unless {@code + * fromExclusive} and {@code toExclusive} are both true. The returned set + * is backed by this set, so changes in the returned set are reflected in + * this set, and vice-versa. The returned set supports all optional set + * operations that this set supports. + * + * <p>The returned set will throw an {@code IllegalArgumentException} + * on an attempt to insert an element outside its range. + * + * @param fromElement low endpoint of the returned set + * @param fromInclusive {@code true} if the low endpoint + * is to be included in the returned view + * @param toElement high endpoint of the returned set + * @param toInclusive {@code true} if the high endpoint + * is to be included in the returned view + * @return a view of the portion of this set whose elements range from + * {@code fromElement}, inclusive, to {@code toElement}, exclusive + * @throws ClassCastException if {@code fromElement} and + * {@code toElement} cannot be compared to one another using this + * set's comparator (or, if the set has no comparator, using + * natural ordering). Implementations may, but are not required + * to, throw this exception if {@code fromElement} or + * {@code toElement} cannot be compared to elements currently in + * the set. + * @throws NullPointerException if {@code fromElement} or + * {@code toElement} is null and this set does + * not permit null elements + * @throws IllegalArgumentException if {@code fromElement} is + * greater than {@code toElement}; or if this set itself + * has a restricted range, and {@code fromElement} or + * {@code toElement} lies outside the bounds of the range. + */ + NavigableSet<E> subSet(E fromElement, boolean fromInclusive, + E toElement, boolean toInclusive); + + /** + * Returns a view of the portion of this set whose elements are less than + * (or equal to, if {@code inclusive} is true) {@code toElement}. The + * returned set is backed by this set, so changes in the returned set are + * reflected in this set, and vice-versa. The returned set supports all + * optional set operations that this set supports. + * + * <p>The returned set will throw an {@code IllegalArgumentException} + * on an attempt to insert an element outside its range. + * + * @param toElement high endpoint of the returned set + * @param inclusive {@code true} if the high endpoint + * is to be included in the returned view + * @return a view of the portion of this set whose elements are less than + * (or equal to, if {@code inclusive} is true) {@code toElement} + * @throws ClassCastException if {@code toElement} is not compatible + * with this set's comparator (or, if the set has no comparator, + * if {@code toElement} does not implement {@link Comparable}). + * Implementations may, but are not required to, throw this + * exception if {@code toElement} cannot be compared to elements + * currently in the set. + * @throws NullPointerException if {@code toElement} is null and + * this set does not permit null elements + * @throws IllegalArgumentException if this set itself has a + * restricted range, and {@code toElement} lies outside the + * bounds of the range + */ + NavigableSet<E> headSet(E toElement, boolean inclusive); + + /** + * Returns a view of the portion of this set whose elements are greater + * than (or equal to, if {@code inclusive} is true) {@code fromElement}. + * The returned set is backed by this set, so changes in the returned set + * are reflected in this set, and vice-versa. The returned set supports + * all optional set operations that this set supports. + * + * <p>The returned set will throw an {@code IllegalArgumentException} + * on an attempt to insert an element outside its range. + * + * @param fromElement low endpoint of the returned set + * @param inclusive {@code true} if the low endpoint + * is to be included in the returned view + * @return a view of the portion of this set whose elements are greater + * than or equal to {@code fromElement} + * @throws ClassCastException if {@code fromElement} is not compatible + * with this set's comparator (or, if the set has no comparator, + * if {@code fromElement} does not implement {@link Comparable}). + * Implementations may, but are not required to, throw this + * exception if {@code fromElement} cannot be compared to elements + * currently in the set. + * @throws NullPointerException if {@code fromElement} is null + * and this set does not permit null elements + * @throws IllegalArgumentException if this set itself has a + * restricted range, and {@code fromElement} lies outside the + * bounds of the range + */ + NavigableSet<E> tailSet(E fromElement, boolean inclusive); + + /** + * {@inheritDoc} + * + * <p>Equivalent to {@code subSet(fromElement, true, toElement, false)}. + * + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + SortedSet<E> subSet(E fromElement, E toElement); + + /** + * {@inheritDoc} + * + * <p>Equivalent to {@code headSet(toElement, false)}. + * + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} +na */ + SortedSet<E> headSet(E toElement); + + /** + * {@inheritDoc} + * + * <p>Equivalent to {@code tailSet(fromElement, true)}. + * + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + SortedSet<E> tailSet(E fromElement); +} diff --git a/libjava/classpath/external/jsr166/java/util/Queue.java b/libjava/classpath/external/jsr166/java/util/Queue.java new file mode 100644 index 000000000..5711545b0 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/Queue.java @@ -0,0 +1,189 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util; + +/** + * A collection designed for holding elements prior to processing. + * Besides basic {@link java.util.Collection Collection} operations, + * queues provide additional insertion, extraction, and inspection + * operations. Each of these methods exists in two forms: one throws + * an exception if the operation fails, the other returns a special + * value (either <tt>null</tt> or <tt>false</tt>, depending on the + * operation). The latter form of the insert operation is designed + * specifically for use with capacity-restricted <tt>Queue</tt> + * implementations; in most implementations, insert operations cannot + * fail. + * + * <p> + * <table BORDER CELLPADDING=3 CELLSPACING=1> + * <tr> + * <td></td> + * <td ALIGN=CENTER><em>Throws exception</em></td> + * <td ALIGN=CENTER><em>Returns special value</em></td> + * </tr> + * <tr> + * <td><b>Insert</b></td> + * <td>{@link #add add(e)}</td> + * <td>{@link #offer offer(e)}</td> + * </tr> + * <tr> + * <td><b>Remove</b></td> + * <td>{@link #remove remove()}</td> + * <td>{@link #poll poll()}</td> + * </tr> + * <tr> + * <td><b>Examine</b></td> + * <td>{@link #element element()}</td> + * <td>{@link #peek peek()}</td> + * </tr> + * </table> + * + * <p>Queues typically, but do not necessarily, order elements in a + * FIFO (first-in-first-out) manner. Among the exceptions are + * priority queues, which order elements according to a supplied + * comparator, or the elements' natural ordering, and LIFO queues (or + * stacks) which order the elements LIFO (last-in-first-out). + * Whatever the ordering used, the <em>head</em> of the queue is that + * element which would be removed by a call to {@link #remove() } or + * {@link #poll()}. In a FIFO queue, all new elements are inserted at + * the <em> tail</em> of the queue. Other kinds of queues may use + * different placement rules. Every <tt>Queue</tt> implementation + * must specify its ordering properties. + * + * <p>The {@link #offer offer} method inserts an element if possible, + * otherwise returning <tt>false</tt>. This differs from the {@link + * java.util.Collection#add Collection.add} method, which can fail to + * add an element only by throwing an unchecked exception. The + * <tt>offer</tt> method is designed for use when failure is a normal, + * rather than exceptional occurrence, for example, in fixed-capacity + * (or "bounded") queues. + * + * <p>The {@link #remove()} and {@link #poll()} methods remove and + * return the head of the queue. + * Exactly which element is removed from the queue is a + * function of the queue's ordering policy, which differs from + * implementation to implementation. The <tt>remove()</tt> and + * <tt>poll()</tt> methods differ only in their behavior when the + * queue is empty: the <tt>remove()</tt> method throws an exception, + * while the <tt>poll()</tt> method returns <tt>null</tt>. + * + * <p>The {@link #element()} and {@link #peek()} methods return, but do + * not remove, the head of the queue. + * + * <p>The <tt>Queue</tt> interface does not define the <i>blocking queue + * methods</i>, which are common in concurrent programming. These methods, + * which wait for elements to appear or for space to become available, are + * defined in the {@link java.util.concurrent.BlockingQueue} interface, which + * extends this interface. + * + * <p><tt>Queue</tt> implementations generally do not allow insertion + * of <tt>null</tt> elements, although some implementations, such as + * {@link LinkedList}, do not prohibit insertion of <tt>null</tt>. + * Even in the implementations that permit it, <tt>null</tt> should + * not be inserted into a <tt>Queue</tt>, as <tt>null</tt> is also + * used as a special return value by the <tt>poll</tt> method to + * indicate that the queue contains no elements. + * + * <p><tt>Queue</tt> implementations generally do not define + * element-based versions of methods <tt>equals</tt> and + * <tt>hashCode</tt> but instead inherit the identity based versions + * from class <tt>Object</tt>, because element-based equality is not + * always well-defined for queues with the same elements but different + * ordering properties. + * + * + * <p>This interface is a member of the + * <a href="{@docRoot}/../technotes/guides/collections/index.html"> + * Java Collections Framework</a>. + * + * @see java.util.Collection + * @see LinkedList + * @see PriorityQueue + * @see java.util.concurrent.LinkedBlockingQueue + * @see java.util.concurrent.BlockingQueue + * @see java.util.concurrent.ArrayBlockingQueue + * @see java.util.concurrent.LinkedBlockingQueue + * @see java.util.concurrent.PriorityBlockingQueue + * @since 1.5 + * @author Doug Lea + * @param <E> the type of elements held in this collection + */ +public interface Queue<E> extends Collection<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> + * if no space is currently available. + * + * @param e the element to add + * @return <tt>true</tt> (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 + * prevents it from being added to this queue + * @throws NullPointerException if the specified element is null and + * this queue does not permit null elements + * @throws IllegalArgumentException if some property of this element + * prevents it from being added to this queue + */ + boolean add(E e); + + /** + * Inserts the specified element into this queue if it is possible to do + * so immediately without violating capacity restrictions. + * When using a capacity-restricted queue, this method is generally + * preferable to {@link #add}, which can fail to insert an element only + * by throwing an exception. + * + * @param e the element to add + * @return <tt>true</tt> if the element was added to this queue, else + * <tt>false</tt> + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this queue + * @throws NullPointerException if the specified element is null and + * this queue does not permit null elements + * @throws IllegalArgumentException if some property of this element + * prevents it from being added to this queue + */ + boolean offer(E e); + + /** + * Retrieves and removes the head of this queue. This method differs + * from {@link #poll poll} only in that it throws an exception if this + * queue is empty. + * + * @return the head of this queue + * @throws NoSuchElementException if this queue is empty + */ + E remove(); + + /** + * Retrieves and removes the head of this queue, + * or returns <tt>null</tt> if this queue is empty. + * + * @return the head of this queue, or <tt>null</tt> if this queue is empty + */ + E poll(); + + /** + * Retrieves, but does not remove, the head of this queue. This method + * differs from {@link #peek peek} only in that it throws an exception + * if this queue is empty. + * + * @return the head of this queue + * @throws NoSuchElementException if this queue is empty + */ + E element(); + + /** + * Retrieves, but does not remove, the head of this queue, + * or returns <tt>null</tt> if this queue is empty. + * + * @return the head of this queue, or <tt>null</tt> if this queue is empty + */ + E peek(); +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/AbstractExecutorService.java b/libjava/classpath/external/jsr166/java/util/concurrent/AbstractExecutorService.java new file mode 100644 index 000000000..ac15c5010 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/AbstractExecutorService.java @@ -0,0 +1,270 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.*; + +/** + * Provides default implementations of {@link ExecutorService} + * execution methods. This class implements the <tt>submit</tt>, + * <tt>invokeAny</tt> and <tt>invokeAll</tt> methods using a + * {@link RunnableFuture} returned by <tt>newTaskFor</tt>, which defaults + * to the {@link FutureTask} class provided in this package. For example, + * the implementation of <tt>submit(Runnable)</tt> creates an + * associated <tt>RunnableFuture</tt> that is executed and + * returned. Subclasses may override the <tt>newTaskFor</tt> methods + * to return <tt>RunnableFuture</tt> implementations other than + * <tt>FutureTask</tt>. + * + * <p> <b>Extension example</b>. Here is a sketch of a class + * that customizes {@link ThreadPoolExecutor} to use + * a <tt>CustomTask</tt> class instead of the default <tt>FutureTask</tt>: + * <pre> + * public class CustomThreadPoolExecutor extends ThreadPoolExecutor { + * + * static class CustomTask<V> implements RunnableFuture<V> {...} + * + * protected <V> RunnableFuture<V> newTaskFor(Callable<V> c) { + * return new CustomTask<V>(c); + * } + * protected <V> RunnableFuture<V> newTaskFor(Runnable r, V v) { + * return new CustomTask<V>(r, v); + * } + * // ... add constructors, etc. + * } + * </pre> + * @since 1.5 + * @author Doug Lea + */ +public abstract class AbstractExecutorService implements ExecutorService { + + /** + * Returns a <tt>RunnableFuture</tt> for the given runnable and default + * value. + * + * @param runnable the runnable task being wrapped + * @param value the default value for the returned future + * @return a <tt>RunnableFuture</tt> which when run will run the + * underlying runnable and which, as a <tt>Future</tt>, will yield + * the given value as its result and provide for cancellation of + * the underlying task. + * @since 1.6 + */ + protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) { + return new FutureTask<T>(runnable, value); + } + + /** + * Returns a <tt>RunnableFuture</tt> for the given callable task. + * + * @param callable the callable task being wrapped + * @return a <tt>RunnableFuture</tt> which when run will call the + * underlying callable and which, as a <tt>Future</tt>, will yield + * the callable's result as its result and provide for + * cancellation of the underlying task. + * @since 1.6 + */ + protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) { + return new FutureTask<T>(callable); + } + + public Future<?> submit(Runnable task) { + if (task == null) throw new NullPointerException(); + RunnableFuture<Object> ftask = newTaskFor(task, null); + execute(ftask); + return ftask; + } + + public <T> Future<T> submit(Runnable task, T result) { + if (task == null) throw new NullPointerException(); + RunnableFuture<T> ftask = newTaskFor(task, result); + execute(ftask); + return ftask; + } + + public <T> Future<T> submit(Callable<T> task) { + if (task == null) throw new NullPointerException(); + RunnableFuture<T> ftask = newTaskFor(task); + execute(ftask); + return ftask; + } + + /** + * the main mechanics of invokeAny. + */ + private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks, + boolean timed, long nanos) + throws InterruptedException, ExecutionException, TimeoutException { + if (tasks == null) + throw new NullPointerException(); + int ntasks = tasks.size(); + if (ntasks == 0) + throw new IllegalArgumentException(); + List<Future<T>> futures= new ArrayList<Future<T>>(ntasks); + ExecutorCompletionService<T> ecs = + new ExecutorCompletionService<T>(this); + + // For efficiency, especially in executors with limited + // parallelism, check to see if previously submitted tasks are + // done before submitting more of them. This interleaving + // plus the exception mechanics account for messiness of main + // loop. + + try { + // Record exceptions so that if we fail to obtain any + // result, we can throw the last exception we got. + ExecutionException ee = null; + long lastTime = (timed)? System.nanoTime() : 0; + Iterator<? extends Callable<T>> it = tasks.iterator(); + + // Start one task for sure; the rest incrementally + futures.add(ecs.submit(it.next())); + --ntasks; + int active = 1; + + for (;;) { + Future<T> f = ecs.poll(); + if (f == null) { + if (ntasks > 0) { + --ntasks; + futures.add(ecs.submit(it.next())); + ++active; + } + else if (active == 0) + break; + else if (timed) { + f = ecs.poll(nanos, TimeUnit.NANOSECONDS); + if (f == null) + throw new TimeoutException(); + long now = System.nanoTime(); + nanos -= now - lastTime; + lastTime = now; + } + else + f = ecs.take(); + } + if (f != null) { + --active; + try { + return f.get(); + } catch (InterruptedException ie) { + throw ie; + } catch (ExecutionException eex) { + ee = eex; + } catch (RuntimeException rex) { + ee = new ExecutionException(rex); + } + } + } + + if (ee == null) + ee = new ExecutionException(); + throw ee; + + } finally { + for (Future<T> f : futures) + f.cancel(true); + } + } + + public <T> T invokeAny(Collection<? extends Callable<T>> tasks) + throws InterruptedException, ExecutionException { + try { + return doInvokeAny(tasks, false, 0); + } catch (TimeoutException cannotHappen) { + assert false; + return null; + } + } + + public <T> T invokeAny(Collection<? extends Callable<T>> tasks, + long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { + return doInvokeAny(tasks, true, unit.toNanos(timeout)); + } + + public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) + throws InterruptedException { + if (tasks == null) + throw new NullPointerException(); + List<Future<T>> futures = new ArrayList<Future<T>>(tasks.size()); + boolean done = false; + try { + for (Callable<T> t : tasks) { + RunnableFuture<T> f = newTaskFor(t); + futures.add(f); + execute(f); + } + for (Future<T> f : futures) { + if (!f.isDone()) { + try { + f.get(); + } catch (CancellationException ignore) { + } catch (ExecutionException ignore) { + } + } + } + done = true; + return futures; + } finally { + if (!done) + for (Future<T> f : futures) + f.cancel(true); + } + } + + public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, + long timeout, TimeUnit unit) + throws InterruptedException { + if (tasks == null || unit == null) + throw new NullPointerException(); + long nanos = unit.toNanos(timeout); + List<Future<T>> futures = new ArrayList<Future<T>>(tasks.size()); + boolean done = false; + try { + for (Callable<T> t : tasks) + futures.add(newTaskFor(t)); + + long lastTime = System.nanoTime(); + + // Interleave time checks and calls to execute in case + // executor doesn't have any/much parallelism. + Iterator<Future<T>> it = futures.iterator(); + while (it.hasNext()) { + execute((Runnable)(it.next())); + long now = System.nanoTime(); + nanos -= now - lastTime; + lastTime = now; + if (nanos <= 0) + return futures; + } + + for (Future<T> f : futures) { + if (!f.isDone()) { + if (nanos <= 0) + return futures; + try { + f.get(nanos, TimeUnit.NANOSECONDS); + } catch (CancellationException ignore) { + } catch (ExecutionException ignore) { + } catch (TimeoutException toe) { + return futures; + } + long now = System.nanoTime(); + nanos -= now - lastTime; + lastTime = now; + } + } + done = true; + return futures; + } finally { + if (!done) + for (Future<T> f : futures) + f.cancel(true); + } + } + +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/ArrayBlockingQueue.java b/libjava/classpath/external/jsr166/java/util/concurrent/ArrayBlockingQueue.java new file mode 100644 index 000000000..3ce9ed859 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/ArrayBlockingQueue.java @@ -0,0 +1,778 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.concurrent.locks.*; +import java.util.*; + +/** + * A bounded {@linkplain BlockingQueue blocking queue} backed by an + * array. This queue orders elements FIFO (first-in-first-out). The + * <em>head</em> of the queue is that element that has been on the + * queue the longest time. The <em>tail</em> of the queue is that + * element that has been on the queue the shortest time. New elements + * are inserted at the tail of the queue, and the queue retrieval + * operations obtain elements at the head of the queue. + * + * <p>This is a classic "bounded buffer", in which a + * fixed-sized array holds elements inserted by producers and + * extracted by consumers. Once created, the capacity cannot be + * increased. Attempts to <tt>put</tt> an element into a full queue + * will result in the operation blocking; attempts to <tt>take</tt> an + * element from an empty queue will similarly block. + * + * <p> This class supports an optional fairness policy for ordering + * waiting producer and consumer threads. By default, this ordering + * is not guaranteed. However, a queue constructed with fairness set + * to <tt>true</tt> grants threads access in FIFO order. Fairness + * generally decreases throughput but reduces variability and avoids + * starvation. + * + * <p>This class and its iterator implement all of the + * <em>optional</em> methods of the {@link Collection} and {@link + * Iterator} interfaces. + * + * <p>This class is a member of the + * <a href="{@docRoot}/../technotes/guides/collections/index.html"> + * Java Collections Framework</a>. + * + * @since 1.5 + * @author Doug Lea + * @param <E> the type of elements held in this collection + */ +public class ArrayBlockingQueue<E> extends AbstractQueue<E> + implements BlockingQueue<E>, java.io.Serializable { + + /** + * Serialization ID. This class relies on default serialization + * even for the items array, which is default-serialized, even if + * it is empty. Otherwise it could not be declared final, which is + * necessary here. + */ + private static final long serialVersionUID = -817911632652898426L; + + /** The queued items */ + private final E[] items; + /** items index for next take, poll or remove */ + private int takeIndex; + /** items index for next put, offer, or add. */ + private int putIndex; + /** Number of items in the queue */ + private int count; + + /* + * Concurrency control uses the classic two-condition algorithm + * found in any textbook. + */ + + /** Main lock guarding all access */ + private final ReentrantLock lock; + /** Condition for waiting takes */ + private final Condition notEmpty; + /** Condition for waiting puts */ + private final Condition notFull; + + // Internal helper methods + + /** + * Circularly increment i. + */ + final int inc(int i) { + return (++i == items.length)? 0 : i; + } + + /** + * Inserts element at current put position, advances, and signals. + * Call only when holding lock. + */ + private void insert(E x) { + items[putIndex] = x; + putIndex = inc(putIndex); + ++count; + notEmpty.signal(); + } + + /** + * Extracts element at current take position, advances, and signals. + * Call only when holding lock. + */ + private E extract() { + final E[] items = this.items; + E x = items[takeIndex]; + items[takeIndex] = null; + takeIndex = inc(takeIndex); + --count; + notFull.signal(); + return x; + } + + /** + * Utility for remove and iterator.remove: Delete item at position i. + * Call only when holding lock. + */ + void removeAt(int i) { + final E[] items = this.items; + // if removing front item, just advance + if (i == takeIndex) { + items[takeIndex] = null; + takeIndex = inc(takeIndex); + } else { + // slide over all others up through putIndex. + for (;;) { + int nexti = inc(i); + if (nexti != putIndex) { + items[i] = items[nexti]; + i = nexti; + } else { + items[i] = null; + putIndex = i; + break; + } + } + } + --count; + notFull.signal(); + } + + /** + * Creates an <tt>ArrayBlockingQueue</tt> with the given (fixed) + * capacity and default access policy. + * + * @param capacity the capacity of this queue + * @throws IllegalArgumentException if <tt>capacity</tt> is less than 1 + */ + public ArrayBlockingQueue(int capacity) { + this(capacity, false); + } + + /** + * Creates an <tt>ArrayBlockingQueue</tt> with the given (fixed) + * capacity and the specified access policy. + * + * @param capacity the capacity of this queue + * @param fair if <tt>true</tt> then queue accesses for threads blocked + * on insertion or removal, are processed in FIFO order; + * if <tt>false</tt> the access order is unspecified. + * @throws IllegalArgumentException if <tt>capacity</tt> is less than 1 + */ + public ArrayBlockingQueue(int capacity, boolean fair) { + if (capacity <= 0) + throw new IllegalArgumentException(); + this.items = (E[]) new Object[capacity]; + lock = new ReentrantLock(fair); + notEmpty = lock.newCondition(); + notFull = lock.newCondition(); + } + + /** + * Creates an <tt>ArrayBlockingQueue</tt> with the given (fixed) + * capacity, the specified access policy and initially containing the + * elements of the given collection, + * added in traversal order of the collection's iterator. + * + * @param capacity the capacity of this queue + * @param fair if <tt>true</tt> then queue accesses for threads blocked + * on insertion or removal, are processed in FIFO order; + * if <tt>false</tt> the access order is unspecified. + * @param c the collection of elements to initially contain + * @throws IllegalArgumentException if <tt>capacity</tt> is less than + * <tt>c.size()</tt>, or less than 1. + * @throws NullPointerException if the specified collection or any + * of its elements are null + */ + public ArrayBlockingQueue(int capacity, boolean fair, + Collection<? extends E> c) { + this(capacity, fair); + if (capacity < c.size()) + throw new IllegalArgumentException(); + + for (Iterator<? extends E> it = c.iterator(); it.hasNext();) + add(it.next()); + } + + /** + * Inserts the specified element at the tail of this queue if it is + * possible to do so immediately without exceeding the queue's capacity, + * returning <tt>true</tt> upon success and throwing an + * <tt>IllegalStateException</tt> if this queue is full. + * + * @param e the element to add + * @return <tt>true</tt> (as specified by {@link Collection#add}) + * @throws IllegalStateException if this queue is full + * @throws NullPointerException if the specified element is null + */ + public boolean add(E e) { + return super.add(e); + } + + /** + * Inserts the specified element at the tail of this queue if it is + * possible to do so immediately without exceeding the queue's capacity, + * returning <tt>true</tt> upon success and <tt>false</tt> if this queue + * is full. This method is generally preferable to method {@link #add}, + * which can fail to insert an element only by throwing an exception. + * + * @throws NullPointerException if the specified element is null + */ + public boolean offer(E e) { + if (e == null) throw new NullPointerException(); + final ReentrantLock lock = this.lock; + lock.lock(); + try { + if (count == items.length) + return false; + else { + insert(e); + return true; + } + } finally { + lock.unlock(); + } + } + + /** + * Inserts the specified element at the tail of this queue, waiting + * for space to become available if the queue is full. + * + * @throws InterruptedException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public void put(E e) throws InterruptedException { + if (e == null) throw new NullPointerException(); + final E[] items = this.items; + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + try { + while (count == items.length) + notFull.await(); + } catch (InterruptedException ie) { + notFull.signal(); // propagate to non-interrupted thread + throw ie; + } + insert(e); + } finally { + lock.unlock(); + } + } + + /** + * Inserts the specified element at the tail of this queue, waiting + * up to the specified wait time for space to become available if + * the queue is full. + * + * @throws InterruptedException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public boolean offer(E e, long timeout, TimeUnit unit) + throws InterruptedException { + + if (e == null) throw new NullPointerException(); + long nanos = unit.toNanos(timeout); + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + for (;;) { + if (count != items.length) { + insert(e); + return true; + } + if (nanos <= 0) + return false; + try { + nanos = notFull.awaitNanos(nanos); + } catch (InterruptedException ie) { + notFull.signal(); // propagate to non-interrupted thread + throw ie; + } + } + } finally { + lock.unlock(); + } + } + + public E poll() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + if (count == 0) + return null; + E x = extract(); + return x; + } finally { + lock.unlock(); + } + } + + public E take() throws InterruptedException { + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + try { + while (count == 0) + notEmpty.await(); + } catch (InterruptedException ie) { + notEmpty.signal(); // propagate to non-interrupted thread + throw ie; + } + E x = extract(); + return x; + } finally { + lock.unlock(); + } + } + + public E poll(long timeout, TimeUnit unit) throws InterruptedException { + long nanos = unit.toNanos(timeout); + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + for (;;) { + if (count != 0) { + E x = extract(); + return x; + } + if (nanos <= 0) + return null; + try { + nanos = notEmpty.awaitNanos(nanos); + } catch (InterruptedException ie) { + notEmpty.signal(); // propagate to non-interrupted thread + throw ie; + } + + } + } finally { + lock.unlock(); + } + } + + public E peek() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return (count == 0) ? null : items[takeIndex]; + } finally { + lock.unlock(); + } + } + + // this doc comment is overridden to remove the reference to collections + // greater in size than Integer.MAX_VALUE + /** + * Returns the number of elements in this queue. + * + * @return the number of elements in this queue + */ + public int size() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return count; + } finally { + lock.unlock(); + } + } + + // this doc comment is a modified copy of the inherited doc comment, + // without the reference to unlimited queues. + /** + * Returns the number of additional elements that this queue can ideally + * (in the absence of memory or resource constraints) accept without + * blocking. This is always equal to the initial capacity of this queue + * less the current <tt>size</tt> of this queue. + * + * <p>Note that you <em>cannot</em> always tell if an attempt to insert + * an element will succeed by inspecting <tt>remainingCapacity</tt> + * because it may be the case that another thread is about to + * insert or remove an element. + */ + public int remainingCapacity() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return items.length - count; + } finally { + lock.unlock(); + } + } + + /** + * Removes a single instance of the specified element from this queue, + * if it is present. More formally, removes an element <tt>e</tt> such + * that <tt>o.equals(e)</tt>, if this queue contains one or more such + * elements. + * Returns <tt>true</tt> if this queue contained the specified element + * (or equivalently, if this queue changed as a result of the call). + * + * @param o element to be removed from this queue, if present + * @return <tt>true</tt> if this queue changed as a result of the call + */ + public boolean remove(Object o) { + if (o == null) return false; + final E[] items = this.items; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + int i = takeIndex; + int k = 0; + for (;;) { + if (k++ >= count) + return false; + if (o.equals(items[i])) { + removeAt(i); + return true; + } + i = inc(i); + } + + } finally { + lock.unlock(); + } + } + + /** + * Returns <tt>true</tt> if this queue contains the specified element. + * More formally, returns <tt>true</tt> if and only if this queue contains + * at least one element <tt>e</tt> such that <tt>o.equals(e)</tt>. + * + * @param o object to be checked for containment in this queue + * @return <tt>true</tt> if this queue contains the specified element + */ + public boolean contains(Object o) { + if (o == null) return false; + final E[] items = this.items; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + int i = takeIndex; + int k = 0; + while (k++ < count) { + if (o.equals(items[i])) + return true; + i = inc(i); + } + return false; + } finally { + lock.unlock(); + } + } + + /** + * 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() { + final E[] items = this.items; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + Object[] a = new Object[count]; + int k = 0; + int i = takeIndex; + while (k < count) { + a[k++] = items[i]; + i = inc(i); + } + return a; + } finally { + lock.unlock(); + } + } + + /** + * 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 + * <tt>null</tt>. + * + * <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 <tt>x</tt> is a queue known to contain only strings. + * The following code can be used to dump the queue into a newly + * allocated array of <tt>String</tt>: + * + * <pre> + * String[] y = x.toArray(new String[0]);</pre> + * + * Note that <tt>toArray(new Object[0])</tt> is identical in function to + * <tt>toArray()</tt>. + * + * @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 + */ + public <T> T[] toArray(T[] a) { + final E[] items = this.items; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + if (a.length < count) + a = (T[])java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), + count + ); + + int k = 0; + int i = takeIndex; + while (k < count) { + a[k++] = (T)items[i]; + i = inc(i); + } + if (a.length > count) + a[count] = null; + return a; + } finally { + lock.unlock(); + } + } + + public String toString() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return super.toString(); + } finally { + lock.unlock(); + } + } + + /** + * Atomically removes all of the elements from this queue. + * The queue will be empty after this call returns. + */ + public void clear() { + final E[] items = this.items; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + int i = takeIndex; + int k = count; + while (k-- > 0) { + items[i] = null; + i = inc(i); + } + count = 0; + putIndex = 0; + takeIndex = 0; + notFull.signalAll(); + } finally { + lock.unlock(); + } + } + + /** + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public int drainTo(Collection<? super E> c) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + final E[] items = this.items; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + int i = takeIndex; + int n = 0; + int max = count; + while (n < max) { + c.add(items[i]); + items[i] = null; + i = inc(i); + ++n; + } + if (n > 0) { + count = 0; + putIndex = 0; + takeIndex = 0; + notFull.signalAll(); + } + return n; + } finally { + lock.unlock(); + } + } + + /** + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public int drainTo(Collection<? super E> c, int maxElements) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + if (maxElements <= 0) + return 0; + final E[] items = this.items; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + int i = takeIndex; + int n = 0; + int sz = count; + int max = (maxElements < count)? maxElements : count; + while (n < max) { + c.add(items[i]); + items[i] = null; + i = inc(i); + ++n; + } + if (n > 0) { + count -= n; + takeIndex = i; + notFull.signalAll(); + } + return n; + } finally { + lock.unlock(); + } + } + + + /** + * Returns an iterator over the elements in this queue in proper sequence. + * The returned <tt>Iterator</tt> is a "weakly consistent" iterator that + * will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + * + * @return an iterator over the elements in this queue in proper sequence + */ + public Iterator<E> iterator() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return new Itr(); + } finally { + lock.unlock(); + } + } + + /** + * Iterator for ArrayBlockingQueue + */ + private class Itr implements Iterator<E> { + /** + * Index of element to be returned by next, + * or a negative number if no such. + */ + private int nextIndex; + + /** + * nextItem holds on to item fields because once we claim + * that an element exists in hasNext(), we must return it in + * the following next() call even if it was in the process of + * being removed when hasNext() was called. + */ + private E nextItem; + + /** + * Index of element returned by most recent call to next. + * Reset to -1 if this element is deleted by a call to remove. + */ + private int lastRet; + + Itr() { + lastRet = -1; + if (count == 0) + nextIndex = -1; + else { + nextIndex = takeIndex; + nextItem = items[takeIndex]; + } + } + + public boolean hasNext() { + /* + * No sync. We can return true by mistake here + * only if this iterator passed across threads, + * which we don't support anyway. + */ + return nextIndex >= 0; + } + + /** + * Checks whether nextIndex is valid; if so setting nextItem. + * Stops iterator when either hits putIndex or sees null item. + */ + private void checkNext() { + if (nextIndex == putIndex) { + nextIndex = -1; + nextItem = null; + } else { + nextItem = items[nextIndex]; + if (nextItem == null) + nextIndex = -1; + } + } + + public E next() { + final ReentrantLock lock = ArrayBlockingQueue.this.lock; + lock.lock(); + try { + if (nextIndex < 0) + throw new NoSuchElementException(); + lastRet = nextIndex; + E x = nextItem; + nextIndex = inc(nextIndex); + checkNext(); + return x; + } finally { + lock.unlock(); + } + } + + public void remove() { + final ReentrantLock lock = ArrayBlockingQueue.this.lock; + lock.lock(); + try { + int i = lastRet; + if (i == -1) + throw new IllegalStateException(); + lastRet = -1; + + int ti = takeIndex; + removeAt(i); + // back up cursor (reset to front if was first element) + nextIndex = (i == ti) ? takeIndex : i; + checkNext(); + } finally { + lock.unlock(); + } + } + } +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/BlockingDeque.java b/libjava/classpath/external/jsr166/java/util/concurrent/BlockingDeque.java new file mode 100644 index 000000000..d77a96555 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/BlockingDeque.java @@ -0,0 +1,613 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.*; + +/** + * A {@link Deque} that additionally supports blocking operations that wait + * for the deque to become non-empty when retrieving an element, and wait for + * space to become available in the deque when storing an element. + * + * <p><tt>BlockingDeque</tt> methods come in four forms, with different ways + * of handling operations that cannot be satisfied immediately, but may be + * satisfied at some point in the future: + * one throws an exception, the second returns a special value (either + * <tt>null</tt> or <tt>false</tt>, depending on the operation), the third + * blocks the current thread indefinitely until the operation can succeed, + * and the fourth blocks for only a given maximum time limit before giving + * up. These methods are summarized in the following table: + * + * <p> + * <table BORDER CELLPADDING=3 CELLSPACING=1> + * <tr> + * <td ALIGN=CENTER COLSPAN = 5> <b>First Element (Head)</b></td> + * </tr> + * <tr> + * <td></td> + * <td ALIGN=CENTER><em>Throws exception</em></td> + * <td ALIGN=CENTER><em>Special value</em></td> + * <td ALIGN=CENTER><em>Blocks</em></td> + * <td ALIGN=CENTER><em>Times out</em></td> + * </tr> + * <tr> + * <td><b>Insert</b></td> + * <td>{@link #addFirst addFirst(e)}</td> + * <td>{@link #offerFirst(Object) offerFirst(e)}</td> + * <td>{@link #putFirst putFirst(e)}</td> + * <td>{@link #offerFirst(Object, long, TimeUnit) offerFirst(e, time, unit)}</td> + * </tr> + * <tr> + * <td><b>Remove</b></td> + * <td>{@link #removeFirst removeFirst()}</td> + * <td>{@link #pollFirst pollFirst()}</td> + * <td>{@link #takeFirst takeFirst()}</td> + * <td>{@link #pollFirst(long, TimeUnit) pollFirst(time, unit)}</td> + * </tr> + * <tr> + * <td><b>Examine</b></td> + * <td>{@link #getFirst getFirst()}</td> + * <td>{@link #peekFirst peekFirst()}</td> + * <td><em>not applicable</em></td> + * <td><em>not applicable</em></td> + * </tr> + * <tr> + * <td ALIGN=CENTER COLSPAN = 5> <b>Last Element (Tail)</b></td> + * </tr> + * <tr> + * <td></td> + * <td ALIGN=CENTER><em>Throws exception</em></td> + * <td ALIGN=CENTER><em>Special value</em></td> + * <td ALIGN=CENTER><em>Blocks</em></td> + * <td ALIGN=CENTER><em>Times out</em></td> + * </tr> + * <tr> + * <td><b>Insert</b></td> + * <td>{@link #addLast addLast(e)}</td> + * <td>{@link #offerLast(Object) offerLast(e)}</td> + * <td>{@link #putLast putLast(e)}</td> + * <td>{@link #offerLast(Object, long, TimeUnit) offerLast(e, time, unit)}</td> + * </tr> + * <tr> + * <td><b>Remove</b></td> + * <td>{@link #removeLast() removeLast()}</td> + * <td>{@link #pollLast() pollLast()}</td> + * <td>{@link #takeLast takeLast()}</td> + * <td>{@link #pollLast(long, TimeUnit) pollLast(time, unit)}</td> + * </tr> + * <tr> + * <td><b>Examine</b></td> + * <td>{@link #getLast getLast()}</td> + * <td>{@link #peekLast peekLast()}</td> + * <td><em>not applicable</em></td> + * <td><em>not applicable</em></td> + * </tr> + * </table> + * + * <p>Like any {@link BlockingQueue}, a <tt>BlockingDeque</tt> is thread safe, + * does not permit null elements, and may (or may not) be + * capacity-constrained. + * + * <p>A <tt>BlockingDeque</tt> implementation may be used directly as a FIFO + * <tt>BlockingQueue</tt>. The methods inherited from the + * <tt>BlockingQueue</tt> interface are precisely equivalent to + * <tt>BlockingDeque</tt> methods as indicated in the following table: + * + * <p> + * <table BORDER CELLPADDING=3 CELLSPACING=1> + * <tr> + * <td ALIGN=CENTER> <b><tt>BlockingQueue</tt> Method</b></td> + * <td ALIGN=CENTER> <b>Equivalent <tt>BlockingDeque</tt> Method</b></td> + * </tr> + * <tr> + * <td ALIGN=CENTER COLSPAN = 2> <b>Insert</b></td> + * </tr> + * <tr> + * <td>{@link #add(Object) add(e)}</td> + * <td>{@link #addLast(Object) addLast(e)}</td> + * </tr> + * <tr> + * <td>{@link #offer(Object) offer(e)}</td> + * <td>{@link #offerLast(Object) offerLast(e)}</td> + * </tr> + * <tr> + * <td>{@link #put(Object) put(e)}</td> + * <td>{@link #putLast(Object) putLast(e)}</td> + * </tr> + * <tr> + * <td>{@link #offer(Object, long, TimeUnit) offer(e, time, unit)}</td> + * <td>{@link #offerLast(Object, long, TimeUnit) offerLast(e, time, unit)}</td> + * </tr> + * <tr> + * <td ALIGN=CENTER COLSPAN = 2> <b>Remove</b></td> + * </tr> + * <tr> + * <td>{@link #remove() remove()}</td> + * <td>{@link #removeFirst() removeFirst()}</td> + * </tr> + * <tr> + * <td>{@link #poll() poll()}</td> + * <td>{@link #pollFirst() pollFirst()}</td> + * </tr> + * <tr> + * <td>{@link #take() take()}</td> + * <td>{@link #takeFirst() takeFirst()}</td> + * </tr> + * <tr> + * <td>{@link #poll(long, TimeUnit) poll(time, unit)}</td> + * <td>{@link #pollFirst(long, TimeUnit) pollFirst(time, unit)}</td> + * </tr> + * <tr> + * <td ALIGN=CENTER COLSPAN = 2> <b>Examine</b></td> + * </tr> + * <tr> + * <td>{@link #element() element()}</td> + * <td>{@link #getFirst() getFirst()}</td> + * </tr> + * <tr> + * <td>{@link #peek() peek()}</td> + * <td>{@link #peekFirst() peekFirst()}</td> + * </tr> + * </table> + * + * <p>Memory consistency effects: As with other concurrent + * collections, actions in a thread prior to placing an object into a + * {@code BlockingDeque} + * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a> + * actions subsequent to the access or removal of that element from + * the {@code BlockingDeque} in another thread. + * + * <p>This interface is a member of the + * <a href="{@docRoot}/../technotes/guides/collections/index.html"> + * Java Collections Framework</a>. + * + * @since 1.6 + * @author Doug Lea + * @param <E> the type of elements held in this collection + */ +public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> { + /* + * We have "diamond" multiple interface inheritance here, and that + * introduces ambiguities. Methods might end up with different + * specs depending on the branch chosen by javadoc. Thus a lot of + * methods specs here are copied from superinterfaces. + */ + + /** + * Inserts the specified element at the front of this deque if it is + * possible to do so immediately without violating capacity restrictions, + * throwing an <tt>IllegalStateException</tt> if no space is currently + * available. When using a capacity-restricted deque, it is generally + * preferable to use {@link #offerFirst(Object) offerFirst}. + * + * @param e the element to add + * @throws IllegalStateException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException {@inheritDoc} + */ + void addFirst(E e); + + /** + * Inserts the specified element at the end of this deque if it is + * possible to do so immediately without violating capacity restrictions, + * throwing an <tt>IllegalStateException</tt> if no space is currently + * available. When using a capacity-restricted deque, it is generally + * preferable to use {@link #offerLast(Object) offerLast}. + * + * @param e the element to add + * @throws IllegalStateException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException {@inheritDoc} + */ + void addLast(E e); + + /** + * Inserts the specified element at the front of this deque if it is + * possible to do so immediately without violating capacity restrictions, + * returning <tt>true</tt> upon success and <tt>false</tt> if no space is + * currently available. + * When using a capacity-restricted deque, this method is generally + * preferable to the {@link #addFirst(Object) addFirst} method, which can + * fail to insert an element only by throwing an exception. + * + * @param e the element to add + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException {@inheritDoc} + */ + boolean offerFirst(E e); + + /** + * Inserts the specified element at the end of this deque if it is + * possible to do so immediately without violating capacity restrictions, + * returning <tt>true</tt> upon success and <tt>false</tt> if no space is + * currently available. + * When using a capacity-restricted deque, this method is generally + * preferable to the {@link #addLast(Object) addLast} method, which can + * fail to insert an element only by throwing an exception. + * + * @param e the element to add + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException {@inheritDoc} + */ + boolean offerLast(E e); + + /** + * Inserts the specified element at the front of this deque, + * waiting if necessary for space to become available. + * + * @param e the element to add + * @throws InterruptedException if interrupted while waiting + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this deque + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this deque + */ + void putFirst(E e) throws InterruptedException; + + /** + * Inserts the specified element at the end of this deque, + * waiting if necessary for space to become available. + * + * @param e the element to add + * @throws InterruptedException if interrupted while waiting + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this deque + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this deque + */ + void putLast(E e) throws InterruptedException; + + /** + * Inserts the specified element at the front of this deque, + * waiting up to the specified wait time if necessary for space to + * become available. + * + * @param e the element to add + * @param timeout how long to wait before giving up, in units of + * <tt>unit</tt> + * @param unit a <tt>TimeUnit</tt> determining how to interpret the + * <tt>timeout</tt> parameter + * @return <tt>true</tt> if successful, or <tt>false</tt> if + * the specified waiting time elapses before space is available + * @throws InterruptedException if interrupted while waiting + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this deque + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this deque + */ + boolean offerFirst(E e, long timeout, TimeUnit unit) + throws InterruptedException; + + /** + * Inserts the specified element at the end of this deque, + * waiting up to the specified wait time if necessary for space to + * become available. + * + * @param e the element to add + * @param timeout how long to wait before giving up, in units of + * <tt>unit</tt> + * @param unit a <tt>TimeUnit</tt> determining how to interpret the + * <tt>timeout</tt> parameter + * @return <tt>true</tt> if successful, or <tt>false</tt> if + * the specified waiting time elapses before space is available + * @throws InterruptedException if interrupted while waiting + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this deque + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this deque + */ + boolean offerLast(E e, long timeout, TimeUnit unit) + throws InterruptedException; + + /** + * Retrieves and removes the first element of this deque, waiting + * if necessary until an element becomes available. + * + * @return the head of this deque + * @throws InterruptedException if interrupted while waiting + */ + E takeFirst() throws InterruptedException; + + /** + * Retrieves and removes the last element of this deque, waiting + * if necessary until an element becomes available. + * + * @return the tail of this deque + * @throws InterruptedException if interrupted while waiting + */ + E takeLast() throws InterruptedException; + + /** + * Retrieves and removes the first element of this deque, waiting + * up to the specified wait time if necessary for an element to + * become available. + * + * @param timeout how long to wait before giving up, in units of + * <tt>unit</tt> + * @param unit a <tt>TimeUnit</tt> determining how to interpret the + * <tt>timeout</tt> parameter + * @return the head of this deque, or <tt>null</tt> if the specified + * waiting time elapses before an element is available + * @throws InterruptedException if interrupted while waiting + */ + E pollFirst(long timeout, TimeUnit unit) + throws InterruptedException; + + /** + * Retrieves and removes the last element of this deque, waiting + * up to the specified wait time if necessary for an element to + * become available. + * + * @param timeout how long to wait before giving up, in units of + * <tt>unit</tt> + * @param unit a <tt>TimeUnit</tt> determining how to interpret the + * <tt>timeout</tt> parameter + * @return the tail of this deque, or <tt>null</tt> if the specified + * waiting time elapses before an element is available + * @throws InterruptedException if interrupted while waiting + */ + E pollLast(long timeout, TimeUnit unit) + throws InterruptedException; + + /** + * 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 <tt>e</tt> such that + * <tt>o.equals(e)</tt> (if such an element exists). + * Returns <tt>true</tt> 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 <tt>true</tt> 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 (optional) + * @throws NullPointerException if the specified element is null (optional) + */ + boolean removeFirstOccurrence(Object o); + + /** + * 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 <tt>e</tt> such that + * <tt>o.equals(e)</tt> (if such an element exists). + * Returns <tt>true</tt> 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 <tt>true</tt> 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 (optional) + * @throws NullPointerException if the specified element is null (optional) + */ + boolean removeLastOccurrence(Object o); + + // *** BlockingQueue methods *** + + /** + * Inserts the specified element into the queue represented by this deque + * (in other words, at the tail of this deque) if it is possible to do so + * immediately without violating capacity restrictions, returning + * <tt>true</tt> upon success and throwing an + * <tt>IllegalStateException</tt> if no space is currently available. + * When using a capacity-restricted deque, it is generally preferable to + * use {@link #offer(Object) offer}. + * + * <p>This method is equivalent to {@link #addLast(Object) addLast}. + * + * @param e the element to add + * @throws IllegalStateException {@inheritDoc} + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this deque + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this deque + */ + boolean add(E e); + + /** + * Inserts the specified element into the queue represented by this deque + * (in other words, at the tail of this deque) if it is possible to do so + * immediately without violating capacity restrictions, returning + * <tt>true</tt> upon success and <tt>false</tt> if no space is currently + * available. When using a capacity-restricted deque, this method is + * generally preferable to the {@link #add} method, which can fail to + * insert an element only by throwing an exception. + * + * <p>This method is equivalent to {@link #offerLast(Object) offerLast}. + * + * @param e the element to add + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this deque + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this deque + */ + boolean offer(E e); + + /** + * Inserts the specified element into the queue represented by this deque + * (in other words, at the tail of this deque), waiting if necessary for + * space to become available. + * + * <p>This method is equivalent to {@link #putLast(Object) putLast}. + * + * @param e the element to add + * @throws InterruptedException {@inheritDoc} + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this deque + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this deque + */ + void put(E e) throws InterruptedException; + + /** + * Inserts the specified element into the queue represented by this deque + * (in other words, at the tail of this deque), waiting up to the + * specified wait time if necessary for space to become available. + * + * <p>This method is equivalent to + * {@link #offerLast(Object,long,TimeUnit) offerLast}. + * + * @param e the element to add + * @return <tt>true</tt> if the element was added to this deque, else + * <tt>false</tt> + * @throws InterruptedException {@inheritDoc} + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this deque + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this deque + */ + boolean offer(E e, long timeout, TimeUnit unit) + throws InterruptedException; + + /** + * Retrieves and removes the head of the queue represented by this deque + * (in other words, the first element of this deque). + * This method differs from {@link #poll poll} only in that it + * throws an exception if this deque is empty. + * + * <p>This method is equivalent to {@link #removeFirst() removeFirst}. + * + * @return the head of the queue represented by this deque + * @throws NoSuchElementException if this deque is empty + */ + E remove(); + + /** + * Retrieves and removes the head of the queue represented by this deque + * (in other words, the first element of this deque), or returns + * <tt>null</tt> if this deque is empty. + * + * <p>This method is equivalent to {@link #pollFirst()}. + * + * @return the head of this deque, or <tt>null</tt> if this deque is empty + */ + E poll(); + + /** + * Retrieves and removes the head of the queue represented by this deque + * (in other words, the first element of this deque), waiting if + * necessary until an element becomes available. + * + * <p>This method is equivalent to {@link #takeFirst() takeFirst}. + * + * @return the head of this deque + * @throws InterruptedException if interrupted while waiting + */ + E take() throws InterruptedException; + + /** + * Retrieves and removes the head of the queue represented by this deque + * (in other words, the first element of this deque), waiting up to the + * specified wait time if necessary for an element to become available. + * + * <p>This method is equivalent to + * {@link #pollFirst(long,TimeUnit) pollFirst}. + * + * @return the head of this deque, or <tt>null</tt> if the + * specified waiting time elapses before an element is available + * @throws InterruptedException if interrupted while waiting + */ + E poll(long timeout, TimeUnit unit) + throws InterruptedException; + + /** + * Retrieves, but does not remove, the head of the queue represented by + * this deque (in other words, the first element of this deque). + * This method differs from {@link #peek peek} only in that it throws an + * exception if this deque is empty. + * + * <p>This method is equivalent to {@link #getFirst() getFirst}. + * + * @return the head of this deque + * @throws NoSuchElementException if this deque is empty + */ + E element(); + + /** + * Retrieves, but does not remove, the head of the queue represented by + * this deque (in other words, the first element of this deque), or + * returns <tt>null</tt> if this deque is empty. + * + * <p>This method is equivalent to {@link #peekFirst() peekFirst}. + * + * @return the head of this deque, or <tt>null</tt> if this deque is empty + */ + E peek(); + + /** + * 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 <tt>e</tt> such that + * <tt>o.equals(e)</tt> (if such an element exists). + * Returns <tt>true</tt> 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) removeFirstOccurrence}. + * + * @param o element to be removed from this deque, if present + * @return <tt>true</tt> if this deque changed as a result of the call + * @throws ClassCastException if the class of the specified element + * is incompatible with this deque (optional) + * @throws NullPointerException if the specified element is null (optional) + */ + boolean remove(Object o); + + /** + * Returns <tt>true</tt> if this deque contains the specified element. + * More formally, returns <tt>true</tt> if and only if this deque contains + * at least one element <tt>e</tt> such that <tt>o.equals(e)</tt>. + * + * @param o object to be checked for containment in this deque + * @return <tt>true</tt> if this deque contains the specified element + * @throws ClassCastException if the class of the specified element + * is incompatible with this deque (optional) + * @throws NullPointerException if the specified element is null (optional) + */ + public boolean contains(Object o); + + /** + * Returns the number of elements in this deque. + * + * @return the number of elements in this deque + */ + public int size(); + + /** + * Returns an iterator over the elements in this deque in proper sequence. + * The elements will be returned in order from first (head) to last (tail). + * + * @return an iterator over the elements in this deque in proper sequence + */ + Iterator<E> iterator(); + + // *** Stack methods *** + + /** + * Pushes an element onto the stack represented by this deque. In other + * words, inserts the element at the front of this deque unless it would + * violate capacity restrictions. + * + * <p>This method is equivalent to {@link #addFirst(Object) addFirst}. + * + * @throws IllegalStateException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException {@inheritDoc} + */ + void push(E e); +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/BlockingQueue.java b/libjava/classpath/external/jsr166/java/util/concurrent/BlockingQueue.java new file mode 100644 index 000000000..b47cc9842 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/BlockingQueue.java @@ -0,0 +1,344 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; + +import java.util.Collection; +import java.util.Queue; + +/** + * A {@link java.util.Queue} that additionally supports operations + * that wait for the queue to become non-empty when retrieving an + * element, and wait for space to become available in the queue when + * storing an element. + * + * <p><tt>BlockingQueue</tt> methods come in four forms, with different ways + * of handling operations that cannot be satisfied immediately, but may be + * satisfied at some point in the future: + * one throws an exception, the second returns a special value (either + * <tt>null</tt> or <tt>false</tt>, depending on the operation), the third + * blocks the current thread indefinitely until the operation can succeed, + * and the fourth blocks for only a given maximum time limit before giving + * up. These methods are summarized in the following table: + * + * <p> + * <table BORDER CELLPADDING=3 CELLSPACING=1> + * <tr> + * <td></td> + * <td ALIGN=CENTER><em>Throws exception</em></td> + * <td ALIGN=CENTER><em>Special value</em></td> + * <td ALIGN=CENTER><em>Blocks</em></td> + * <td ALIGN=CENTER><em>Times out</em></td> + * </tr> + * <tr> + * <td><b>Insert</b></td> + * <td>{@link #add add(e)}</td> + * <td>{@link #offer offer(e)}</td> + * <td>{@link #put put(e)}</td> + * <td>{@link #offer(Object, long, TimeUnit) offer(e, time, unit)}</td> + * </tr> + * <tr> + * <td><b>Remove</b></td> + * <td>{@link #remove remove()}</td> + * <td>{@link #poll poll()}</td> + * <td>{@link #take take()}</td> + * <td>{@link #poll(long, TimeUnit) poll(time, unit)}</td> + * </tr> + * <tr> + * <td><b>Examine</b></td> + * <td>{@link #element element()}</td> + * <td>{@link #peek peek()}</td> + * <td><em>not applicable</em></td> + * <td><em>not applicable</em></td> + * </tr> + * </table> + * + * <p>A <tt>BlockingQueue</tt> does not accept <tt>null</tt> elements. + * Implementations throw <tt>NullPointerException</tt> on attempts + * to <tt>add</tt>, <tt>put</tt> or <tt>offer</tt> a <tt>null</tt>. A + * <tt>null</tt> is used as a sentinel value to indicate failure of + * <tt>poll</tt> operations. + * + * <p>A <tt>BlockingQueue</tt> may be capacity bounded. At any given + * time it may have a <tt>remainingCapacity</tt> beyond which no + * additional elements can be <tt>put</tt> without blocking. + * A <tt>BlockingQueue</tt> without any intrinsic capacity constraints always + * reports a remaining capacity of <tt>Integer.MAX_VALUE</tt>. + * + * <p> <tt>BlockingQueue</tt> implementations are designed to be used + * primarily for producer-consumer queues, but additionally support + * the {@link java.util.Collection} interface. So, for example, it is + * possible to remove an arbitrary element from a queue using + * <tt>remove(x)</tt>. However, such operations are in general + * <em>not</em> performed very efficiently, and are intended for only + * occasional use, such as when a queued message is cancelled. + * + * <p> <tt>BlockingQueue</tt> implementations are thread-safe. All + * queuing methods achieve their effects atomically using internal + * locks or other forms of concurrency control. However, the + * <em>bulk</em> Collection operations <tt>addAll</tt>, + * <tt>containsAll</tt>, <tt>retainAll</tt> and <tt>removeAll</tt> are + * <em>not</em> necessarily performed atomically unless specified + * otherwise in an implementation. So it is possible, for example, for + * <tt>addAll(c)</tt> to fail (throwing an exception) after adding + * only some of the elements in <tt>c</tt>. + * + * <p>A <tt>BlockingQueue</tt> does <em>not</em> intrinsically support + * any kind of "close" or "shutdown" operation to + * indicate that no more items will be added. The needs and usage of + * such features tend to be implementation-dependent. For example, a + * common tactic is for producers to insert special + * <em>end-of-stream</em> or <em>poison</em> objects, that are + * interpreted accordingly when taken by consumers. + * + * <p> + * Usage example, based on a typical producer-consumer scenario. + * Note that a <tt>BlockingQueue</tt> can safely be used with multiple + * producers and multiple consumers. + * <pre> + * class Producer implements Runnable { + * private final BlockingQueue queue; + * Producer(BlockingQueue q) { queue = q; } + * public void run() { + * try { + * while (true) { queue.put(produce()); } + * } catch (InterruptedException ex) { ... handle ...} + * } + * Object produce() { ... } + * } + * + * class Consumer implements Runnable { + * private final BlockingQueue queue; + * Consumer(BlockingQueue q) { queue = q; } + * public void run() { + * try { + * while (true) { consume(queue.take()); } + * } catch (InterruptedException ex) { ... handle ...} + * } + * void consume(Object x) { ... } + * } + * + * class Setup { + * void main() { + * BlockingQueue q = new SomeQueueImplementation(); + * Producer p = new Producer(q); + * Consumer c1 = new Consumer(q); + * Consumer c2 = new Consumer(q); + * new Thread(p).start(); + * new Thread(c1).start(); + * new Thread(c2).start(); + * } + * } + * </pre> + * + * <p>Memory consistency effects: As with other concurrent + * collections, actions in a thread prior to placing an object into a + * {@code BlockingQueue} + * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a> + * actions subsequent to the access or removal of that element from + * the {@code BlockingQueue} in another thread. + * + * <p>This interface is a member of the + * <a href="{@docRoot}/../technotes/guides/collections/index.html"> + * Java Collections Framework</a>. + * + * @since 1.5 + * @author Doug Lea + * @param <E> the type of elements held in this collection + */ +public interface BlockingQueue<E> extends Queue<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> if no space is currently available. + * When using a capacity-restricted queue, it is generally preferable to + * use {@link #offer(Object) offer}. + * + * @param e the element to add + * @return <tt>true</tt> (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 + * prevents it from being added to this queue + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this queue + */ + boolean add(E 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 <tt>false</tt> if no space is currently + * available. When using a capacity-restricted queue, this method is + * generally preferable to {@link #add}, which can fail to insert an + * element only by throwing an exception. + * + * @param e the element to add + * @return <tt>true</tt> if the element was added to this queue, else + * <tt>false</tt> + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this queue + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this queue + */ + boolean offer(E e); + + /** + * Inserts the specified element into this queue, waiting if necessary + * for space to become available. + * + * @param e the element to add + * @throws InterruptedException if interrupted while waiting + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this queue + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this queue + */ + void put(E e) throws InterruptedException; + + /** + * Inserts the specified element into this queue, waiting up to the + * specified wait time if necessary for space to become available. + * + * @param e the element to add + * @param timeout how long to wait before giving up, in units of + * <tt>unit</tt> + * @param unit a <tt>TimeUnit</tt> determining how to interpret the + * <tt>timeout</tt> parameter + * @return <tt>true</tt> if successful, or <tt>false</tt> if + * the specified waiting time elapses before space is available + * @throws InterruptedException if interrupted while waiting + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this queue + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this queue + */ + boolean offer(E e, long timeout, TimeUnit unit) + throws InterruptedException; + + /** + * Retrieves and removes the head of this queue, waiting if necessary + * until an element becomes available. + * + * @return the head of this queue + * @throws InterruptedException if interrupted while waiting + */ + E take() throws InterruptedException; + + /** + * Retrieves and removes the head of this queue, waiting up to the + * specified wait time if necessary for an element to become available. + * + * @param timeout how long to wait before giving up, in units of + * <tt>unit</tt> + * @param unit a <tt>TimeUnit</tt> determining how to interpret the + * <tt>timeout</tt> parameter + * @return the head of this queue, or <tt>null</tt> if the + * specified waiting time elapses before an element is available + * @throws InterruptedException if interrupted while waiting + */ + E poll(long timeout, TimeUnit unit) + throws InterruptedException; + + /** + * Returns the number of additional elements that this queue can ideally + * (in the absence of memory or resource constraints) accept without + * blocking, or <tt>Integer.MAX_VALUE</tt> if there is no intrinsic + * limit. + * + * <p>Note that you <em>cannot</em> always tell if an attempt to insert + * an element will succeed by inspecting <tt>remainingCapacity</tt> + * because it may be the case that another thread is about to + * insert or remove an element. + * + * @return the remaining capacity + */ + int remainingCapacity(); + + /** + * Removes a single instance of the specified element from this queue, + * if it is present. More formally, removes an element <tt>e</tt> such + * that <tt>o.equals(e)</tt>, if this queue contains one or more such + * elements. + * Returns <tt>true</tt> if this queue contained the specified element + * (or equivalently, if this queue changed as a result of the call). + * + * @param o element to be removed from this queue, if present + * @return <tt>true</tt> if this queue changed as a result of the call + * @throws ClassCastException if the class of the specified element + * is incompatible with this queue (optional) + * @throws NullPointerException if the specified element is null (optional) + */ + boolean remove(Object o); + + /** + * Returns <tt>true</tt> if this queue contains the specified element. + * More formally, returns <tt>true</tt> if and only if this queue contains + * at least one element <tt>e</tt> such that <tt>o.equals(e)</tt>. + * + * @param o object to be checked for containment in this queue + * @return <tt>true</tt> if this queue contains the specified element + * @throws ClassCastException if the class of the specified element + * is incompatible with this queue (optional) + * @throws NullPointerException if the specified element is null (optional) + */ + public boolean contains(Object o); + + /** + * Removes all available elements from this queue and adds them + * to the given collection. This operation may be more + * efficient than repeatedly polling this queue. A failure + * encountered while attempting to add elements to + * collection <tt>c</tt> may result in elements being in neither, + * either or both collections when the associated exception is + * thrown. Attempts to drain a queue to itself result in + * <tt>IllegalArgumentException</tt>. Further, the behavior of + * this operation is undefined if the specified collection is + * modified while the operation is in progress. + * + * @param c the collection to transfer elements into + * @return the number of elements transferred + * @throws UnsupportedOperationException if addition of elements + * is not supported by the specified collection + * @throws ClassCastException if the class of an element of this queue + * prevents it from being added to the specified collection + * @throws NullPointerException if the specified collection is null + * @throws IllegalArgumentException if the specified collection is this + * queue, or some property of an element of this queue prevents + * it from being added to the specified collection + */ + int drainTo(Collection<? super E> c); + + /** + * Removes at most the given number of available elements from + * this queue and adds them to the given collection. A failure + * encountered while attempting to add elements to + * collection <tt>c</tt> may result in elements being in neither, + * either or both collections when the associated exception is + * thrown. Attempts to drain a queue to itself result in + * <tt>IllegalArgumentException</tt>. Further, the behavior of + * this operation is undefined if the specified collection is + * modified while the operation is in progress. + * + * @param c the collection to transfer elements into + * @param maxElements the maximum number of elements to transfer + * @return the number of elements transferred + * @throws UnsupportedOperationException if addition of elements + * is not supported by the specified collection + * @throws ClassCastException if the class of an element of this queue + * prevents it from being added to the specified collection + * @throws NullPointerException if the specified collection is null + * @throws IllegalArgumentException if the specified collection is this + * queue, or some property of an element of this queue prevents + * it from being added to the specified collection + */ + int drainTo(Collection<? super E> c, int maxElements); +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/BrokenBarrierException.java b/libjava/classpath/external/jsr166/java/util/concurrent/BrokenBarrierException.java new file mode 100644 index 000000000..3f93fbb9d --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/BrokenBarrierException.java @@ -0,0 +1,38 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; + +/** + * Exception thrown when a thread tries to wait upon a barrier that is + * in a broken state, or which enters the broken state while the thread + * is waiting. + * + * @see CyclicBarrier + * + * @since 1.5 + * @author Doug Lea + * + */ +public class BrokenBarrierException extends Exception { + private static final long serialVersionUID = 7117394618823254244L; + + /** + * Constructs a <tt>BrokenBarrierException</tt> with no specified detail + * message. + */ + public BrokenBarrierException() {} + + /** + * Constructs a <tt>BrokenBarrierException</tt> with the specified + * detail message. + * + * @param message the detail message + */ + public BrokenBarrierException(String message) { + super(message); + } +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/Callable.java b/libjava/classpath/external/jsr166/java/util/concurrent/Callable.java new file mode 100644 index 000000000..abc4d0407 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/Callable.java @@ -0,0 +1,36 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; + +/** + * A task that returns a result and may throw an exception. + * Implementors define a single method with no arguments called + * <tt>call</tt>. + * + * <p>The <tt>Callable</tt> interface is similar to {@link + * java.lang.Runnable}, in that both are designed for classes whose + * instances are potentially executed by another thread. A + * <tt>Runnable</tt>, however, does not return a result and cannot + * throw a checked exception. + * + * <p> The {@link Executors} class contains utility methods to + * convert from other common forms to <tt>Callable</tt> classes. + * + * @see Executor + * @since 1.5 + * @author Doug Lea + * @param <V> the result type of method <tt>call</tt> + */ +public interface Callable<V> { + /** + * Computes a result, or throws an exception if unable to do so. + * + * @return computed result + * @throws Exception if unable to compute a result + */ + V call() throws Exception; +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/CancellationException.java b/libjava/classpath/external/jsr166/java/util/concurrent/CancellationException.java new file mode 100644 index 000000000..2c29544a0 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/CancellationException.java @@ -0,0 +1,34 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; + +/** + * Exception indicating that the result of a value-producing task, + * such as a {@link FutureTask}, cannot be retrieved because the task + * was cancelled. + * + * @since 1.5 + * @author Doug Lea + */ +public class CancellationException extends IllegalStateException { + private static final long serialVersionUID = -9202173006928992231L; + + /** + * Constructs a <tt>CancellationException</tt> with no detail message. + */ + public CancellationException() {} + + /** + * Constructs a <tt>CancellationException</tt> with the specified detail + * message. + * + * @param message the detail message + */ + public CancellationException(String message) { + super(message); + } +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/CompletionService.java b/libjava/classpath/external/jsr166/java/util/concurrent/CompletionService.java new file mode 100644 index 000000000..df9f719c4 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/CompletionService.java @@ -0,0 +1,97 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; + +/** + * A service that decouples the production of new asynchronous tasks + * from the consumption of the results of completed tasks. Producers + * <tt>submit</tt> tasks for execution. Consumers <tt>take</tt> + * completed tasks and process their results in the order they + * complete. A <tt>CompletionService</tt> can for example be used to + * manage asynchronous IO, in which tasks that perform reads are + * submitted in one part of a program or system, and then acted upon + * in a different part of the program when the reads complete, + * possibly in a different order than they were requested. + * + * <p>Typically, a <tt>CompletionService</tt> relies on a separate + * {@link Executor} to actually execute the tasks, in which case the + * <tt>CompletionService</tt> only manages an internal completion + * queue. The {@link ExecutorCompletionService} class provides an + * implementation of this approach. + * + * <p>Memory consistency effects: Actions in a thread prior to + * submitting a task to a {@code CompletionService} + * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a> + * actions taken by that task, which in turn <i>happen-before</i> + * actions following a successful return from the corresponding {@code take()}. + * + */ +public interface CompletionService<V> { + /** + * Submits a value-returning task for execution and returns a Future + * representing the pending results of the task. Upon completion, + * this task may be taken or polled. + * + * @param task the task to submit + * @return a Future representing pending completion of the task + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + * @throws NullPointerException if the task is null + */ + Future<V> submit(Callable<V> task); + + /** + * Submits a Runnable task for execution and returns a Future + * representing that task. Upon completion, this task may be + * taken or polled. + * + * @param task the task to submit + * @param result the result to return upon successful completion + * @return a Future representing pending completion of the task, + * and whose <tt>get()</tt> method will return the given + * result value upon completion + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + * @throws NullPointerException if the task is null + */ + Future<V> submit(Runnable task, V result); + + /** + * Retrieves and removes the Future representing the next + * completed task, waiting if none are yet present. + * + * @return the Future representing the next completed task + * @throws InterruptedException if interrupted while waiting + */ + Future<V> take() throws InterruptedException; + + + /** + * Retrieves and removes the Future representing the next + * completed task or <tt>null</tt> if none are present. + * + * @return the Future representing the next completed task, or + * <tt>null</tt> if none are present + */ + Future<V> poll(); + + /** + * Retrieves and removes the Future representing the next + * completed task, waiting if necessary up to the specified wait + * time if none are yet present. + * + * @param timeout how long to wait before giving up, in units of + * <tt>unit</tt> + * @param unit a <tt>TimeUnit</tt> determining how to interpret the + * <tt>timeout</tt> parameter + * @return the Future representing the next completed task or + * <tt>null</tt> if the specified waiting time elapses + * before one is present + * @throws InterruptedException if interrupted while waiting + */ + Future<V> poll(long timeout, TimeUnit unit) throws InterruptedException; +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/ConcurrentHashMap.java b/libjava/classpath/external/jsr166/java/util/concurrent/ConcurrentHashMap.java new file mode 100644 index 000000000..9ad9ab25b --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/ConcurrentHashMap.java @@ -0,0 +1,1277 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.concurrent.locks.*; +import java.util.*; +import java.io.Serializable; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +/** + * A hash table supporting full concurrency of retrievals and + * adjustable expected concurrency for updates. This class obeys the + * same functional specification as {@link java.util.Hashtable}, and + * includes versions of methods corresponding to each method of + * <tt>Hashtable</tt>. However, even though all operations are + * thread-safe, retrieval operations do <em>not</em> entail locking, + * and there is <em>not</em> any support for locking the entire table + * in a way that prevents all access. This class is fully + * interoperable with <tt>Hashtable</tt> in programs that rely on its + * thread safety but not on its synchronization details. + * + * <p> Retrieval operations (including <tt>get</tt>) generally do not + * block, so may overlap with update operations (including + * <tt>put</tt> and <tt>remove</tt>). Retrievals reflect the results + * of the most recently <em>completed</em> update operations holding + * upon their onset. For aggregate operations such as <tt>putAll</tt> + * and <tt>clear</tt>, concurrent retrievals may reflect insertion or + * removal of only some entries. Similarly, Iterators and + * Enumerations return elements reflecting the state of the hash table + * at some point at or since the creation of the iterator/enumeration. + * They do <em>not</em> throw {@link ConcurrentModificationException}. + * However, iterators are designed to be used by only one thread at a time. + * + * <p> The allowed concurrency among update operations is guided by + * the optional <tt>concurrencyLevel</tt> constructor argument + * (default <tt>16</tt>), which is used as a hint for internal sizing. The + * table is internally partitioned to try to permit the indicated + * number of concurrent updates without contention. Because placement + * in hash tables is essentially random, the actual concurrency will + * vary. Ideally, you should choose a value to accommodate as many + * threads as will ever concurrently modify the table. Using a + * significantly higher value than you need can waste space and time, + * and a significantly lower value can lead to thread contention. But + * overestimates and underestimates within an order of magnitude do + * not usually have much noticeable impact. A value of one is + * appropriate when it is known that only one thread will modify and + * all others will only read. Also, resizing this or any other kind of + * hash table is a relatively slow operation, so, when possible, it is + * a good idea to provide estimates of expected table sizes in + * constructors. + * + * <p>This class and its views and iterators implement all of the + * <em>optional</em> methods of the {@link Map} and {@link Iterator} + * interfaces. + * + * <p> Like {@link Hashtable} but unlike {@link HashMap}, this class + * does <em>not</em> allow <tt>null</tt> to be used as a key or value. + * + * <p>This class is a member of the + * <a href="{@docRoot}/../technotes/guides/collections/index.html"> + * Java Collections Framework</a>. + * + * @since 1.5 + * @author Doug Lea + * @param <K> the type of keys maintained by this map + * @param <V> the type of mapped values + */ +public class ConcurrentHashMap<K, V> extends AbstractMap<K, V> + implements ConcurrentMap<K, V>, Serializable { + private static final long serialVersionUID = 7249069246763182397L; + + /* + * The basic strategy is to subdivide the table among Segments, + * each of which itself is a concurrently readable hash table. + */ + + /* ---------------- Constants -------------- */ + + /** + * The default initial capacity for this table, + * used when not otherwise specified in a constructor. + */ + static final int DEFAULT_INITIAL_CAPACITY = 16; + + /** + * The default load factor for this table, used when not + * otherwise specified in a constructor. + */ + static final float DEFAULT_LOAD_FACTOR = 0.75f; + + /** + * The default concurrency level for this table, used when not + * otherwise specified in a constructor. + */ + static final int DEFAULT_CONCURRENCY_LEVEL = 16; + + /** + * The maximum capacity, used if a higher value is implicitly + * specified by either of the constructors with arguments. MUST + * be a power of two <= 1<<30 to ensure that entries are indexable + * using ints. + */ + static final int MAXIMUM_CAPACITY = 1 << 30; + + /** + * The maximum number of segments to allow; used to bound + * constructor arguments. + */ + static final int MAX_SEGMENTS = 1 << 16; // slightly conservative + + /** + * Number of unsynchronized retries in size and containsValue + * methods before resorting to locking. This is used to avoid + * unbounded retries if tables undergo continuous modification + * which would make it impossible to obtain an accurate result. + */ + static final int RETRIES_BEFORE_LOCK = 2; + + /* ---------------- Fields -------------- */ + + /** + * Mask value for indexing into segments. The upper bits of a + * key's hash code are used to choose the segment. + */ + final int segmentMask; + + /** + * Shift value for indexing within segments. + */ + final int segmentShift; + + /** + * The segments, each of which is a specialized hash table + */ + final Segment<K,V>[] segments; + + transient Set<K> keySet; + transient Set<Map.Entry<K,V>> entrySet; + transient Collection<V> values; + + /* ---------------- Small Utilities -------------- */ + + /** + * Applies a supplemental hash function to a given hashCode, which + * defends against poor quality hash functions. This is critical + * because ConcurrentHashMap uses power-of-two length hash tables, + * that otherwise encounter collisions for hashCodes that do not + * differ in lower bits. + */ + private static int hash(int h) { + // This function ensures that hashCodes that differ only by + // constant multiples at each bit position have a bounded + // number of collisions (approximately 8 at default load factor). + h ^= (h >>> 20) ^ (h >>> 12); + return h ^ (h >>> 7) ^ (h >>> 4); + } + + /** + * Returns the segment that should be used for key with given hash + * @param hash the hash code for the key + * @return the segment + */ + final Segment<K,V> segmentFor(int hash) { + return segments[(hash >>> segmentShift) & segmentMask]; + } + + /* ---------------- Inner Classes -------------- */ + + /** + * ConcurrentHashMap list entry. Note that this is never exported + * out as a user-visible Map.Entry. + * + * Because the value field is volatile, not final, it is legal wrt + * the Java Memory Model for an unsynchronized reader to see null + * instead of initial value when read via a data race. Although a + * reordering leading to this is not likely to ever actually + * occur, the Segment.readValueUnderLock method is used as a + * backup in case a null (pre-initialized) value is ever seen in + * an unsynchronized access method. + */ + static final class HashEntry<K,V> { + final K key; + final int hash; + volatile V value; + final HashEntry<K,V> next; + + HashEntry(K key, int hash, HashEntry<K,V> next, V value) { + this.key = key; + this.hash = hash; + this.next = next; + this.value = value; + } + + @SuppressWarnings("unchecked") + static final <K,V> HashEntry<K,V>[] newArray(int i) { + return new HashEntry[i]; + } + } + + /** + * Segments are specialized versions of hash tables. This + * subclasses from ReentrantLock opportunistically, just to + * simplify some locking and avoid separate construction. + */ + static final class Segment<K,V> extends ReentrantLock implements Serializable { + /* + * Segments maintain a table of entry lists that are ALWAYS + * kept in a consistent state, so can be read without locking. + * Next fields of nodes are immutable (final). All list + * additions are performed at the front of each bin. This + * makes it easy to check changes, and also fast to traverse. + * When nodes would otherwise be changed, new nodes are + * created to replace them. This works well for hash tables + * since the bin lists tend to be short. (The average length + * is less than two for the default load factor threshold.) + * + * Read operations can thus proceed without locking, but rely + * on selected uses of volatiles to ensure that completed + * write operations performed by other threads are + * noticed. For most purposes, the "count" field, tracking the + * number of elements, serves as that volatile variable + * ensuring visibility. This is convenient because this field + * needs to be read in many read operations anyway: + * + * - All (unsynchronized) read operations must first read the + * "count" field, and should not look at table entries if + * it is 0. + * + * - All (synchronized) write operations should write to + * the "count" field after structurally changing any bin. + * The operations must not take any action that could even + * momentarily cause a concurrent read operation to see + * inconsistent data. This is made easier by the nature of + * the read operations in Map. For example, no operation + * can reveal that the table has grown but the threshold + * has not yet been updated, so there are no atomicity + * requirements for this with respect to reads. + * + * As a guide, all critical volatile reads and writes to the + * count field are marked in code comments. + */ + + private static final long serialVersionUID = 2249069246763182397L; + + /** + * The number of elements in this segment's region. + */ + transient volatile int count; + + /** + * Number of updates that alter the size of the table. This is + * used during bulk-read methods to make sure they see a + * consistent snapshot: If modCounts change during a traversal + * of segments computing size or checking containsValue, then + * we might have an inconsistent view of state so (usually) + * must retry. + */ + transient int modCount; + + /** + * The table is rehashed when its size exceeds this threshold. + * (The value of this field is always <tt>(int)(capacity * + * loadFactor)</tt>.) + */ + transient int threshold; + + /** + * The per-segment table. + */ + transient volatile HashEntry<K,V>[] table; + + /** + * The load factor for the hash table. Even though this value + * is same for all segments, it is replicated to avoid needing + * links to outer object. + * @serial + */ + final float loadFactor; + + Segment(int initialCapacity, float lf) { + loadFactor = lf; + setTable(HashEntry.<K,V>newArray(initialCapacity)); + } + + @SuppressWarnings("unchecked") + static final <K,V> Segment<K,V>[] newArray(int i) { + return new Segment[i]; + } + + /** + * Sets table to new HashEntry array. + * Call only while holding lock or in constructor. + */ + void setTable(HashEntry<K,V>[] newTable) { + threshold = (int)(newTable.length * loadFactor); + table = newTable; + } + + /** + * Returns properly casted first entry of bin for given hash. + */ + HashEntry<K,V> getFirst(int hash) { + HashEntry<K,V>[] tab = table; + return tab[hash & (tab.length - 1)]; + } + + /** + * Reads value field of an entry under lock. Called if value + * field ever appears to be null. This is possible only if a + * compiler happens to reorder a HashEntry initialization with + * its table assignment, which is legal under memory model + * but is not known to ever occur. + */ + V readValueUnderLock(HashEntry<K,V> e) { + lock(); + try { + return e.value; + } finally { + unlock(); + } + } + + /* Specialized implementations of map methods */ + + V get(Object key, int hash) { + if (count != 0) { // read-volatile + HashEntry<K,V> e = getFirst(hash); + while (e != null) { + if (e.hash == hash && key.equals(e.key)) { + V v = e.value; + if (v != null) + return v; + return readValueUnderLock(e); // recheck + } + e = e.next; + } + } + return null; + } + + boolean containsKey(Object key, int hash) { + if (count != 0) { // read-volatile + HashEntry<K,V> e = getFirst(hash); + while (e != null) { + if (e.hash == hash && key.equals(e.key)) + return true; + e = e.next; + } + } + return false; + } + + boolean containsValue(Object value) { + if (count != 0) { // read-volatile + HashEntry<K,V>[] tab = table; + int len = tab.length; + for (int i = 0 ; i < len; i++) { + for (HashEntry<K,V> e = tab[i]; e != null; e = e.next) { + V v = e.value; + if (v == null) // recheck + v = readValueUnderLock(e); + if (value.equals(v)) + return true; + } + } + } + return false; + } + + boolean replace(K key, int hash, V oldValue, V newValue) { + lock(); + try { + HashEntry<K,V> e = getFirst(hash); + while (e != null && (e.hash != hash || !key.equals(e.key))) + e = e.next; + + boolean replaced = false; + if (e != null && oldValue.equals(e.value)) { + replaced = true; + e.value = newValue; + } + return replaced; + } finally { + unlock(); + } + } + + V replace(K key, int hash, V newValue) { + lock(); + try { + HashEntry<K,V> e = getFirst(hash); + while (e != null && (e.hash != hash || !key.equals(e.key))) + e = e.next; + + V oldValue = null; + if (e != null) { + oldValue = e.value; + e.value = newValue; + } + return oldValue; + } finally { + unlock(); + } + } + + + V put(K key, int hash, V value, boolean onlyIfAbsent) { + lock(); + try { + int c = count; + if (c++ > threshold) // ensure capacity + rehash(); + HashEntry<K,V>[] tab = table; + int index = hash & (tab.length - 1); + HashEntry<K,V> first = tab[index]; + HashEntry<K,V> e = first; + while (e != null && (e.hash != hash || !key.equals(e.key))) + e = e.next; + + V oldValue; + if (e != null) { + oldValue = e.value; + if (!onlyIfAbsent) + e.value = value; + } + else { + oldValue = null; + ++modCount; + tab[index] = new HashEntry<K,V>(key, hash, first, value); + count = c; // write-volatile + } + return oldValue; + } finally { + unlock(); + } + } + + void rehash() { + HashEntry<K,V>[] oldTable = table; + int oldCapacity = oldTable.length; + if (oldCapacity >= MAXIMUM_CAPACITY) + return; + + /* + * Reclassify nodes in each list to new Map. Because we are + * using power-of-two expansion, the elements from each bin + * must either stay at same index, or move with a power of two + * offset. We eliminate unnecessary node creation by catching + * cases where old nodes can be reused because their next + * fields won't change. Statistically, at the default + * threshold, only about one-sixth of them need cloning when + * a table doubles. The nodes they replace will be garbage + * collectable as soon as they are no longer referenced by any + * reader thread that may be in the midst of traversing table + * right now. + */ + + HashEntry<K,V>[] newTable = HashEntry.newArray(oldCapacity<<1); + threshold = (int)(newTable.length * loadFactor); + int sizeMask = newTable.length - 1; + for (int i = 0; i < oldCapacity ; i++) { + // We need to guarantee that any existing reads of old Map can + // proceed. So we cannot yet null out each bin. + HashEntry<K,V> e = oldTable[i]; + + if (e != null) { + HashEntry<K,V> next = e.next; + int idx = e.hash & sizeMask; + + // Single node on list + if (next == null) + newTable[idx] = e; + + else { + // Reuse trailing consecutive sequence at same slot + HashEntry<K,V> lastRun = e; + int lastIdx = idx; + for (HashEntry<K,V> last = next; + last != null; + last = last.next) { + int k = last.hash & sizeMask; + if (k != lastIdx) { + lastIdx = k; + lastRun = last; + } + } + newTable[lastIdx] = lastRun; + + // Clone all remaining nodes + for (HashEntry<K,V> p = e; p != lastRun; p = p.next) { + int k = p.hash & sizeMask; + HashEntry<K,V> n = newTable[k]; + newTable[k] = new HashEntry<K,V>(p.key, p.hash, + n, p.value); + } + } + } + } + table = newTable; + } + + /** + * Remove; match on key only if value null, else match both. + */ + V remove(Object key, int hash, Object value) { + lock(); + try { + int c = count - 1; + HashEntry<K,V>[] tab = table; + int index = hash & (tab.length - 1); + HashEntry<K,V> first = tab[index]; + HashEntry<K,V> e = first; + while (e != null && (e.hash != hash || !key.equals(e.key))) + e = e.next; + + V oldValue = null; + if (e != null) { + V v = e.value; + if (value == null || value.equals(v)) { + oldValue = v; + // All entries following removed node can stay + // in list, but all preceding ones need to be + // cloned. + ++modCount; + HashEntry<K,V> newFirst = e.next; + for (HashEntry<K,V> p = first; p != e; p = p.next) + newFirst = new HashEntry<K,V>(p.key, p.hash, + newFirst, p.value); + tab[index] = newFirst; + count = c; // write-volatile + } + } + return oldValue; + } finally { + unlock(); + } + } + + void clear() { + if (count != 0) { + lock(); + try { + HashEntry<K,V>[] tab = table; + for (int i = 0; i < tab.length ; i++) + tab[i] = null; + ++modCount; + count = 0; // write-volatile + } finally { + unlock(); + } + } + } + } + + + + /* ---------------- Public operations -------------- */ + + /** + * Creates a new, empty map with the specified initial + * capacity, load factor and concurrency level. + * + * @param initialCapacity the initial capacity. The implementation + * performs internal sizing to accommodate this many elements. + * @param loadFactor the load factor threshold, used to control resizing. + * Resizing may be performed when the average number of elements per + * bin exceeds this threshold. + * @param concurrencyLevel the estimated number of concurrently + * updating threads. The implementation performs internal sizing + * to try to accommodate this many threads. + * @throws IllegalArgumentException if the initial capacity is + * negative or the load factor or concurrencyLevel are + * nonpositive. + */ + public ConcurrentHashMap(int initialCapacity, + float loadFactor, int concurrencyLevel) { + if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0) + throw new IllegalArgumentException(); + + if (concurrencyLevel > MAX_SEGMENTS) + concurrencyLevel = MAX_SEGMENTS; + + // Find power-of-two sizes best matching arguments + int sshift = 0; + int ssize = 1; + while (ssize < concurrencyLevel) { + ++sshift; + ssize <<= 1; + } + segmentShift = 32 - sshift; + segmentMask = ssize - 1; + this.segments = Segment.newArray(ssize); + + if (initialCapacity > MAXIMUM_CAPACITY) + initialCapacity = MAXIMUM_CAPACITY; + int c = initialCapacity / ssize; + if (c * ssize < initialCapacity) + ++c; + int cap = 1; + while (cap < c) + cap <<= 1; + + for (int i = 0; i < this.segments.length; ++i) + this.segments[i] = new Segment<K,V>(cap, loadFactor); + } + + /** + * Creates a new, empty map with the specified initial capacity + * and load factor and with the default concurrencyLevel (16). + * + * @param initialCapacity The implementation performs internal + * sizing to accommodate this many elements. + * @param loadFactor the load factor threshold, used to control resizing. + * Resizing may be performed when the average number of elements per + * bin exceeds this threshold. + * @throws IllegalArgumentException if the initial capacity of + * elements is negative or the load factor is nonpositive + * + * @since 1.6 + */ + public ConcurrentHashMap(int initialCapacity, float loadFactor) { + this(initialCapacity, loadFactor, DEFAULT_CONCURRENCY_LEVEL); + } + + /** + * Creates a new, empty map with the specified initial capacity, + * and with default load factor (0.75) and concurrencyLevel (16). + * + * @param initialCapacity the initial capacity. The implementation + * performs internal sizing to accommodate this many elements. + * @throws IllegalArgumentException if the initial capacity of + * elements is negative. + */ + public ConcurrentHashMap(int initialCapacity) { + this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL); + } + + /** + * Creates a new, empty map with a default initial capacity (16), + * load factor (0.75) and concurrencyLevel (16). + */ + public ConcurrentHashMap() { + this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL); + } + + /** + * Creates a new map with the same mappings as the given map. + * The map is created with a capacity of 1.5 times the number + * of mappings in the given map or 16 (whichever is greater), + * and a default load factor (0.75) and concurrencyLevel (16). + * + * @param m the map + */ + public ConcurrentHashMap(Map<? extends K, ? extends V> m) { + this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, + DEFAULT_INITIAL_CAPACITY), + DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL); + putAll(m); + } + + /** + * Returns <tt>true</tt> if this map contains no key-value mappings. + * + * @return <tt>true</tt> if this map contains no key-value mappings + */ + public boolean isEmpty() { + final Segment<K,V>[] segments = this.segments; + /* + * We keep track of per-segment modCounts to avoid ABA + * problems in which an element in one segment was added and + * in another removed during traversal, in which case the + * table was never actually empty at any point. Note the + * similar use of modCounts in the size() and containsValue() + * methods, which are the only other methods also susceptible + * to ABA problems. + */ + int[] mc = new int[segments.length]; + int mcsum = 0; + for (int i = 0; i < segments.length; ++i) { + if (segments[i].count != 0) + return false; + else + mcsum += mc[i] = segments[i].modCount; + } + // If mcsum happens to be zero, then we know we got a snapshot + // before any modifications at all were made. This is + // probably common enough to bother tracking. + if (mcsum != 0) { + for (int i = 0; i < segments.length; ++i) { + if (segments[i].count != 0 || + mc[i] != segments[i].modCount) + return false; + } + } + return true; + } + + /** + * Returns the number of key-value mappings in this map. If the + * map contains more than <tt>Integer.MAX_VALUE</tt> elements, returns + * <tt>Integer.MAX_VALUE</tt>. + * + * @return the number of key-value mappings in this map + */ + public int size() { + final Segment<K,V>[] segments = this.segments; + long sum = 0; + long check = 0; + int[] mc = new int[segments.length]; + // Try a few times to get accurate count. On failure due to + // continuous async changes in table, resort to locking. + for (int k = 0; k < RETRIES_BEFORE_LOCK; ++k) { + check = 0; + sum = 0; + int mcsum = 0; + for (int i = 0; i < segments.length; ++i) { + sum += segments[i].count; + mcsum += mc[i] = segments[i].modCount; + } + if (mcsum != 0) { + for (int i = 0; i < segments.length; ++i) { + check += segments[i].count; + if (mc[i] != segments[i].modCount) { + check = -1; // force retry + break; + } + } + } + if (check == sum) + break; + } + if (check != sum) { // Resort to locking all segments + sum = 0; + for (int i = 0; i < segments.length; ++i) + segments[i].lock(); + for (int i = 0; i < segments.length; ++i) + sum += segments[i].count; + for (int i = 0; i < segments.length; ++i) + segments[i].unlock(); + } + if (sum > Integer.MAX_VALUE) + return Integer.MAX_VALUE; + else + return (int)sum; + } + + /** + * Returns the value to which the specified key is mapped, + * or {@code null} if this map contains no mapping for the key. + * + * <p>More formally, if this map contains a mapping from a key + * {@code k} to a value {@code v} such that {@code key.equals(k)}, + * then this method returns {@code v}; otherwise it returns + * {@code null}. (There can be at most one such mapping.) + * + * @throws NullPointerException if the specified key is null + */ + public V get(Object key) { + int hash = hash(key.hashCode()); + return segmentFor(hash).get(key, hash); + } + + /** + * Tests if the specified object is a key in this table. + * + * @param key possible key + * @return <tt>true</tt> if and only if the specified object + * is a key in this table, as determined by the + * <tt>equals</tt> method; <tt>false</tt> otherwise. + * @throws NullPointerException if the specified key is null + */ + public boolean containsKey(Object key) { + int hash = hash(key.hashCode()); + return segmentFor(hash).containsKey(key, hash); + } + + /** + * Returns <tt>true</tt> if this map maps one or more keys to the + * specified value. Note: This method requires a full internal + * traversal of the hash table, and so is much slower than + * method <tt>containsKey</tt>. + * + * @param value value whose presence in this map is to be tested + * @return <tt>true</tt> if this map maps one or more keys to the + * specified value + * @throws NullPointerException if the specified value is null + */ + public boolean containsValue(Object value) { + if (value == null) + throw new NullPointerException(); + + // See explanation of modCount use above + + final Segment<K,V>[] segments = this.segments; + int[] mc = new int[segments.length]; + + // Try a few times without locking + for (int k = 0; k < RETRIES_BEFORE_LOCK; ++k) { + int sum = 0; + int mcsum = 0; + for (int i = 0; i < segments.length; ++i) { + int c = segments[i].count; + mcsum += mc[i] = segments[i].modCount; + if (segments[i].containsValue(value)) + return true; + } + boolean cleanSweep = true; + if (mcsum != 0) { + for (int i = 0; i < segments.length; ++i) { + int c = segments[i].count; + if (mc[i] != segments[i].modCount) { + cleanSweep = false; + break; + } + } + } + if (cleanSweep) + return false; + } + // Resort to locking all segments + for (int i = 0; i < segments.length; ++i) + segments[i].lock(); + boolean found = false; + try { + for (int i = 0; i < segments.length; ++i) { + if (segments[i].containsValue(value)) { + found = true; + break; + } + } + } finally { + for (int i = 0; i < segments.length; ++i) + segments[i].unlock(); + } + return found; + } + + /** + * Legacy method testing if some key maps into the specified value + * in this table. This method is identical in functionality to + * {@link #containsValue}, 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. + + * @param value a value to search for + * @return <tt>true</tt> if and only if some key maps to the + * <tt>value</tt> argument in this table as + * determined by the <tt>equals</tt> method; + * <tt>false</tt> otherwise + * @throws NullPointerException if the specified value is null + */ + public boolean contains(Object value) { + return containsValue(value); + } + + /** + * Maps the specified key to the specified value in this table. + * Neither the key nor the value can be null. + * + * <p> The value can be retrieved by calling the <tt>get</tt> method + * with a key that is equal to the original key. + * + * @param key key with which the specified value is to be associated + * @param value value to be associated with the specified key + * @return the previous value associated with <tt>key</tt>, or + * <tt>null</tt> if there was no mapping for <tt>key</tt> + * @throws NullPointerException if the specified key or value is null + */ + public V put(K key, V value) { + if (value == null) + throw new NullPointerException(); + int hash = hash(key.hashCode()); + return segmentFor(hash).put(key, hash, value, false); + } + + /** + * {@inheritDoc} + * + * @return the previous value associated with the specified key, + * or <tt>null</tt> if there was no mapping for the key + * @throws NullPointerException if the specified key or value is null + */ + public V putIfAbsent(K key, V value) { + if (value == null) + throw new NullPointerException(); + int hash = hash(key.hashCode()); + return segmentFor(hash).put(key, hash, value, true); + } + + /** + * Copies all of the mappings from the specified map to this one. + * These mappings replace any mappings that this map had for any of the + * keys currently in the specified map. + * + * @param m mappings to be stored in this map + */ + public void putAll(Map<? extends K, ? extends V> m) { + for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) + put(e.getKey(), e.getValue()); + } + + /** + * Removes the key (and its corresponding value) from this map. + * This method does nothing if the key is not in the map. + * + * @param key the key that needs to be removed + * @return the previous value associated with <tt>key</tt>, or + * <tt>null</tt> if there was no mapping for <tt>key</tt> + * @throws NullPointerException if the specified key is null + */ + public V remove(Object key) { + int hash = hash(key.hashCode()); + return segmentFor(hash).remove(key, hash, null); + } + + /** + * {@inheritDoc} + * + * @throws NullPointerException if the specified key is null + */ + public boolean remove(Object key, Object value) { + int hash = hash(key.hashCode()); + if (value == null) + return false; + return segmentFor(hash).remove(key, hash, value) != null; + } + + /** + * {@inheritDoc} + * + * @throws NullPointerException if any of the arguments are null + */ + public boolean replace(K key, V oldValue, V newValue) { + if (oldValue == null || newValue == null) + throw new NullPointerException(); + int hash = hash(key.hashCode()); + return segmentFor(hash).replace(key, hash, oldValue, newValue); + } + + /** + * {@inheritDoc} + * + * @return the previous value associated with the specified key, + * or <tt>null</tt> if there was no mapping for the key + * @throws NullPointerException if the specified key or value is null + */ + public V replace(K key, V value) { + if (value == null) + throw new NullPointerException(); + int hash = hash(key.hashCode()); + return segmentFor(hash).replace(key, hash, value); + } + + /** + * Removes all of the mappings from this map. + */ + public void clear() { + for (int i = 0; i < segments.length; ++i) + segments[i].clear(); + } + + /** + * Returns a {@link Set} view of the keys contained in this map. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. The set supports element + * removal, which removes the corresponding mapping from this map, + * via the <tt>Iterator.remove</tt>, <tt>Set.remove</tt>, + * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> + * operations. It does not support the <tt>add</tt> or + * <tt>addAll</tt> operations. + * + * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator + * that will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + */ + public Set<K> keySet() { + Set<K> ks = keySet; + return (ks != null) ? ks : (keySet = new KeySet()); + } + + /** + * Returns a {@link Collection} view of the values contained in this map. + * The collection is backed by the map, so changes to the map are + * reflected in the collection, and vice-versa. The collection + * supports element removal, which removes the corresponding + * mapping from this map, via the <tt>Iterator.remove</tt>, + * <tt>Collection.remove</tt>, <tt>removeAll</tt>, + * <tt>retainAll</tt>, and <tt>clear</tt> operations. It does not + * support the <tt>add</tt> or <tt>addAll</tt> operations. + * + * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator + * that will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + */ + public Collection<V> values() { + Collection<V> vs = values; + return (vs != null) ? vs : (values = new Values()); + } + + /** + * Returns a {@link Set} view of the mappings contained in this map. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. The set supports element + * removal, which removes the corresponding mapping from the map, + * via the <tt>Iterator.remove</tt>, <tt>Set.remove</tt>, + * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> + * operations. It does not support the <tt>add</tt> or + * <tt>addAll</tt> operations. + * + * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator + * that will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + */ + public Set<Map.Entry<K,V>> entrySet() { + Set<Map.Entry<K,V>> es = entrySet; + return (es != null) ? es : (entrySet = new EntrySet()); + } + + /** + * Returns an enumeration of the keys in this table. + * + * @return an enumeration of the keys in this table + * @see #keySet + */ + public Enumeration<K> keys() { + return new KeyIterator(); + } + + /** + * Returns an enumeration of the values in this table. + * + * @return an enumeration of the values in this table + * @see #values + */ + public Enumeration<V> elements() { + return new ValueIterator(); + } + + /* ---------------- Iterator Support -------------- */ + + abstract class HashIterator { + int nextSegmentIndex; + int nextTableIndex; + HashEntry<K,V>[] currentTable; + HashEntry<K, V> nextEntry; + HashEntry<K, V> lastReturned; + + HashIterator() { + nextSegmentIndex = segments.length - 1; + nextTableIndex = -1; + advance(); + } + + public boolean hasMoreElements() { return hasNext(); } + + final void advance() { + if (nextEntry != null && (nextEntry = nextEntry.next) != null) + return; + + while (nextTableIndex >= 0) { + if ( (nextEntry = currentTable[nextTableIndex--]) != null) + return; + } + + while (nextSegmentIndex >= 0) { + Segment<K,V> seg = segments[nextSegmentIndex--]; + if (seg.count != 0) { + currentTable = seg.table; + for (int j = currentTable.length - 1; j >= 0; --j) { + if ( (nextEntry = currentTable[j]) != null) { + nextTableIndex = j - 1; + return; + } + } + } + } + } + + public boolean hasNext() { return nextEntry != null; } + + HashEntry<K,V> nextEntry() { + if (nextEntry == null) + throw new NoSuchElementException(); + lastReturned = nextEntry; + advance(); + return lastReturned; + } + + public void remove() { + if (lastReturned == null) + throw new IllegalStateException(); + ConcurrentHashMap.this.remove(lastReturned.key); + lastReturned = null; + } + } + + final class KeyIterator + extends HashIterator + implements Iterator<K>, Enumeration<K> + { + public K next() { return super.nextEntry().key; } + public K nextElement() { return super.nextEntry().key; } + } + + final class ValueIterator + extends HashIterator + implements Iterator<V>, Enumeration<V> + { + public V next() { return super.nextEntry().value; } + public V nextElement() { return super.nextEntry().value; } + } + + /** + * Custom Entry class used by EntryIterator.next(), that relays + * setValue changes to the underlying map. + */ + final class WriteThroughEntry + extends AbstractMap.SimpleEntry<K,V> + { + WriteThroughEntry(K k, V v) { + super(k,v); + } + + /** + * Set our entry's value and write through to the map. The + * value to return is somewhat arbitrary here. Since a + * WriteThroughEntry does not necessarily track asynchronous + * changes, the most recent "previous" value could be + * different from what we return (or could even have been + * removed in which case the put will re-establish). We do not + * and cannot guarantee more. + */ + public V setValue(V value) { + if (value == null) throw new NullPointerException(); + V v = super.setValue(value); + ConcurrentHashMap.this.put(getKey(), value); + return v; + } + } + + final class EntryIterator + extends HashIterator + implements Iterator<Entry<K,V>> + { + public Map.Entry<K,V> next() { + HashEntry<K,V> e = super.nextEntry(); + return new WriteThroughEntry(e.key, e.value); + } + } + + final class KeySet extends AbstractSet<K> { + public Iterator<K> iterator() { + return new KeyIterator(); + } + public int size() { + return ConcurrentHashMap.this.size(); + } + public boolean contains(Object o) { + return ConcurrentHashMap.this.containsKey(o); + } + public boolean remove(Object o) { + return ConcurrentHashMap.this.remove(o) != null; + } + public void clear() { + ConcurrentHashMap.this.clear(); + } + } + + final class Values extends AbstractCollection<V> { + public Iterator<V> iterator() { + return new ValueIterator(); + } + public int size() { + return ConcurrentHashMap.this.size(); + } + public boolean contains(Object o) { + return ConcurrentHashMap.this.containsValue(o); + } + public void clear() { + ConcurrentHashMap.this.clear(); + } + } + + final class EntrySet extends AbstractSet<Map.Entry<K,V>> { + public Iterator<Map.Entry<K,V>> iterator() { + return new EntryIterator(); + } + public boolean contains(Object o) { + if (!(o instanceof Map.Entry)) + return false; + Map.Entry<?,?> e = (Map.Entry<?,?>)o; + V v = ConcurrentHashMap.this.get(e.getKey()); + return v != null && v.equals(e.getValue()); + } + public boolean remove(Object o) { + if (!(o instanceof Map.Entry)) + return false; + Map.Entry<?,?> e = (Map.Entry<?,?>)o; + return ConcurrentHashMap.this.remove(e.getKey(), e.getValue()); + } + public int size() { + return ConcurrentHashMap.this.size(); + } + public void clear() { + ConcurrentHashMap.this.clear(); + } + } + + /* ---------------- Serialization Support -------------- */ + + /** + * Save the state of the <tt>ConcurrentHashMap</tt> instance to a + * stream (i.e., serialize it). + * @param s the stream + * @serialData + * the key (Object) and value (Object) + * for each key-value mapping, followed by a null pair. + * The key-value mappings are emitted in no particular order. + */ + private void writeObject(java.io.ObjectOutputStream s) throws IOException { + s.defaultWriteObject(); + + for (int k = 0; k < segments.length; ++k) { + Segment<K,V> seg = segments[k]; + seg.lock(); + try { + HashEntry<K,V>[] tab = seg.table; + for (int i = 0; i < tab.length; ++i) { + for (HashEntry<K,V> e = tab[i]; e != null; e = e.next) { + s.writeObject(e.key); + s.writeObject(e.value); + } + } + } finally { + seg.unlock(); + } + } + s.writeObject(null); + s.writeObject(null); + } + + /** + * Reconstitute the <tt>ConcurrentHashMap</tt> instance from a + * stream (i.e., deserialize it). + * @param s the stream + */ + private void readObject(java.io.ObjectInputStream s) + throws IOException, ClassNotFoundException { + s.defaultReadObject(); + + // Initialize each segment to be minimally sized, and let grow. + for (int i = 0; i < segments.length; ++i) { + segments[i].setTable(new HashEntry[1]); + } + + // Read the keys and values, and put the mappings in the table + for (;;) { + K key = (K) s.readObject(); + V value = (V) s.readObject(); + if (key == null) + break; + put(key, value); + } + } +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/ConcurrentLinkedQueue.java b/libjava/classpath/external/jsr166/java/util/concurrent/ConcurrentLinkedQueue.java new file mode 100644 index 000000000..000f4a4c9 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/ConcurrentLinkedQueue.java @@ -0,0 +1,480 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.*; +import java.util.concurrent.atomic.*; + + +/** + * An unbounded thread-safe {@linkplain Queue queue} based on linked nodes. + * This queue orders elements FIFO (first-in-first-out). + * The <em>head</em> of the queue is that element that has been on the + * queue the longest time. + * The <em>tail</em> of the queue is that element that has been on the + * queue the shortest time. New elements + * are inserted at the tail of the queue, and the queue retrieval + * operations obtain elements at the head of the queue. + * A <tt>ConcurrentLinkedQueue</tt> is an appropriate choice when + * many threads will share access to a common collection. + * This queue does not permit <tt>null</tt> elements. + * + * <p>This implementation employs an efficient "wait-free" + * 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 + * Algorithms</a> by Maged M. Michael and Michael L. Scott. + * + * <p>Beware that, unlike in most collections, the <tt>size</tt> method + * is <em>NOT</em> a constant-time operation. Because of the + * asynchronous nature of these queues, determining the current number + * of elements requires a traversal of the elements. + * + * <p>This class and its iterator implement all of the + * <em>optional</em> methods of the {@link Collection} and {@link + * Iterator} interfaces. + * + * <p>Memory consistency effects: As with other concurrent + * collections, actions in a thread prior to placing an object into a + * {@code ConcurrentLinkedQueue} + * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a> + * actions subsequent to the access or removal of that element from + * the {@code ConcurrentLinkedQueue} in another thread. + * + * <p>This class is a member of the + * <a href="{@docRoot}/../technotes/guides/collections/index.html"> + * Java Collections Framework</a>. + * + * @since 1.5 + * @author Doug Lea + * @param <E> the type of elements held in this collection + * + */ +public class ConcurrentLinkedQueue<E> extends AbstractQueue<E> + implements Queue<E>, java.io.Serializable { + private static final long serialVersionUID = 196745693267521676L; + + /* + * This is a straight adaptation of Michael & Scott algorithm. + * For explanation, read the paper. The only (minor) algorithmic + * difference is that this version supports lazy deletion of + * internal nodes (method remove(Object)) -- remove CAS'es item + * fields to null. The normal queue operations unlink but then + * pass over nodes with null item fields. Similarly, iteration + * methods ignore those with nulls. + * + * Also note that like most non-blocking algorithms in this + * package, this implementation relies on the fact that in garbage + * collected systems, there is no possibility of ABA problems due + * to recycled nodes, so there is no need to use "counted + * pointers" or related techniques seen in versions used in + * non-GC'ed settings. + */ + + private static class Node<E> { + private volatile E item; + private volatile Node<E> next; + + private static final + AtomicReferenceFieldUpdater<Node, Node> + nextUpdater = + AtomicReferenceFieldUpdater.newUpdater + (Node.class, Node.class, "next"); + private static final + AtomicReferenceFieldUpdater<Node, Object> + itemUpdater = + AtomicReferenceFieldUpdater.newUpdater + (Node.class, Object.class, "item"); + + Node(E x) { item = x; } + + Node(E x, Node<E> n) { item = x; next = n; } + + E getItem() { + return item; + } + + boolean casItem(E cmp, E val) { + return itemUpdater.compareAndSet(this, cmp, val); + } + + void setItem(E val) { + itemUpdater.set(this, val); + } + + Node<E> getNext() { + return next; + } + + boolean casNext(Node<E> cmp, Node<E> val) { + return nextUpdater.compareAndSet(this, cmp, val); + } + + void setNext(Node<E> val) { + nextUpdater.set(this, val); + } + + } + + private static final + AtomicReferenceFieldUpdater<ConcurrentLinkedQueue, Node> + tailUpdater = + AtomicReferenceFieldUpdater.newUpdater + (ConcurrentLinkedQueue.class, Node.class, "tail"); + private static final + AtomicReferenceFieldUpdater<ConcurrentLinkedQueue, Node> + headUpdater = + AtomicReferenceFieldUpdater.newUpdater + (ConcurrentLinkedQueue.class, Node.class, "head"); + + private boolean casTail(Node<E> cmp, Node<E> val) { + return tailUpdater.compareAndSet(this, cmp, val); + } + + private boolean casHead(Node<E> cmp, Node<E> val) { + return headUpdater.compareAndSet(this, cmp, val); + } + + + /** + * Pointer to header node, initialized to a dummy node. The first + * actual node is at head.getNext(). + */ + private transient volatile Node<E> head = new Node<E>(null, null); + + /** Pointer to last node on list **/ + private transient volatile Node<E> tail = head; + + + /** + * Creates a <tt>ConcurrentLinkedQueue</tt> that is initially empty. + */ + public ConcurrentLinkedQueue() {} + + /** + * Creates a <tt>ConcurrentLinkedQueue</tt> + * initially containing the elements of the given collection, + * added in traversal order of the collection's iterator. + * @param c the collection of elements to initially contain + * @throws NullPointerException if the specified collection or any + * of its elements are null + */ + public ConcurrentLinkedQueue(Collection<? extends E> c) { + for (Iterator<? extends E> it = c.iterator(); it.hasNext();) + add(it.next()); + } + + // Have to override just to update the javadoc + + /** + * Inserts the specified element at the tail of this queue. + * + * @return <tt>true</tt> (as specified by {@link Collection#add}) + * @throws NullPointerException if the specified element is null + */ + public boolean add(E e) { + return offer(e); + } + + /** + * Inserts the specified element at the tail of this queue. + * + * @return <tt>true</tt> (as specified by {@link Queue#offer}) + * @throws NullPointerException if the specified element is null + */ + public boolean offer(E e) { + if (e == null) throw new NullPointerException(); + Node<E> n = new Node<E>(e, null); + for (;;) { + Node<E> t = tail; + Node<E> s = t.getNext(); + if (t == tail) { + if (s == null) { + if (t.casNext(s, n)) { + casTail(t, n); + return true; + } + } else { + casTail(t, s); + } + } + } + } + + public E poll() { + for (;;) { + Node<E> h = head; + Node<E> t = tail; + Node<E> first = h.getNext(); + if (h == head) { + if (h == t) { + if (first == null) + return null; + else + casTail(t, first); + } else if (casHead(h, first)) { + E item = first.getItem(); + if (item != null) { + first.setItem(null); + return item; + } + // else skip over deleted item, continue loop, + } + } + } + } + + public E peek() { // same as poll except don't remove item + for (;;) { + Node<E> h = head; + Node<E> t = tail; + Node<E> first = h.getNext(); + if (h == head) { + if (h == t) { + if (first == null) + return null; + else + casTail(t, first); + } else { + E item = first.getItem(); + if (item != null) + return item; + else // remove deleted node and continue + casHead(h, first); + } + } + } + } + + /** + * Returns the first actual (non-header) node on list. This is yet + * another variant of poll/peek; here returning out the first + * node, not element (so we cannot collapse with peek() without + * introducing race.) + */ + Node<E> first() { + for (;;) { + Node<E> h = head; + Node<E> t = tail; + Node<E> first = h.getNext(); + if (h == head) { + if (h == t) { + if (first == null) + return null; + else + casTail(t, first); + } else { + if (first.getItem() != null) + return first; + else // remove deleted node and continue + casHead(h, first); + } + } + } + } + + + /** + * Returns <tt>true</tt> if this queue contains no elements. + * + * @return <tt>true</tt> if this queue contains no elements + */ + public boolean isEmpty() { + return first() == null; + } + + /** + * Returns the number of elements in this queue. If this queue + * contains more than <tt>Integer.MAX_VALUE</tt> elements, returns + * <tt>Integer.MAX_VALUE</tt>. + * + * <p>Beware that, unlike in most collections, this method is + * <em>NOT</em> a constant-time operation. Because of the + * asynchronous nature of these queues, determining the current + * number of elements requires an O(n) traversal. + * + * @return the number of elements in this queue + */ + public int size() { + int count = 0; + for (Node<E> p = first(); p != null; p = p.getNext()) { + if (p.getItem() != null) { + // Collections.size() spec says to max out + if (++count == Integer.MAX_VALUE) + break; + } + } + return count; + } + + /** + * Returns <tt>true</tt> if this queue contains the specified element. + * More formally, returns <tt>true</tt> if and only if this queue contains + * at least one element <tt>e</tt> such that <tt>o.equals(e)</tt>. + * + * @param o object to be checked for containment in this queue + * @return <tt>true</tt> 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 = p.getNext()) { + E item = p.getItem(); + if (item != null && + o.equals(item)) + return true; + } + return false; + } + + /** + * Removes a single instance of the specified element from this queue, + * if it is present. More formally, removes an element <tt>e</tt> such + * that <tt>o.equals(e)</tt>, if this queue contains one or more such + * elements. + * Returns <tt>true</tt> if this queue contained the specified element + * (or equivalently, if this queue changed as a result of the call). + * + * @param o element to be removed from this queue, if present + * @return <tt>true</tt> if this queue changed as a result of the call + */ + public boolean remove(Object o) { + if (o == null) return false; + for (Node<E> p = first(); p != null; p = p.getNext()) { + E item = p.getItem(); + if (item != null && + o.equals(item) && + p.casItem(item, null)) + return true; + } + return false; + } + + /** + * Returns an iterator over the elements in this queue in proper sequence. + * The returned iterator is a "weakly consistent" iterator that + * will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + * + * @return an iterator over the elements in this queue in proper sequence + */ + public Iterator<E> iterator() { + return new Itr(); + } + + private class Itr implements Iterator<E> { + /** + * Next node to return item for. + */ + private Node<E> nextNode; + + /** + * nextItem holds on to item fields because once we claim + * that an element exists in hasNext(), we must return it in + * the following next() call even if it was in the process of + * being removed when hasNext() was called. + */ + private E nextItem; + + /** + * Node of the last returned item, to support remove. + */ + 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> p = (nextNode == null)? first() : nextNode.getNext(); + for (;;) { + if (p == null) { + nextNode = null; + nextItem = null; + return x; + } + E item = p.getItem(); + if (item != null) { + nextNode = p; + nextItem = item; + return x; + } else // skip over nulls + p = p.getNext(); + } + } + + public boolean hasNext() { + return nextNode != null; + } + + public E next() { + if (nextNode == null) throw new NoSuchElementException(); + return advance(); + } + + public void remove() { + Node<E> l = lastRet; + if (l == null) throw new IllegalStateException(); + // rely on a future traversal to relink. + l.setItem(null); + lastRet = null; + } + } + + /** + * Save the state to a stream (that is, serialize it). + * + * @serialData All of the elements (each an <tt>E</tt>) in + * the proper order, followed by a null + * @param s the stream + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + + // Write out any hidden stuff + s.defaultWriteObject(); + + // Write out all elements in the proper order. + for (Node<E> p = first(); p != null; p = p.getNext()) { + Object item = p.getItem(); + if (item != null) + s.writeObject(item); + } + + // Use trailing null as sentinel + s.writeObject(null); + } + + /** + * Reconstitute the Queue instance from a stream (that is, + * deserialize it). + * @param s the stream + */ + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + // Read in capacity, and any hidden stuff + s.defaultReadObject(); + head = new Node<E>(null, null); + tail = head; + // Read in all elements and place in queue + for (;;) { + E item = (E)s.readObject(); + if (item == null) + break; + else + offer(item); + } + } + +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/ConcurrentMap.java b/libjava/classpath/external/jsr166/java/util/concurrent/ConcurrentMap.java new file mode 100644 index 000000000..6e5bd0738 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/ConcurrentMap.java @@ -0,0 +1,134 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.Map; + +/** + * A {@link java.util.Map} providing additional atomic + * <tt>putIfAbsent</tt>, <tt>remove</tt>, and <tt>replace</tt> methods. + * + * <p>Memory consistency effects: As with other concurrent + * collections, actions in a thread prior to placing an object into a + * {@code ConcurrentMap} as a key or value + * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a> + * actions subsequent to the access or removal of that object from + * the {@code ConcurrentMap} in another thread. + * + * <p>This interface is a member of the + * <a href="{@docRoot}/../technotes/guides/collections/index.html"> + * Java Collections Framework</a>. + * + * @since 1.5 + * @author Doug Lea + * @param <K> the type of keys maintained by this map + * @param <V> the type of mapped values + */ +public interface ConcurrentMap<K, V> extends Map<K, V> { + /** + * If the specified key is not already associated + * with a value, associate it with the given value. + * This is equivalent to + * <pre> + * if (!map.containsKey(key)) + * return map.put(key, value); + * else + * return map.get(key);</pre> + * except that the action is performed atomically. + * + * @param key key with which the specified value is to be associated + * @param value value to be associated with the specified key + * @return the previous value associated with the specified key, or + * <tt>null</tt> if there was no mapping for the key. + * (A <tt>null</tt> return can also indicate that the map + * previously associated <tt>null</tt> with the key, + * if the implementation supports null values.) + * @throws UnsupportedOperationException if the <tt>put</tt> operation + * is not supported by this map + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map + * @throws NullPointerException if the specified key or value is null, + * and this map does not permit null keys or values + * @throws IllegalArgumentException if some property of the specified key + * or value prevents it from being stored in this map + * + */ + V putIfAbsent(K key, V value); + + /** + * Removes the entry for a key only if currently mapped to a given value. + * This is equivalent to + * <pre> + * if (map.containsKey(key) && map.get(key).equals(value)) { + * map.remove(key); + * return true; + * } else return false;</pre> + * except that the action is performed atomically. + * + * @param key key with which the specified value is associated + * @param value value expected to be associated with the specified key + * @return <tt>true</tt> if the value was removed + * @throws UnsupportedOperationException if the <tt>remove</tt> operation + * is not supported by this map + * @throws ClassCastException if the key or value is of an inappropriate + * type for this map (optional) + * @throws NullPointerException if the specified key or value is null, + * and this map does not permit null keys or values (optional) + */ + boolean remove(Object key, Object value); + + /** + * Replaces the entry for a key only if currently mapped to a given value. + * This is equivalent to + * <pre> + * if (map.containsKey(key) && map.get(key).equals(oldValue)) { + * map.put(key, newValue); + * return true; + * } else return false;</pre> + * except that the action is performed atomically. + * + * @param key key with which the specified value is associated + * @param oldValue value expected to be associated with the specified key + * @param newValue value to be associated with the specified key + * @return <tt>true</tt> if the value was replaced + * @throws UnsupportedOperationException if the <tt>put</tt> operation + * is not supported by this map + * @throws ClassCastException if the class of a specified key or value + * prevents it from being stored in this map + * @throws NullPointerException if a specified key or value is null, + * and this map does not permit null keys or values + * @throws IllegalArgumentException if some property of a specified key + * or value prevents it from being stored in this map + */ + boolean replace(K key, V oldValue, V newValue); + + /** + * Replaces the entry for a key only if currently mapped to some value. + * This is equivalent to + * <pre> + * if (map.containsKey(key)) { + * return map.put(key, value); + * } else return null;</pre> + * except that the action is performed atomically. + * + * @param key key with which the specified value is associated + * @param value value to be associated with the specified key + * @return the previous value associated with the specified key, or + * <tt>null</tt> if there was no mapping for the key. + * (A <tt>null</tt> return can also indicate that the map + * previously associated <tt>null</tt> with the key, + * if the implementation supports null values.) + * @throws UnsupportedOperationException if the <tt>put</tt> operation + * is not supported by this map + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map + * @throws NullPointerException if the specified key or value is null, + * and this map does not permit null keys or values + * @throws IllegalArgumentException if some property of the specified key + * or value prevents it from being stored in this map + */ + V replace(K key, V value); +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/ConcurrentNavigableMap.java b/libjava/classpath/external/jsr166/java/util/concurrent/ConcurrentNavigableMap.java new file mode 100644 index 000000000..7d86afb70 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/ConcurrentNavigableMap.java @@ -0,0 +1,148 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.*; + +/** + * A {@link ConcurrentMap} supporting {@link NavigableMap} operations, + * and recursively so for its navigable sub-maps. + * + * <p>This interface is a member of the + * <a href="{@docRoot}/../technotes/guides/collections/index.html"> + * Java Collections Framework</a>. + * + * @author Doug Lea + * @param <K> the type of keys maintained by this map + * @param <V> the type of mapped values + * @since 1.6 + */ +public interface ConcurrentNavigableMap<K,V> + extends ConcurrentMap<K,V>, NavigableMap<K,V> +{ + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + ConcurrentNavigableMap<K,V> subMap(K fromKey, boolean fromInclusive, + K toKey, boolean toInclusive); + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + ConcurrentNavigableMap<K,V> headMap(K toKey, boolean inclusive); + + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + ConcurrentNavigableMap<K,V> tailMap(K fromKey, boolean inclusive); + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + ConcurrentNavigableMap<K,V> subMap(K fromKey, K toKey); + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + ConcurrentNavigableMap<K,V> headMap(K toKey); + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + ConcurrentNavigableMap<K,V> tailMap(K fromKey); + + /** + * Returns a reverse order view of the mappings contained in this map. + * The descending map is backed by this map, so changes to the map are + * reflected in the descending map, and vice-versa. + * + * <p>The returned map has an ordering equivalent to + * <tt>{@link Collections#reverseOrder(Comparator) Collections.reverseOrder}(comparator())</tt>. + * The expression {@code m.descendingMap().descendingMap()} returns a + * view of {@code m} essentially equivalent to {@code m}. + * + * @return a reverse order view of this map + */ + ConcurrentNavigableMap<K,V> descendingMap(); + + /** + * Returns a {@link NavigableSet} view of the keys contained in this map. + * The set's iterator returns the keys in ascending order. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. The set supports element + * removal, which removes the corresponding mapping from the map, + * via the {@code Iterator.remove}, {@code Set.remove}, + * {@code removeAll}, {@code retainAll}, and {@code clear} + * operations. It does not support the {@code add} or {@code addAll} + * operations. + * + * <p>The view's {@code iterator} is a "weakly consistent" iterator + * that will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + * + * @return a navigable set view of the keys in this map + */ + public NavigableSet<K> navigableKeySet(); + + /** + * Returns a {@link NavigableSet} view of the keys contained in this map. + * The set's iterator returns the keys in ascending order. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. The set supports element + * removal, which removes the corresponding mapping from the map, + * via the {@code Iterator.remove}, {@code Set.remove}, + * {@code removeAll}, {@code retainAll}, and {@code clear} + * operations. It does not support the {@code add} or {@code addAll} + * operations. + * + * <p>The view's {@code iterator} is a "weakly consistent" iterator + * that will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + * + * <p>This method is equivalent to method {@code navigableKeySet}. + * + * @return a navigable set view of the keys in this map + */ + NavigableSet<K> keySet(); + + /** + * Returns a reverse order {@link NavigableSet} view of the keys contained in this map. + * The set's iterator returns the keys in descending order. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. The set supports element + * removal, which removes the corresponding mapping from the map, + * via the {@code Iterator.remove}, {@code Set.remove}, + * {@code removeAll}, {@code retainAll}, and {@code clear} + * operations. It does not support the {@code add} or {@code addAll} + * operations. + * + * <p>The view's {@code iterator} is a "weakly consistent" iterator + * that will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + * + * @return a reverse order navigable set view of the keys in this map + */ + public NavigableSet<K> descendingKeySet(); +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/ConcurrentSkipListMap.java b/libjava/classpath/external/jsr166/java/util/concurrent/ConcurrentSkipListMap.java new file mode 100644 index 000000000..1ad924454 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/ConcurrentSkipListMap.java @@ -0,0 +1,3114 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.*; +import java.util.concurrent.atomic.*; + +/** + * A scalable concurrent {@link ConcurrentNavigableMap} implementation. + * The map is sorted according to the {@linkplain Comparable natural + * ordering} of its keys, or by a {@link Comparator} provided at map + * creation time, depending on which constructor is used. + * + * <p>This class implements a concurrent variant of <a + * href="http://www.cs.umd.edu/~pugh/">SkipLists</a> providing + * expected average <i>log(n)</i> time cost for the + * <tt>containsKey</tt>, <tt>get</tt>, <tt>put</tt> and + * <tt>remove</tt> operations and their variants. Insertion, removal, + * update, and access operations safely execute concurrently by + * multiple threads. Iterators are <i>weakly consistent</i>, returning + * elements reflecting the state of the map at some point at or since + * the creation of the iterator. They do <em>not</em> throw {@link + * ConcurrentModificationException}, and may proceed concurrently with + * other operations. Ascending key ordered views and their iterators + * are faster than descending ones. + * + * <p>All <tt>Map.Entry</tt> pairs returned by methods in this class + * and its views represent snapshots of mappings at the time they were + * produced. They do <em>not</em> support the <tt>Entry.setValue</tt> + * method. (Note however that it is possible to change mappings in the + * associated map using <tt>put</tt>, <tt>putIfAbsent</tt>, or + * <tt>replace</tt>, depending on exactly which effect you need.) + * + * <p>Beware that, unlike in most collections, the <tt>size</tt> + * method is <em>not</em> a constant-time operation. Because of the + * asynchronous nature of these maps, determining the current number + * of elements requires a traversal of the elements. Additionally, + * the bulk operations <tt>putAll</tt>, <tt>equals</tt>, and + * <tt>clear</tt> are <em>not</em> guaranteed to be performed + * atomically. For example, an iterator operating concurrently with a + * <tt>putAll</tt> operation might view only some of the added + * elements. + * + * <p>This class and its views and iterators implement all of the + * <em>optional</em> methods of the {@link Map} and {@link Iterator} + * interfaces. Like most other concurrent collections, this class does + * <em>not</em> permit the use of <tt>null</tt> keys or values because some + * null return values cannot be reliably distinguished from the absence of + * elements. + * + * <p>This class is a member of the + * <a href="{@docRoot}/../technotes/guides/collections/index.html"> + * Java Collections Framework</a>. + * + * @author Doug Lea + * @param <K> the type of keys maintained by this map + * @param <V> the type of mapped values + * @since 1.6 + */ +public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V> + implements ConcurrentNavigableMap<K,V>, + Cloneable, + java.io.Serializable { + /* + * This class implements a tree-like two-dimensionally linked skip + * list in which the index levels are represented in separate + * nodes from the base nodes holding data. There are two reasons + * for taking this approach instead of the usual array-based + * structure: 1) Array based implementations seem to encounter + * more complexity and overhead 2) We can use cheaper algorithms + * for the heavily-traversed index lists than can be used for the + * base lists. Here's a picture of some of the basics for a + * possible list with 2 levels of index: + * + * Head nodes Index nodes + * +-+ right +-+ +-+ + * |2|---------------->| |--------------------->| |->null + * +-+ +-+ +-+ + * | down | | + * v v v + * +-+ +-+ +-+ +-+ +-+ +-+ + * |1|----------->| |->| |------>| |----------->| |------>| |->null + * +-+ +-+ +-+ +-+ +-+ +-+ + * v | | | | | + * Nodes next v v v v v + * +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ + * | |->|A|->|B|->|C|->|D|->|E|->|F|->|G|->|H|->|I|->|J|->|K|->null + * +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ + * + * The base lists use a variant of the HM linked ordered set + * algorithm. See Tim Harris, "A pragmatic implementation of + * non-blocking linked lists" + * http://www.cl.cam.ac.uk/~tlh20/publications.html and Maged + * Michael "High Performance Dynamic Lock-Free Hash Tables and + * List-Based Sets" + * http://www.research.ibm.com/people/m/michael/pubs.htm. The + * basic idea in these lists is to mark the "next" pointers of + * deleted nodes when deleting to avoid conflicts with concurrent + * insertions, and when traversing to keep track of triples + * (predecessor, node, successor) in order to detect when and how + * to unlink these deleted nodes. + * + * Rather than using mark-bits to mark list deletions (which can + * be slow and space-intensive using AtomicMarkedReference), nodes + * use direct CAS'able next pointers. On deletion, instead of + * marking a pointer, they splice in another node that can be + * thought of as standing for a marked pointer (indicating this by + * using otherwise impossible field values). Using plain nodes + * acts roughly like "boxed" implementations of marked pointers, + * but uses new nodes only when nodes are deleted, not for every + * link. This requires less space and supports faster + * traversal. Even if marked references were better supported by + * JVMs, traversal using this technique might still be faster + * because any search need only read ahead one more node than + * otherwise required (to check for trailing marker) rather than + * unmasking mark bits or whatever on each read. + * + * This approach maintains the essential property needed in the HM + * algorithm of changing the next-pointer of a deleted node so + * that any other CAS of it will fail, but implements the idea by + * changing the pointer to point to a different node, not by + * marking it. While it would be possible to further squeeze + * space by defining marker nodes not to have key/value fields, it + * isn't worth the extra type-testing overhead. The deletion + * markers are rarely encountered during traversal and are + * normally quickly garbage collected. (Note that this technique + * would not work well in systems without garbage collection.) + * + * In addition to using deletion markers, the lists also use + * nullness of value fields to indicate deletion, in a style + * similar to typical lazy-deletion schemes. If a node's value is + * null, then it is considered logically deleted and ignored even + * though it is still reachable. This maintains proper control of + * concurrent replace vs delete operations -- an attempted replace + * must fail if a delete beat it by nulling field, and a delete + * must return the last non-null value held in the field. (Note: + * Null, rather than some special marker, is used for value fields + * here because it just so happens to mesh with the Map API + * requirement that method get returns null if there is no + * mapping, which allows nodes to remain concurrently readable + * even when deleted. Using any other marker value here would be + * messy at best.) + * + * Here's the sequence of events for a deletion of node n with + * predecessor b and successor f, initially: + * + * +------+ +------+ +------+ + * ... | b |------>| n |----->| f | ... + * +------+ +------+ +------+ + * + * 1. CAS n's value field from non-null to null. + * From this point on, no public operations encountering + * the node consider this mapping to exist. However, other + * ongoing insertions and deletions might still modify + * n's next pointer. + * + * 2. CAS n's next pointer to point to a new marker node. + * From this point on, no other nodes can be appended to n. + * which avoids deletion errors in CAS-based linked lists. + * + * +------+ +------+ +------+ +------+ + * ... | b |------>| n |----->|marker|------>| f | ... + * +------+ +------+ +------+ +------+ + * + * 3. CAS b's next pointer over both n and its marker. + * From this point on, no new traversals will encounter n, + * and it can eventually be GCed. + * +------+ +------+ + * ... | b |----------------------------------->| f | ... + * +------+ +------+ + * + * A failure at step 1 leads to simple retry due to a lost race + * with another operation. Steps 2-3 can fail because some other + * thread noticed during a traversal a node with null value and + * helped out by marking and/or unlinking. This helping-out + * ensures that no thread can become stuck waiting for progress of + * the deleting thread. The use of marker nodes slightly + * complicates helping-out code because traversals must track + * consistent reads of up to four nodes (b, n, marker, f), not + * just (b, n, f), although the next field of a marker is + * immutable, and once a next field is CAS'ed to point to a + * marker, it never again changes, so this requires less care. + * + * Skip lists add indexing to this scheme, so that the base-level + * traversals start close to the locations being found, inserted + * or deleted -- usually base level traversals only traverse a few + * nodes. This doesn't change the basic algorithm except for the + * need to make sure base traversals start at predecessors (here, + * b) that are not (structurally) deleted, otherwise retrying + * after processing the deletion. + * + * Index levels are maintained as lists with volatile next fields, + * using CAS to link and unlink. Races are allowed in index-list + * operations that can (rarely) fail to link in a new index node + * or delete one. (We can't do this of course for data nodes.) + * However, even when this happens, the index lists remain sorted, + * so correctly serve as indices. This can impact performance, + * but since skip lists are probabilistic anyway, the net result + * is that under contention, the effective "p" value may be lower + * than its nominal value. And race windows are kept small enough + * that in practice these failures are rare, even under a lot of + * contention. + * + * The fact that retries (for both base and index lists) are + * relatively cheap due to indexing allows some minor + * simplifications of retry logic. Traversal restarts are + * performed after most "helping-out" CASes. This isn't always + * strictly necessary, but the implicit backoffs tend to help + * reduce other downstream failed CAS's enough to outweigh restart + * cost. This worsens the worst case, but seems to improve even + * highly contended cases. + * + * Unlike most skip-list implementations, index insertion and + * deletion here require a separate traversal pass occuring after + * the base-level action, to add or remove index nodes. This adds + * to single-threaded overhead, but improves contended + * multithreaded performance by narrowing interference windows, + * and allows deletion to ensure that all index nodes will be made + * unreachable upon return from a public remove operation, thus + * avoiding unwanted garbage retention. This is more important + * here than in some other data structures because we cannot null + * out node fields referencing user keys since they might still be + * read by other ongoing traversals. + * + * Indexing uses skip list parameters that maintain good search + * performance while using sparser-than-usual indices: The + * hardwired parameters k=1, p=0.5 (see method randomLevel) mean + * that about one-quarter of the nodes have indices. Of those that + * do, half have one level, a quarter have two, and so on (see + * Pugh's Skip List Cookbook, sec 3.4). The expected total space + * requirement for a map is slightly less than for the current + * implementation of java.util.TreeMap. + * + * Changing the level of the index (i.e, the height of the + * tree-like structure) also uses CAS. The head index has initial + * level/height of one. Creation of an index with height greater + * than the current level adds a level to the head index by + * CAS'ing on a new top-most head. To maintain good performance + * after a lot of removals, deletion methods heuristically try to + * reduce the height if the topmost levels appear to be empty. + * This may encounter races in which it possible (but rare) to + * reduce and "lose" a level just as it is about to contain an + * index (that will then never be encountered). This does no + * structural harm, and in practice appears to be a better option + * than allowing unrestrained growth of levels. + * + * The code for all this is more verbose than you'd like. Most + * operations entail locating an element (or position to insert an + * element). The code to do this can't be nicely factored out + * because subsequent uses require a snapshot of predecessor + * and/or successor and/or value fields which can't be returned + * all at once, at least not without creating yet another object + * to hold them -- creating such little objects is an especially + * bad idea for basic internal search operations because it adds + * to GC overhead. (This is one of the few times I've wished Java + * had macros.) Instead, some traversal code is interleaved within + * insertion and removal operations. The control logic to handle + * all the retry conditions is sometimes twisty. Most search is + * broken into 2 parts. findPredecessor() searches index nodes + * only, returning a base-level predecessor of the key. findNode() + * finishes out the base-level search. Even with this factoring, + * there is a fair amount of near-duplication of code to handle + * variants. + * + * For explanation of algorithms sharing at least a couple of + * features with this one, see Mikhail Fomitchev's thesis + * (http://www.cs.yorku.ca/~mikhail/), Keir Fraser's thesis + * (http://www.cl.cam.ac.uk/users/kaf24/), and Hakan Sundell's + * thesis (http://www.cs.chalmers.se/~phs/). + * + * Given the use of tree-like index nodes, you might wonder why + * this doesn't use some kind of search tree instead, which would + * support somewhat faster search operations. The reason is that + * there are no known efficient lock-free insertion and deletion + * algorithms for search trees. The immutability of the "down" + * links of index nodes (as opposed to mutable "left" fields in + * true trees) makes this tractable using only CAS operations. + * + * Notation guide for local variables + * Node: b, n, f for predecessor, node, successor + * Index: q, r, d for index node, right, down. + * t for another index node + * Head: h + * Levels: j + * Keys: k, key + * Values: v, value + * Comparisons: c + */ + + private static final long serialVersionUID = -8627078645895051609L; + + /** + * Generates the initial random seed for the cheaper per-instance + * random number generators used in randomLevel. + */ + private static final Random seedGenerator = new Random(); + + /** + * Special value used to identify base-level header + */ + private static final Object BASE_HEADER = new Object(); + + /** + * The topmost head index of the skiplist. + */ + private transient volatile HeadIndex<K,V> head; + + /** + * The comparator used to maintain order in this map, or null + * if using natural ordering. + * @serial + */ + private final Comparator<? super K> comparator; + + /** + * Seed for simple random number generator. Not volatile since it + * doesn't matter too much if different threads don't see updates. + */ + private transient int randomSeed; + + /** Lazily initialized key set */ + private transient KeySet keySet; + /** Lazily initialized entry set */ + private transient EntrySet entrySet; + /** Lazily initialized values collection */ + private transient Values values; + /** Lazily initialized descending key set */ + private transient ConcurrentNavigableMap<K,V> descendingMap; + + /** + * Initializes or resets state. Needed by constructors, clone, + * clear, readObject. and ConcurrentSkipListSet.clone. + * (Note that comparator must be separately initialized.) + */ + final void initialize() { + keySet = null; + entrySet = null; + values = null; + descendingMap = null; + randomSeed = seedGenerator.nextInt() | 0x0100; // ensure nonzero + head = new HeadIndex<K,V>(new Node<K,V>(null, BASE_HEADER, null), + null, null, 1); + } + + /** Updater for casHead */ + private static final + AtomicReferenceFieldUpdater<ConcurrentSkipListMap, HeadIndex> + headUpdater = AtomicReferenceFieldUpdater.newUpdater + (ConcurrentSkipListMap.class, HeadIndex.class, "head"); + + /** + * compareAndSet head node + */ + private boolean casHead(HeadIndex<K,V> cmp, HeadIndex<K,V> val) { + return headUpdater.compareAndSet(this, cmp, val); + } + + /* ---------------- Nodes -------------- */ + + /** + * Nodes hold keys and values, and are singly linked in sorted + * order, possibly with some intervening marker nodes. The list is + * headed by a dummy node accessible as head.node. The value field + * is declared only as Object because it takes special non-V + * values for marker and header nodes. + */ + static final class Node<K,V> { + final K key; + volatile Object value; + volatile Node<K,V> next; + + /** + * Creates a new regular node. + */ + Node(K key, Object value, Node<K,V> next) { + this.key = key; + this.value = value; + this.next = next; + } + + /** + * Creates a new marker node. A marker is distinguished by + * having its value field point to itself. Marker nodes also + * have null keys, a fact that is exploited in a few places, + * but this doesn't distinguish markers from the base-level + * header node (head.node), which also has a null key. + */ + Node(Node<K,V> next) { + this.key = null; + this.value = this; + this.next = next; + } + + /** Updater for casNext */ + static final AtomicReferenceFieldUpdater<Node, Node> + nextUpdater = AtomicReferenceFieldUpdater.newUpdater + (Node.class, Node.class, "next"); + + /** Updater for casValue */ + static final AtomicReferenceFieldUpdater<Node, Object> + valueUpdater = AtomicReferenceFieldUpdater.newUpdater + (Node.class, Object.class, "value"); + + /** + * compareAndSet value field + */ + boolean casValue(Object cmp, Object val) { + return valueUpdater.compareAndSet(this, cmp, val); + } + + /** + * compareAndSet next field + */ + boolean casNext(Node<K,V> cmp, Node<K,V> val) { + return nextUpdater.compareAndSet(this, cmp, val); + } + + /** + * Returns true if this node is a marker. This method isn't + * actually called in any current code checking for markers + * because callers will have already read value field and need + * to use that read (not another done here) and so directly + * test if value points to node. + * @param n a possibly null reference to a node + * @return true if this node is a marker node + */ + boolean isMarker() { + return value == this; + } + + /** + * Returns true if this node is the header of base-level list. + * @return true if this node is header node + */ + boolean isBaseHeader() { + return value == BASE_HEADER; + } + + /** + * Tries to append a deletion marker to this node. + * @param f the assumed current successor of this node + * @return true if successful + */ + boolean appendMarker(Node<K,V> f) { + return casNext(f, new Node<K,V>(f)); + } + + /** + * Helps out a deletion by appending marker or unlinking from + * predecessor. This is called during traversals when value + * field seen to be null. + * @param b predecessor + * @param f successor + */ + void helpDelete(Node<K,V> b, Node<K,V> f) { + /* + * Rechecking links and then doing only one of the + * help-out stages per call tends to minimize CAS + * interference among helping threads. + */ + if (f == next && this == b.next) { + if (f == null || f.value != f) // not already marked + appendMarker(f); + else + b.casNext(this, f.next); + } + } + + /** + * Returns value if this node contains a valid key-value pair, + * else null. + * @return this node's value if it isn't a marker or header or + * is deleted, else null. + */ + V getValidValue() { + Object v = value; + if (v == this || v == BASE_HEADER) + return null; + return (V)v; + } + + /** + * Creates and returns a new SimpleImmutableEntry holding current + * mapping if this node holds a valid value, else null. + * @return new entry or null + */ + AbstractMap.SimpleImmutableEntry<K,V> createSnapshot() { + V v = getValidValue(); + if (v == null) + return null; + return new AbstractMap.SimpleImmutableEntry<K,V>(key, v); + } + } + + /* ---------------- Indexing -------------- */ + + /** + * Index nodes represent the levels of the skip list. Note that + * even though both Nodes and Indexes have forward-pointing + * fields, they have different types and are handled in different + * ways, that can't nicely be captured by placing field in a + * shared abstract class. + */ + static class Index<K,V> { + final Node<K,V> node; + final Index<K,V> down; + volatile Index<K,V> right; + + /** + * Creates index node with given values. + */ + Index(Node<K,V> node, Index<K,V> down, Index<K,V> right) { + this.node = node; + this.down = down; + this.right = right; + } + + /** Updater for casRight */ + static final AtomicReferenceFieldUpdater<Index, Index> + rightUpdater = AtomicReferenceFieldUpdater.newUpdater + (Index.class, Index.class, "right"); + + /** + * compareAndSet right field + */ + final boolean casRight(Index<K,V> cmp, Index<K,V> val) { + return rightUpdater.compareAndSet(this, cmp, val); + } + + /** + * Returns true if the node this indexes has been deleted. + * @return true if indexed node is known to be deleted + */ + final boolean indexesDeletedNode() { + return node.value == null; + } + + /** + * Tries to CAS newSucc as successor. To minimize races with + * unlink that may lose this index node, if the node being + * indexed is known to be deleted, it doesn't try to link in. + * @param succ the expected current successor + * @param newSucc the new successor + * @return true if successful + */ + final boolean link(Index<K,V> succ, Index<K,V> newSucc) { + Node<K,V> n = node; + newSucc.right = succ; + return n.value != null && casRight(succ, newSucc); + } + + /** + * Tries to CAS right field to skip over apparent successor + * succ. Fails (forcing a retraversal by caller) if this node + * is known to be deleted. + * @param succ the expected current successor + * @return true if successful + */ + final boolean unlink(Index<K,V> succ) { + return !indexesDeletedNode() && casRight(succ, succ.right); + } + } + + /* ---------------- Head nodes -------------- */ + + /** + * Nodes heading each level keep track of their level. + */ + static final class HeadIndex<K,V> extends Index<K,V> { + final int level; + HeadIndex(Node<K,V> node, Index<K,V> down, Index<K,V> right, int level) { + super(node, down, right); + this.level = level; + } + } + + /* ---------------- Comparison utilities -------------- */ + + /** + * Represents a key with a comparator as a Comparable. + * + * Because most sorted collections seem to use natural ordering on + * Comparables (Strings, Integers, etc), most internal methods are + * geared to use them. This is generally faster than checking + * per-comparison whether to use comparator or comparable because + * it doesn't require a (Comparable) cast for each comparison. + * (Optimizers can only sometimes remove such redundant checks + * themselves.) When Comparators are used, + * ComparableUsingComparators are created so that they act in the + * same way as natural orderings. This penalizes use of + * Comparators vs Comparables, which seems like the right + * tradeoff. + */ + static final class ComparableUsingComparator<K> implements Comparable<K> { + final K actualKey; + final Comparator<? super K> cmp; + ComparableUsingComparator(K key, Comparator<? super K> cmp) { + this.actualKey = key; + this.cmp = cmp; + } + public int compareTo(K k2) { + return cmp.compare(actualKey, k2); + } + } + + /** + * If using comparator, return a ComparableUsingComparator, else + * cast key as Comparable, which may cause ClassCastException, + * which is propagated back to caller. + */ + private Comparable<? super K> comparable(Object key) throws ClassCastException { + if (key == null) + throw new NullPointerException(); + if (comparator != null) + return new ComparableUsingComparator<K>((K)key, comparator); + else + return (Comparable<? super K>)key; + } + + /** + * Compares using comparator or natural ordering. Used when the + * ComparableUsingComparator approach doesn't apply. + */ + int compare(K k1, K k2) throws ClassCastException { + Comparator<? super K> cmp = comparator; + if (cmp != null) + return cmp.compare(k1, k2); + else + return ((Comparable<? super K>)k1).compareTo(k2); + } + + /** + * Returns true if given key greater than or equal to least and + * strictly less than fence, bypassing either test if least or + * fence are null. Needed mainly in submap operations. + */ + boolean inHalfOpenRange(K key, K least, K fence) { + if (key == null) + throw new NullPointerException(); + return ((least == null || compare(key, least) >= 0) && + (fence == null || compare(key, fence) < 0)); + } + + /** + * Returns true if given key greater than or equal to least and less + * or equal to fence. Needed mainly in submap operations. + */ + boolean inOpenRange(K key, K least, K fence) { + if (key == null) + throw new NullPointerException(); + return ((least == null || compare(key, least) >= 0) && + (fence == null || compare(key, fence) <= 0)); + } + + /* ---------------- Traversal -------------- */ + + /** + * Returns a base-level node with key strictly less than given key, + * or the base-level header if there is no such node. Also + * unlinks indexes to deleted nodes found along the way. Callers + * rely on this side-effect of clearing indices to deleted nodes. + * @param key the key + * @return a predecessor of key + */ + private Node<K,V> findPredecessor(Comparable<? super K> key) { + if (key == null) + throw new NullPointerException(); // don't postpone errors + for (;;) { + Index<K,V> q = head; + Index<K,V> r = q.right; + for (;;) { + if (r != null) { + Node<K,V> n = r.node; + K k = n.key; + if (n.value == null) { + if (!q.unlink(r)) + break; // restart + r = q.right; // reread r + continue; + } + if (key.compareTo(k) > 0) { + q = r; + r = r.right; + continue; + } + } + Index<K,V> d = q.down; + if (d != null) { + q = d; + r = d.right; + } else + return q.node; + } + } + } + + /** + * Returns node holding key or null if no such, clearing out any + * deleted nodes seen along the way. Repeatedly traverses at + * base-level looking for key starting at predecessor returned + * from findPredecessor, processing base-level deletions as + * encountered. Some callers rely on this side-effect of clearing + * deleted nodes. + * + * Restarts occur, at traversal step centered on node n, if: + * + * (1) After reading n's next field, n is no longer assumed + * predecessor b's current successor, which means that + * we don't have a consistent 3-node snapshot and so cannot + * unlink any subsequent deleted nodes encountered. + * + * (2) n's value field is null, indicating n is deleted, in + * which case we help out an ongoing structural deletion + * before retrying. Even though there are cases where such + * unlinking doesn't require restart, they aren't sorted out + * here because doing so would not usually outweigh cost of + * restarting. + * + * (3) n is a marker or n's predecessor's value field is null, + * indicating (among other possibilities) that + * findPredecessor returned a deleted node. We can't unlink + * the node because we don't know its predecessor, so rely + * on another call to findPredecessor to notice and return + * some earlier predecessor, which it will do. This check is + * only strictly needed at beginning of loop, (and the + * b.value check isn't strictly needed at all) but is done + * each iteration to help avoid contention with other + * threads by callers that will fail to be able to change + * links, and so will retry anyway. + * + * 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. + * + * @param key the key + * @return node holding key, or null if no such + */ + private Node<K,V> findNode(Comparable<? super K> key) { + for (;;) { + Node<K,V> b = findPredecessor(key); + Node<K,V> n = b.next; + for (;;) { + if (n == null) + return null; + Node<K,V> f = n.next; + if (n != b.next) // inconsistent read + break; + Object v = n.value; + if (v == null) { // n is deleted + n.helpDelete(b, f); + break; + } + if (v == n || b.value == null) // b is deleted + break; + int c = key.compareTo(n.key); + if (c == 0) + return n; + if (c < 0) + return null; + b = n; + n = f; + } + } + } + + /** + * Specialized variant of findNode to perform Map.get. Does a weak + * traversal, not bothering to fix any deleted index nodes, + * returning early if it happens to see key in index, and passing + * over any deleted base nodes, falling back to getUsingFindNode + * only if it would otherwise return value from an ongoing + * deletion. Also uses "bound" to eliminate need for some + * comparisons (see Pugh Cookbook). Also folds uses of null checks + * and node-skipping because markers have null keys. + * @param okey the key + * @return the value, or null if absent + */ + private V doGet(Object okey) { + Comparable<? super K> key = comparable(okey); + Node<K,V> bound = null; + Index<K,V> q = head; + Index<K,V> r = q.right; + Node<K,V> n; + K k; + int c; + for (;;) { + Index<K,V> d; + // Traverse rights + if (r != null && (n = r.node) != bound && (k = n.key) != null) { + if ((c = key.compareTo(k)) > 0) { + q = r; + r = r.right; + continue; + } else if (c == 0) { + Object v = n.value; + return (v != null)? (V)v : getUsingFindNode(key); + } else + bound = n; + } + + // Traverse down + if ((d = q.down) != null) { + q = d; + r = d.right; + } else + break; + } + + // Traverse nexts + for (n = q.node.next; n != null; n = n.next) { + if ((k = n.key) != null) { + if ((c = key.compareTo(k)) == 0) { + Object v = n.value; + return (v != null)? (V)v : getUsingFindNode(key); + } else if (c < 0) + break; + } + } + return null; + } + + /** + * Performs map.get via findNode. Used as a backup if doGet + * encounters an in-progress deletion. + * @param key the key + * @return the value, or null if absent + */ + private V getUsingFindNode(Comparable<? super K> key) { + /* + * Loop needed here and elsewhere in case value field goes + * null just as it is about to be returned, in which case we + * lost a race with a deletion, so must retry. + */ + for (;;) { + Node<K,V> n = findNode(key); + if (n == null) + return null; + Object v = n.value; + if (v != null) + return (V)v; + } + } + + /* ---------------- Insertion -------------- */ + + /** + * Main insertion method. Adds element if not present, or + * replaces value if present and onlyIfAbsent is false. + * @param kkey the key + * @param value the value that must be associated with key + * @param onlyIfAbsent if should not insert if already present + * @return the old value, or null if newly inserted + */ + private V doPut(K kkey, V value, boolean onlyIfAbsent) { + Comparable<? super K> key = comparable(kkey); + for (;;) { + Node<K,V> b = findPredecessor(key); + Node<K,V> n = b.next; + for (;;) { + if (n != null) { + Node<K,V> f = n.next; + if (n != b.next) // inconsistent read + break; + Object v = n.value; + if (v == null) { // n is deleted + n.helpDelete(b, f); + break; + } + if (v == n || b.value == null) // b is deleted + break; + int c = key.compareTo(n.key); + if (c > 0) { + b = n; + n = f; + continue; + } + if (c == 0) { + if (onlyIfAbsent || n.casValue(v, value)) + return (V)v; + else + break; // restart if lost race to replace value + } + // else c < 0; fall through + } + + Node<K,V> z = new Node<K,V>(kkey, value, n); + if (!b.casNext(n, z)) + break; // restart if lost race to append to b + int level = randomLevel(); + if (level > 0) + insertIndex(z, level); + return null; + } + } + } + + /** + * Returns a random level for inserting a new node. + * Hardwired to k=1, p=0.5, max 31 (see above and + * Pugh's "Skip List Cookbook", sec 3.4). + * + * This uses the simplest of the generators described in George + * Marsaglia's "Xorshift RNGs" paper. This is not a high-quality + * generator but is acceptable here. + */ + private int randomLevel() { + int x = randomSeed; + x ^= x << 13; + x ^= x >>> 17; + randomSeed = x ^= x << 5; + if ((x & 0x8001) != 0) // test highest and lowest bits + return 0; + int level = 1; + while (((x >>>= 1) & 1) != 0) ++level; + return level; + } + + /** + * Creates and adds index nodes for the given node. + * @param z the node + * @param level the level of the index + */ + private void insertIndex(Node<K,V> z, int level) { + HeadIndex<K,V> h = head; + int max = h.level; + + if (level <= max) { + Index<K,V> idx = null; + for (int i = 1; i <= level; ++i) + idx = new Index<K,V>(z, idx, null); + addIndex(idx, h, level); + + } else { // Add a new level + /* + * To reduce interference by other threads checking for + * empty levels in tryReduceLevel, new levels are added + * with initialized right pointers. Which in turn requires + * keeping levels in an array to access them while + * creating new head index nodes from the opposite + * direction. + */ + level = max + 1; + Index<K,V>[] idxs = (Index<K,V>[])new Index[level+1]; + Index<K,V> idx = null; + for (int i = 1; i <= level; ++i) + idxs[i] = idx = new Index<K,V>(z, idx, null); + + HeadIndex<K,V> oldh; + int k; + for (;;) { + oldh = head; + int oldLevel = oldh.level; + if (level <= oldLevel) { // lost race to add level + k = level; + break; + } + HeadIndex<K,V> newh = oldh; + Node<K,V> oldbase = oldh.node; + for (int j = oldLevel+1; j <= level; ++j) + newh = new HeadIndex<K,V>(oldbase, newh, idxs[j], j); + if (casHead(oldh, newh)) { + k = oldLevel; + break; + } + } + addIndex(idxs[k], oldh, k); + } + } + + /** + * Adds given index nodes from given level down to 1. + * @param idx the topmost index node being inserted + * @param h the value of head to use to insert. This must be + * snapshotted by callers to provide correct insertion level + * @param indexLevel the level of the index + */ + private void addIndex(Index<K,V> idx, HeadIndex<K,V> h, int indexLevel) { + // Track next level to insert in case of retries + int insertionLevel = indexLevel; + Comparable<? super K> key = comparable(idx.node.key); + if (key == null) throw new NullPointerException(); + + // Similar to findPredecessor, but adding index nodes along + // path to key. + for (;;) { + int j = h.level; + Index<K,V> q = h; + Index<K,V> r = q.right; + Index<K,V> t = idx; + for (;;) { + if (r != null) { + Node<K,V> n = r.node; + // compare before deletion check avoids needing recheck + int c = key.compareTo(n.key); + if (n.value == null) { + if (!q.unlink(r)) + break; + r = q.right; + continue; + } + if (c > 0) { + q = r; + r = r.right; + continue; + } + } + + if (j == insertionLevel) { + // Don't insert index if node already deleted + if (t.indexesDeletedNode()) { + findNode(key); // cleans up + return; + } + if (!q.link(r, t)) + break; // restart + if (--insertionLevel == 0) { + // need final deletion check before return + if (t.indexesDeletedNode()) + findNode(key); + return; + } + } + + if (--j >= insertionLevel && j < indexLevel) + t = t.down; + q = q.down; + r = q.right; + } + } + } + + /* ---------------- Deletion -------------- */ + + /** + * Main deletion method. Locates node, nulls value, appends a + * deletion marker, unlinks predecessor, removes associated index + * nodes, and possibly reduces head index level. + * + * Index nodes are cleared out simply by calling findPredecessor. + * which unlinks indexes to deleted nodes found along path to key, + * which will include the indexes to this node. This is done + * unconditionally. We can't check beforehand whether there are + * index nodes because it might be the case that some or all + * indexes hadn't been inserted yet for this node during initial + * search for it, and we'd like to ensure lack of garbage + * retention, so must call to be sure. + * + * @param okey the key + * @param value if non-null, the value that must be + * associated with key + * @return the node, or null if not found + */ + final V doRemove(Object okey, Object value) { + Comparable<? super K> key = comparable(okey); + for (;;) { + Node<K,V> b = findPredecessor(key); + Node<K,V> n = b.next; + for (;;) { + if (n == null) + return null; + Node<K,V> f = n.next; + if (n != b.next) // inconsistent read + break; + Object v = n.value; + if (v == null) { // n is deleted + n.helpDelete(b, f); + break; + } + if (v == n || b.value == null) // b is deleted + break; + int c = key.compareTo(n.key); + if (c < 0) + return null; + if (c > 0) { + b = n; + n = f; + continue; + } + if (value != null && !value.equals(v)) + return null; + if (!n.casValue(v, null)) + break; + if (!n.appendMarker(f) || !b.casNext(n, f)) + findNode(key); // Retry via findNode + else { + findPredecessor(key); // Clean index + if (head.right == null) + tryReduceLevel(); + } + return (V)v; + } + } + } + + /** + * Possibly reduce head level if it has no nodes. This method can + * (rarely) make mistakes, in which case levels can disappear even + * though they are about to contain index nodes. This impacts + * performance, not correctness. To minimize mistakes as well as + * to reduce hysteresis, the level is reduced by one only if the + * topmost three levels look empty. Also, if the removed level + * looks non-empty after CAS, we try to change it back quick + * before anyone notices our mistake! (This trick works pretty + * well because this method will practically never make mistakes + * unless current thread stalls immediately before first CAS, in + * which case it is very unlikely to stall again immediately + * afterwards, so will recover.) + * + * We put up with all this rather than just let levels grow + * because otherwise, even a small map that has undergone a large + * number of insertions and removals will have a lot of levels, + * slowing down access more than would an occasional unwanted + * reduction. + */ + private void tryReduceLevel() { + HeadIndex<K,V> h = head; + HeadIndex<K,V> d; + HeadIndex<K,V> e; + if (h.level > 3 && + (d = (HeadIndex<K,V>)h.down) != null && + (e = (HeadIndex<K,V>)d.down) != null && + e.right == null && + d.right == null && + h.right == null && + casHead(h, d) && // try to set + h.right != null) // recheck + casHead(d, h); // try to backout + } + + /* ---------------- Finding and removing first element -------------- */ + + /** + * Specialized variant of findNode to get first valid node. + * @return first node or null if empty + */ + Node<K,V> findFirst() { + for (;;) { + Node<K,V> b = head.node; + Node<K,V> n = b.next; + if (n == null) + return null; + if (n.value != null) + return n; + n.helpDelete(b, n.next); + } + } + + /** + * Removes first entry; returns its snapshot. + * @return null if empty, else snapshot of first entry + */ + Map.Entry<K,V> doRemoveFirstEntry() { + for (;;) { + Node<K,V> b = head.node; + Node<K,V> n = b.next; + if (n == null) + return null; + Node<K,V> f = n.next; + if (n != b.next) + continue; + Object v = n.value; + if (v == null) { + n.helpDelete(b, f); + continue; + } + if (!n.casValue(v, null)) + continue; + if (!n.appendMarker(f) || !b.casNext(n, f)) + findFirst(); // retry + clearIndexToFirst(); + return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, (V)v); + } + } + + /** + * Clears out index nodes associated with deleted first entry. + */ + private void clearIndexToFirst() { + for (;;) { + Index<K,V> q = head; + for (;;) { + Index<K,V> r = q.right; + if (r != null && r.indexesDeletedNode() && !q.unlink(r)) + break; + if ((q = q.down) == null) { + if (head.right == null) + tryReduceLevel(); + return; + } + } + } + } + + + /* ---------------- Finding and removing last element -------------- */ + + /** + * Specialized version of find to get last valid node. + * @return last node or null if empty + */ + Node<K,V> findLast() { + /* + * findPredecessor can't be used to traverse index level + * because this doesn't use comparisons. So traversals of + * both levels are folded together. + */ + Index<K,V> q = head; + for (;;) { + Index<K,V> d, r; + if ((r = q.right) != null) { + if (r.indexesDeletedNode()) { + q.unlink(r); + q = head; // restart + } + else + q = r; + } else if ((d = q.down) != null) { + q = d; + } else { + Node<K,V> b = q.node; + Node<K,V> n = b.next; + for (;;) { + if (n == null) + return (b.isBaseHeader())? null : b; + Node<K,V> f = n.next; // inconsistent read + if (n != b.next) + break; + Object v = n.value; + if (v == null) { // n is deleted + n.helpDelete(b, f); + break; + } + if (v == n || b.value == null) // b is deleted + break; + b = n; + n = f; + } + q = head; // restart + } + } + } + + /** + * Specialized variant of findPredecessor to get predecessor of last + * valid node. Needed when removing the last entry. It is possible + * that all successors of returned node will have been deleted upon + * return, in which case this method can be retried. + * @return likely predecessor of last node + */ + private Node<K,V> findPredecessorOfLast() { + for (;;) { + Index<K,V> q = head; + for (;;) { + Index<K,V> d, r; + if ((r = q.right) != null) { + if (r.indexesDeletedNode()) { + q.unlink(r); + break; // must restart + } + // proceed as far across as possible without overshooting + if (r.node.next != null) { + q = r; + continue; + } + } + if ((d = q.down) != null) + q = d; + else + return q.node; + } + } + } + + /** + * Removes last entry; returns its snapshot. + * Specialized variant of doRemove. + * @return null if empty, else snapshot of last entry + */ + Map.Entry<K,V> doRemoveLastEntry() { + for (;;) { + Node<K,V> b = findPredecessorOfLast(); + Node<K,V> n = b.next; + if (n == null) { + if (b.isBaseHeader()) // empty + return null; + else + continue; // all b's successors are deleted; retry + } + for (;;) { + Node<K,V> f = n.next; + if (n != b.next) // inconsistent read + break; + Object v = n.value; + if (v == null) { // n is deleted + n.helpDelete(b, f); + break; + } + if (v == n || b.value == null) // b is deleted + break; + if (f != null) { + b = n; + n = f; + continue; + } + if (!n.casValue(v, null)) + break; + K key = n.key; + Comparable<? super K> ck = comparable(key); + if (!n.appendMarker(f) || !b.casNext(n, f)) + findNode(ck); // Retry via findNode + else { + findPredecessor(ck); // Clean index + if (head.right == null) + tryReduceLevel(); + } + return new AbstractMap.SimpleImmutableEntry<K,V>(key, (V)v); + } + } + } + + /* ---------------- Relational operations -------------- */ + + // Control values OR'ed as arguments to findNear + + private static final int EQ = 1; + private static final int LT = 2; + private static final int GT = 0; // Actually checked as !LT + + /** + * Utility for ceiling, floor, lower, higher methods. + * @param kkey the key + * @param rel the relation -- OR'ed combination of EQ, LT, GT + * @return nearest node fitting relation, or null if no such + */ + Node<K,V> findNear(K kkey, int rel) { + Comparable<? super K> key = comparable(kkey); + for (;;) { + Node<K,V> b = findPredecessor(key); + Node<K,V> n = b.next; + for (;;) { + if (n == null) + return ((rel & LT) == 0 || b.isBaseHeader())? null : b; + Node<K,V> f = n.next; + if (n != b.next) // inconsistent read + break; + Object v = n.value; + if (v == null) { // n is deleted + n.helpDelete(b, f); + break; + } + if (v == n || b.value == null) // b is deleted + break; + int c = key.compareTo(n.key); + if ((c == 0 && (rel & EQ) != 0) || + (c < 0 && (rel & LT) == 0)) + return n; + if ( c <= 0 && (rel & LT) != 0) + return (b.isBaseHeader())? null : b; + b = n; + n = f; + } + } + } + + /** + * Returns SimpleImmutableEntry for results of findNear. + * @param key the key + * @param rel the relation -- OR'ed combination of EQ, LT, GT + * @return Entry fitting relation, or null if no such + */ + AbstractMap.SimpleImmutableEntry<K,V> getNear(K key, int rel) { + for (;;) { + Node<K,V> n = findNear(key, rel); + if (n == null) + return null; + AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot(); + if (e != null) + return e; + } + } + + + /* ---------------- Constructors -------------- */ + + /** + * Constructs a new, empty map, sorted according to the + * {@linkplain Comparable natural ordering} of the keys. + */ + public ConcurrentSkipListMap() { + this.comparator = null; + initialize(); + } + + /** + * Constructs a new, empty map, sorted according to the specified + * comparator. + * + * @param comparator the comparator that will be used to order this map. + * If <tt>null</tt>, the {@linkplain Comparable natural + * ordering} of the keys will be used. + */ + public ConcurrentSkipListMap(Comparator<? super K> comparator) { + this.comparator = comparator; + initialize(); + } + + /** + * Constructs a new map containing the same mappings as the given map, + * sorted according to the {@linkplain Comparable natural ordering} of + * the keys. + * + * @param m the map whose mappings are to be placed in this map + * @throws ClassCastException if the keys in <tt>m</tt> are not + * {@link Comparable}, or are not mutually comparable + * @throws NullPointerException if the specified map or any of its keys + * or values are null + */ + public ConcurrentSkipListMap(Map<? extends K, ? extends V> m) { + this.comparator = null; + initialize(); + putAll(m); + } + + /** + * Constructs a new map containing the same mappings and using the + * same ordering as the specified sorted map. + * + * @param m the sorted map whose mappings are to be placed in this + * map, and whose comparator is to be used to sort this map + * @throws NullPointerException if the specified sorted map or any of + * its keys or values are null + */ + public ConcurrentSkipListMap(SortedMap<K, ? extends V> m) { + this.comparator = m.comparator(); + initialize(); + buildFromSorted(m); + } + + /** + * Returns a shallow copy of this <tt>ConcurrentSkipListMap</tt> + * instance. (The keys and values themselves are not cloned.) + * + * @return a shallow copy of this map + */ + public ConcurrentSkipListMap<K,V> clone() { + ConcurrentSkipListMap<K,V> clone = null; + try { + clone = (ConcurrentSkipListMap<K,V>) super.clone(); + } catch (CloneNotSupportedException e) { + throw new InternalError(); + } + + clone.initialize(); + clone.buildFromSorted(this); + return clone; + } + + /** + * Streamlined bulk insertion to initialize from elements of + * given sorted map. Call only from constructor or clone + * method. + */ + private void buildFromSorted(SortedMap<K, ? extends V> map) { + if (map == null) + throw new NullPointerException(); + + HeadIndex<K,V> h = head; + Node<K,V> basepred = h.node; + + // 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>>(); + + // initialize + for (int i = 0; i <= h.level; ++i) + preds.add(null); + Index<K,V> q = h; + for (int i = h.level; i > 0; --i) { + preds.set(i, q); + q = q.down; + } + + Iterator<? extends Map.Entry<? extends K, ? extends V>> it = + map.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry<? extends K, ? extends V> e = it.next(); + int j = randomLevel(); + if (j > h.level) j = h.level + 1; + K k = e.getKey(); + V v = e.getValue(); + if (k == null || v == null) + throw new NullPointerException(); + Node<K,V> z = new Node<K,V>(k, v, null); + basepred.next = z; + basepred = z; + if (j > 0) { + Index<K,V> idx = null; + for (int i = 1; i <= j; ++i) { + idx = new Index<K,V>(z, idx, null); + if (i > h.level) + h = new HeadIndex<K,V>(h.node, h, idx, i); + + if (i < preds.size()) { + preds.get(i).right = idx; + preds.set(i, idx); + } else + preds.add(idx); + } + } + } + head = h; + } + + /* ---------------- Serialization -------------- */ + + /** + * Save the state of this map to a stream. + * + * @serialData The key (Object) and value (Object) for each + * key-value mapping represented by the map, followed by + * <tt>null</tt>. The key-value mappings are emitted in key-order + * (as determined by the Comparator, or by the keys' natural + * ordering if no Comparator). + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + // Write out the Comparator and any hidden stuff + s.defaultWriteObject(); + + // Write out keys and values (alternating) + for (Node<K,V> n = findFirst(); n != null; n = n.next) { + V v = n.getValidValue(); + if (v != null) { + s.writeObject(n.key); + s.writeObject(v); + } + } + s.writeObject(null); + } + + /** + * Reconstitute the map from a stream. + */ + private void readObject(final java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + // Read in the Comparator and any hidden stuff + s.defaultReadObject(); + // Reset transients + initialize(); + + /* + * This is nearly identical to buildFromSorted, but is + * 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. + */ + + HeadIndex<K,V> h = head; + Node<K,V> basepred = h.node; + ArrayList<Index<K,V>> preds = new ArrayList<Index<K,V>>(); + for (int i = 0; i <= h.level; ++i) + preds.add(null); + Index<K,V> q = h; + for (int i = h.level; i > 0; --i) { + preds.set(i, q); + q = q.down; + } + + for (;;) { + Object k = s.readObject(); + if (k == null) + break; + Object v = s.readObject(); + if (v == null) + throw new NullPointerException(); + K key = (K) k; + V val = (V) v; + int j = randomLevel(); + if (j > h.level) j = h.level + 1; + Node<K,V> z = new Node<K,V>(key, val, null); + basepred.next = z; + basepred = z; + if (j > 0) { + Index<K,V> idx = null; + for (int i = 1; i <= j; ++i) { + idx = new Index<K,V>(z, idx, null); + if (i > h.level) + h = new HeadIndex<K,V>(h.node, h, idx, i); + + if (i < preds.size()) { + preds.get(i).right = idx; + preds.set(i, idx); + } else + preds.add(idx); + } + } + } + head = h; + } + + /* ------ Map API methods ------ */ + + /** + * Returns <tt>true</tt> if this map contains a mapping for the specified + * key. + * + * @param key key whose presence in this map is to be tested + * @return <tt>true</tt> if this map contains a mapping for the specified key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + */ + public boolean containsKey(Object key) { + return doGet(key) != null; + } + + /** + * Returns the value to which the specified key is mapped, + * or {@code null} if this map contains no mapping for the key. + * + * <p>More formally, if this map contains a mapping from a key + * {@code k} to a value {@code v} such that {@code key} compares + * equal to {@code k} according to the map's ordering, then this + * method returns {@code v}; otherwise it returns {@code null}. + * (There can be at most one such mapping.) + * + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + */ + public V get(Object key) { + return doGet(key); + } + + /** + * Associates the specified value with the specified key in this map. + * If the map previously contained a mapping for the key, the old + * value is replaced. + * + * @param key key with which the specified value is to be associated + * @param value value to be associated with the specified key + * @return the previous value associated with the specified key, or + * <tt>null</tt> if there was no mapping for the key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key or value is null + */ + public V put(K key, V value) { + if (value == null) + throw new NullPointerException(); + return doPut(key, value, false); + } + + /** + * Removes the mapping for the specified key from this map if present. + * + * @param key key for which mapping should be removed + * @return the previous value associated with the specified key, or + * <tt>null</tt> if there was no mapping for the key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + */ + public V remove(Object key) { + return doRemove(key, null); + } + + /** + * Returns <tt>true</tt> if this map maps one or more keys to the + * specified value. This operation requires time linear in the + * map size. + * + * @param value value whose presence in this map is to be tested + * @return <tt>true</tt> if a mapping to <tt>value</tt> exists; + * <tt>false</tt> otherwise + * @throws NullPointerException if the specified value is null + */ + public boolean containsValue(Object value) { + if (value == null) + throw new NullPointerException(); + for (Node<K,V> n = findFirst(); n != null; n = n.next) { + V v = n.getValidValue(); + if (v != null && value.equals(v)) + return true; + } + return false; + } + + /** + * Returns the number of key-value mappings in this map. If this map + * contains more than <tt>Integer.MAX_VALUE</tt> elements, it + * returns <tt>Integer.MAX_VALUE</tt>. + * + * <p>Beware that, unlike in most collections, this method is + * <em>NOT</em> a constant-time operation. Because of the + * asynchronous nature of these maps, determining the current + * number of elements requires traversing them all to count them. + * Additionally, it is possible for the size to change during + * execution of this method, in which case the returned result + * will be inaccurate. Thus, this method is typically not very + * useful in concurrent applications. + * + * @return the number of elements in this map + */ + public int size() { + long count = 0; + for (Node<K,V> n = findFirst(); n != null; n = n.next) { + if (n.getValidValue() != null) + ++count; + } + return (count >= Integer.MAX_VALUE)? Integer.MAX_VALUE : (int)count; + } + + /** + * Returns <tt>true</tt> if this map contains no key-value mappings. + * @return <tt>true</tt> if this map contains no key-value mappings + */ + public boolean isEmpty() { + return findFirst() == null; + } + + /** + * Removes all of the mappings from this map. + */ + public void clear() { + initialize(); + } + + /* ---------------- View methods -------------- */ + + /* + * Note: Lazy initialization works for views because view classes + * are stateless/immutable so it doesn't matter wrt correctness if + * more than one is created (which will only rarely happen). Even + * so, the following idiom conservatively ensures that the method + * returns the one it created if it does so, not one created by + * another racing thread. + */ + + /** + * Returns a {@link NavigableSet} view of the keys contained in this map. + * The set's iterator returns the keys in ascending order. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. The set supports element + * removal, which removes the corresponding mapping from the map, + * via the {@code Iterator.remove}, {@code Set.remove}, + * {@code removeAll}, {@code retainAll}, and {@code clear} + * operations. It does not support the {@code add} or {@code addAll} + * operations. + * + * <p>The view's {@code iterator} is a "weakly consistent" iterator + * that will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + * + * <p>This method is equivalent to method {@code navigableKeySet}. + * + * @return a navigable set view of the keys in this map + */ + public NavigableSet<K> keySet() { + KeySet ks = keySet; + return (ks != null) ? ks : (keySet = new KeySet(this)); + } + + public NavigableSet<K> navigableKeySet() { + KeySet ks = keySet; + return (ks != null) ? ks : (keySet = new KeySet(this)); + } + + /** + * Returns a {@link Collection} view of the values contained in this map. + * The collection's iterator returns the values in ascending order + * of the corresponding keys. + * The collection is backed by the map, so changes to the map are + * reflected in the collection, and vice-versa. The collection + * supports element removal, which removes the corresponding + * mapping from the map, via the <tt>Iterator.remove</tt>, + * <tt>Collection.remove</tt>, <tt>removeAll</tt>, + * <tt>retainAll</tt> and <tt>clear</tt> operations. It does not + * support the <tt>add</tt> or <tt>addAll</tt> operations. + * + * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator + * that will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + */ + public Collection<V> values() { + Values vs = values; + return (vs != null) ? vs : (values = new Values(this)); + } + + /** + * Returns a {@link Set} view of the mappings contained in this map. + * The set's iterator returns the entries in ascending key order. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. The set supports element + * removal, which removes the corresponding mapping from the map, + * via the <tt>Iterator.remove</tt>, <tt>Set.remove</tt>, + * <tt>removeAll</tt>, <tt>retainAll</tt> and <tt>clear</tt> + * operations. It does not support the <tt>add</tt> or + * <tt>addAll</tt> operations. + * + * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator + * that will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + * + * <p>The <tt>Map.Entry</tt> elements returned by + * <tt>iterator.next()</tt> do <em>not</em> support the + * <tt>setValue</tt> operation. + * + * @return a set view of the mappings contained in this map, + * sorted in ascending key order + */ + public Set<Map.Entry<K,V>> entrySet() { + EntrySet es = entrySet; + return (es != null) ? es : (entrySet = new EntrySet(this)); + } + + public ConcurrentNavigableMap<K,V> descendingMap() { + ConcurrentNavigableMap<K,V> dm = descendingMap; + return (dm != null) ? dm : (descendingMap = new SubMap<K,V> + (this, null, false, null, false, true)); + } + + public NavigableSet<K> descendingKeySet() { + return descendingMap().navigableKeySet(); + } + + /* ---------------- AbstractMap Overrides -------------- */ + + /** + * Compares the specified object with this map for equality. + * Returns <tt>true</tt> if the given object is also a map and the + * two maps represent the same mappings. More formally, two maps + * <tt>m1</tt> and <tt>m2</tt> represent the same mappings if + * <tt>m1.entrySet().equals(m2.entrySet())</tt>. This + * operation may return misleading results if either map is + * concurrently modified during execution of this method. + * + * @param o object to be compared for equality with this map + * @return <tt>true</tt> if the specified object is equal to this map + */ + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof Map)) + return false; + Map<?,?> m = (Map<?,?>) o; + try { + for (Map.Entry<K,V> e : this.entrySet()) + if (! e.getValue().equals(m.get(e.getKey()))) + return false; + for (Map.Entry<?,?> e : m.entrySet()) { + Object k = e.getKey(); + Object v = e.getValue(); + if (k == null || v == null || !v.equals(get(k))) + return false; + } + return true; + } catch (ClassCastException unused) { + return false; + } catch (NullPointerException unused) { + return false; + } + } + + /* ------ ConcurrentMap API methods ------ */ + + /** + * {@inheritDoc} + * + * @return the previous value associated with the specified key, + * or <tt>null</tt> if there was no mapping for the key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key or value is null + */ + public V putIfAbsent(K key, V value) { + if (value == null) + throw new NullPointerException(); + return doPut(key, value, true); + } + + /** + * {@inheritDoc} + * + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + */ + public boolean remove(Object key, Object value) { + if (key == null) + throw new NullPointerException(); + if (value == null) + return false; + return doRemove(key, value) != null; + } + + /** + * {@inheritDoc} + * + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if any of the arguments are null + */ + public boolean replace(K key, V oldValue, V newValue) { + if (oldValue == null || newValue == null) + throw new NullPointerException(); + Comparable<? super K> k = comparable(key); + for (;;) { + Node<K,V> n = findNode(k); + if (n == null) + return false; + Object v = n.value; + if (v != null) { + if (!oldValue.equals(v)) + return false; + if (n.casValue(v, newValue)) + return true; + } + } + } + + /** + * {@inheritDoc} + * + * @return the previous value associated with the specified key, + * or <tt>null</tt> if there was no mapping for the key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key or value is null + */ + public V replace(K key, V value) { + if (value == null) + throw new NullPointerException(); + Comparable<? super K> k = comparable(key); + for (;;) { + Node<K,V> n = findNode(k); + if (n == null) + return null; + Object v = n.value; + if (v != null && n.casValue(v, value)) + return (V)v; + } + } + + /* ------ SortedMap API methods ------ */ + + public Comparator<? super K> comparator() { + return comparator; + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public K firstKey() { + Node<K,V> n = findFirst(); + if (n == null) + throw new NoSuchElementException(); + return n.key; + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public K lastKey() { + Node<K,V> n = findLast(); + if (n == null) + throw new NoSuchElementException(); + return n.key; + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromKey} or {@code toKey} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public ConcurrentNavigableMap<K,V> subMap(K fromKey, + boolean fromInclusive, + K toKey, + boolean toInclusive) { + if (fromKey == null || toKey == null) + throw new NullPointerException(); + return new SubMap<K,V> + (this, fromKey, fromInclusive, toKey, toInclusive, false); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code toKey} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public ConcurrentNavigableMap<K,V> headMap(K toKey, + boolean inclusive) { + if (toKey == null) + throw new NullPointerException(); + return new SubMap<K,V> + (this, null, false, toKey, inclusive, false); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromKey} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public ConcurrentNavigableMap<K,V> tailMap(K fromKey, + boolean inclusive) { + if (fromKey == null) + throw new NullPointerException(); + return new SubMap<K,V> + (this, fromKey, inclusive, null, false, false); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromKey} or {@code toKey} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public ConcurrentNavigableMap<K,V> subMap(K fromKey, K toKey) { + return subMap(fromKey, true, toKey, false); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code toKey} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public ConcurrentNavigableMap<K,V> headMap(K toKey) { + return headMap(toKey, false); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromKey} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public ConcurrentNavigableMap<K,V> tailMap(K fromKey) { + return tailMap(fromKey, true); + } + + /* ---------------- Relational operations -------------- */ + + /** + * Returns a key-value mapping associated with the greatest key + * strictly less than the given key, or <tt>null</tt> if there is + * no such key. The returned entry does <em>not</em> support the + * <tt>Entry.setValue</tt> method. + * + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + */ + public Map.Entry<K,V> lowerEntry(K key) { + return getNear(key, LT); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + */ + public K lowerKey(K key) { + Node<K,V> n = findNear(key, LT); + return (n == null)? null : n.key; + } + + /** + * Returns a key-value mapping associated with the greatest key + * less than or equal to the given key, or <tt>null</tt> if there + * is no such key. The returned entry does <em>not</em> support + * the <tt>Entry.setValue</tt> method. + * + * @param key the key + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + */ + public Map.Entry<K,V> floorEntry(K key) { + return getNear(key, LT|EQ); + } + + /** + * @param key the key + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + */ + public K floorKey(K key) { + Node<K,V> n = findNear(key, LT|EQ); + return (n == null)? null : n.key; + } + + /** + * Returns a key-value mapping associated with the least key + * greater than or equal to the given key, or <tt>null</tt> if + * there is no such entry. The returned entry does <em>not</em> + * support the <tt>Entry.setValue</tt> method. + * + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + */ + public Map.Entry<K,V> ceilingEntry(K key) { + return getNear(key, GT|EQ); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + */ + public K ceilingKey(K key) { + Node<K,V> n = findNear(key, GT|EQ); + return (n == null)? null : n.key; + } + + /** + * Returns a key-value mapping associated with the least key + * strictly greater than the given key, or <tt>null</tt> if there + * is no such key. The returned entry does <em>not</em> support + * the <tt>Entry.setValue</tt> method. + * + * @param key the key + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + */ + public Map.Entry<K,V> higherEntry(K key) { + return getNear(key, GT); + } + + /** + * @param key the key + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + */ + public K higherKey(K key) { + Node<K,V> n = findNear(key, GT); + return (n == null)? null : n.key; + } + + /** + * Returns a key-value mapping associated with the least + * key in this map, or <tt>null</tt> if the map is empty. + * The returned entry does <em>not</em> support + * the <tt>Entry.setValue</tt> method. + */ + public Map.Entry<K,V> firstEntry() { + for (;;) { + Node<K,V> n = findFirst(); + if (n == null) + return null; + AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot(); + if (e != null) + return e; + } + } + + /** + * Returns a key-value mapping associated with the greatest + * key in this map, or <tt>null</tt> if the map is empty. + * The returned entry does <em>not</em> support + * the <tt>Entry.setValue</tt> method. + */ + public Map.Entry<K,V> lastEntry() { + for (;;) { + Node<K,V> n = findLast(); + if (n == null) + return null; + AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot(); + if (e != null) + return e; + } + } + + /** + * Removes and returns a key-value mapping associated with + * the least key in this map, or <tt>null</tt> if the map is empty. + * The returned entry does <em>not</em> support + * the <tt>Entry.setValue</tt> method. + */ + public Map.Entry<K,V> pollFirstEntry() { + return doRemoveFirstEntry(); + } + + /** + * Removes and returns a key-value mapping associated with + * the greatest key in this map, or <tt>null</tt> if the map is empty. + * The returned entry does <em>not</em> support + * the <tt>Entry.setValue</tt> method. + */ + public Map.Entry<K,V> pollLastEntry() { + return doRemoveLastEntry(); + } + + + /* ---------------- Iterators -------------- */ + + /** + * Base of iterator classes: + */ + abstract class Iter<T> implements Iterator<T> { + /** the last node returned by next() */ + Node<K,V> lastReturned; + /** the next node to return from next(); */ + Node<K,V> next; + /** Cache of next value field to maintain weak consistency */ + V nextValue; + + /** Initializes ascending iterator for entire range. */ + Iter() { + for (;;) { + next = findFirst(); + if (next == null) + break; + Object x = next.value; + if (x != null && x != next) { + nextValue = (V) x; + break; + } + } + } + + public final boolean hasNext() { + return next != null; + } + + /** Advances next to higher entry. */ + final void advance() { + if ((lastReturned = next) == null) + throw new NoSuchElementException(); + for (;;) { + next = next.next; + if (next == null) + break; + Object x = next.value; + if (x != null && x != next) { + nextValue = (V) x; + break; + } + } + } + + public void remove() { + Node<K,V> l = lastReturned; + if (l == null) + throw new IllegalStateException(); + // It would not be worth all of the overhead to directly + // unlink from here. Using remove is fast enough. + ConcurrentSkipListMap.this.remove(l.key); + lastReturned = null; + } + + } + + final class ValueIterator extends Iter<V> { + public V next() { + V v = nextValue; + advance(); + return v; + } + } + + final class KeyIterator extends Iter<K> { + public K next() { + Node<K,V> n = next; + advance(); + return n.key; + } + } + + final class EntryIterator extends Iter<Map.Entry<K,V>> { + public Map.Entry<K,V> next() { + Node<K,V> n = next; + V v = nextValue; + advance(); + return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, 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 -------------- */ + + /* + * View classes are static, delegating to a ConcurrentNavigableMap + * to allow use by SubMaps, which outweighs the ugliness of + * needing type-tests for Iterator methods. + */ + + static final <E> List<E> toList(Collection<E> c) { + // Using size() here would be a pessimization. + List<E> list = new ArrayList<E>(); + for (E e : c) + list.add(e); + return list; + } + + static final class KeySet<E> extends AbstractSet<E> implements NavigableSet<E> { + private final ConcurrentNavigableMap<E,Object> m; + KeySet(ConcurrentNavigableMap<E,Object> 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,Object> e = m.pollFirstEntry(); + return e == null? null : e.getKey(); + } + public E pollLast() { + Map.Entry<E,Object> e = m.pollLastEntry(); + return e == null? null : e.getKey(); + } + public Iterator<E> iterator() { + if (m instanceof ConcurrentSkipListMap) + return ((ConcurrentSkipListMap<E,Object>)m).keyIterator(); + else + return ((ConcurrentSkipListMap.SubMap<E,Object>)m).keyIterator(); + } + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof Set)) + return false; + Collection<?> c = (Collection<?>) o; + try { + return containsAll(c) && c.containsAll(this); + } catch (ClassCastException unused) { + return false; + } catch (NullPointerException unused) { + return false; + } + } + public Object[] toArray() { return toList(this).toArray(); } + public <T> T[] toArray(T[] a) { return toList(this).toArray(a); } + public Iterator<E> descendingIterator() { + return descendingSet().iterator(); + } + public NavigableSet<E> subSet(E fromElement, + boolean fromInclusive, + E toElement, + boolean toInclusive) { + return new ConcurrentSkipListSet<E> + (m.subMap(fromElement, fromInclusive, + toElement, toInclusive)); + } + public NavigableSet<E> headSet(E toElement, boolean inclusive) { + return new ConcurrentSkipListSet<E>(m.headMap(toElement, inclusive)); + } + public NavigableSet<E> tailSet(E fromElement, boolean inclusive) { + return new ConcurrentSkipListSet<E>(m.tailMap(fromElement, inclusive)); + } + public NavigableSet<E> subSet(E fromElement, E toElement) { + return subSet(fromElement, true, toElement, false); + } + public NavigableSet<E> headSet(E toElement) { + return headSet(toElement, false); + } + public NavigableSet<E> tailSet(E fromElement) { + return tailSet(fromElement, true); + } + public NavigableSet<E> descendingSet() { + return new ConcurrentSkipListSet(m.descendingMap()); + } + } + + static final class Values<E> extends AbstractCollection<E> { + private final ConcurrentNavigableMap<Object, E> m; + Values(ConcurrentNavigableMap<Object, E> map) { + m = map; + } + public Iterator<E> iterator() { + if (m instanceof ConcurrentSkipListMap) + return ((ConcurrentSkipListMap<Object,E>)m).valueIterator(); + else + return ((SubMap<Object,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 Object[] toArray() { return toList(this).toArray(); } + public <T> T[] toArray(T[] a) { return toList(this).toArray(a); } + } + + static final class EntrySet<K1,V1> extends AbstractSet<Map.Entry<K1,V1>> { + private final ConcurrentNavigableMap<K1, V1> m; + EntrySet(ConcurrentNavigableMap<K1, V1> map) { + m = map; + } + + 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 boolean contains(Object o) { + if (!(o instanceof Map.Entry)) + return false; + Map.Entry<K1,V1> e = (Map.Entry<K1,V1>)o; + V1 v = m.get(e.getKey()); + return v != null && v.equals(e.getValue()); + } + public boolean remove(Object o) { + if (!(o instanceof Map.Entry)) + return false; + Map.Entry<K1,V1> e = (Map.Entry<K1,V1>)o; + return m.remove(e.getKey(), + e.getValue()); + } + public boolean isEmpty() { + return m.isEmpty(); + } + public int size() { + return m.size(); + } + public void clear() { + m.clear(); + } + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof Set)) + return false; + Collection<?> c = (Collection<?>) o; + try { + return containsAll(c) && c.containsAll(this); + } catch (ClassCastException unused) { + return false; + } catch (NullPointerException unused) { + return false; + } + } + public Object[] toArray() { return toList(this).toArray(); } + public <T> T[] toArray(T[] a) { return toList(this).toArray(a); } + } + + /** + * 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 <tt>subMap</tt>, <tt>headMap</tt>, and + * <tt>tailMap</tt> methods of their underlying maps. + * + * @serial include + */ + static final class SubMap<K,V> extends AbstractMap<K,V> + implements ConcurrentNavigableMap<K,V>, Cloneable, + java.io.Serializable { + private static final long serialVersionUID = -7647078645895051609L; + + /** Underlying map */ + private 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 */ + private final K hi; + /** inclusion flag for lo */ + private final boolean loInclusive; + /** inclusion flag for hi */ + private final boolean hiInclusive; + /** direction */ + private final boolean isDescending; + + // Lazily initialized view holders + private transient KeySet<K> keySetView; + private transient Set<Map.Entry<K,V>> entrySetView; + private transient Collection<V> valuesView; + + /** + * Creates a new submap, initializing all fields + */ + SubMap(ConcurrentSkipListMap<K,V> map, + K fromKey, boolean fromInclusive, + K toKey, boolean toInclusive, + boolean isDescending) { + if (fromKey != null && toKey != null && + map.compare(fromKey, toKey) > 0) + throw new IllegalArgumentException("inconsistent range"); + this.m = map; + this.lo = fromKey; + this.hi = toKey; + this.loInclusive = fromInclusive; + this.hiInclusive = toInclusive; + this.isDescending = isDescending; + } + + /* ---------------- Utilities -------------- */ + + private boolean tooLow(K key) { + if (lo != null) { + int c = m.compare(key, lo); + if (c < 0 || (c == 0 && !loInclusive)) + return true; + } + return false; + } + + private boolean tooHigh(K key) { + if (hi != null) { + int c = m.compare(key, hi); + if (c > 0 || (c == 0 && !hiInclusive)) + return true; + } + return false; + } + + private boolean inBounds(K key) { + return !tooLow(key) && !tooHigh(key); + } + + private void checkKeyBounds(K key) throws IllegalArgumentException { + if (key == null) + throw new NullPointerException(); + if (!inBounds(key)) + throw new IllegalArgumentException("key out of range"); + } + + /** + * Returns true if node key is less than upper bound of range + */ + private boolean isBeforeEnd(ConcurrentSkipListMap.Node<K,V> n) { + if (n == null) + return false; + if (hi == null) + return true; + K k = n.key; + if (k == null) // pass by markers and headers + return true; + int c = m.compare(k, hi); + if (c > 0 || (c == 0 && !hiInclusive)) + return false; + return true; + } + + /** + * Returns lowest node. This node might not be in range, so + * most usages need to check bounds + */ + private ConcurrentSkipListMap.Node<K,V> loNode() { + if (lo == null) + return m.findFirst(); + else if (loInclusive) + return m.findNear(lo, m.GT|m.EQ); + else + return m.findNear(lo, m.GT); + } + + /** + * Returns highest node. This node might not be in range, so + * most usages need to check bounds + */ + private ConcurrentSkipListMap.Node<K,V> hiNode() { + if (hi == null) + return m.findLast(); + else if (hiInclusive) + return m.findNear(hi, m.LT|m.EQ); + else + return m.findNear(hi, m.LT); + } + + /** + * Returns lowest absolute key (ignoring directonality) + */ + private K lowestKey() { + ConcurrentSkipListMap.Node<K,V> n = loNode(); + if (isBeforeEnd(n)) + return n.key; + else + throw new NoSuchElementException(); + } + + /** + * Returns highest absolute key (ignoring directonality) + */ + private K highestKey() { + ConcurrentSkipListMap.Node<K,V> n = hiNode(); + if (n != null) { + K last = n.key; + if (inBounds(last)) + return last; + } + throw new NoSuchElementException(); + } + + private Map.Entry<K,V> lowestEntry() { + for (;;) { + ConcurrentSkipListMap.Node<K,V> n = loNode(); + if (!isBeforeEnd(n)) + return null; + Map.Entry<K,V> e = n.createSnapshot(); + if (e != null) + return e; + } + } + + private Map.Entry<K,V> highestEntry() { + for (;;) { + ConcurrentSkipListMap.Node<K,V> n = hiNode(); + if (n == null || !inBounds(n.key)) + return null; + Map.Entry<K,V> e = n.createSnapshot(); + if (e != null) + return e; + } + } + + private Map.Entry<K,V> removeLowest() { + for (;;) { + Node<K,V> n = loNode(); + if (n == null) + return null; + K k = n.key; + if (!inBounds(k)) + return null; + V v = m.doRemove(k, null); + if (v != null) + return new AbstractMap.SimpleImmutableEntry<K,V>(k, v); + } + } + + private Map.Entry<K,V> removeHighest() { + for (;;) { + Node<K,V> n = hiNode(); + if (n == null) + return null; + K k = n.key; + if (!inBounds(k)) + return null; + V v = m.doRemove(k, null); + if (v != null) + return new AbstractMap.SimpleImmutableEntry<K,V>(k, v); + } + } + + /** + * Submap version of ConcurrentSkipListMap.getNearEntry + */ + private Map.Entry<K,V> getNearEntry(K key, int rel) { + if (isDescending) { // adjust relation for direction + if ((rel & m.LT) == 0) + rel |= m.LT; + else + rel &= ~m.LT; + } + if (tooLow(key)) + return ((rel & m.LT) != 0)? null : lowestEntry(); + if (tooHigh(key)) + return ((rel & m.LT) != 0)? highestEntry() : null; + for (;;) { + Node<K,V> n = m.findNear(key, rel); + if (n == null || !inBounds(n.key)) + return null; + K k = n.key; + V v = n.getValidValue(); + if (v != null) + return new AbstractMap.SimpleImmutableEntry<K,V>(k, v); + } + } + + // Almost the same as getNearEntry, except for keys + private K getNearKey(K key, int rel) { + if (isDescending) { // adjust relation for direction + if ((rel & m.LT) == 0) + rel |= m.LT; + else + rel &= ~m.LT; + } + if (tooLow(key)) { + if ((rel & m.LT) == 0) { + ConcurrentSkipListMap.Node<K,V> n = loNode(); + if (isBeforeEnd(n)) + return n.key; + } + return null; + } + if (tooHigh(key)) { + if ((rel & m.LT) != 0) { + ConcurrentSkipListMap.Node<K,V> n = hiNode(); + if (n != null) { + K last = n.key; + if (inBounds(last)) + return last; + } + } + return null; + } + for (;;) { + Node<K,V> n = m.findNear(key, rel); + if (n == null || !inBounds(n.key)) + return null; + K k = n.key; + V v = n.getValidValue(); + if (v != null) + return k; + } + } + + /* ---------------- Map API methods -------------- */ + + public boolean containsKey(Object key) { + if (key == null) throw new NullPointerException(); + K k = (K)key; + return inBounds(k) && m.containsKey(k); + } + + public V get(Object key) { + if (key == null) throw new NullPointerException(); + K k = (K)key; + return ((!inBounds(k)) ? null : m.get(k)); + } + + public V put(K key, V value) { + checkKeyBounds(key); + return m.put(key, value); + } + + public V remove(Object key) { + K k = (K)key; + return (!inBounds(k))? null : m.remove(k); + } + + public int size() { + long count = 0; + for (ConcurrentSkipListMap.Node<K,V> n = loNode(); + isBeforeEnd(n); + n = n.next) { + if (n.getValidValue() != null) + ++count; + } + return count >= Integer.MAX_VALUE? Integer.MAX_VALUE : (int)count; + } + + public boolean isEmpty() { + return !isBeforeEnd(loNode()); + } + + public boolean containsValue(Object value) { + if (value == null) + throw new NullPointerException(); + for (ConcurrentSkipListMap.Node<K,V> n = loNode(); + isBeforeEnd(n); + n = n.next) { + V v = n.getValidValue(); + if (v != null && value.equals(v)) + return true; + } + return false; + } + + public void clear() { + for (ConcurrentSkipListMap.Node<K,V> n = loNode(); + isBeforeEnd(n); + n = n.next) { + if (n.getValidValue() != null) + m.remove(n.key); + } + } + + /* ---------------- ConcurrentMap API methods -------------- */ + + public V putIfAbsent(K key, V value) { + checkKeyBounds(key); + return m.putIfAbsent(key, value); + } + + public boolean remove(Object key, Object value) { + K k = (K)key; + return inBounds(k) && m.remove(k, value); + } + + public boolean replace(K key, V oldValue, V newValue) { + checkKeyBounds(key); + return m.replace(key, oldValue, newValue); + } + + public V replace(K key, V value) { + checkKeyBounds(key); + return m.replace(key, value); + } + + /* ---------------- SortedMap API methods -------------- */ + + public Comparator<? super K> comparator() { + Comparator<? super K> cmp = m.comparator(); + if (isDescending) + return Collections.reverseOrder(cmp); + else + return cmp; + } + + /** + * Utility to create submaps, where given bounds override + * unbounded(null) ones and/or are checked against bounded ones. + */ + private SubMap<K,V> newSubMap(K fromKey, + boolean fromInclusive, + K toKey, + boolean toInclusive) { + if (isDescending) { // flip senses + K tk = fromKey; + fromKey = toKey; + toKey = tk; + boolean ti = fromInclusive; + fromInclusive = toInclusive; + toInclusive = ti; + } + if (lo != null) { + if (fromKey == null) { + fromKey = lo; + fromInclusive = loInclusive; + } + else { + int c = m.compare(fromKey, lo); + if (c < 0 || (c == 0 && !loInclusive && fromInclusive)) + throw new IllegalArgumentException("key out of range"); + } + } + if (hi != null) { + if (toKey == null) { + toKey = hi; + toInclusive = hiInclusive; + } + else { + int c = m.compare(toKey, hi); + if (c > 0 || (c == 0 && !hiInclusive && toInclusive)) + throw new IllegalArgumentException("key out of range"); + } + } + return new SubMap<K,V>(m, fromKey, fromInclusive, + toKey, toInclusive, isDescending); + } + + public SubMap<K,V> subMap(K fromKey, + boolean fromInclusive, + K toKey, + boolean toInclusive) { + if (fromKey == null || toKey == null) + throw new NullPointerException(); + return newSubMap(fromKey, fromInclusive, toKey, toInclusive); + } + + public SubMap<K,V> headMap(K toKey, + boolean inclusive) { + if (toKey == null) + throw new NullPointerException(); + return newSubMap(null, false, toKey, inclusive); + } + + public SubMap<K,V> tailMap(K fromKey, + boolean inclusive) { + if (fromKey == null) + throw new NullPointerException(); + return newSubMap(fromKey, inclusive, null, false); + } + + public SubMap<K,V> subMap(K fromKey, K toKey) { + return subMap(fromKey, true, toKey, false); + } + + public SubMap<K,V> headMap(K toKey) { + return headMap(toKey, false); + } + + public SubMap<K,V> tailMap(K fromKey) { + return tailMap(fromKey, true); + } + + public SubMap<K,V> descendingMap() { + return new SubMap<K,V>(m, lo, loInclusive, + hi, hiInclusive, !isDescending); + } + + /* ---------------- Relational methods -------------- */ + + public Map.Entry<K,V> ceilingEntry(K key) { + return getNearEntry(key, (m.GT|m.EQ)); + } + + public K ceilingKey(K key) { + return getNearKey(key, (m.GT|m.EQ)); + } + + public Map.Entry<K,V> lowerEntry(K key) { + return getNearEntry(key, (m.LT)); + } + + public K lowerKey(K key) { + return getNearKey(key, (m.LT)); + } + + public Map.Entry<K,V> floorEntry(K key) { + return getNearEntry(key, (m.LT|m.EQ)); + } + + public K floorKey(K key) { + return getNearKey(key, (m.LT|m.EQ)); + } + + public Map.Entry<K,V> higherEntry(K key) { + return getNearEntry(key, (m.GT)); + } + + public K higherKey(K key) { + return getNearKey(key, (m.GT)); + } + + public K firstKey() { + return isDescending? highestKey() : lowestKey(); + } + + public K lastKey() { + return isDescending? lowestKey() : highestKey(); + } + + public Map.Entry<K,V> firstEntry() { + return isDescending? highestEntry() : lowestEntry(); + } + + public Map.Entry<K,V> lastEntry() { + return isDescending? lowestEntry() : highestEntry(); + } + + public Map.Entry<K,V> pollFirstEntry() { + return isDescending? removeHighest() : removeLowest(); + } + + public Map.Entry<K,V> pollLastEntry() { + return isDescending? removeLowest() : removeHighest(); + } + + /* ---------------- Submap Views -------------- */ + + public NavigableSet<K> keySet() { + KeySet<K> 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(this)); + } + + public Collection<V> values() { + Collection<V> vs = valuesView; + return (vs != null) ? vs : (valuesView = new Values(this)); + } + + public Set<Map.Entry<K,V>> entrySet() { + Set<Map.Entry<K,V>> es = entrySetView; + return (es != null) ? es : (entrySetView = new EntrySet(this)); + } + + public NavigableSet<K> descendingKeySet() { + 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. + */ + abstract class SubMapIter<T> implements Iterator<T> { + /** the last node returned by next() */ + Node<K,V> lastReturned; + /** the next node to return from next(); */ + Node<K,V> next; + /** Cache of next value field to maintain weak consistency */ + V nextValue; + + SubMapIter() { + for (;;) { + next = isDescending ? hiNode() : loNode(); + if (next == null) + break; + Object x = next.value; + if (x != null && x != next) { + if (! inBounds(next.key)) + next = null; + else + nextValue = (V) x; + break; + } + } + } + + public final boolean hasNext() { + return next != null; + } + + final void advance() { + if ((lastReturned = next) == null) + throw new NoSuchElementException(); + if (isDescending) + descend(); + else + ascend(); + } + + private void ascend() { + for (;;) { + next = next.next; + if (next == null) + break; + Object x = next.value; + if (x != null && x != next) { + if (tooHigh(next.key)) + next = null; + else + nextValue = (V) x; + break; + } + } + } + + private void descend() { + for (;;) { + next = m.findNear(lastReturned.key, LT); + if (next == null) + break; + Object x = next.value; + if (x != null && x != next) { + if (tooLow(next.key)) + next = null; + else + nextValue = (V) x; + break; + } + } + } + + public void remove() { + Node<K,V> l = lastReturned; + if (l == null) + throw new IllegalStateException(); + m.remove(l.key); + lastReturned = null; + } + + } + + final class SubMapValueIterator extends SubMapIter<V> { + public V next() { + V v = nextValue; + advance(); + return v; + } + } + + final class SubMapKeyIterator extends SubMapIter<K> { + public K next() { + Node<K,V> n = next; + advance(); + return n.key; + } + } + + final class SubMapEntryIterator extends SubMapIter<Map.Entry<K,V>> { + public Map.Entry<K,V> next() { + Node<K,V> n = next; + V v = nextValue; + advance(); + return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v); + } + } + } +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/ConcurrentSkipListSet.java b/libjava/classpath/external/jsr166/java/util/concurrent/ConcurrentSkipListSet.java new file mode 100644 index 000000000..7fd1c7608 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/ConcurrentSkipListSet.java @@ -0,0 +1,456 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.*; +import sun.misc.Unsafe; + +/** + * A scalable concurrent {@link NavigableSet} implementation based on + * a {@link ConcurrentSkipListMap}. The elements of the set are kept + * sorted according to their {@linkplain Comparable natural ordering}, + * or by a {@link Comparator} provided at set creation time, depending + * on which constructor is used. + * + * <p>This implementation provides expected average <i>log(n)</i> time + * cost for the <tt>contains</tt>, <tt>add</tt>, and <tt>remove</tt> + * operations and their variants. Insertion, removal, and access + * operations safely execute concurrently by multiple threads. + * Iterators are <i>weakly consistent</i>, returning elements + * reflecting the state of the set at some point at or since the + * creation of the iterator. They do <em>not</em> throw {@link + * ConcurrentModificationException}, and may proceed concurrently with + * other operations. Ascending ordered views and their iterators are + * faster than descending ones. + * + * <p>Beware that, unlike in most collections, the <tt>size</tt> + * method is <em>not</em> a constant-time operation. Because of the + * asynchronous nature of these sets, determining the current number + * of elements requires a traversal of the elements. Additionally, the + * bulk operations <tt>addAll</tt>, <tt>removeAll</tt>, + * <tt>retainAll</tt>, and <tt>containsAll</tt> are <em>not</em> + * guaranteed to be performed atomically. For example, an iterator + * operating concurrently with an <tt>addAll</tt> operation might view + * only some of the added elements. + * + * <p>This class and its iterators implement all of the + * <em>optional</em> methods of the {@link Set} and {@link Iterator} + * interfaces. Like most other concurrent collection implementations, + * this class does not permit the use of <tt>null</tt> elements, + * because <tt>null</tt> arguments and return values cannot be reliably + * distinguished from the absence of elements. + * + * <p>This class is a member of the + * <a href="{@docRoot}/../technotes/guides/collections/index.html"> + * Java Collections Framework</a>. + * + * @author Doug Lea + * @param <E> the type of elements maintained by this set + * @since 1.6 + */ +public class ConcurrentSkipListSet<E> + extends AbstractSet<E> + implements NavigableSet<E>, Cloneable, java.io.Serializable { + + private static final long serialVersionUID = -2479143111061671589L; + + /** + * The underlying map. Uses Boolean.TRUE as value for each + * element. This field is declared final for the sake of thread + * safety, which entails some ugliness in clone() + */ + private final ConcurrentNavigableMap<E,Object> m; + + /** + * Constructs a new, empty set that orders its elements according to + * their {@linkplain Comparable natural ordering}. + */ + public ConcurrentSkipListSet() { + m = new ConcurrentSkipListMap<E,Object>(); + } + + /** + * Constructs a new, empty set that orders its elements according to + * the specified comparator. + * + * @param comparator the comparator that will be used to order this set. + * If <tt>null</tt>, the {@linkplain Comparable natural + * ordering} of the elements will be used. + */ + public ConcurrentSkipListSet(Comparator<? super E> comparator) { + m = new ConcurrentSkipListMap<E,Object>(comparator); + } + + /** + * Constructs a new set containing the elements in the specified + * collection, that orders its elements according to their + * {@linkplain Comparable natural ordering}. + * + * @param c The elements that will comprise the new set + * @throws ClassCastException if the elements in <tt>c</tt> are + * not {@link Comparable}, or are not mutually comparable + * @throws NullPointerException if the specified collection or any + * of its elements are null + */ + public ConcurrentSkipListSet(Collection<? extends E> c) { + m = new ConcurrentSkipListMap<E,Object>(); + addAll(c); + } + + /** + * Constructs a new set containing the same elements and using the + * same ordering as the specified sorted set. + * + * @param s sorted set whose elements will comprise the new set + * @throws NullPointerException if the specified sorted set or any + * of its elements are null + */ + public ConcurrentSkipListSet(SortedSet<E> s) { + m = new ConcurrentSkipListMap<E,Object>(s.comparator()); + addAll(s); + } + + /** + * For use by submaps + */ + ConcurrentSkipListSet(ConcurrentNavigableMap<E,Object> m) { + this.m = m; + } + + /** + * Returns a shallow copy of this <tt>ConcurrentSkipListSet</tt> + * instance. (The elements themselves are not cloned.) + * + * @return a shallow copy of this set + */ + public ConcurrentSkipListSet<E> clone() { + ConcurrentSkipListSet<E> clone = null; + try { + clone = (ConcurrentSkipListSet<E>) super.clone(); + clone.setMap(new ConcurrentSkipListMap(m)); + } catch (CloneNotSupportedException e) { + throw new InternalError(); + } + + return clone; + } + + /* ---------------- Set operations -------------- */ + + /** + * Returns the number of elements in this set. If this set + * contains more than <tt>Integer.MAX_VALUE</tt> elements, it + * returns <tt>Integer.MAX_VALUE</tt>. + * + * <p>Beware that, unlike in most collections, this method is + * <em>NOT</em> a constant-time operation. Because of the + * asynchronous nature of these sets, determining the current + * number of elements requires traversing them all to count them. + * Additionally, it is possible for the size to change during + * execution of this method, in which case the returned result + * will be inaccurate. Thus, this method is typically not very + * useful in concurrent applications. + * + * @return the number of elements in this set + */ + public int size() { + return m.size(); + } + + /** + * Returns <tt>true</tt> if this set contains no elements. + * @return <tt>true</tt> if this set contains no elements + */ + public boolean isEmpty() { + return m.isEmpty(); + } + + /** + * Returns <tt>true</tt> if this set contains the specified element. + * More formally, returns <tt>true</tt> if and only if this set + * contains an element <tt>e</tt> such that <tt>o.equals(e)</tt>. + * + * @param o object to be checked for containment in this set + * @return <tt>true</tt> if this set contains the specified element + * @throws ClassCastException if the specified element cannot be + * compared with the elements currently in this set + * @throws NullPointerException if the specified element is null + */ + public boolean contains(Object o) { + return m.containsKey(o); + } + + /** + * Adds the specified element to this set if it is not already present. + * More formally, adds the specified element <tt>e</tt> to this set if + * the set contains no element <tt>e2</tt> such that <tt>e.equals(e2)</tt>. + * If this set already contains the element, the call leaves the set + * unchanged and returns <tt>false</tt>. + * + * @param e element to be added to this set + * @return <tt>true</tt> if this set did not already contain the + * specified element + * @throws ClassCastException if <tt>e</tt> cannot be compared + * with the elements currently in this set + * @throws NullPointerException if the specified element is null + */ + public boolean add(E e) { + return m.putIfAbsent(e, Boolean.TRUE) == null; + } + + /** + * Removes the specified element from this set if it is present. + * More formally, removes an element <tt>e</tt> such that + * <tt>o.equals(e)</tt>, if this set contains such an element. + * Returns <tt>true</tt> 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 <tt>true</tt> if this set contained the specified element + * @throws ClassCastException if <tt>o</tt> cannot be compared + * with the elements currently in this set + * @throws NullPointerException if the specified element is null + */ + public boolean remove(Object o) { + return m.remove(o, Boolean.TRUE); + } + + /** + * Removes all of the elements from this set. + */ + public void clear() { + m.clear(); + } + + /** + * Returns an iterator over the elements in this set in ascending order. + * + * @return an iterator over the elements in this set in ascending order + */ + public Iterator<E> iterator() { + return m.navigableKeySet().iterator(); + } + + /** + * Returns an iterator over the elements in this set in descending order. + * + * @return an iterator over the elements in this set in descending order + */ + public Iterator<E> descendingIterator() { + return m.descendingKeySet().iterator(); + } + + + /* ---------------- AbstractSet Overrides -------------- */ + + /** + * Compares the specified object with this set for equality. Returns + * <tt>true</tt> if the specified object is also a set, the two sets + * have the same size, and every member of the specified set is + * contained in this set (or equivalently, every member of this set is + * contained in the specified set). This definition ensures that the + * equals method works properly across different implementations of the + * set interface. + * + * @param o the object to be compared for equality with this set + * @return <tt>true</tt> if the specified object is equal to this set + */ + public boolean equals(Object o) { + // Override AbstractSet version to avoid calling size() + if (o == this) + return true; + if (!(o instanceof Set)) + return false; + Collection<?> c = (Collection<?>) o; + try { + return containsAll(c) && c.containsAll(this); + } catch (ClassCastException unused) { + return false; + } catch (NullPointerException unused) { + return false; + } + } + + /** + * Removes from this set all of its elements that are contained in + * the specified collection. If the specified collection is also + * a set, this operation effectively modifies this set so that its + * value is the <i>asymmetric set difference</i> of the two sets. + * + * @param c collection containing elements to be removed from this set + * @return <tt>true</tt> 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 NullPointerException if the specified collection or any + * of its elements are null + */ + public boolean removeAll(Collection<?> c) { + // Override AbstractSet version to avoid unnecessary call to size() + boolean modified = false; + for (Iterator<?> i = c.iterator(); i.hasNext(); ) + if (remove(i.next())) + modified = true; + return modified; + } + + /* ---------------- Relational operations -------------- */ + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + */ + public E lower(E e) { + return m.lowerKey(e); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + */ + public E floor(E e) { + return m.floorKey(e); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + */ + public E ceiling(E e) { + return m.ceilingKey(e); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + */ + public E higher(E e) { + return m.higherKey(e); + } + + public E pollFirst() { + Map.Entry<E,Object> e = m.pollFirstEntry(); + return e == null? null : e.getKey(); + } + + public E pollLast() { + Map.Entry<E,Object> e = m.pollLastEntry(); + return e == null? null : e.getKey(); + } + + + /* ---------------- SortedSet operations -------------- */ + + + public Comparator<? super E> comparator() { + return m.comparator(); + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E first() { + return m.firstKey(); + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E last() { + return m.lastKey(); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromElement} or + * {@code toElement} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public NavigableSet<E> subSet(E fromElement, + boolean fromInclusive, + E toElement, + boolean toInclusive) { + return new ConcurrentSkipListSet<E> + (m.subMap(fromElement, fromInclusive, + toElement, toInclusive)); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code toElement} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public NavigableSet<E> headSet(E toElement, boolean inclusive) { + return new ConcurrentSkipListSet<E>(m.headMap(toElement, inclusive)); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromElement} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public NavigableSet<E> tailSet(E fromElement, boolean inclusive) { + return new ConcurrentSkipListSet<E>(m.tailMap(fromElement, inclusive)); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromElement} or + * {@code toElement} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public NavigableSet<E> subSet(E fromElement, E toElement) { + return subSet(fromElement, true, toElement, false); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code toElement} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public NavigableSet<E> headSet(E toElement) { + return headSet(toElement, false); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromElement} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public NavigableSet<E> tailSet(E fromElement) { + return tailSet(fromElement, true); + } + + /** + * Returns a reverse order view of the elements contained in this set. + * The descending set is backed by this set, so changes to the set are + * reflected in the descending set, and vice-versa. + * + * <p>The returned set has an ordering equivalent to + * <tt>{@link Collections#reverseOrder(Comparator) Collections.reverseOrder}(comparator())</tt>. + * The expression {@code s.descendingSet().descendingSet()} returns a + * view of {@code s} essentially equivalent to {@code s}. + * + * @return a reverse order view of this set + */ + public NavigableSet<E> descendingSet() { + return new ConcurrentSkipListSet(m.descendingMap()); + } + + // Support for resetting map in clone + private static final Unsafe unsafe = Unsafe.getUnsafe(); + private static final long mapOffset; + static { + try { + mapOffset = unsafe.objectFieldOffset + (ConcurrentSkipListSet.class.getDeclaredField("m")); + } catch (Exception ex) { throw new Error(ex); } + } + private void setMap(ConcurrentNavigableMap<E,Object> map) { + unsafe.putObjectVolatile(this, mapOffset, map); + } + +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/CopyOnWriteArraySet.java b/libjava/classpath/external/jsr166/java/util/concurrent/CopyOnWriteArraySet.java new file mode 100644 index 000000000..063636bd8 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/CopyOnWriteArraySet.java @@ -0,0 +1,364 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain. Use, modify, and + * redistribute this code in any way without acknowledgement. + */ + +package java.util.concurrent; +import java.util.*; + +/** + * A {@link java.util.Set} that uses an internal {@link CopyOnWriteArrayList} + * for all of its operations. Thus, it shares the same basic properties: + * <ul> + * <li>It is best suited for applications in which set sizes generally + * stay small, read-only operations + * vastly outnumber mutative operations, and you need + * to prevent interference among threads during traversal. + * <li>It is thread-safe. + * <li>Mutative operations (<tt>add</tt>, <tt>set</tt>, <tt>remove</tt>, etc.) + * are expensive since they usually entail copying the entire underlying + * array. + * <li>Iterators do not support the mutative <tt>remove</tt> operation. + * <li>Traversal via iterators is fast and cannot encounter + * interference from other threads. Iterators rely on + * unchanging snapshots of the array at the time the iterators were + * constructed. + * </ul> + * + * <p> <b>Sample Usage.</b> The following code sketch uses a + * copy-on-write set to maintain a set of Handler objects that + * perform some action upon state updates. + * + * <pre> + * class Handler { void handle(); ... } + * + * class X { + * private final CopyOnWriteArraySet<Handler> handlers + * = new CopyOnWriteArraySet<Handler>(); + * public void addHandler(Handler h) { handlers.add(h); } + * + * private long internalState; + * private synchronized void changeState() { internalState = ...; } + * + * public void update() { + * changeState(); + * for (Handler handler : handlers) + * handler.handle(); + * } + * } + * </pre> + * + * <p>This class is a member of the + * <a href="{@docRoot}/../technotes/guides/collections/index.html"> + * Java Collections Framework</a>. + * + * @see CopyOnWriteArrayList + * @since 1.5 + * @author Doug Lea + * @param <E> the type of elements held in this collection + */ +public class CopyOnWriteArraySet<E> extends AbstractSet<E> + implements java.io.Serializable { + private static final long serialVersionUID = 5457747651344034263L; + + private final CopyOnWriteArrayList<E> al; + + /** + * Creates an empty set. + */ + public CopyOnWriteArraySet() { + al = new CopyOnWriteArrayList<E>(); + } + + /** + * Creates a set containing all of the elements of the specified + * collection. + * + * @param c the collection of elements to initially contain + * @throws NullPointerException if the specified collection is null + */ + public CopyOnWriteArraySet(Collection<? extends E> c) { + al = new CopyOnWriteArrayList<E>(); + al.addAllAbsent(c); + } + + /** + * Returns the number of elements in this set. + * + * @return the number of elements in this set + */ + public int size() { + return al.size(); + } + + /** + * Returns <tt>true</tt> if this set contains no elements. + * + * @return <tt>true</tt> if this set contains no elements + */ + public boolean isEmpty() { + return al.isEmpty(); + } + + /** + * Returns <tt>true</tt> if this set contains the specified element. + * More formally, returns <tt>true</tt> if and only if this set + * contains an element <tt>e</tt> such that + * <tt>(o==null ? e==null : o.equals(e))</tt>. + * + * @param o element whose presence in this set is to be tested + * @return <tt>true</tt> if this set contains the specified element + */ + public boolean contains(Object o) { + return al.contains(o); + } + + /** + * Returns an array containing all of the elements in this set. + * If this set makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the + * elements in the same order. + * + * <p>The returned array will be "safe" in that no references to it + * are maintained by this set. (In other words, this method must + * allocate a new array even if this set is backed by an 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 the elements in this set + */ + public Object[] toArray() { + return al.toArray(); + } + + /** + * Returns an array containing all of the elements in this set; the + * runtime type of the returned array is that of the specified array. + * If the set 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 set. + * + * <p>If this set fits in the specified array with room to spare + * (i.e., the array has more elements than this set), the element in + * the array immediately following the end of the set is set to + * <tt>null</tt>. (This is useful in determining the length of this + * set <i>only</i> if the caller knows that this set does not contain + * any null elements.) + * + * <p>If this set makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the elements + * in the same order. + * + * <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 <tt>x</tt> is a set known to contain only strings. + * The following code can be used to dump the set into a newly allocated + * array of <tt>String</tt>: + * + * <pre> + * String[] y = x.toArray(new String[0]);</pre> + * + * Note that <tt>toArray(new Object[0])</tt> is identical in function to + * <tt>toArray()</tt>. + * + * @param a the array into which the elements of this set 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 the elements in this set + * @throws ArrayStoreException if the runtime type of the specified array + * is not a supertype of the runtime type of every element in this + * set + * @throws NullPointerException if the specified array is null + */ + public <T> T[] toArray(T[] a) { + return al.toArray(a); + } + + /** + * Removes all of the elements from this set. + * The set will be empty after this call returns. + */ + public void clear() { + al.clear(); + } + + /** + * Removes the specified element from this set if it is present. + * More formally, removes an element <tt>e</tt> such that + * <tt>(o==null ? e==null : o.equals(e))</tt>, + * if this set contains such an element. Returns <tt>true</tt> 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 <tt>true</tt> if this set contained the specified element + */ + public boolean remove(Object o) { + return al.remove(o); + } + + /** + * Adds the specified element to this set if it is not already present. + * More formally, adds the specified element <tt>e</tt> to this set if + * the set contains no element <tt>e2</tt> such that + * <tt>(e==null ? e2==null : e.equals(e2))</tt>. + * If this set already contains the element, the call leaves the set + * unchanged and returns <tt>false</tt>. + * + * @param e element to be added to this set + * @return <tt>true</tt> if this set did not already contain the specified + * element + */ + public boolean add(E e) { + return al.addIfAbsent(e); + } + + /** + * Returns <tt>true</tt> if this set contains all of the elements of the + * specified collection. If the specified collection is also a set, this + * method returns <tt>true</tt> if it is a <i>subset</i> of this set. + * + * @param c collection to be checked for containment in this set + * @return <tt>true</tt> if this set contains all of the elements of the + * specified collection + * @throws NullPointerException if the specified collection is null + * @see #contains(Object) + */ + public boolean containsAll(Collection<?> c) { + return al.containsAll(c); + } + + /** + * Adds all of the elements in the specified collection to this set if + * they're not already present. If the specified collection is also a + * set, the <tt>addAll</tt> operation effectively modifies this set so + * that its value is the <i>union</i> of the two sets. The behavior of + * this operation is undefined if the specified collection is modified + * while the operation is in progress. + * + * @param c collection containing elements to be added to this set + * @return <tt>true</tt> if this set changed as a result of the call + * @throws NullPointerException if the specified collection is null + * @see #add(Object) + */ + public boolean addAll(Collection<? extends E> c) { + return al.addAllAbsent(c) > 0; + } + + /** + * Removes from this set all of its elements that are contained in the + * specified collection. If the specified collection is also a set, + * this operation effectively modifies this set so that its value is the + * <i>asymmetric set difference</i> of the two sets. + * + * @param c collection containing elements to be removed from this set + * @return <tt>true</tt> 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) + * @throws NullPointerException if this set contains a null element and the + * specified collection does not permit null elements (optional), + * or if the specified collection is null + * @see #remove(Object) + */ + public boolean removeAll(Collection<?> c) { + return al.removeAll(c); + } + + /** + * Retains only the elements in this set that are contained in the + * specified collection. In other words, removes from this set all of + * its elements that are not contained in the specified collection. If + * the specified collection is also a set, this operation effectively + * modifies this set so that its value is the <i>intersection</i> of the + * two sets. + * + * @param c collection containing elements to be retained in this set + * @return <tt>true</tt> 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) + * @throws NullPointerException if this set contains a null element and the + * specified collection does not permit null elements (optional), + * or if the specified collection is null + * @see #remove(Object) + */ + public boolean retainAll(Collection<?> c) { + return al.retainAll(c); + } + + /** + * Returns an iterator over the elements contained in this set + * in the order in which these elements were added. + * + * <p>The returned iterator provides a snapshot of the state of the set + * when the iterator was constructed. No synchronization is needed while + * traversing the iterator. The iterator does <em>NOT</em> support the + * <tt>remove</tt> method. + * + * @return an iterator over the elements in this set + */ + public Iterator<E> iterator() { + return al.iterator(); + } + + /** + * Compares the specified object with this set for equality. + * Returns {@code true} if the specified object is the same object + * as this object, or if it is also a {@link Set} and the elements + * returned by an {@linkplain List#iterator() iterator} over the + * specified set are the same as the elements returned by an + * iterator over this set. More formally, the two iterators are + * considered to return the same elements if they return the same + * 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))}. + * + * @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; + } + + /** + * Test for equality, coping with nulls. + */ + private static boolean eq(Object o1, Object o2) { + return (o1 == null ? o2 == null : o1.equals(o2)); + } +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/CountDownLatch.java b/libjava/classpath/external/jsr166/java/util/concurrent/CountDownLatch.java new file mode 100644 index 000000000..016c1a7a5 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/CountDownLatch.java @@ -0,0 +1,290 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.concurrent.locks.*; +import java.util.concurrent.atomic.*; + +/** + * A synchronization aid that allows one or more threads to wait until + * a set of operations being performed in other threads completes. + * + * <p>A {@code CountDownLatch} is initialized with a given <em>count</em>. + * The {@link #await await} methods block until the current count reaches + * zero due to invocations of the {@link #countDown} method, after which + * all waiting threads are released and any subsequent invocations of + * {@link #await await} return immediately. This is a one-shot phenomenon + * -- the count cannot be reset. If you need a version that resets the + * count, consider using a {@link CyclicBarrier}. + * + * <p>A {@code CountDownLatch} is a versatile synchronization tool + * and can be used for a number of purposes. A + * {@code CountDownLatch} initialized with a count of one serves as a + * simple on/off latch, or gate: all threads invoking {@link #await await} + * wait at the gate until it is opened by a thread invoking {@link + * #countDown}. A {@code CountDownLatch} initialized to <em>N</em> + * can be used to make one thread wait until <em>N</em> threads have + * completed some action, or some action has been completed N times. + * + * <p>A useful property of a {@code CountDownLatch} is that it + * doesn't require that threads calling {@code countDown} wait for + * the count to reach zero before proceeding, it simply prevents any + * thread from proceeding past an {@link #await await} until all + * threads could pass. + * + * <p><b>Sample usage:</b> Here is a pair of classes in which a group + * of worker threads use two countdown latches: + * <ul> + * <li>The first is a start signal that prevents any worker from proceeding + * until the driver is ready for them to proceed; + * <li>The second is a completion signal that allows the driver to wait + * until all workers have completed. + * </ul> + * + * <pre> + * class Driver { // ... + * void main() throws InterruptedException { + * CountDownLatch startSignal = new CountDownLatch(1); + * CountDownLatch doneSignal = new CountDownLatch(N); + * + * for (int i = 0; i < N; ++i) // create and start threads + * new Thread(new Worker(startSignal, doneSignal)).start(); + * + * doSomethingElse(); // don't let run yet + * startSignal.countDown(); // let all threads proceed + * doSomethingElse(); + * doneSignal.await(); // wait for all to finish + * } + * } + * + * class Worker implements Runnable { + * private final CountDownLatch startSignal; + * private final CountDownLatch doneSignal; + * Worker(CountDownLatch startSignal, CountDownLatch doneSignal) { + * this.startSignal = startSignal; + * this.doneSignal = doneSignal; + * } + * public void run() { + * try { + * startSignal.await(); + * doWork(); + * doneSignal.countDown(); + * } catch (InterruptedException ex) {} // return; + * } + * + * void doWork() { ... } + * } + * + * </pre> + * + * <p>Another typical usage would be to divide a problem into N parts, + * describe each part with a Runnable that executes that portion and + * counts down on the latch, and queue all the Runnables to an + * Executor. When all sub-parts are complete, the coordinating thread + * will be able to pass through await. (When threads must repeatedly + * count down in this way, instead use a {@link CyclicBarrier}.) + * + * <pre> + * class Driver2 { // ... + * void main() throws InterruptedException { + * CountDownLatch doneSignal = new CountDownLatch(N); + * Executor e = ... + * + * for (int i = 0; i < N; ++i) // create and start threads + * e.execute(new WorkerRunnable(doneSignal, i)); + * + * doneSignal.await(); // wait for all to finish + * } + * } + * + * class WorkerRunnable implements Runnable { + * private final CountDownLatch doneSignal; + * private final int i; + * WorkerRunnable(CountDownLatch doneSignal, int i) { + * this.doneSignal = doneSignal; + * this.i = i; + * } + * public void run() { + * try { + * doWork(i); + * doneSignal.countDown(); + * } catch (InterruptedException ex) {} // return; + * } + * + * void doWork() { ... } + * } + * + * </pre> + * + * <p>Memory consistency effects: Actions in a thread prior to calling + * {@code countDown()} + * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a> + * actions following a successful return from a corresponding + * {@code await()} in another thread. + * + * @since 1.5 + * @author Doug Lea + */ +public class CountDownLatch { + /** + * Synchronization control For CountDownLatch. + * Uses AQS state to represent count. + */ + private static final class Sync extends AbstractQueuedSynchronizer { + private static final long serialVersionUID = 4982264981922014374L; + + Sync(int count) { + setState(count); + } + + int getCount() { + return getState(); + } + + public int tryAcquireShared(int acquires) { + return getState() == 0? 1 : -1; + } + + public boolean tryReleaseShared(int releases) { + // Decrement count; signal when transition to zero + for (;;) { + int c = getState(); + if (c == 0) + return false; + int nextc = c-1; + if (compareAndSetState(c, nextc)) + return nextc == 0; + } + } + } + + private final Sync sync; + + /** + * Constructs a {@code CountDownLatch} initialized with the given count. + * + * @param count the number of times {@link #countDown} must be invoked + * before threads can pass through {@link #await} + * @throws IllegalArgumentException if {@code count} is negative + */ + public CountDownLatch(int count) { + if (count < 0) throw new IllegalArgumentException("count < 0"); + this.sync = new Sync(count); + } + + /** + * Causes the current thread to wait until the latch has counted down to + * zero, unless the thread is {@linkplain Thread#interrupt interrupted}. + * + * <p>If the current count is zero then this method returns immediately. + * + * <p>If the current count is greater than zero then the current + * thread becomes disabled for thread scheduling purposes and lies + * dormant until one of two things happen: + * <ul> + * <li>The count reaches zero due to invocations of the + * {@link #countDown} method; or + * <li>Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread. + * </ul> + * + * <p>If the current thread: + * <ul> + * <li>has its interrupted status set on entry to this method; or + * <li>is {@linkplain Thread#interrupt interrupted} while waiting, + * </ul> + * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * + * @throws InterruptedException if the current thread is interrupted + * while waiting + */ + public void await() throws InterruptedException { + sync.acquireSharedInterruptibly(1); + } + + /** + * Causes the current thread to wait until the latch has counted down to + * zero, unless the thread is {@linkplain Thread#interrupt interrupted}, + * or the specified waiting time elapses. + * + * <p>If the current count is zero then this method returns immediately + * with the value {@code true}. + * + * <p>If the current count is greater than zero then the current + * thread becomes disabled for thread scheduling purposes and lies + * dormant until one of three things happen: + * <ul> + * <li>The count reaches zero due to invocations of the + * {@link #countDown} method; or + * <li>Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread; or + * <li>The specified waiting time elapses. + * </ul> + * + * <p>If the count reaches zero then the method returns with the + * value {@code true}. + * + * <p>If the current thread: + * <ul> + * <li>has its interrupted status set on entry to this method; or + * <li>is {@linkplain Thread#interrupt interrupted} while waiting, + * </ul> + * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * + * <p>If the specified waiting time elapses then the value {@code false} + * is returned. If the time is less than or equal to zero, the method + * will not wait at all. + * + * @param timeout the maximum time to wait + * @param unit the time unit of the {@code timeout} argument + * @return {@code true} if the count reached zero and {@code false} + * if the waiting time elapsed before the count reached zero + * @throws InterruptedException if the current thread is interrupted + * while waiting + */ + public boolean await(long timeout, TimeUnit unit) + throws InterruptedException { + return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout)); + } + + /** + * Decrements the count of the latch, releasing all waiting threads if + * the count reaches zero. + * + * <p>If the current count is greater than zero then it is decremented. + * If the new count is zero then all waiting threads are re-enabled for + * thread scheduling purposes. + * + * <p>If the current count equals zero then nothing happens. + */ + public void countDown() { + sync.releaseShared(1); + } + + /** + * Returns the current count. + * + * <p>This method is typically used for debugging and testing purposes. + * + * @return the current count + */ + public long getCount() { + return sync.getCount(); + } + + /** + * Returns a string identifying this latch, as well as its state. + * The state, in brackets, includes the String {@code "Count ="} + * followed by the current count. + * + * @return a string identifying this latch, as well as its state + */ + public String toString() { + return super.toString() + "[Count = " + sync.getCount() + "]"; + } +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/CyclicBarrier.java b/libjava/classpath/external/jsr166/java/util/concurrent/CyclicBarrier.java new file mode 100644 index 000000000..d5738c5ae --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/CyclicBarrier.java @@ -0,0 +1,454 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.concurrent.locks.*; + +/** + * A synchronization aid that allows a set of threads to all wait for + * each other to reach a common barrier point. CyclicBarriers are + * useful in programs involving a fixed sized party of threads that + * must occasionally wait for each other. The barrier is called + * <em>cyclic</em> because it can be re-used after the waiting threads + * are released. + * + * <p>A <tt>CyclicBarrier</tt> supports an optional {@link Runnable} command + * that is run once per barrier point, after the last thread in the party + * arrives, but before any threads are released. + * This <em>barrier action</em> is useful + * for updating shared-state before any of the parties continue. + * + * <p><b>Sample usage:</b> Here is an example of + * using a barrier in a parallel decomposition design: + * <pre> + * class Solver { + * final int N; + * final float[][] data; + * final CyclicBarrier barrier; + * + * class Worker implements Runnable { + * int myRow; + * Worker(int row) { myRow = row; } + * public void run() { + * while (!done()) { + * processRow(myRow); + * + * try { + * barrier.await(); + * } catch (InterruptedException ex) { + * return; + * } catch (BrokenBarrierException ex) { + * return; + * } + * } + * } + * } + * + * public Solver(float[][] matrix) { + * data = matrix; + * N = matrix.length; + * barrier = new CyclicBarrier(N, + * new Runnable() { + * public void run() { + * mergeRows(...); + * } + * }); + * for (int i = 0; i < N; ++i) + * new Thread(new Worker(i)).start(); + * + * waitUntilDone(); + * } + * } + * </pre> + * Here, each worker thread processes a row of the matrix then waits at the + * barrier until all rows have been processed. When all rows are processed + * the supplied {@link Runnable} barrier action is executed and merges the + * rows. If the merger + * determines that a solution has been found then <tt>done()</tt> will return + * <tt>true</tt> and each worker will terminate. + * + * <p>If the barrier action does not rely on the parties being suspended when + * it is executed, then any of the threads in the party could execute that + * action when it is released. To facilitate this, each invocation of + * {@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> if (barrier.await() == 0) { + * // log the completion of this iteration + * }</pre> + * + * <p>The <tt>CyclicBarrier</tt> uses an all-or-none breakage model + * for failed synchronization attempts: If a thread leaves a barrier + * point prematurely because of interruption, failure, or timeout, all + * other threads waiting at that barrier point will also leave + * abnormally via {@link BrokenBarrierException} (or + * {@link InterruptedException} if they too were interrupted at about + * the same time). + * + * <p>Memory consistency effects: Actions in a thread prior to calling + * {@code await()} + * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a> + * actions that are part of the barrier action, which in turn + * <i>happen-before</i> actions following a successful return from the + * corresponding {@code await()} in other threads. + * + * @since 1.5 + * @see CountDownLatch + * + * @author Doug Lea + */ +public class CyclicBarrier { + /** + * Each use of the barrier is represented as a generation instance. + * The generation changes whenever the barrier is tripped, or + * is reset. There can be many generations associated with threads + * using the barrier - due to the non-deterministic way the lock + * may be allocated to waiting threads - but only one of these + * can be active at a time (the one to which <tt>count</tt> applies) + * and all the rest are either broken or tripped. + * There need not be an active generation if there has been a break + * but no subsequent reset. + */ + private static class Generation { + boolean broken = false; + } + + /** The lock for guarding barrier entry */ + private final ReentrantLock lock = new ReentrantLock(); + /** Condition to wait on until tripped */ + private final Condition trip = lock.newCondition(); + /** The number of parties */ + private final int parties; + /* The command to run when tripped */ + private final Runnable barrierCommand; + /** The current generation */ + private Generation generation = new Generation(); + + /** + * Number of parties still waiting. Counts down from parties to 0 + * on each generation. It is reset to parties on each new + * generation or when broken. + */ + private int count; + + /** + * Updates state on barrier trip and wakes up everyone. + * Called only while holding lock. + */ + private void nextGeneration() { + // signal completion of last generation + trip.signalAll(); + // set up next generation + count = parties; + generation = new Generation(); + } + + /** + * Sets current barrier generation as broken and wakes up everyone. + * Called only while holding lock. + */ + private void breakBarrier() { + generation.broken = true; + count = parties; + trip.signalAll(); + } + + /** + * Main barrier code, covering the various policies. + */ + private int dowait(boolean timed, long nanos) + throws InterruptedException, BrokenBarrierException, + TimeoutException { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + final Generation g = generation; + + if (g.broken) + throw new BrokenBarrierException(); + + if (Thread.interrupted()) { + breakBarrier(); + throw new InterruptedException(); + } + + int index = --count; + if (index == 0) { // tripped + boolean ranAction = false; + try { + final Runnable command = barrierCommand; + if (command != null) + command.run(); + ranAction = true; + nextGeneration(); + return 0; + } finally { + if (!ranAction) + breakBarrier(); + } + } + + // loop until tripped, broken, interrupted, or timed out + for (;;) { + try { + if (!timed) + trip.await(); + else if (nanos > 0L) + nanos = trip.awaitNanos(nanos); + } catch (InterruptedException ie) { + if (g == generation && ! g.broken) { + breakBarrier(); + throw ie; + } else { + // We're about to finish waiting even if we had not + // been interrupted, so this interrupt is deemed to + // "belong" to subsequent execution. + Thread.currentThread().interrupt(); + } + } + + if (g.broken) + throw new BrokenBarrierException(); + + if (g != generation) + return index; + + if (timed && nanos <= 0L) { + breakBarrier(); + throw new TimeoutException(); + } + } + } finally { + lock.unlock(); + } + } + + /** + * Creates a new <tt>CyclicBarrier</tt> that will trip when the + * given number of parties (threads) are waiting upon it, and which + * will execute the given barrier action when the barrier is tripped, + * performed by the last thread entering the barrier. + * + * @param parties the number of threads that must invoke {@link #await} + * before the barrier is tripped + * @param barrierAction the command to execute when the barrier is + * tripped, or {@code null} if there is no action + * @throws IllegalArgumentException if {@code parties} is less than 1 + */ + public CyclicBarrier(int parties, Runnable barrierAction) { + if (parties <= 0) throw new IllegalArgumentException(); + this.parties = parties; + this.count = parties; + this.barrierCommand = barrierAction; + } + + /** + * Creates a new <tt>CyclicBarrier</tt> that will trip when the + * given number of parties (threads) are waiting upon it, and + * does not perform a predefined action when the barrier is tripped. + * + * @param parties the number of threads that must invoke {@link #await} + * before the barrier is tripped + * @throws IllegalArgumentException if {@code parties} is less than 1 + */ + public CyclicBarrier(int parties) { + this(parties, null); + } + + /** + * Returns the number of parties required to trip this barrier. + * + * @return the number of parties required to trip this barrier + */ + public int getParties() { + return parties; + } + + /** + * Waits until all {@linkplain #getParties parties} have invoked + * <tt>await</tt> on this barrier. + * + * <p>If the current thread is not the last to arrive then it is + * disabled for thread scheduling purposes and lies dormant until + * one of the following things happens: + * <ul> + * <li>The last thread arrives; or + * <li>Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread; or + * <li>Some other thread {@linkplain Thread#interrupt interrupts} + * one of the other waiting threads; or + * <li>Some other thread times out while waiting for barrier; or + * <li>Some other thread invokes {@link #reset} on this barrier. + * </ul> + * + * <p>If the current thread: + * <ul> + * <li>has its interrupted status set on entry to this method; or + * <li>is {@linkplain Thread#interrupt interrupted} while waiting + * </ul> + * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * + * <p>If the barrier is {@link #reset} while any thread is waiting, + * or if the barrier {@linkplain #isBroken is broken} when + * <tt>await</tt> is invoked, or while any thread is waiting, then + * {@link BrokenBarrierException} is thrown. + * + * <p>If any thread is {@linkplain Thread#interrupt interrupted} while waiting, + * then all other waiting threads will throw + * {@link BrokenBarrierException} and the barrier is placed in the broken + * state. + * + * <p>If the current thread is the last thread to arrive, and a + * non-null barrier action was supplied in the constructor, then the + * current thread runs the action before allowing the other threads to + * continue. + * If an exception occurs during the barrier action then that exception + * will be propagated in the current thread and the barrier is placed in + * the broken state. + * + * @return the arrival index of the current thread, where index + * <tt>{@link #getParties()} - 1</tt> indicates the first + * to arrive and zero indicates the last to arrive + * @throws InterruptedException if the current thread was interrupted + * while waiting + * @throws BrokenBarrierException if <em>another</em> thread was + * interrupted or timed out while the current thread was + * waiting, or the barrier was reset, or the barrier was + * broken when {@code await} was called, or the barrier + * action (if present) failed due an exception. + */ + public int await() throws InterruptedException, BrokenBarrierException { + try { + return dowait(false, 0L); + } catch (TimeoutException toe) { + throw new Error(toe); // cannot happen; + } + } + + /** + * Waits until all {@linkplain #getParties parties} have invoked + * <tt>await</tt> on this barrier, or the specified waiting time elapses. + * + * <p>If the current thread is not the last to arrive then it is + * disabled for thread scheduling purposes and lies dormant until + * one of the following things happens: + * <ul> + * <li>The last thread arrives; or + * <li>The specified timeout elapses; or + * <li>Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread; or + * <li>Some other thread {@linkplain Thread#interrupt interrupts} + * one of the other waiting threads; or + * <li>Some other thread times out while waiting for barrier; or + * <li>Some other thread invokes {@link #reset} on this barrier. + * </ul> + * + * <p>If the current thread: + * <ul> + * <li>has its interrupted status set on entry to this method; or + * <li>is {@linkplain Thread#interrupt interrupted} while waiting + * </ul> + * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * + * <p>If the specified waiting time elapses then {@link TimeoutException} + * is thrown. If the time is less than or equal to zero, the + * method will not wait at all. + * + * <p>If the barrier is {@link #reset} while any thread is waiting, + * or if the barrier {@linkplain #isBroken is broken} when + * <tt>await</tt> is invoked, or while any thread is waiting, then + * {@link BrokenBarrierException} is thrown. + * + * <p>If any thread is {@linkplain Thread#interrupt interrupted} while + * waiting, then all other waiting threads will throw {@link + * BrokenBarrierException} and the barrier is placed in the broken + * state. + * + * <p>If the current thread is the last thread to arrive, and a + * non-null barrier action was supplied in the constructor, then the + * current thread runs the action before allowing the other threads to + * continue. + * If an exception occurs during the barrier action then that exception + * will be propagated in the current thread and the barrier is placed in + * the broken state. + * + * @param timeout the time to wait for the barrier + * @param unit the time unit of the timeout parameter + * @return the arrival index of the current thread, where index + * <tt>{@link #getParties()} - 1</tt> indicates the first + * to arrive and zero indicates the last to arrive + * @throws InterruptedException if the current thread was interrupted + * while waiting + * @throws TimeoutException if the specified timeout elapses + * @throws BrokenBarrierException if <em>another</em> thread was + * interrupted or timed out while the current thread was + * waiting, or the barrier was reset, or the barrier was broken + * when {@code await} was called, or the barrier action (if + * present) failed due an exception + */ + public int await(long timeout, TimeUnit unit) + throws InterruptedException, + BrokenBarrierException, + TimeoutException { + return dowait(true, unit.toNanos(timeout)); + } + + /** + * Queries if this barrier is in a broken state. + * + * @return {@code true} if one or more parties broke out of this + * barrier due to interruption or timeout since + * construction or the last reset, or a barrier action + * failed due to an exception; {@code false} otherwise. + */ + public boolean isBroken() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return generation.broken; + } finally { + lock.unlock(); + } + } + + /** + * Resets the barrier to its initial state. If any parties are + * currently waiting at the barrier, they will return with a + * {@link BrokenBarrierException}. Note that resets <em>after</em> + * a breakage has occurred for other reasons can be complicated to + * carry out; threads need to re-synchronize in some other way, + * and choose one to perform the reset. It may be preferable to + * instead create a new barrier for subsequent use. + */ + public void reset() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + breakBarrier(); // break the current generation + nextGeneration(); // start a new generation + } finally { + lock.unlock(); + } + } + + /** + * Returns the number of parties currently waiting at the barrier. + * This method is primarily useful for debugging and assertions. + * + * @return the number of parties currently blocked in {@link #await} + */ + public int getNumberWaiting() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return parties - count; + } finally { + lock.unlock(); + } + } +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/DelayQueue.java b/libjava/classpath/external/jsr166/java/util/concurrent/DelayQueue.java new file mode 100644 index 000000000..4ce7bc652 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/DelayQueue.java @@ -0,0 +1,487 @@ +/* + * 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/licenses/publicdomain + */ + + +package java.util.concurrent; +import java.util.concurrent.locks.*; +import java.util.*; + +/** + * An unbounded {@linkplain BlockingQueue blocking queue} of + * <tt>Delayed</tt> elements, in which an element can only be taken + * when its delay has expired. The <em>head</em> of the queue is that + * <tt>Delayed</tt> element whose delay expired furthest in the + * past. If no delay has expired there is no head and <tt>poll</tt> + * will return <tt>null</tt>. Expiration occurs when an element's + * <tt>getDelay(TimeUnit.NANOSECONDS)</tt> method returns a value less + * than or equal to zero. Even though unexpired elements cannot be + * removed using <tt>take</tt> or <tt>poll</tt>, they are otherwise + * treated as normal elements. For example, the <tt>size</tt> method + * returns the count of both expired and unexpired elements. + * This queue does not permit null elements. + * + * <p>This class and its iterator implement all of the + * <em>optional</em> methods of the {@link Collection} and {@link + * Iterator} interfaces. + * + * <p>This class is a member of the + * <a href="{@docRoot}/../technotes/guides/collections/index.html"> + * Java Collections Framework</a>. + * + * @since 1.5 + * @author Doug Lea + * @param <E> the type of elements held in this collection + */ + +public class DelayQueue<E extends Delayed> extends AbstractQueue<E> + implements BlockingQueue<E> { + + private transient final ReentrantLock lock = new ReentrantLock(); + private transient final Condition available = lock.newCondition(); + private final PriorityQueue<E> q = new PriorityQueue<E>(); + + /** + * Creates a new <tt>DelayQueue</tt> that is initially empty. + */ + public DelayQueue() {} + + /** + * Creates a <tt>DelayQueue</tt> initially containing the elements of the + * given collection of {@link Delayed} instances. + * + * @param c the collection of elements to initially contain + * @throws NullPointerException if the specified collection or any + * of its elements are null + */ + public DelayQueue(Collection<? extends E> c) { + this.addAll(c); + } + + /** + * Inserts the specified element into this delay queue. + * + * @param e the element to add + * @return <tt>true</tt> (as specified by {@link Collection#add}) + * @throws NullPointerException if the specified element is null + */ + public boolean add(E e) { + return offer(e); + } + + /** + * Inserts the specified element into this delay queue. + * + * @param e the element to add + * @return <tt>true</tt> + * @throws NullPointerException if the specified element is null + */ + public boolean offer(E e) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + E first = q.peek(); + q.offer(e); + if (first == null || e.compareTo(first) < 0) + available.signalAll(); + return true; + } finally { + lock.unlock(); + } + } + + /** + * Inserts the specified element into this delay queue. As the queue is + * unbounded this method will never block. + * + * @param e the element to add + * @throws NullPointerException {@inheritDoc} + */ + public void put(E e) { + offer(e); + } + + /** + * Inserts the specified element into this delay queue. As the queue is + * unbounded this method will never block. + * + * @param e the element to add + * @param timeout This parameter is ignored as the method never blocks + * @param unit This parameter is ignored as the method never blocks + * @return <tt>true</tt> + * @throws NullPointerException {@inheritDoc} + */ + public boolean offer(E e, long timeout, TimeUnit unit) { + return offer(e); + } + + /** + * Retrieves and removes the head of this queue, or returns <tt>null</tt> + * if this queue has no elements with an expired delay. + * + * @return the head of this queue, or <tt>null</tt> if this + * queue has no elements with an expired delay + */ + public E poll() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + E first = q.peek(); + if (first == null || first.getDelay(TimeUnit.NANOSECONDS) > 0) + return null; + else { + E x = q.poll(); + assert x != null; + if (q.size() != 0) + available.signalAll(); + return x; + } + } finally { + lock.unlock(); + } + } + + /** + * Retrieves and removes the head of this queue, waiting if necessary + * until an element with an expired delay is available on this queue. + * + * @return the head of this queue + * @throws InterruptedException {@inheritDoc} + */ + public E take() throws InterruptedException { + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + for (;;) { + E first = q.peek(); + if (first == null) { + available.await(); + } else { + long delay = first.getDelay(TimeUnit.NANOSECONDS); + if (delay > 0) { + long tl = available.awaitNanos(delay); + } else { + E x = q.poll(); + assert x != null; + if (q.size() != 0) + available.signalAll(); // wake up other takers + return x; + + } + } + } + } finally { + lock.unlock(); + } + } + + /** + * Retrieves and removes the head of this queue, waiting if necessary + * until an element with an expired delay is available on this queue, + * or the specified wait time expires. + * + * @return the head of this queue, or <tt>null</tt> if the + * specified waiting time elapses before an element with + * an expired delay becomes available + * @throws InterruptedException {@inheritDoc} + */ + public E poll(long timeout, TimeUnit unit) throws InterruptedException { + long nanos = unit.toNanos(timeout); + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + for (;;) { + E first = q.peek(); + if (first == null) { + if (nanos <= 0) + return null; + else + nanos = available.awaitNanos(nanos); + } else { + long delay = first.getDelay(TimeUnit.NANOSECONDS); + if (delay > 0) { + if (nanos <= 0) + return null; + if (delay > nanos) + delay = nanos; + long timeLeft = available.awaitNanos(delay); + nanos -= delay - timeLeft; + } else { + E x = q.poll(); + assert x != null; + if (q.size() != 0) + available.signalAll(); + return x; + } + } + } + } finally { + lock.unlock(); + } + } + + /** + * Retrieves, but does not remove, the head of this queue, or + * returns <tt>null</tt> if this queue is empty. Unlike + * <tt>poll</tt>, if no expired elements are available in the queue, + * this method returns the element that will expire next, + * if one exists. + * + * @return the head of this queue, or <tt>null</tt> if this + * queue is empty. + */ + public E peek() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return q.peek(); + } finally { + lock.unlock(); + } + } + + public int size() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return q.size(); + } finally { + lock.unlock(); + } + } + + /** + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public int drainTo(Collection<? super E> c) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + final ReentrantLock lock = this.lock; + lock.lock(); + try { + int n = 0; + for (;;) { + E first = q.peek(); + if (first == null || first.getDelay(TimeUnit.NANOSECONDS) > 0) + break; + c.add(q.poll()); + ++n; + } + if (n > 0) + available.signalAll(); + return n; + } finally { + lock.unlock(); + } + } + + /** + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public int drainTo(Collection<? super E> c, int maxElements) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + if (maxElements <= 0) + return 0; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + int n = 0; + while (n < maxElements) { + E first = q.peek(); + if (first == null || first.getDelay(TimeUnit.NANOSECONDS) > 0) + break; + c.add(q.poll()); + ++n; + } + if (n > 0) + available.signalAll(); + return n; + } finally { + lock.unlock(); + } + } + + /** + * Atomically removes all of the elements from this delay queue. + * The queue will be empty after this call returns. + * Elements with an unexpired delay are not waited for; they are + * simply discarded from the queue. + */ + public void clear() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + q.clear(); + } finally { + lock.unlock(); + } + } + + /** + * Always returns <tt>Integer.MAX_VALUE</tt> because + * a <tt>DelayQueue</tt> is not capacity constrained. + * + * @return <tt>Integer.MAX_VALUE</tt> + */ + public int remainingCapacity() { + return Integer.MAX_VALUE; + } + + /** + * 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 q.toArray(); + } finally { + lock.unlock(); + } + } + + /** + * Returns an array containing all of the elements in this queue; the + * runtime type of the returned array is that of the specified array. + * The returned array elements are in no particular order. + * 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 + * <tt>null</tt>. + * + * <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>The following code can be used to dump a delay queue into a newly + * allocated array of <tt>Delayed</tt>: + * + * <pre> + * Delayed[] a = q.toArray(new Delayed[0]);</pre> + * + * Note that <tt>toArray(new Object[0])</tt> is identical in function to + * <tt>toArray()</tt>. + * + * @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 + */ + public <T> T[] toArray(T[] a) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return q.toArray(a); + } finally { + lock.unlock(); + } + } + + /** + * Removes a single instance of the specified element from this + * queue, if it is present, whether or not it has expired. + */ + public boolean remove(Object o) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return q.remove(o); + } finally { + lock.unlock(); + } + } + + /** + * Returns an iterator over all the elements (both expired and + * unexpired) in this queue. The iterator does not return the + * elements in any particular order. The returned + * <tt>Iterator</tt> is a "weakly consistent" iterator that will + * never throw {@link ConcurrentModificationException}, and + * guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed + * to) reflect any modifications subsequent to construction. + * + * @return an iterator over the elements in this queue + */ + public Iterator<E> iterator() { + return new Itr(toArray()); + } + + /** + * Snapshot iterator that works off copy of underlying q array. + */ + private class Itr implements Iterator<E> { + final Object[] array; // Array of all elements + int cursor; // index of next element to return; + int lastRet; // index of last element, or -1 if no such + + Itr(Object[] array) { + lastRet = -1; + this.array = array; + } + + public boolean hasNext() { + return cursor < array.length; + } + + public E next() { + if (cursor >= array.length) + throw new NoSuchElementException(); + lastRet = cursor; + return (E)array[cursor++]; + } + + public void remove() { + if (lastRet < 0) + throw new IllegalStateException(); + Object x = array[lastRet]; + lastRet = -1; + // Traverse underlying queue to find == element, + // not just a .equals element. + lock.lock(); + try { + for (Iterator it = q.iterator(); it.hasNext(); ) { + if (it.next() == x) { + it.remove(); + return; + } + } + } finally { + lock.unlock(); + } + } + } + +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/Delayed.java b/libjava/classpath/external/jsr166/java/util/concurrent/Delayed.java new file mode 100644 index 000000000..b1ff4eee5 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/Delayed.java @@ -0,0 +1,33 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; + +import java.util.*; + +/** + * A mix-in style interface for marking objects that should be + * acted upon after a given delay. + * + * <p>An implementation of this interface must define a + * <tt>compareTo</tt> method that provides an ordering consistent with + * its <tt>getDelay</tt> method. + * + * @since 1.5 + * @author Doug Lea + */ +public interface Delayed extends Comparable<Delayed> { + + /** + * Returns the remaining delay associated with this object, in the + * given time unit. + * + * @param unit the time unit + * @return the remaining delay; zero or negative values indicate + * that the delay has already elapsed + */ + long getDelay(TimeUnit unit); +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/Exchanger.java b/libjava/classpath/external/jsr166/java/util/concurrent/Exchanger.java new file mode 100644 index 000000000..fb917f432 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/Exchanger.java @@ -0,0 +1,656 @@ +/* + * Written by Doug Lea, Bill Scherer, and Michael Scott with + * assistance from members of JCP JSR-166 Expert Group and released to + * the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.concurrent.atomic.*; +import java.util.concurrent.locks.LockSupport; + +/** + * A synchronization point at which threads can pair and swap elements + * within pairs. Each thread presents some object on entry to the + * {@link #exchange exchange} method, matches with a partner thread, + * and receives its partner's object on return. An Exchanger may be + * viewed as a bidirectional form of a {@link SynchronousQueue}. + * Exchangers may be useful in applications such as genetic algorithms + * and pipeline designs. + * + * <p><b>Sample Usage:</b> + * Here are the highlights of a class that uses an {@code Exchanger} + * 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 + * class FillAndEmpty { + * Exchanger<DataBuffer> exchanger = new Exchanger<DataBuffer>(); + * DataBuffer initialEmptyBuffer = ... a made-up type + * DataBuffer initialFullBuffer = ... + * + * class FillingLoop implements Runnable { + * public void run() { + * DataBuffer currentBuffer = initialEmptyBuffer; + * try { + * while (currentBuffer != null) { + * addToBuffer(currentBuffer); + * if (currentBuffer.isFull()) + * currentBuffer = exchanger.exchange(currentBuffer); + * } + * } catch (InterruptedException ex) { ... handle ... } + * } + * } + * + * class EmptyingLoop implements Runnable { + * public void run() { + * DataBuffer currentBuffer = initialFullBuffer; + * try { + * while (currentBuffer != null) { + * takeFromBuffer(currentBuffer); + * if (currentBuffer.isEmpty()) + * currentBuffer = exchanger.exchange(currentBuffer); + * } + * } catch (InterruptedException ex) { ... handle ...} + * } + * } + * + * void start() { + * new Thread(new FillingLoop()).start(); + * new Thread(new EmptyingLoop()).start(); + * } + * } + * }</pre> + * + * <p>Memory consistency effects: For each pair of threads that + * successfully exchange objects via an {@code Exchanger}, actions + * prior to the {@code exchange()} in each thread + * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a> + * those subsequent to a return from the corresponding {@code exchange()} + * in the other thread. + * + * @since 1.5 + * @author Doug Lea and Bill Scherer and Michael Scott + * @param <V> The type of objects that may be exchanged + */ +public class Exchanger<V> { + /* + * Algorithm Description: + * + * The basic idea is to maintain a "slot", which is a reference to + * a Node containing both an Item to offer and a "hole" waiting to + * get filled in. If an incoming "occupying" thread sees that the + * slot is null, it CAS'es (compareAndSets) a Node there and waits + * for another to invoke exchange. That second "fulfilling" thread + * sees that the slot is non-null, and so CASes it back to null, + * also exchanging items by CASing the hole, plus waking up the + * occupying thread if it is blocked. In each case CAS'es may + * fail because a slot at first appears non-null but is null upon + * CAS, or vice-versa. So threads may need to retry these + * actions. + * + * This simple approach works great when there are only a few + * threads using an Exchanger, but performance rapidly + * deteriorates due to CAS contention on the single slot when + * there are lots of threads using an exchanger. So instead we use + * an "arena"; basically a kind of hash table with a dynamically + * varying number of slots, any one of which can be used by + * threads performing an exchange. Incoming threads pick slots + * based on a hash of their Thread ids. If an incoming thread + * fails to CAS in its chosen slot, it picks an alternative slot + * instead. And similarly from there. If a thread successfully + * CASes into a slot but no other thread arrives, it tries + * another, heading toward the zero slot, which always exists even + * if the table shrinks. The particular mechanics controlling this + * are as follows: + * + * Waiting: Slot zero is special in that it is the only slot that + * exists when there is no contention. A thread occupying slot + * zero will block if no thread fulfills it after a short spin. + * In other cases, occupying threads eventually give up and try + * another slot. Waiting threads spin for a while (a period that + * should be a little less than a typical context-switch time) + * before either blocking (if slot zero) or giving up (if other + * slots) and restarting. There is no reason for threads to block + * unless there are unlikely to be any other threads present. + * Occupants are mainly avoiding memory contention so sit there + * quietly polling for a shorter period than it would take to + * block and then unblock them. Non-slot-zero waits that elapse + * because of lack of other threads waste around one extra + * context-switch time per try, which is still on average much + * faster than alternative approaches. + * + * Sizing: Usually, using only a few slots suffices to reduce + * contention. Especially with small numbers of threads, using + * too many slots can lead to just as poor performance as using + * too few of them, and there's not much room for error. The + * variable "max" maintains the number of slots actually in + * use. It is increased when a thread sees too many CAS + * failures. (This is analogous to resizing a regular hash table + * based on a target load factor, except here, growth steps are + * just one-by-one rather than proportional.) Growth requires + * contention failures in each of three tried slots. Requiring + * multiple failures for expansion copes with the fact that some + * failed CASes are not due to contention but instead to simple + * races between two threads or thread pre-emptions occurring + * between reading and CASing. Also, very transient peak + * contention can be much higher than the average sustainable + * levels. The max limit is decreased on average 50% of the times + * that a non-slot-zero wait elapses without being fulfilled. + * Threads experiencing elapsed waits move closer to zero, so + * eventually find existing (or future) threads even if the table + * has been shrunk due to inactivity. The chosen mechanics and + * thresholds for growing and shrinking are intrinsically + * entangled with indexing and hashing inside the exchange code, + * and can't be nicely abstracted out. + * + * Hashing: Each thread picks its initial slot to use in accord + * with a simple hashcode. The sequence is the same on each + * encounter by any given thread, but effectively random across + * threads. Using arenas encounters the classic cost vs quality + * tradeoffs of all hash tables. Here, we use a one-step FNV-1a + * hash code based on the current thread's Thread.getId(), along + * with a cheap approximation to a mod operation to select an + * index. The downside of optimizing index selection in this way + * is that the code is hardwired to use a maximum table size of + * 32. But this value more than suffices for known platforms and + * applications. + * + * Probing: On sensed contention of a selected slot, we probe + * sequentially through the table, analogously to linear probing + * after collision in a hash table. (We move circularly, in + * reverse order, to mesh best with table growth and shrinkage + * rules.) Except that to minimize the effects of false-alarms + * and cache thrashing, we try the first selected slot twice + * before moving. + * + * Padding: Even with contention management, slots are heavily + * contended, so use cache-padding to avoid poor memory + * performance. Because of this, slots are lazily constructed + * only when used, to avoid wasting this space unnecessarily. + * While isolation of locations is not much of an issue at first + * in an application, as time goes on and garbage-collectors + * perform compaction, slots are very likely to be moved adjacent + * to each other, which can cause much thrashing of cache lines on + * MPs unless padding is employed. + * + * This is an improvement of the algorithm described in the paper + * "A Scalable Elimination-based Exchange Channel" by William + * Scherer, Doug Lea, and Michael Scott in Proceedings of SCOOL05 + * workshop. Available at: http://hdl.handle.net/1802/2104 + */ + + /** The number of CPUs, for sizing and spin control */ + private static final int NCPU = Runtime.getRuntime().availableProcessors(); + + /** + * The capacity of the arena. Set to a value that provides more + * than enough space to handle contention. On small machines + * most slots won't be used, but it is still not wasted because + * the extra space provides some machine-level address padding + * to minimize interference with heavily CAS'ed Slot locations. + * And on very large machines, performance eventually becomes + * bounded by memory bandwidth, not numbers of threads/CPUs. + * This constant cannot be changed without also modifying + * indexing and hashing algorithms. + */ + private static final int CAPACITY = 32; + + /** + * The value of "max" that will hold all threads without + * contention. When this value is less than CAPACITY, some + * otherwise wasted expansion can be avoided. + */ + private static final int FULL = + Math.max(0, Math.min(CAPACITY, NCPU / 2) - 1); + + /** + * The number of times to spin (doing nothing except polling a + * memory location) before blocking or giving up while waiting to + * be fulfilled. Should be zero on uniprocessors. On + * multiprocessors, this value should be large enough so that two + * threads exchanging items as fast as possible block only when + * one of them is stalled (due to GC or preemption), but not much + * longer, to avoid wasting CPU resources. Seen differently, this + * value is a little over half the number of cycles of an average + * context switch time on most systems. The value here is + * approximately the average of those across a range of tested + * systems. + */ + private static final int SPINS = (NCPU == 1) ? 0 : 2000; + + /** + * The number of times to spin before blocking in timed waits. + * Timed waits spin more slowly because checking the time takes + * time. The best value relies mainly on the relative rate of + * System.nanoTime vs memory accesses. The value is empirically + * derived to work well across a variety of systems. + */ + private static final int TIMED_SPINS = SPINS / 20; + + /** + * Sentinel item representing cancellation of a wait due to + * interruption, timeout, or elapsed spin-waits. This value is + * placed in holes on cancellation, and used as a return value + * from waiting methods to indicate failure to set or get hole. + */ + private static final Object CANCEL = new Object(); + + /** + * Value representing null arguments/returns from public + * methods. This disambiguates from internal requirement that + * holes start out as null to mean they are not yet set. + */ + private static final Object NULL_ITEM = new Object(); + + /** + * Nodes hold partially exchanged data. This class + * opportunistically subclasses AtomicReference to represent the + * hole. So get() returns hole, and compareAndSet CAS'es value + * into hole. This class cannot be parameterized as "V" because + * of the use of non-V CANCEL sentinels. + */ + private static final class Node extends AtomicReference<Object> { + /** The element offered by the Thread creating this node. */ + public final Object item; + + /** The Thread waiting to be signalled; null until waiting. */ + public volatile Thread waiter; + + /** + * Creates node with given item and empty hole. + * @param item the item + */ + public Node(Object item) { + this.item = item; + } + } + + /** + * A Slot is an AtomicReference with heuristic padding to lessen + * cache effects of this heavily CAS'ed location. While the + * padding adds noticeable space, all slots are created only on + * demand, and there will be more than one of them only when it + * would improve throughput more than enough to outweigh using + * extra space. + */ + private static final class Slot extends AtomicReference<Object> { + // Improve likelihood of isolation on <= 64 byte cache lines + long q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, qa, qb, qc, qd, qe; + } + + /** + * Slot array. Elements are lazily initialized when needed. + * Declared volatile to enable double-checked lazy construction. + */ + private volatile Slot[] arena = new Slot[CAPACITY]; + + /** + * The maximum slot index being used. The value sometimes + * increases when a thread experiences too many CAS contentions, + * and sometimes decreases when a spin-wait elapses. Changes + * are performed only via compareAndSet, to avoid stale values + * when a thread happens to stall right before setting. + */ + private final AtomicInteger max = new AtomicInteger(); + + /** + * Main exchange function, handling the different policy variants. + * Uses Object, not "V" as argument and return value to simplify + * handling of sentinel values. Callers from public methods decode + * and cast accordingly. + * + * @param item the (non-null) item to exchange + * @param timed true if the wait is timed + * @param nanos if timed, the maximum wait time + * @return the other thread's item, or CANCEL if interrupted or timed out + */ + private Object doExchange(Object item, boolean timed, long nanos) { + Node me = new Node(item); // Create in case occupying + int index = hashIndex(); // Index of current slot + int fails = 0; // Number of CAS failures + + for (;;) { + Object y; // Contents of current slot + Slot slot = arena[index]; + if (slot == null) // Lazily initialize slots + createSlot(index); // Continue loop to reread + else if ((y = slot.get()) != null && // Try to fulfill + slot.compareAndSet(y, null)) { + Node you = (Node)y; // Transfer item + if (you.compareAndSet(null, item)) { + LockSupport.unpark(you.waiter); + return you.item; + } // Else cancelled; continue + } + else if (y == null && // Try to occupy + slot.compareAndSet(null, me)) { + if (index == 0) // Blocking wait for slot 0 + return timed? awaitNanos(me, slot, nanos): await(me, slot); + Object v = spinWait(me, slot); // Spin wait for non-0 + if (v != CANCEL) + return v; + me = new Node(item); // Throw away cancelled node + int m = max.get(); + if (m > (index >>>= 1)) // Decrease index + max.compareAndSet(m, m - 1); // Maybe shrink table + } + else if (++fails > 1) { // Allow 2 fails on 1st slot + int m = max.get(); + if (fails > 3 && m < FULL && max.compareAndSet(m, m + 1)) + index = m + 1; // Grow on 3rd failed slot + else if (--index < 0) + index = m; // Circularly traverse + } + } + } + + /** + * Returns a hash index for the current thread. Uses a one-step + * FNV-1a hash code (http://www.isthe.com/chongo/tech/comp/fnv/) + * based on the current thread's Thread.getId(). These hash codes + * have more uniform distribution properties with respect to small + * moduli (here 1-31) than do other simple hashing functions. + * + * <p>To return an index between 0 and max, we use a cheap + * approximation to a mod operation, that also corrects for bias + * due to non-power-of-2 remaindering (see {@link + * java.util.Random#nextInt}). Bits of the hashcode are masked + * with "nbits", the ceiling power of two of table size (looked up + * in a table packed into three ints). If too large, this is + * retried after rotating the hash by nbits bits, while forcing new + * top bit to 0, which guarantees eventual termination (although + * with a non-random-bias). This requires an average of less than + * 2 tries for all table sizes, and has a maximum 2% difference + * from perfectly uniform slot probabilities when applied to all + * possible hash codes for sizes less than 32. + * + * @return a per-thread-random index, 0 <= index < max + */ + private final int hashIndex() { + long id = Thread.currentThread().getId(); + int hash = (((int)(id ^ (id >>> 32))) ^ 0x811c9dc5) * 0x01000193; + + int m = max.get(); + int nbits = (((0xfffffc00 >> m) & 4) | // Compute ceil(log2(m+1)) + ((0x000001f8 >>> m) & 2) | // The constants hold + ((0xffff00f2 >>> m) & 1)); // a lookup table + int index; + while ((index = hash & ((1 << nbits) - 1)) > m) // May retry on + hash = (hash >>> nbits) | (hash << (33 - nbits)); // non-power-2 m + return index; + } + + /** + * Creates a new slot at given index. Called only when the slot + * appears to be null. Relies on double-check using builtin + * locks, since they rarely contend. This in turn relies on the + * arena array being declared volatile. + * + * @param index the index to add slot at + */ + private void createSlot(int index) { + // Create slot outside of lock to narrow sync region + Slot newSlot = new Slot(); + Slot[] a = arena; + synchronized (a) { + if (a[index] == null) + a[index] = newSlot; + } + } + + /** + * Tries to cancel a wait for the given node waiting in the given + * slot, if so, helping clear the node from its slot to avoid + * garbage retention. + * + * @param node the waiting node + * @param the slot it is waiting in + * @return true if successfully cancelled + */ + private static boolean tryCancel(Node node, Slot slot) { + if (!node.compareAndSet(null, CANCEL)) + return false; + if (slot.get() == node) // pre-check to minimize contention + slot.compareAndSet(node, null); + return true; + } + + // Three forms of waiting. Each just different enough not to merge + // code with others. + + /** + * Spin-waits for hole for a non-0 slot. Fails if spin elapses + * before hole filled. Does not check interrupt, relying on check + * in public exchange method to abort if interrupted on entry. + * + * @param node the waiting node + * @return on success, the hole; on failure, CANCEL + */ + private static Object spinWait(Node node, Slot slot) { + int spins = SPINS; + for (;;) { + Object v = node.get(); + if (v != null) + return v; + else if (spins > 0) + --spins; + else + tryCancel(node, slot); + } + } + + /** + * Waits for (by spinning and/or blocking) and gets the hole + * filled in by another thread. Fails if interrupted before + * hole filled. + * + * When a node/thread is about to block, it sets its waiter field + * and then rechecks state at least one more time before actually + * parking, thus covering race vs fulfiller noticing that waiter + * is non-null so should be woken. + * + * Thread interruption status is checked only surrounding calls to + * park. The caller is assumed to have checked interrupt status + * on entry. + * + * @param node the waiting node + * @return on success, the hole; on failure, CANCEL + */ + private static Object await(Node node, Slot slot) { + Thread w = Thread.currentThread(); + int spins = SPINS; + for (;;) { + Object v = node.get(); + if (v != null) + return v; + else if (spins > 0) // Spin-wait phase + --spins; + else if (node.waiter == null) // Set up to block next + node.waiter = w; + else if (w.isInterrupted()) // Abort on interrupt + tryCancel(node, slot); + else // Block + LockSupport.park(node); + } + } + + /** + * Waits for (at index 0) and gets the hole filled in by another + * thread. Fails if timed out or interrupted before hole filled. + * Same basic logic as untimed version, but a bit messier. + * + * @param node the waiting node + * @param nanos the wait time + * @return on success, the hole; on failure, CANCEL + */ + private Object awaitNanos(Node node, Slot slot, long nanos) { + int spins = TIMED_SPINS; + long lastTime = 0; + Thread w = null; + for (;;) { + Object v = node.get(); + if (v != null) + return v; + long now = System.nanoTime(); + if (w == null) + w = Thread.currentThread(); + else + nanos -= now - lastTime; + lastTime = now; + if (nanos > 0) { + if (spins > 0) + --spins; + else if (node.waiter == null) + node.waiter = w; + else if (w.isInterrupted()) + tryCancel(node, slot); + else + LockSupport.parkNanos(node, nanos); + } + else if (tryCancel(node, slot) && !w.isInterrupted()) + return scanOnTimeout(node); + } + } + + /** + * Sweeps through arena checking for any waiting threads. Called + * only upon return from timeout while waiting in slot 0. When a + * thread gives up on a timed wait, it is possible that a + * previously-entered thread is still waiting in some other + * slot. So we scan to check for any. This is almost always + * overkill, but decreases the likelihood of timeouts when there + * are other threads present to far less than that in lock-based + * exchangers in which earlier-arriving threads may still be + * waiting on entry locks. + * + * @param node the waiting node + * @return another thread's item, or CANCEL + */ + private Object scanOnTimeout(Node node) { + Object y; + for (int j = arena.length - 1; j >= 0; --j) { + Slot slot = arena[j]; + if (slot != null) { + while ((y = slot.get()) != null) { + if (slot.compareAndSet(y, null)) { + Node you = (Node)y; + if (you.compareAndSet(null, node.item)) { + LockSupport.unpark(you.waiter); + return you.item; + } + } + } + } + } + return CANCEL; + } + + /** + * Creates a new Exchanger. + */ + public Exchanger() { + } + + /** + * Waits for another thread to arrive at this exchange point (unless + * the current thread is {@linkplain Thread#interrupt interrupted}), + * and then transfers the given object to it, receiving its object + * in return. + * + * <p>If another thread is already waiting at the exchange point then + * it is resumed for thread scheduling purposes and receives the object + * passed in by the current thread. The current thread returns immediately, + * receiving the object passed to the exchange by that other thread. + * + * <p>If no other thread is already waiting at the exchange then the + * current thread is disabled for thread scheduling purposes and lies + * dormant until one of two things happens: + * <ul> + * <li>Some other thread enters the exchange; or + * <li>Some other thread {@linkplain Thread#interrupt interrupts} the current + * thread. + * </ul> + * <p>If the current thread: + * <ul> + * <li>has its interrupted status set on entry to this method; or + * <li>is {@linkplain Thread#interrupt interrupted} while waiting + * for the exchange, + * </ul> + * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * + * @param x the object to exchange + * @return the object provided by the other thread + * @throws InterruptedException if the current thread was + * interrupted while waiting + */ + public V exchange(V x) throws InterruptedException { + if (!Thread.interrupted()) { + Object v = doExchange(x == null? NULL_ITEM : x, false, 0); + if (v == NULL_ITEM) + return null; + if (v != CANCEL) + return (V)v; + Thread.interrupted(); // Clear interrupt status on IE throw + } + throw new InterruptedException(); + } + + /** + * Waits for another thread to arrive at this exchange point (unless + * the current thread is {@linkplain Thread#interrupt interrupted} or + * the specified waiting time elapses), and then transfers the given + * object to it, receiving its object in return. + * + * <p>If another thread is already waiting at the exchange point then + * it is resumed for thread scheduling purposes and receives the object + * passed in by the current thread. The current thread returns immediately, + * receiving the object passed to the exchange by that other thread. + * + * <p>If no other thread is already waiting at the exchange then the + * current thread is disabled for thread scheduling purposes and lies + * dormant until one of three things happens: + * <ul> + * <li>Some other thread enters the exchange; or + * <li>Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread; or + * <li>The specified waiting time elapses. + * </ul> + * <p>If the current thread: + * <ul> + * <li>has its interrupted status set on entry to this method; or + * <li>is {@linkplain Thread#interrupt interrupted} while waiting + * for the exchange, + * </ul> + * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * + * <p>If the specified waiting time elapses then {@link + * TimeoutException} is thrown. If the time is less than or equal + * to zero, the method will not wait at all. + * + * @param x the object to exchange + * @param timeout the maximum time to wait + * @param unit the time unit of the <tt>timeout</tt> argument + * @return the object provided by the other thread + * @throws InterruptedException if the current thread was + * interrupted while waiting + * @throws TimeoutException if the specified waiting time elapses + * before another thread enters the exchange + */ + public V exchange(V x, long timeout, TimeUnit unit) + throws InterruptedException, TimeoutException { + if (!Thread.interrupted()) { + Object v = doExchange(x == null? NULL_ITEM : x, + true, unit.toNanos(timeout)); + if (v == NULL_ITEM) + return null; + if (v != CANCEL) + return (V)v; + if (!Thread.interrupted()) + throw new TimeoutException(); + } + throw new InterruptedException(); + } +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/ExecutionException.java b/libjava/classpath/external/jsr166/java/util/concurrent/ExecutionException.java new file mode 100644 index 000000000..bc561e58e --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/ExecutionException.java @@ -0,0 +1,65 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; + +/** + * Exception thrown when attempting to retrieve the result of a task + * that aborted by throwing an exception. This exception can be + * inspected using the {@link #getCause()} method. + * + * @see Future + * @since 1.5 + * @author Doug Lea + */ +public class ExecutionException extends Exception { + private static final long serialVersionUID = 7830266012832686185L; + + /** + * Constructs an <tt>ExecutionException</tt> with no detail message. + * The cause is not initialized, and may subsequently be + * initialized by a call to {@link #initCause(Throwable) initCause}. + */ + protected ExecutionException() { } + + /** + * Constructs an <tt>ExecutionException</tt> with the specified detail + * message. The cause is not initialized, and may subsequently be + * initialized by a call to {@link #initCause(Throwable) initCause}. + * + * @param message the detail message + */ + protected ExecutionException(String message) { + super(message); + } + + /** + * Constructs an <tt>ExecutionException</tt> with the specified detail + * message and cause. + * + * @param message the detail message + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method) + */ + public ExecutionException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructs an <tt>ExecutionException</tt> with the specified cause. + * The detail message is set to: + * <pre> + * (cause == null ? null : cause.toString())</pre> + * (which typically contains the class and detail message of + * <tt>cause</tt>). + * + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method) + */ + public ExecutionException(Throwable cause) { + super(cause); + } +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/Executor.java b/libjava/classpath/external/jsr166/java/util/concurrent/Executor.java new file mode 100644 index 000000000..a61e92152 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/Executor.java @@ -0,0 +1,112 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; + +/** + * An object that executes submitted {@link Runnable} tasks. This + * interface provides a way of decoupling task submission from the + * mechanics of how each task will be run, including details of thread + * use, scheduling, etc. An <tt>Executor</tt> is normally used + * instead of explicitly creating threads. For example, rather than + * invoking <tt>new Thread(new(RunnableTask())).start()</tt> for each + * of a set of tasks, you might use: + * + * <pre> + * Executor executor = <em>anExecutor</em>; + * executor.execute(new RunnableTask1()); + * executor.execute(new RunnableTask2()); + * ... + * </pre> + * + * However, the <tt>Executor</tt> 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> + * 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. + * + * <pre> + * class ThreadPerTaskExecutor implements Executor { + * public void execute(Runnable r) { + * new Thread(r).start(); + * } + * }</pre> + * + * Many <tt>Executor</tt> implementations impose some sort of + * limitation on how and when tasks are scheduled. The executor below + * serializes the submission of tasks to a second executor, + * illustrating a composite executor. + * + * <pre> + * class SerialExecutor implements Executor { + * final Queue<Runnable> tasks = new ArrayDeque<Runnable>(); + * final Executor executor; + * Runnable active; + * + * SerialExecutor(Executor executor) { + * this.executor = executor; + * } + * + * public synchronized void execute(final Runnable r) { + * tasks.offer(new Runnable() { + * public void run() { + * try { + * r.run(); + * } finally { + * scheduleNext(); + * } + * } + * }); + * if (active == null) { + * scheduleNext(); + * } + * } + * + * protected synchronized void scheduleNext() { + * if ((active = tasks.poll()) != null) { + * executor.execute(active); + * } + * } + * }</pre> + * + * The <tt>Executor</tt> implementations provided in this package + * implement {@link ExecutorService}, which is a more extensive + * interface. The {@link ThreadPoolExecutor} class provides an + * extensible thread pool implementation. The {@link Executors} class + * provides convenient factory methods for these Executors. + * + * <p>Memory consistency effects: Actions in a thread prior to + * submitting a {@code Runnable} object to an {@code Executor} + * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a> + * its execution begins, perhaps in another thread. + * + * @since 1.5 + * @author Doug Lea + */ +public interface Executor { + + /** + * Executes the given command at some time in the future. The command + * may execute in a new thread, in a pooled thread, or in the calling + * thread, at the discretion of the <tt>Executor</tt> implementation. + * + * @param command the runnable task + * @throws RejectedExecutionException if this task cannot be + * accepted for execution. + * @throws NullPointerException if command is null + */ + void execute(Runnable command); +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/ExecutorCompletionService.java b/libjava/classpath/external/jsr166/java/util/concurrent/ExecutorCompletionService.java new file mode 100644 index 000000000..9b7a0e027 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/ExecutorCompletionService.java @@ -0,0 +1,174 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; + +/** + * A {@link CompletionService} that uses a supplied {@link Executor} + * to execute tasks. This class arranges that submitted tasks are, + * upon completion, placed on a queue accessible using <tt>take</tt>. + * The class is lightweight enough to be suitable for transient use + * when processing groups of tasks. + * + * <p> + * + * <b>Usage Examples.</b> + * + * Suppose you have a set of solvers for a certain problem, each + * returning a value of some type <tt>Result</tt>, and would like to + * run them concurrently, processing the results of each of them that + * return a non-null value, in some method <tt>use(Result r)</tt>. You + * could write this as: + * + * <pre> + * 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); + * } + * } + * </pre> + * + * Suppose instead that you would like to use the first non-null result + * of the set of tasks, ignoring any that encounter exceptions, + * and cancelling all other tasks when the first one is ready: + * + * <pre> + * 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) {} + * } + * } + * finally { + * for (Future<Result> f : futures) + * f.cancel(true); + * } + * + * if (result != null) + * use(result); + * } + * </pre> + */ +public class ExecutorCompletionService<V> implements CompletionService<V> { + private final Executor executor; + private final AbstractExecutorService aes; + private final BlockingQueue<Future<V>> completionQueue; + + /** + * FutureTask extension to enqueue upon completion + */ + private class QueueingFuture extends FutureTask<Void> { + QueueingFuture(RunnableFuture<V> task) { + super(task, null); + this.task = task; + } + protected void done() { completionQueue.add(task); } + private final Future<V> task; + } + + private RunnableFuture<V> newTaskFor(Callable<V> task) { + if (aes == null) + return new FutureTask<V>(task); + else + return aes.newTaskFor(task); + } + + private RunnableFuture<V> newTaskFor(Runnable task, V result) { + if (aes == null) + return new FutureTask<V>(task, result); + else + return aes.newTaskFor(task, result); + } + + /** + * Creates an ExecutorCompletionService using the supplied + * executor for base task execution and a + * {@link LinkedBlockingQueue} as a completion queue. + * + * @param executor the executor to use + * @throws NullPointerException if executor is <tt>null</tt> + */ + public ExecutorCompletionService(Executor executor) { + if (executor == null) + throw new NullPointerException(); + this.executor = executor; + this.aes = (executor instanceof AbstractExecutorService) ? + (AbstractExecutorService) executor : null; + this.completionQueue = new LinkedBlockingQueue<Future<V>>(); + } + + /** + * Creates an ExecutorCompletionService using the supplied + * executor for base task execution and the supplied queue as its + * completion queue. + * + * @param executor the executor to use + * @param completionQueue the queue to use as the completion queue + * normally one dedicated for use by this service + * @throws NullPointerException if executor or completionQueue are <tt>null</tt> + */ + public ExecutorCompletionService(Executor executor, + BlockingQueue<Future<V>> completionQueue) { + if (executor == null || completionQueue == null) + throw new NullPointerException(); + this.executor = executor; + this.aes = (executor instanceof AbstractExecutorService) ? + (AbstractExecutorService) executor : null; + this.completionQueue = completionQueue; + } + + public Future<V> submit(Callable<V> task) { + if (task == null) throw new NullPointerException(); + RunnableFuture<V> f = newTaskFor(task); + executor.execute(new QueueingFuture(f)); + 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)); + return f; + } + + public Future<V> take() throws InterruptedException { + return completionQueue.take(); + } + + public Future<V> poll() { + return completionQueue.poll(); + } + + public Future<V> poll(long timeout, TimeUnit unit) throws InterruptedException { + return completionQueue.poll(timeout, unit); + } + +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/ExecutorService.java b/libjava/classpath/external/jsr166/java/util/concurrent/ExecutorService.java new file mode 100644 index 000000000..777319265 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/ExecutorService.java @@ -0,0 +1,306 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.List; +import java.util.Collection; +import java.security.PrivilegedAction; +import java.security.PrivilegedExceptionAction; + +/** + * An {@link Executor} that provides methods to manage termination and + * methods that can produce a {@link Future} for tracking progress of + * one or more asynchronous tasks. + * + * <p> + * An <tt>ExecutorService</tt> can be shut down, which will cause it + * to stop accepting new tasks. After being shut down, the executor + * will eventually terminate, at which point no tasks are actively + * executing, no tasks are awaiting execution, and no new tasks can be + * submitted. An unused <tt>ExecutorService</tt> should be shut down + * to allow reclamation of its resources. + * + * <p> Method <tt>submit</tt> extends base method {@link + * Executor#execute} by creating and returning a {@link Future} that + * can be used to cancel execution and/or wait for completion. + * Methods <tt>invokeAny</tt> and <tt>invokeAll</tt> perform the most + * commonly useful forms of bulk execution, executing a collection of + * tasks and then waiting for at least one, or all, to + * complete. (Class {@link ExecutorCompletionService} can be used to + * write customized variants of these methods.) + * + * <p>The {@link Executors} class provides factory methods for the + * executor services provided in this package. + * + * <h3>Usage Example</h3> + * + * Here is a sketch of a network service in which threads in a thread + * pool service incoming requests. It uses the preconfigured {@link + * Executors#newFixedThreadPool} factory method: + * + * <pre> + * class NetworkService { + * private final ServerSocket serverSocket; + * private final ExecutorService pool; + * + * public NetworkService(int port, int poolSize) + * throws IOException { + * serverSocket = new ServerSocket(port); + * pool = Executors.newFixedThreadPool(poolSize); + * } + * + * public void serve() { + * try { + * for (;;) { + * pool.execute(new Handler(serverSocket.accept())); + * } + * } catch (IOException ex) { + * pool.shutdown(); + * } + * } + * } + * + * class Handler implements Runnable { + * private final Socket socket; + * Handler(Socket socket) { this.socket = socket; } + * public void run() { + * // read and service request + * } + * } + * </pre> + * + * <p>Memory consistency effects: Actions in a thread prior to the + * submission of a {@code Runnable} or {@code Callable} task to an + * {@code ExecutorService} + * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a> + * any actions taken by that task, which in turn <i>happen-before</i> the + * result is retrieved via {@code Future.get()}. + * + * @since 1.5 + * @author Doug Lea + */ +public interface ExecutorService extends Executor { + + /** + * Initiates an orderly shutdown in which previously submitted + * tasks are executed, but no new tasks will be accepted. + * Invocation has no additional effect if already shut down. + * + * @throws SecurityException if a security manager exists and + * shutting down this ExecutorService may manipulate + * threads that the caller is not permitted to modify + * because it does not hold {@link + * java.lang.RuntimePermission}<tt>("modifyThread")</tt>, + * or the security manager's <tt>checkAccess</tt> method + * denies access. + */ + void shutdown(); + + /** + * Attempts to stop all actively executing tasks, halts the + * processing of waiting tasks, and returns a list of the tasks that were + * awaiting execution. + * + * <p>There are no guarantees beyond best-effort attempts to stop + * processing actively executing tasks. For example, typical + * implementations will cancel via {@link Thread#interrupt}, so any + * task that fails to respond to interrupts may never terminate. + * + * @return list of tasks that never commenced execution + * @throws SecurityException if a security manager exists and + * shutting down this ExecutorService may manipulate + * threads that the caller is not permitted to modify + * because it does not hold {@link + * java.lang.RuntimePermission}<tt>("modifyThread")</tt>, + * or the security manager's <tt>checkAccess</tt> method + * denies access. + */ + List<Runnable> shutdownNow(); + + /** + * Returns <tt>true</tt> if this executor has been shut down. + * + * @return <tt>true</tt> if this executor has been shut down + */ + boolean isShutdown(); + + /** + * Returns <tt>true</tt> if all tasks have completed following shut down. + * Note that <tt>isTerminated</tt> is never <tt>true</tt> unless + * either <tt>shutdown</tt> or <tt>shutdownNow</tt> was called first. + * + * @return <tt>true</tt> if all tasks have completed following shut down + */ + boolean isTerminated(); + + /** + * Blocks until all tasks have completed execution after a shutdown + * request, or the timeout occurs, or the current thread is + * interrupted, whichever happens first. + * + * @param timeout the maximum time to wait + * @param unit the time unit of the timeout argument + * @return <tt>true</tt> if this executor terminated and + * <tt>false</tt> if the timeout elapsed before termination + * @throws InterruptedException if interrupted while waiting + */ + boolean awaitTermination(long timeout, TimeUnit unit) + throws InterruptedException; + + + /** + * Submits a value-returning task for execution and returns a + * Future representing the pending results of the task. The + * Future's <tt>get</tt> method will return the task's result upon + * successful completion. + * + * <p> + * If you would like to immediately block waiting + * for a task, you can use constructions of the form + * <tt>result = exec.submit(aCallable).get();</tt> + * + * <p> Note: The {@link Executors} class includes a set of methods + * that can convert some other common closure-like objects, + * for example, {@link java.security.PrivilegedAction} to + * {@link Callable} form so they can be submitted. + * + * @param task the task to submit + * @return a Future representing pending completion of the task + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + * @throws NullPointerException if the task is null + */ + <T> Future<T> submit(Callable<T> task); + + /** + * Submits a Runnable task for execution and returns a Future + * representing that task. The Future's <tt>get</tt> method will + * return the given result upon successful completion. + * + * @param task the task to submit + * @param result the result to return + * @return a Future representing pending completion of the task + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + * @throws NullPointerException if the task is null + */ + <T> Future<T> submit(Runnable task, T result); + + /** + * Submits a Runnable task for execution and returns a Future + * representing that task. The Future's <tt>get</tt> method will + * return <tt>null</tt> upon <em>successful</em> completion. + * + * @param task the task to submit + * @return a Future representing pending completion of the task + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + * @throws NullPointerException if the task is null + */ + Future<?> submit(Runnable task); + + /** + * Executes the given tasks, returning a list of Futures holding + * their status and results when all complete. + * {@link Future#isDone} is <tt>true</tt> for each + * element of the returned list. + * Note that a <em>completed</em> task could have + * terminated either normally or by throwing an exception. + * The results of this method are undefined if the given + * collection is modified while this operation is in progress. + * + * @param tasks the collection of tasks + * @return A list of Futures representing the tasks, in the same + * sequential order as produced by the iterator for the + * given task list, each of which has completed. + * @throws InterruptedException if interrupted while waiting, in + * which case unfinished tasks are cancelled. + * @throws NullPointerException if tasks or any of its elements are <tt>null</tt> + * @throws RejectedExecutionException if any task cannot be + * scheduled for execution + */ + + <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) + throws InterruptedException; + + /** + * Executes the given tasks, returning a list of Futures holding + * their status and results + * when all complete or the timeout expires, whichever happens first. + * {@link Future#isDone} is <tt>true</tt> for each + * element of the returned list. + * Upon return, tasks that have not completed are cancelled. + * Note that a <em>completed</em> task could have + * terminated either normally or by throwing an exception. + * The results of this method are undefined if the given + * collection is modified while this operation is in progress. + * + * @param tasks the collection of tasks + * @param timeout the maximum time to wait + * @param unit the time unit of the timeout argument + * @return a list of Futures representing the tasks, in the same + * sequential order as produced by the iterator for the + * given task list. If the operation did not time out, + * each task will have completed. If it did time out, some + * of these tasks will not have completed. + * @throws InterruptedException if interrupted while waiting, in + * which case unfinished tasks are cancelled + * @throws NullPointerException if tasks, any of its elements, or + * unit are <tt>null</tt> + * @throws RejectedExecutionException if any task cannot be scheduled + * for execution + */ + <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, + long timeout, TimeUnit unit) + throws InterruptedException; + + /** + * Executes the given tasks, returning the result + * of one that has completed successfully (i.e., without throwing + * an exception), if any do. Upon normal or exceptional return, + * tasks that have not completed are cancelled. + * The results of this method are undefined if the given + * collection is modified while this operation is in progress. + * + * @param tasks the collection of tasks + * @return the result returned by one of the tasks + * @throws InterruptedException if interrupted while waiting + * @throws NullPointerException if tasks or any of its elements + * are <tt>null</tt> + * @throws IllegalArgumentException if tasks is empty + * @throws ExecutionException if no task successfully completes + * @throws RejectedExecutionException if tasks cannot be scheduled + * for execution + */ + <T> T invokeAny(Collection<? extends Callable<T>> tasks) + throws InterruptedException, ExecutionException; + + /** + * Executes the given tasks, returning the result + * of one that has completed successfully (i.e., without throwing + * an exception), if any do before the given timeout elapses. + * Upon normal or exceptional return, tasks that have not + * completed are cancelled. + * The results of this method are undefined if the given + * collection is modified while this operation is in progress. + * + * @param tasks the collection of tasks + * @param timeout the maximum time to wait + * @param unit the time unit of the timeout argument + * @return the result returned by one of the tasks. + * @throws InterruptedException if interrupted while waiting + * @throws NullPointerException if tasks, any of its elements, or + * unit are <tt>null</tt> + * @throws TimeoutException if the given timeout elapses before + * any task successfully completes + * @throws ExecutionException if no task successfully completes + * @throws RejectedExecutionException if tasks cannot be scheduled + * for execution + */ + <T> T invokeAny(Collection<? extends Callable<T>> tasks, + long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException; +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/Executors.java b/libjava/classpath/external/jsr166/java/util/concurrent/Executors.java new file mode 100644 index 000000000..18e6b33cc --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/Executors.java @@ -0,0 +1,666 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedExceptionAction; +import java.security.AccessControlException; + +/** + * Factory and utility methods for {@link Executor}, {@link + * ExecutorService}, {@link ScheduledExecutorService}, {@link + * ThreadFactory}, and {@link Callable} classes defined in this + * 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 <tt>Callable</tt>. + * </ul> + * + * @since 1.5 + * @author Doug Lea + */ +public class Executors { + + /** + * Creates a thread pool that reuses a fixed number of threads + * operating off a shared unbounded queue. At any point, at most + * <tt>nThreads</tt> threads will be active processing tasks. + * If additional tasks are submitted when all threads are active, + * they will wait in the queue until a thread is available. + * If any thread terminates due to a failure during execution + * prior to shutdown, a new one will take its place if needed to + * execute subsequent tasks. The threads in the pool will exist + * until it is explicitly {@link ExecutorService#shutdown shutdown}. + * + * @param nThreads the number of threads in the pool + * @return the newly created thread pool + * @throws IllegalArgumentException if <tt>nThreads <= 0</tt> + */ + public static ExecutorService newFixedThreadPool(int nThreads) { + return new ThreadPoolExecutor(nThreads, nThreads, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<Runnable>()); + } + + /** + * Creates a thread pool that reuses a fixed number of threads + * operating off a shared unbounded queue, using the provided + * ThreadFactory to create new threads when needed. At any point, + * at most <tt>nThreads</tt> threads will be active processing + * tasks. If additional tasks are submitted when all threads are + * active, they will wait in the queue until a thread is + * available. If any thread terminates due to a failure during + * execution prior to shutdown, a new one will take its place if + * needed to execute subsequent tasks. The threads in the pool will + * exist until it is explicitly {@link ExecutorService#shutdown + * shutdown}. + * + * @param nThreads the number of threads in the pool + * @param threadFactory the factory to use when creating new threads + * @return the newly created thread pool + * @throws NullPointerException if threadFactory is null + * @throws IllegalArgumentException if <tt>nThreads <= 0</tt> + */ + public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) { + return new ThreadPoolExecutor(nThreads, nThreads, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<Runnable>(), + threadFactory); + } + + /** + * Creates an Executor that uses a single worker thread operating + * off an unbounded queue. (Note however that if this single + * thread terminates due to a failure during execution prior to + * shutdown, a new one will take its place if needed to execute + * subsequent tasks.) Tasks are guaranteed to execute + * sequentially, and no more than one task will be active at any + * given time. Unlike the otherwise equivalent + * <tt>newFixedThreadPool(1)</tt> the returned executor is + * guaranteed not to be reconfigurable to use additional threads. + * + * @return the newly created single-threaded Executor + */ + public static ExecutorService newSingleThreadExecutor() { + return new FinalizableDelegatedExecutorService + (new ThreadPoolExecutor(1, 1, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<Runnable>())); + } + + /** + * Creates an Executor that uses a single worker thread operating + * off an unbounded queue, and uses the provided ThreadFactory to + * create a new thread when needed. Unlike the otherwise + * equivalent <tt>newFixedThreadPool(1, threadFactory)</tt> the + * returned executor is guaranteed not to be reconfigurable to use + * additional threads. + * + * @param threadFactory the factory to use when creating new + * threads + * + * @return the newly created single-threaded Executor + * @throws NullPointerException if threadFactory is null + */ + public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) { + return new FinalizableDelegatedExecutorService + (new ThreadPoolExecutor(1, 1, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<Runnable>(), + threadFactory)); + } + + /** + * Creates a thread pool that creates new threads as needed, but + * will reuse previously constructed threads when they are + * available. These pools will typically improve the performance + * of programs that execute many short-lived asynchronous tasks. + * Calls to <tt>execute</tt> will reuse previously constructed + * threads if available. If no existing thread is available, a new + * thread will be created and added to the pool. Threads that have + * not been used for sixty seconds are terminated and removed from + * the cache. Thus, a pool that remains idle for long enough will + * not consume any resources. Note that pools with similar + * properties but different details (for example, timeout parameters) + * may be created using {@link ThreadPoolExecutor} constructors. + * + * @return the newly created thread pool + */ + public static ExecutorService newCachedThreadPool() { + return new ThreadPoolExecutor(0, Integer.MAX_VALUE, + 60L, TimeUnit.SECONDS, + new SynchronousQueue<Runnable>()); + } + + /** + * Creates a thread pool that creates new threads as needed, but + * will reuse previously constructed threads when they are + * available, and uses the provided + * ThreadFactory to create new threads when needed. + * @param threadFactory the factory to use when creating new threads + * @return the newly created thread pool + * @throws NullPointerException if threadFactory is null + */ + public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) { + return new ThreadPoolExecutor(0, Integer.MAX_VALUE, + 60L, TimeUnit.SECONDS, + new SynchronousQueue<Runnable>(), + threadFactory); + } + + /** + * Creates a single-threaded executor that can schedule commands + * to run after a given delay, or to execute periodically. + * (Note however that if this single + * thread terminates due to a failure during execution prior to + * shutdown, a new one will take its place if needed to execute + * subsequent tasks.) Tasks are guaranteed to execute + * sequentially, and no more than one task will be active at any + * given time. Unlike the otherwise equivalent + * <tt>newScheduledThreadPool(1)</tt> the returned executor is + * guaranteed not to be reconfigurable to use additional threads. + * @return the newly created scheduled executor + */ + public static ScheduledExecutorService newSingleThreadScheduledExecutor() { + return new DelegatedScheduledExecutorService + (new ScheduledThreadPoolExecutor(1)); + } + + /** + * Creates a single-threaded executor that can schedule commands + * to run after a given delay, or to execute periodically. (Note + * however that if this single thread terminates due to a failure + * during execution prior to shutdown, a new one will take its + * place if needed to execute subsequent tasks.) Tasks are + * guaranteed to execute sequentially, and no more than one task + * will be active at any given time. Unlike the otherwise + * equivalent <tt>newScheduledThreadPool(1, threadFactory)</tt> + * the returned executor is guaranteed not to be reconfigurable to + * use additional threads. + * @param threadFactory the factory to use when creating new + * threads + * @return a newly created scheduled executor + * @throws NullPointerException if threadFactory is null + */ + public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) { + return new DelegatedScheduledExecutorService + (new ScheduledThreadPoolExecutor(1, threadFactory)); + } + + /** + * Creates a thread pool that can schedule commands to run after a + * given delay, or to execute periodically. + * @param corePoolSize the number of threads to keep in the pool, + * even if they are idle. + * @return a newly created scheduled thread pool + * @throws IllegalArgumentException if <tt>corePoolSize < 0</tt> + */ + public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { + return new ScheduledThreadPoolExecutor(corePoolSize); + } + + /** + * Creates a thread pool that can schedule commands to run after a + * given delay, or to execute periodically. + * @param corePoolSize the number of threads to keep in the pool, + * even if they are idle. + * @param threadFactory the factory to use when the executor + * creates a new thread. + * @return a newly created scheduled thread pool + * @throws IllegalArgumentException if <tt>corePoolSize < 0</tt> + * @throws NullPointerException if threadFactory is null + */ + public static ScheduledExecutorService newScheduledThreadPool( + int corePoolSize, ThreadFactory threadFactory) { + return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory); + } + + + /** + * Returns an object that delegates all defined {@link + * ExecutorService} methods to the given executor, but not any + * other methods that might otherwise be accessible using + * casts. This provides a way to safely "freeze" configuration and + * disallow tuning of a given concrete implementation. + * @param executor the underlying implementation + * @return an <tt>ExecutorService</tt> instance + * @throws NullPointerException if executor null + */ + public static ExecutorService unconfigurableExecutorService(ExecutorService executor) { + if (executor == null) + throw new NullPointerException(); + return new DelegatedExecutorService(executor); + } + + /** + * Returns an object that delegates all defined {@link + * ScheduledExecutorService} methods to the given executor, but + * not any other methods that might otherwise be accessible using + * casts. This provides a way to safely "freeze" configuration and + * disallow tuning of a given concrete implementation. + * @param executor the underlying implementation + * @return a <tt>ScheduledExecutorService</tt> instance + * @throws NullPointerException if executor null + */ + public static ScheduledExecutorService unconfigurableScheduledExecutorService(ScheduledExecutorService executor) { + if (executor == null) + throw new NullPointerException(); + return new DelegatedScheduledExecutorService(executor); + } + + /** + * Returns a default thread factory used to create new threads. + * This factory creates all new threads used by an Executor in the + * same {@link ThreadGroup}. If there is a {@link + * java.lang.SecurityManager}, it uses the group of {@link + * System#getSecurityManager}, else the group of the thread + * invoking this <tt>defaultThreadFactory</tt> method. Each new + * thread is created as a non-daemon thread with priority set to + * the smaller of <tt>Thread.NORM_PRIORITY</tt> and the maximum + * priority permitted in the thread group. New threads have names + * accessible via {@link Thread#getName} of + * <em>pool-N-thread-M</em>, where <em>N</em> is the sequence + * number of this factory, and <em>M</em> is the sequence number + * of the thread created by this factory. + * @return a thread factory + */ + public static ThreadFactory defaultThreadFactory() { + return new DefaultThreadFactory(); + } + + /** + * Returns a thread factory used to create new threads that + * have the same permissions as the current thread. + * This factory creates threads with the same settings as {@link + * Executors#defaultThreadFactory}, additionally setting the + * AccessControlContext and contextClassLoader of new threads to + * be the same as the thread invoking this + * <tt>privilegedThreadFactory</tt> method. A new + * <tt>privilegedThreadFactory</tt> can be created within an + * {@link AccessController#doPrivileged} action setting the + * current thread's access control context to create threads with + * the selected permission settings holding within that action. + * + * <p> Note that while tasks running within such threads will have + * the same access control and class loader settings as the + * current thread, they need not have the same {@link + * java.lang.ThreadLocal} or {@link + * java.lang.InheritableThreadLocal} values. If necessary, + * particular values of thread locals can be set or reset before + * any task runs in {@link ThreadPoolExecutor} subclasses using + * {@link ThreadPoolExecutor#beforeExecute}. Also, if it is + * necessary to initialize worker threads to have the same + * InheritableThreadLocal settings as some other designated + * thread, you can create a custom ThreadFactory in which that + * thread waits for and services requests to create others that + * will inherit its values. + * + * @return a thread factory + * @throws AccessControlException if the current access control + * context does not have permission to both get and set context + * class loader. + */ + public static ThreadFactory privilegedThreadFactory() { + return new PrivilegedThreadFactory(); + } + + /** + * Returns a {@link Callable} object that, when + * called, runs the given task and returns the given result. This + * can be useful when applying methods requiring a + * <tt>Callable</tt> to an otherwise resultless action. + * @param task the task to run + * @param result the result to return + * @return a callable object + * @throws NullPointerException if task null + */ + public static <T> Callable<T> callable(Runnable task, T result) { + if (task == null) + throw new NullPointerException(); + return new RunnableAdapter<T>(task, result); + } + + /** + * Returns a {@link Callable} object that, when + * called, runs the given task and returns <tt>null</tt>. + * @param task the task to run + * @return a callable object + * @throws NullPointerException if task null + */ + public static Callable<Object> callable(Runnable task) { + if (task == null) + throw new NullPointerException(); + return new RunnableAdapter<Object>(task, null); + } + + /** + * Returns a {@link Callable} object that, when + * called, runs the given privileged action and returns its result. + * @param action the privileged action to run + * @return a callable object + * @throws NullPointerException if action null + */ + public static Callable<Object> callable(final PrivilegedAction<?> action) { + if (action == null) + throw new NullPointerException(); + return new Callable<Object>() { + public Object call() { return action.run(); }}; + } + + /** + * Returns a {@link Callable} object that, when + * called, runs the given privileged exception action and returns + * its result. + * @param action the privileged exception action to run + * @return a callable object + * @throws NullPointerException if action null + */ + public static Callable<Object> callable(final PrivilegedExceptionAction<?> action) { + if (action == null) + throw new NullPointerException(); + return new Callable<Object>() { + public Object call() throws Exception { return action.run(); }}; + } + + /** + * Returns a {@link Callable} object that will, when + * called, execute the given <tt>callable</tt> under the current + * access control context. This method should normally be + * invoked within an {@link AccessController#doPrivileged} action + * to create callables that will, if possible, execute under the + * selected permission settings holding within that action; or if + * not possible, throw an associated {@link + * AccessControlException}. + * @param callable the underlying task + * @return a callable object + * @throws NullPointerException if callable null + * + */ + public static <T> Callable<T> privilegedCallable(Callable<T> callable) { + if (callable == null) + throw new NullPointerException(); + return new PrivilegedCallable<T>(callable); + } + + /** + * Returns a {@link Callable} object that will, when + * called, execute the given <tt>callable</tt> under the current + * access control context, with the current context class loader + * as the context class loader. This method should normally be + * invoked within an {@link AccessController#doPrivileged} action + * to create callables that will, if possible, execute under the + * selected permission settings holding within that action; or if + * not possible, throw an associated {@link + * AccessControlException}. + * @param callable the underlying task + * + * @return a callable object + * @throws NullPointerException if callable null + * @throws AccessControlException if the current access control + * context does not have permission to both set and get context + * class loader. + */ + public static <T> Callable<T> privilegedCallableUsingCurrentClassLoader(Callable<T> callable) { + if (callable == null) + throw new NullPointerException(); + return new PrivilegedCallableUsingCurrentClassLoader<T>(callable); + } + + // Non-public classes supporting the public methods + + /** + * A callable that runs given task and returns given result + */ + static final class RunnableAdapter<T> implements Callable<T> { + final Runnable task; + final T result; + RunnableAdapter(Runnable task, T result) { + this.task = task; + this.result = result; + } + public T call() { + task.run(); + return result; + } + } + + /** + * A callable that runs under established access control settings + */ + static final class PrivilegedCallable<T> implements Callable<T> { + private final AccessControlContext acc; + private final Callable<T> task; + private T result; + private Exception exception; + PrivilegedCallable(Callable<T> task) { + this.task = task; + this.acc = AccessController.getContext(); + } + + public T call() throws Exception { + AccessController.doPrivileged(new PrivilegedAction<T>() { + public T run() { + try { + result = task.call(); + } catch (Exception ex) { + exception = ex; + } + return null; + } + }, acc); + if (exception != null) + throw exception; + else + return result; + } + } + + /** + * A callable that runs under established access control settings and + * current ClassLoader + */ + static final class PrivilegedCallableUsingCurrentClassLoader<T> implements Callable<T> { + private final ClassLoader ccl; + private final AccessControlContext acc; + private final Callable<T> task; + private T result; + private Exception exception; + PrivilegedCallableUsingCurrentClassLoader(Callable<T> task) { + this.task = task; + this.ccl = Thread.currentThread().getContextClassLoader(); + this.acc = AccessController.getContext(); + acc.checkPermission(new RuntimePermission("getContextClassLoader")); + acc.checkPermission(new RuntimePermission("setContextClassLoader")); + } + + public T call() throws Exception { + AccessController.doPrivileged(new PrivilegedAction<T>() { + public T run() { + ClassLoader savedcl = null; + Thread t = Thread.currentThread(); + try { + ClassLoader cl = t.getContextClassLoader(); + if (ccl != cl) { + t.setContextClassLoader(ccl); + savedcl = cl; + } + result = task.call(); + } catch (Exception ex) { + exception = ex; + } finally { + if (savedcl != null) + t.setContextClassLoader(savedcl); + } + return null; + } + }, acc); + if (exception != null) + throw exception; + else + return result; + } + } + + /** + * The default thread factory + */ + static class DefaultThreadFactory implements ThreadFactory { + static final AtomicInteger poolNumber = new AtomicInteger(1); + final ThreadGroup group; + final AtomicInteger threadNumber = new AtomicInteger(1); + final String namePrefix; + + DefaultThreadFactory() { + SecurityManager s = System.getSecurityManager(); + group = (s != null)? s.getThreadGroup() : + Thread.currentThread().getThreadGroup(); + namePrefix = "pool-" + + poolNumber.getAndIncrement() + + "-thread-"; + } + + public Thread newThread(Runnable r) { + Thread t = new Thread(group, r, + namePrefix + threadNumber.getAndIncrement(), + 0); + if (t.isDaemon()) + t.setDaemon(false); + if (t.getPriority() != Thread.NORM_PRIORITY) + t.setPriority(Thread.NORM_PRIORITY); + return t; + } + } + + /** + * Thread factory capturing access control and class loader + */ + static class PrivilegedThreadFactory extends DefaultThreadFactory { + private final ClassLoader ccl; + private final AccessControlContext acc; + + PrivilegedThreadFactory() { + super(); + this.ccl = Thread.currentThread().getContextClassLoader(); + this.acc = AccessController.getContext(); + acc.checkPermission(new RuntimePermission("setContextClassLoader")); + } + + public Thread newThread(final Runnable r) { + return super.newThread(new Runnable() { + public void run() { + AccessController.doPrivileged(new PrivilegedAction<Object>() { + public Object run() { + Thread.currentThread().setContextClassLoader(ccl); + r.run(); + return null; + } + }, acc); + } + }); + } + + } + + /** + * A wrapper class that exposes only the ExecutorService methods + * of an ExecutorService implementation. + */ + static class DelegatedExecutorService extends AbstractExecutorService { + private final ExecutorService e; + DelegatedExecutorService(ExecutorService executor) { e = executor; } + public void execute(Runnable command) { e.execute(command); } + public void shutdown() { e.shutdown(); } + public List<Runnable> shutdownNow() { return e.shutdownNow(); } + public boolean isShutdown() { return e.isShutdown(); } + public boolean isTerminated() { return e.isTerminated(); } + public boolean awaitTermination(long timeout, TimeUnit unit) + throws InterruptedException { + return e.awaitTermination(timeout, unit); + } + public Future<?> submit(Runnable task) { + return e.submit(task); + } + public <T> Future<T> submit(Callable<T> task) { + return e.submit(task); + } + public <T> Future<T> submit(Runnable task, T result) { + return e.submit(task, result); + } + public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) + throws InterruptedException { + return e.invokeAll(tasks); + } + public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, + long timeout, TimeUnit unit) + throws InterruptedException { + return e.invokeAll(tasks, timeout, unit); + } + public <T> T invokeAny(Collection<? extends Callable<T>> tasks) + throws InterruptedException, ExecutionException { + return e.invokeAny(tasks); + } + public <T> T invokeAny(Collection<? extends Callable<T>> tasks, + long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { + return e.invokeAny(tasks, timeout, unit); + } + } + + static class FinalizableDelegatedExecutorService + extends DelegatedExecutorService { + FinalizableDelegatedExecutorService(ExecutorService executor) { + super(executor); + } + protected void finalize() { + super.shutdown(); + } + } + + /** + * A wrapper class that exposes only the ScheduledExecutorService + * methods of a ScheduledExecutorService implementation. + */ + static class DelegatedScheduledExecutorService + extends DelegatedExecutorService + implements ScheduledExecutorService { + private final ScheduledExecutorService e; + DelegatedScheduledExecutorService(ScheduledExecutorService executor) { + super(executor); + e = executor; + } + public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) { + return e.schedule(command, delay, unit); + } + public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) { + return e.schedule(callable, delay, unit); + } + public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) { + return e.scheduleAtFixedRate(command, initialDelay, period, unit); + } + public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) { + return e.scheduleWithFixedDelay(command, initialDelay, delay, unit); + } + } + + + /** Cannot instantiate. */ + private Executors() {} +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/Future.java b/libjava/classpath/external/jsr166/java/util/concurrent/Future.java new file mode 100644 index 000000000..0459ee453 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/Future.java @@ -0,0 +1,142 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; + +/** + * A <tt>Future</tt> represents the result of an asynchronous + * computation. Methods are provided to check if the computation is + * complete, to wait for its completion, and to retrieve the result of + * the computation. The result can only be retrieved using method + * <tt>get</tt> when the computation has completed, blocking if + * necessary until it is ready. Cancellation is performed by the + * <tt>cancel</tt> method. Additional methods are provided to + * determine if the task completed normally or was cancelled. Once a + * computation has completed, the computation cannot be cancelled. + * If you would like to use a <tt>Future</tt> for the sake + * of cancellability but not provide a usable result, you can + * declare types of the form <tt>Future<?></tt> and + * return <tt>null</tt> as a result of the underlying task. + * + * <p> + * <b>Sample Usage</b> (Note that the following classes are all + * made-up.) <p> + * <pre> + * interface ArchiveSearcher { String search(String target); } + * class App { + * ExecutorService executor = ... + * ArchiveSearcher searcher = ... + * void showSearch(final String target) + * throws InterruptedException { + * Future<String> future + * = executor.submit(new Callable<String>() { + * public String call() { + * return searcher.search(target); + * }}); + * displayOtherThings(); // do other things while searching + * try { + * displayText(future.get()); // use future + * } catch (ExecutionException ex) { cleanup(); return; } + * } + * } + * </pre> + * + * The {@link FutureTask} class is an implementation of <tt>Future</tt> that + * implements <tt>Runnable</tt>, and so may be executed by an <tt>Executor</tt>. + * For example, the above construction with <tt>submit</tt> could be replaced by: + * <pre> + * FutureTask<String> future = + * new FutureTask<String>(new Callable<String>() { + * public String call() { + * return searcher.search(target); + * }}); + * executor.execute(future); + * </pre> + * + * <p>Memory consistency effects: Actions taken by the asynchronous computation + * <a href="package-summary.html#MemoryVisibility"> <i>happen-before</i></a> + * actions following the corresponding {@code Future.get()} in another thread. + * + * @see FutureTask + * @see Executor + * @since 1.5 + * @author Doug Lea + * @param <V> The result type returned by this Future's <tt>get</tt> method + */ +public interface Future<V> { + + /** + * Attempts to cancel execution of this task. This attempt will + * fail if the task has already completed, has already been cancelled, + * or could not be cancelled for some other reason. If successful, + * and this task has not started when <tt>cancel</tt> is called, + * this task should never run. If the task has already started, + * then the <tt>mayInterruptIfRunning</tt> parameter determines + * whether the thread executing this task should be interrupted in + * an attempt to stop the task. + * + * <p>After this method returns, subsequent calls to {@link #isDone} will + * always return <tt>true</tt>. Subsequent calls to {@link #isCancelled} + * will always return <tt>true</tt> if this method returned <tt>true</tt>. + * + * @param mayInterruptIfRunning <tt>true</tt> if the thread executing this + * task should be interrupted; otherwise, in-progress tasks are allowed + * to complete + * @return <tt>false</tt> if the task could not be cancelled, + * typically because it has already completed normally; + * <tt>true</tt> otherwise + */ + boolean cancel(boolean mayInterruptIfRunning); + + /** + * Returns <tt>true</tt> if this task was cancelled before it completed + * normally. + * + * @return <tt>true</tt> if this task was cancelled before it completed + */ + boolean isCancelled(); + + /** + * Returns <tt>true</tt> if this task completed. + * + * Completion may be due to normal termination, an exception, or + * cancellation -- in all of these cases, this method will return + * <tt>true</tt>. + * + * @return <tt>true</tt> if this task completed + */ + boolean isDone(); + + /** + * Waits if necessary for the computation to complete, and then + * retrieves its result. + * + * @return the computed result + * @throws CancellationException if the computation was cancelled + * @throws ExecutionException if the computation threw an + * exception + * @throws InterruptedException if the current thread was interrupted + * while waiting + */ + V get() throws InterruptedException, ExecutionException; + + /** + * Waits if necessary for at most the given time for the computation + * to complete, and then retrieves its result, if available. + * + * @param timeout the maximum time to wait + * @param unit the time unit of the timeout argument + * @return the computed result + * @throws CancellationException if the computation was cancelled + * @throws ExecutionException if the computation threw an + * exception + * @throws InterruptedException if the current thread was interrupted + * while waiting + * @throws TimeoutException if the wait timed out + */ + V get(long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException; +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/FutureTask.java b/libjava/classpath/external/jsr166/java/util/concurrent/FutureTask.java new file mode 100644 index 000000000..94742405d --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/FutureTask.java @@ -0,0 +1,325 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.concurrent.locks.*; + +/** + * A cancellable asynchronous computation. This class provides a base + * implementation of {@link Future}, with methods to start and cancel + * a computation, query to see if the computation is complete, and + * retrieve the result of the computation. The result can only be + * retrieved when the computation has completed; the <tt>get</tt> + * method will block if the computation has not yet completed. Once + * the computation has completed, the computation cannot be restarted + * or cancelled. + * + * <p>A <tt>FutureTask</tt> can be used to wrap a {@link Callable} or + * {@link java.lang.Runnable} object. Because <tt>FutureTask</tt> + * implements <tt>Runnable</tt>, a <tt>FutureTask</tt> can be + * submitted to an {@link Executor} for execution. + * + * <p>In addition to serving as a standalone class, this class provides + * <tt>protected</tt> functionality that may be useful when creating + * customized task classes. + * + * @since 1.5 + * @author Doug Lea + * @param <V> The result type returned by this FutureTask's <tt>get</tt> method + */ +public class FutureTask<V> implements RunnableFuture<V> { + /** Synchronization control for FutureTask */ + private final Sync sync; + + /** + * Creates a <tt>FutureTask</tt> that will upon running, execute the + * given <tt>Callable</tt>. + * + * @param callable the callable task + * @throws NullPointerException if callable is null + */ + public FutureTask(Callable<V> callable) { + if (callable == null) + throw new NullPointerException(); + sync = new Sync(callable); + } + + /** + * Creates a <tt>FutureTask</tt> that will upon running, execute the + * given <tt>Runnable</tt>, and arrange that <tt>get</tt> will return the + * given result on successful completion. + * + * @param runnable the runnable task + * @param result the result to return on successful completion. If + * you don't need a particular result, consider using + * constructions of the form: + * <tt>Future<?> f = new FutureTask<Object>(runnable, null)</tt> + * @throws NullPointerException if runnable is null + */ + public FutureTask(Runnable runnable, V result) { + sync = new Sync(Executors.callable(runnable, result)); + } + + public boolean isCancelled() { + return sync.innerIsCancelled(); + } + + public boolean isDone() { + return sync.innerIsDone(); + } + + public boolean cancel(boolean mayInterruptIfRunning) { + return sync.innerCancel(mayInterruptIfRunning); + } + + /** + * @throws CancellationException {@inheritDoc} + */ + public V get() throws InterruptedException, ExecutionException { + return sync.innerGet(); + } + + /** + * @throws CancellationException {@inheritDoc} + */ + public V get(long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { + return sync.innerGet(unit.toNanos(timeout)); + } + + /** + * Protected method invoked when this task transitions to state + * <tt>isDone</tt> (whether normally or via cancellation). The + * default implementation does nothing. Subclasses may override + * this method to invoke completion callbacks or perform + * bookkeeping. Note that you can query status inside the + * implementation of this method to determine whether this task + * has been cancelled. + */ + protected void done() { } + + /** + * Sets the result of this Future to the given value unless + * this future has already been set or has been cancelled. + * This method is invoked internally by the <tt>run</tt> method + * upon successful completion of the computation. + * @param v the value + */ + protected void set(V v) { + sync.innerSet(v); + } + + /** + * Causes this future to report an <tt>ExecutionException</tt> + * with the given throwable as its cause, unless this Future has + * already been set or has been cancelled. + * This method is invoked internally by the <tt>run</tt> method + * upon failure of the computation. + * @param t the cause of failure + */ + protected void setException(Throwable t) { + sync.innerSetException(t); + } + + // The following (duplicated) doc comment can be removed once + // + // 6270645: Javadoc comments should be inherited from most derived + // superinterface or superclass + // is fixed. + /** + * Sets this Future to the result of its computation + * unless it has been cancelled. + */ + public void run() { + sync.innerRun(); + } + + /** + * Executes the computation without setting its result, and then + * resets this Future to initial state, failing to do so if the + * computation encounters an exception or is cancelled. This is + * designed for use with tasks that intrinsically execute more + * than once. + * @return true if successfully run and reset + */ + protected boolean runAndReset() { + return sync.innerRunAndReset(); + } + + /** + * Synchronization control for FutureTask. Note that this must be + * a non-static inner class in order to invoke the protected + * <tt>done</tt> method. For clarity, all inner class support + * methods are same as outer, prefixed with "inner". + * + * Uses AQS sync state to represent run status + */ + private final class Sync extends AbstractQueuedSynchronizer { + private static final long serialVersionUID = -7828117401763700385L; + + /** State value representing that task is running */ + private static final int RUNNING = 1; + /** State value representing that task ran */ + private static final int RAN = 2; + /** State value representing that task was cancelled */ + private static final int CANCELLED = 4; + + /** The underlying callable */ + private final Callable<V> callable; + /** The result to return from get() */ + private V result; + /** The exception to throw from get() */ + private Throwable exception; + + /** + * The thread running task. When nulled after set/cancel, this + * indicates that the results are accessible. Must be + * volatile, to ensure visibility upon completion. + */ + private volatile Thread runner; + + Sync(Callable<V> callable) { + this.callable = callable; + } + + private boolean ranOrCancelled(int state) { + return (state & (RAN | CANCELLED)) != 0; + } + + /** + * Implements AQS base acquire to succeed if ran or cancelled + */ + protected int tryAcquireShared(int ignore) { + return innerIsDone()? 1 : -1; + } + + /** + * Implements AQS base release to always signal after setting + * final done status by nulling runner thread. + */ + protected boolean tryReleaseShared(int ignore) { + runner = null; + return true; + } + + boolean innerIsCancelled() { + return getState() == CANCELLED; + } + + boolean innerIsDone() { + return ranOrCancelled(getState()) && runner == null; + } + + V innerGet() throws InterruptedException, ExecutionException { + acquireSharedInterruptibly(0); + if (getState() == CANCELLED) + throw new CancellationException(); + if (exception != null) + throw new ExecutionException(exception); + return result; + } + + V innerGet(long nanosTimeout) throws InterruptedException, ExecutionException, TimeoutException { + if (!tryAcquireSharedNanos(0, nanosTimeout)) + throw new TimeoutException(); + if (getState() == CANCELLED) + throw new CancellationException(); + if (exception != null) + throw new ExecutionException(exception); + return result; + } + + void innerSet(V v) { + for (;;) { + int s = getState(); + if (s == RAN) + return; + if (s == CANCELLED) { + // aggressively release to set runner to null, + // in case we are racing with a cancel request + // that will try to interrupt runner + releaseShared(0); + return; + } + if (compareAndSetState(s, RAN)) { + result = v; + releaseShared(0); + done(); + return; + } + } + } + + void innerSetException(Throwable t) { + for (;;) { + int s = getState(); + if (s == RAN) + return; + if (s == CANCELLED) { + // aggressively release to set runner to null, + // in case we are racing with a cancel request + // that will try to interrupt runner + releaseShared(0); + return; + } + if (compareAndSetState(s, RAN)) { + exception = t; + result = null; + releaseShared(0); + done(); + return; + } + } + } + + boolean innerCancel(boolean mayInterruptIfRunning) { + for (;;) { + int s = getState(); + if (ranOrCancelled(s)) + return false; + if (compareAndSetState(s, CANCELLED)) + break; + } + if (mayInterruptIfRunning) { + Thread r = runner; + if (r != null) + r.interrupt(); + } + releaseShared(0); + done(); + return true; + } + + void innerRun() { + if (!compareAndSetState(0, RUNNING)) + return; + try { + runner = Thread.currentThread(); + if (getState() == RUNNING) // recheck after setting thread + innerSet(callable.call()); + else + releaseShared(0); // cancel + } catch (Throwable ex) { + innerSetException(ex); + } + } + + boolean innerRunAndReset() { + if (!compareAndSetState(0, RUNNING)) + return false; + try { + runner = Thread.currentThread(); + if (getState() == RUNNING) + callable.call(); // don't set result + runner = null; + return compareAndSetState(RUNNING, 0); + } catch (Throwable ex) { + innerSetException(ex); + return false; + } + } + } +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/LinkedBlockingDeque.java b/libjava/classpath/external/jsr166/java/util/concurrent/LinkedBlockingDeque.java new file mode 100644 index 000000000..2dc8fa877 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/LinkedBlockingDeque.java @@ -0,0 +1,1021 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.*; +import java.util.concurrent.locks.*; + +/** + * An optionally-bounded {@linkplain BlockingDeque blocking deque} based on + * linked nodes. + * + * <p> The optional capacity bound constructor argument serves as a + * way to prevent excessive expansion. The capacity, if unspecified, + * is equal to {@link Integer#MAX_VALUE}. Linked nodes are + * dynamically created upon each insertion unless this would bring the + * deque above capacity. + * + * <p>Most operations run in constant time (ignoring time spent + * blocking). 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>This class and its iterator implement all of the + * <em>optional</em> methods of the {@link Collection} and {@link + * Iterator} interfaces. + * + * <p>This class is a member of the + * <a href="{@docRoot}/../technotes/guides/collections/index.html"> + * Java Collections Framework</a>. + * + * @since 1.6 + * @author Doug Lea + * @param <E> the type of elements held in this collection + */ +public class LinkedBlockingDeque<E> + extends AbstractQueue<E> + implements BlockingDeque<E>, java.io.Serializable { + + /* + * Implemented as a simple doubly-linked list protected by a + * single lock and using conditions to manage blocking. + */ + + /* + * We have "diamond" multiple interface/abstract class inheritance + * here, and that introduces ambiguities. Often we want the + * BlockingDeque javadoc combined with the AbstractQueue + * implementation, so a lot of method specs are duplicated here. + */ + + private static final long serialVersionUID = -387911632671998426L; + + /** Doubly-linked list node class */ + static final class Node<E> { + E item; + Node<E> prev; + Node<E> next; + Node(E x, Node<E> p, Node<E> n) { + item = x; + prev = p; + next = n; + } + } + + /** Pointer to first node */ + private transient Node<E> first; + /** Pointer to last node */ + private transient Node<E> last; + /** Number of items in the deque */ + private transient int count; + /** Maximum number of items in the deque */ + private final int capacity; + /** Main lock guarding all access */ + private final ReentrantLock lock = new ReentrantLock(); + /** Condition for waiting takes */ + private final Condition notEmpty = lock.newCondition(); + /** Condition for waiting puts */ + private final Condition notFull = lock.newCondition(); + + /** + * Creates a <tt>LinkedBlockingDeque</tt> with a capacity of + * {@link Integer#MAX_VALUE}. + */ + public LinkedBlockingDeque() { + this(Integer.MAX_VALUE); + } + + /** + * Creates a <tt>LinkedBlockingDeque</tt> with the given (fixed) capacity. + * + * @param capacity the capacity of this deque + * @throws IllegalArgumentException if <tt>capacity</tt> is less than 1 + */ + public LinkedBlockingDeque(int capacity) { + if (capacity <= 0) throw new IllegalArgumentException(); + this.capacity = capacity; + } + + /** + * Creates a <tt>LinkedBlockingDeque</tt> with a capacity of + * {@link Integer#MAX_VALUE}, initially containing the elements of + * the given collection, added in traversal order of the + * collection's iterator. + * + * @param c the collection of elements to initially contain + * @throws NullPointerException if the specified collection or any + * of its elements are null + */ + public LinkedBlockingDeque(Collection<? extends E> c) { + this(Integer.MAX_VALUE); + for (E e : c) + add(e); + } + + + // Basic linking and unlinking operations, called only while holding lock + + /** + * Links e as first element, or returns false if full. + */ + private boolean linkFirst(E e) { + if (count >= capacity) + return false; + ++count; + Node<E> f = first; + Node<E> x = new Node<E>(e, null, f); + first = x; + if (last == null) + last = x; + else + f.prev = x; + notEmpty.signal(); + return true; + } + + /** + * Links e as last element, or returns false if full. + */ + private boolean linkLast(E e) { + if (count >= capacity) + return false; + ++count; + Node<E> l = last; + Node<E> x = new Node<E>(e, l, null); + last = x; + if (first == null) + first = x; + else + l.next = x; + notEmpty.signal(); + return true; + } + + /** + * Removes and returns first element, or null if empty. + */ + private E unlinkFirst() { + Node<E> f = first; + if (f == null) + return null; + Node<E> n = f.next; + first = n; + if (n == null) + last = null; + else + n.prev = null; + --count; + notFull.signal(); + return f.item; + } + + /** + * Removes and returns last element, or null if empty. + */ + private E unlinkLast() { + Node<E> l = last; + if (l == null) + return null; + Node<E> p = l.prev; + last = p; + if (p == null) + first = null; + else + p.next = null; + --count; + notFull.signal(); + return l.item; + } + + /** + * Unlink e + */ + private void unlink(Node<E> x) { + Node<E> p = x.prev; + Node<E> n = x.next; + if (p == null) { + if (n == null) + first = last = null; + else { + n.prev = null; + first = n; + } + } else if (n == null) { + p.next = null; + last = p; + } else { + p.next = n; + n.prev = p; + } + --count; + notFull.signalAll(); + } + + // BlockingDeque methods + + /** + * @throws IllegalStateException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public void addFirst(E e) { + if (!offerFirst(e)) + throw new IllegalStateException("Deque full"); + } + + /** + * @throws IllegalStateException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public void addLast(E e) { + if (!offerLast(e)) + throw new IllegalStateException("Deque full"); + } + + /** + * @throws NullPointerException {@inheritDoc} + */ + public boolean offerFirst(E e) { + if (e == null) throw new NullPointerException(); + lock.lock(); + try { + return linkFirst(e); + } finally { + lock.unlock(); + } + } + + /** + * @throws NullPointerException {@inheritDoc} + */ + public boolean offerLast(E e) { + if (e == null) throw new NullPointerException(); + lock.lock(); + try { + return linkLast(e); + } finally { + lock.unlock(); + } + } + + /** + * @throws NullPointerException {@inheritDoc} + * @throws InterruptedException {@inheritDoc} + */ + public void putFirst(E e) throws InterruptedException { + if (e == null) throw new NullPointerException(); + lock.lock(); + try { + while (!linkFirst(e)) + notFull.await(); + } finally { + lock.unlock(); + } + } + + /** + * @throws NullPointerException {@inheritDoc} + * @throws InterruptedException {@inheritDoc} + */ + public void putLast(E e) throws InterruptedException { + if (e == null) throw new NullPointerException(); + lock.lock(); + try { + while (!linkLast(e)) + notFull.await(); + } finally { + lock.unlock(); + } + } + + /** + * @throws NullPointerException {@inheritDoc} + * @throws InterruptedException {@inheritDoc} + */ + public boolean offerFirst(E e, long timeout, TimeUnit unit) + throws InterruptedException { + if (e == null) throw new NullPointerException(); + long nanos = unit.toNanos(timeout); + lock.lockInterruptibly(); + try { + for (;;) { + if (linkFirst(e)) + return true; + if (nanos <= 0) + return false; + nanos = notFull.awaitNanos(nanos); + } + } finally { + lock.unlock(); + } + } + + /** + * @throws NullPointerException {@inheritDoc} + * @throws InterruptedException {@inheritDoc} + */ + public boolean offerLast(E e, long timeout, TimeUnit unit) + throws InterruptedException { + if (e == null) throw new NullPointerException(); + long nanos = unit.toNanos(timeout); + lock.lockInterruptibly(); + try { + for (;;) { + if (linkLast(e)) + return true; + if (nanos <= 0) + return false; + nanos = notFull.awaitNanos(nanos); + } + } finally { + lock.unlock(); + } + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E removeFirst() { + E x = pollFirst(); + if (x == null) throw new NoSuchElementException(); + return x; + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E removeLast() { + E x = pollLast(); + if (x == null) throw new NoSuchElementException(); + return x; + } + + public E pollFirst() { + lock.lock(); + try { + return unlinkFirst(); + } finally { + lock.unlock(); + } + } + + public E pollLast() { + lock.lock(); + try { + return unlinkLast(); + } finally { + lock.unlock(); + } + } + + public E takeFirst() throws InterruptedException { + lock.lock(); + try { + E x; + while ( (x = unlinkFirst()) == null) + notEmpty.await(); + return x; + } finally { + lock.unlock(); + } + } + + public E takeLast() throws InterruptedException { + lock.lock(); + try { + E x; + while ( (x = unlinkLast()) == null) + notEmpty.await(); + return x; + } finally { + lock.unlock(); + } + } + + public E pollFirst(long timeout, TimeUnit unit) + throws InterruptedException { + long nanos = unit.toNanos(timeout); + lock.lockInterruptibly(); + try { + for (;;) { + E x = unlinkFirst(); + if (x != null) + return x; + if (nanos <= 0) + return null; + nanos = notEmpty.awaitNanos(nanos); + } + } finally { + lock.unlock(); + } + } + + public E pollLast(long timeout, TimeUnit unit) + throws InterruptedException { + long nanos = unit.toNanos(timeout); + lock.lockInterruptibly(); + try { + for (;;) { + E x = unlinkLast(); + if (x != null) + return x; + if (nanos <= 0) + return null; + nanos = notEmpty.awaitNanos(nanos); + } + } finally { + lock.unlock(); + } + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E getFirst() { + E x = peekFirst(); + if (x == null) throw new NoSuchElementException(); + return x; + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E getLast() { + E x = peekLast(); + if (x == null) throw new NoSuchElementException(); + return x; + } + + public E peekFirst() { + lock.lock(); + try { + return (first == null) ? null : first.item; + } finally { + lock.unlock(); + } + } + + public E peekLast() { + lock.lock(); + try { + return (last == null) ? null : last.item; + } finally { + lock.unlock(); + } + } + + public boolean removeFirstOccurrence(Object o) { + if (o == null) return false; + lock.lock(); + try { + for (Node<E> p = first; p != null; p = p.next) { + if (o.equals(p.item)) { + unlink(p); + return true; + } + } + return false; + } finally { + lock.unlock(); + } + } + + public boolean removeLastOccurrence(Object o) { + if (o == null) return false; + lock.lock(); + try { + for (Node<E> p = last; p != null; p = p.prev) { + if (o.equals(p.item)) { + unlink(p); + return true; + } + } + return false; + } finally { + lock.unlock(); + } + } + + // BlockingQueue methods + + /** + * Inserts the specified element at the end of this deque unless it would + * violate capacity restrictions. When using a capacity-restricted deque, + * it is generally preferable to use method {@link #offer(Object) offer}. + * + * <p>This method is equivalent to {@link #addLast}. + * + * @throws IllegalStateException if the element cannot be added at this + * time due to capacity restrictions + * @throws NullPointerException if the specified element is null + */ + public boolean add(E e) { + addLast(e); + return true; + } + + /** + * @throws NullPointerException if the specified element is null + */ + public boolean offer(E e) { + return offerLast(e); + } + + /** + * @throws NullPointerException {@inheritDoc} + * @throws InterruptedException {@inheritDoc} + */ + public void put(E e) throws InterruptedException { + putLast(e); + } + + /** + * @throws NullPointerException {@inheritDoc} + * @throws InterruptedException {@inheritDoc} + */ + public boolean offer(E e, long timeout, TimeUnit unit) + throws InterruptedException { + return offerLast(e, timeout, unit); + } + + /** + * Retrieves and removes the head of the queue represented by this deque. + * This method differs from {@link #poll poll} only in that it throws an + * exception if this deque is empty. + * + * <p>This method is equivalent to {@link #removeFirst() removeFirst}. + * + * @return the head of the queue represented by this deque + * @throws NoSuchElementException if this deque is empty + */ + public E remove() { + return removeFirst(); + } + + public E poll() { + return pollFirst(); + } + + public E take() throws InterruptedException { + return takeFirst(); + } + + public E poll(long timeout, TimeUnit unit) throws InterruptedException { + return pollFirst(timeout, unit); + } + + /** + * Retrieves, but does not remove, the head of the queue represented by + * this deque. This method differs from {@link #peek peek} only in that + * it throws an exception if this deque is empty. + * + * <p>This method is equivalent to {@link #getFirst() getFirst}. + * + * @return the head of the queue represented by this deque + * @throws NoSuchElementException if this deque is empty + */ + public E element() { + return getFirst(); + } + + public E peek() { + return peekFirst(); + } + + /** + * Returns the number of additional elements that this deque can ideally + * (in the absence of memory or resource constraints) accept without + * blocking. This is always equal to the initial capacity of this deque + * less the current <tt>size</tt> of this deque. + * + * <p>Note that you <em>cannot</em> always tell if an attempt to insert + * an element will succeed by inspecting <tt>remainingCapacity</tt> + * because it may be the case that another thread is about to + * insert or remove an element. + */ + public int remainingCapacity() { + lock.lock(); + try { + return capacity - count; + } finally { + lock.unlock(); + } + } + + /** + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public int drainTo(Collection<? super E> c) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + lock.lock(); + try { + for (Node<E> p = first; p != null; p = p.next) + c.add(p.item); + int n = count; + count = 0; + first = last = null; + notFull.signalAll(); + return n; + } finally { + lock.unlock(); + } + } + + /** + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public int drainTo(Collection<? super E> c, int maxElements) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + lock.lock(); + try { + int n = 0; + while (n < maxElements && first != null) { + c.add(first.item); + first.prev = null; + first = first.next; + --count; + ++n; + } + if (first == null) + last = null; + notFull.signalAll(); + return n; + } finally { + lock.unlock(); + } + } + + // Stack methods + + /** + * @throws IllegalStateException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public void push(E e) { + addFirst(e); + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E pop() { + return removeFirst(); + } + + // Collection methods + + /** + * 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 <tt>e</tt> such that + * <tt>o.equals(e)</tt> (if such an element exists). + * Returns <tt>true</tt> 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) removeFirstOccurrence}. + * + * @param o element to be removed from this deque, if present + * @return <tt>true</tt> if this deque changed as a result of the call + */ + public boolean remove(Object o) { + return removeFirstOccurrence(o); + } + + /** + * Returns the number of elements in this deque. + * + * @return the number of elements in this deque + */ + public int size() { + lock.lock(); + try { + return count; + } finally { + lock.unlock(); + } + } + + /** + * Returns <tt>true</tt> if this deque contains the specified element. + * More formally, returns <tt>true</tt> if and only if this deque contains + * at least one element <tt>e</tt> such that <tt>o.equals(e)</tt>. + * + * @param o object to be checked for containment in this deque + * @return <tt>true</tt> if this deque contains the specified element + */ + public boolean contains(Object o) { + if (o == null) return false; + lock.lock(); + try { + for (Node<E> p = first; p != null; p = p.next) + if (o.equals(p.item)) + return true; + return false; + } finally { + lock.unlock(); + } + } + + /** + * Variant of removeFirstOccurrence needed by iterator.remove. + * Searches for the node, not its contents. + */ + boolean removeNode(Node<E> e) { + lock.lock(); + try { + for (Node<E> p = first; p != null; p = p.next) { + if (p == e) { + unlink(p); + return true; + } + } + return false; + } finally { + lock.unlock(); + } + } + + /** + * Returns an array containing all of the elements in this deque, in + * proper sequence (from first to last element). + * + * <p>The returned array will be "safe" in that no references to it are + * maintained by this deque. (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 deque + */ + public Object[] toArray() { + lock.lock(); + try { + Object[] a = new Object[count]; + int k = 0; + for (Node<E> p = first; p != null; p = p.next) + a[k++] = p.item; + return a; + } finally { + lock.unlock(); + } + } + + /** + * Returns an array containing all of the elements in this deque, in + * proper sequence; the runtime type of the returned array is that of + * the specified array. If the deque 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 deque. + * + * <p>If this deque fits in the specified array with room to spare + * (i.e., the array has more elements than this deque), the element in + * the array immediately following the end of the deque is set to + * <tt>null</tt>. + * + * <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 <tt>x</tt> is a deque known to contain only strings. + * The following code can be used to dump the deque into a newly + * allocated array of <tt>String</tt>: + * + * <pre> + * String[] y = x.toArray(new String[0]);</pre> + * + * Note that <tt>toArray(new Object[0])</tt> is identical in function to + * <tt>toArray()</tt>. + * + * @param a the array into which the elements of the deque 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 deque + * @throws ArrayStoreException if the runtime type of the specified array + * is not a supertype of the runtime type of every element in + * this deque + * @throws NullPointerException if the specified array is null + */ + public <T> T[] toArray(T[] a) { + lock.lock(); + try { + if (a.length < count) + a = (T[])java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), + count + ); + + int k = 0; + for (Node<E> p = first; p != null; p = p.next) + a[k++] = (T)p.item; + if (a.length > k) + a[k] = null; + return a; + } finally { + lock.unlock(); + } + } + + public String toString() { + lock.lock(); + try { + return super.toString(); + } finally { + lock.unlock(); + } + } + + /** + * Atomically removes all of the elements from this deque. + * The deque will be empty after this call returns. + */ + public void clear() { + lock.lock(); + try { + first = last = null; + count = 0; + notFull.signalAll(); + } finally { + lock.unlock(); + } + } + + /** + * Returns an iterator over the elements in this deque in proper sequence. + * The elements will be returned in order from first (head) to last (tail). + * The returned <tt>Iterator</tt> is a "weakly consistent" iterator that + * will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + * + * @return an iterator over the elements in this deque in proper sequence + */ + public Iterator<E> iterator() { + return new Itr(); + } + + /** + * Returns an iterator over the elements in this deque in reverse + * sequential order. The elements will be returned in order from + * last (tail) to first (head). + * The returned <tt>Iterator</tt> is a "weakly consistent" iterator that + * will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + */ + public Iterator<E> descendingIterator() { + return new DescendingItr(); + } + + /** + * Base class for Iterators for LinkedBlockingDeque + */ + private abstract class AbstractItr implements Iterator<E> { + /** + * The next node to return in next + */ + Node<E> next; + + /** + * nextItem holds on to item fields because once we claim that + * an element exists in hasNext(), we must return item read + * under lock (in advance()) even if it was in the process of + * being removed when hasNext() was called. + */ + E nextItem; + + /** + * Node returned by most recent call to next. Needed by remove. + * Reset to null if this element is deleted by a call to remove. + */ + private Node<E> lastRet; + + AbstractItr() { + advance(); // set to initial position + } + + /** + * Advances next, or if not yet initialized, sets to first node. + * Implemented to move forward vs backward in the two subclasses. + */ + abstract void advance(); + + public boolean hasNext() { + return next != null; + } + + public E next() { + if (next == null) + throw new NoSuchElementException(); + lastRet = next; + E x = nextItem; + advance(); + return x; + } + + public void remove() { + Node<E> n = lastRet; + if (n == null) + throw new IllegalStateException(); + lastRet = null; + // Note: removeNode rescans looking for this node to make + // sure it was not already removed. Otherwise, trying to + // re-remove could corrupt list. + removeNode(n); + } + } + + /** Forward iterator */ + private class Itr extends AbstractItr { + void advance() { + final ReentrantLock lock = LinkedBlockingDeque.this.lock; + lock.lock(); + try { + next = (next == null)? first : next.next; + nextItem = (next == null)? null : next.item; + } finally { + lock.unlock(); + } + } + } + + /** + * Descending iterator for LinkedBlockingDeque + */ + private class DescendingItr extends AbstractItr { + void advance() { + final ReentrantLock lock = LinkedBlockingDeque.this.lock; + lock.lock(); + try { + next = (next == null)? last : next.prev; + nextItem = (next == null)? null : next.item; + } finally { + lock.unlock(); + } + } + } + + /** + * Save the state of this deque to a stream (that is, serialize it). + * + * @serialData The capacity (int), followed by elements (each an + * <tt>Object</tt>) in the proper order, followed by a null + * @param s the stream + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + lock.lock(); + try { + // Write out capacity and any hidden stuff + s.defaultWriteObject(); + // Write out all elements in the proper order. + for (Node<E> p = first; p != null; p = p.next) + s.writeObject(p.item); + // Use trailing null as sentinel + s.writeObject(null); + } finally { + lock.unlock(); + } + } + + /** + * Reconstitute this deque from a stream (that is, + * deserialize it). + * @param s the stream + */ + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + count = 0; + first = null; + last = null; + // Read in all elements and place in queue + for (;;) { + E item = (E)s.readObject(); + if (item == null) + break; + add(item); + } + } + +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/LinkedBlockingQueue.java b/libjava/classpath/external/jsr166/java/util/concurrent/LinkedBlockingQueue.java new file mode 100644 index 000000000..62018096a --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/LinkedBlockingQueue.java @@ -0,0 +1,807 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.concurrent.atomic.*; +import java.util.concurrent.locks.*; +import java.util.*; + +/** + * An optionally-bounded {@linkplain BlockingQueue blocking queue} based on + * linked nodes. + * This queue orders elements FIFO (first-in-first-out). + * The <em>head</em> of the queue is that element that has been on the + * queue the longest time. + * The <em>tail</em> of the queue is that element that has been on the + * queue the shortest time. New elements + * are inserted at the tail of the queue, and the queue retrieval + * operations obtain elements at the head of the queue. + * Linked queues typically have higher throughput than array-based queues but + * less predictable performance in most concurrent applications. + * + * <p> The optional capacity bound constructor argument serves as a + * way to prevent excessive queue expansion. The capacity, if unspecified, + * is equal to {@link Integer#MAX_VALUE}. Linked nodes are + * dynamically created upon each insertion unless this would bring the + * queue above capacity. + * + * <p>This class and its iterator implement all of the + * <em>optional</em> methods of the {@link Collection} and {@link + * Iterator} interfaces. + * + * <p>This class is a member of the + * <a href="{@docRoot}/../technotes/guides/collections/index.html"> + * Java Collections Framework</a>. + * + * @since 1.5 + * @author Doug Lea + * @param <E> the type of elements held in this collection + * + */ +public class LinkedBlockingQueue<E> extends AbstractQueue<E> + implements BlockingQueue<E>, java.io.Serializable { + private static final long serialVersionUID = -6903933977591709194L; + + /* + * A variant of the "two lock queue" algorithm. The putLock gates + * entry to put (and offer), and has an associated condition for + * waiting puts. Similarly for the takeLock. The "count" field + * that they both rely on is maintained as an atomic to avoid + * needing to get both locks in most cases. Also, to minimize need + * for puts to get takeLock and vice-versa, cascading notifies are + * used. When a put notices that it has enabled at least one take, + * it signals taker. That taker in turn signals others if more + * items have been entered since the signal. And symmetrically for + * takes signalling puts. Operations such as remove(Object) and + * iterators acquire both locks. + */ + + /** + * Linked list node class + */ + static class Node<E> { + /** The item, volatile to ensure barrier separating write and read */ + volatile E item; + Node<E> next; + Node(E x) { item = x; } + } + + /** The capacity bound, or Integer.MAX_VALUE if none */ + private final int capacity; + + /** Current number of elements */ + private final AtomicInteger count = new AtomicInteger(0); + + /** Head of linked list */ + private transient Node<E> head; + + /** Tail of linked list */ + private transient Node<E> last; + + /** Lock held by take, poll, etc */ + private final ReentrantLock takeLock = new ReentrantLock(); + + /** Wait queue for waiting takes */ + private final Condition notEmpty = takeLock.newCondition(); + + /** Lock held by put, offer, etc */ + private final ReentrantLock putLock = new ReentrantLock(); + + /** Wait queue for waiting puts */ + private final Condition notFull = putLock.newCondition(); + + /** + * Signals a waiting take. Called only from put/offer (which do not + * otherwise ordinarily lock takeLock.) + */ + private void signalNotEmpty() { + final ReentrantLock takeLock = this.takeLock; + takeLock.lock(); + try { + notEmpty.signal(); + } finally { + takeLock.unlock(); + } + } + + /** + * Signals a waiting put. Called only from take/poll. + */ + private void signalNotFull() { + final ReentrantLock putLock = this.putLock; + putLock.lock(); + try { + notFull.signal(); + } finally { + putLock.unlock(); + } + } + + /** + * Creates a node and links it at end of queue. + * @param x the item + */ + private void insert(E x) { + last = last.next = new Node<E>(x); + } + + /** + * Removes a node from head of queue, + * @return the node + */ + private E extract() { + Node<E> first = head.next; + head = first; + E x = first.item; + first.item = null; + return x; + } + + /** + * Lock to prevent both puts and takes. + */ + private void fullyLock() { + putLock.lock(); + takeLock.lock(); + } + + /** + * Unlock to allow both puts and takes. + */ + private void fullyUnlock() { + takeLock.unlock(); + putLock.unlock(); + } + + + /** + * Creates a <tt>LinkedBlockingQueue</tt> with a capacity of + * {@link Integer#MAX_VALUE}. + */ + public LinkedBlockingQueue() { + this(Integer.MAX_VALUE); + } + + /** + * Creates a <tt>LinkedBlockingQueue</tt> with the given (fixed) capacity. + * + * @param capacity the capacity of this queue + * @throws IllegalArgumentException if <tt>capacity</tt> is not greater + * than zero + */ + public LinkedBlockingQueue(int capacity) { + if (capacity <= 0) throw new IllegalArgumentException(); + this.capacity = capacity; + last = head = new Node<E>(null); + } + + /** + * Creates a <tt>LinkedBlockingQueue</tt> with a capacity of + * {@link Integer#MAX_VALUE}, initially containing the elements of the + * given collection, + * added in traversal order of the collection's iterator. + * + * @param c the collection of elements to initially contain + * @throws NullPointerException if the specified collection or any + * of its elements are null + */ + public LinkedBlockingQueue(Collection<? extends E> c) { + this(Integer.MAX_VALUE); + for (E e : c) + add(e); + } + + + // this doc comment is overridden to remove the reference to collections + // greater in size than Integer.MAX_VALUE + /** + * Returns the number of elements in this queue. + * + * @return the number of elements in this queue + */ + public int size() { + return count.get(); + } + + // this doc comment is a modified copy of the inherited doc comment, + // without the reference to unlimited queues. + /** + * Returns the number of additional elements that this queue can ideally + * (in the absence of memory or resource constraints) accept without + * blocking. This is always equal to the initial capacity of this queue + * less the current <tt>size</tt> of this queue. + * + * <p>Note that you <em>cannot</em> always tell if an attempt to insert + * an element will succeed by inspecting <tt>remainingCapacity</tt> + * because it may be the case that another thread is about to + * insert or remove an element. + */ + public int remainingCapacity() { + return capacity - count.get(); + } + + /** + * Inserts the specified element at the tail of this queue, waiting if + * necessary for space to become available. + * + * @throws InterruptedException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public void put(E e) throws InterruptedException { + if (e == null) throw new NullPointerException(); + // Note: convention in all put/take/etc is to preset + // local var holding count negative to indicate failure unless set. + int c = -1; + final ReentrantLock putLock = this.putLock; + final AtomicInteger count = this.count; + putLock.lockInterruptibly(); + try { + /* + * Note that count is used in wait guard even though it is + * not protected by lock. This works because count can + * only decrease at this point (all other puts are shut + * out by lock), and we (or some other waiting put) are + * signalled if it ever changes from + * capacity. Similarly for all other uses of count in + * other wait guards. + */ + try { + while (count.get() == capacity) + notFull.await(); + } catch (InterruptedException ie) { + notFull.signal(); // propagate to a non-interrupted thread + throw ie; + } + insert(e); + c = count.getAndIncrement(); + if (c + 1 < capacity) + notFull.signal(); + } finally { + putLock.unlock(); + } + if (c == 0) + signalNotEmpty(); + } + + /** + * Inserts the specified element at the tail of this queue, waiting if + * necessary up to the specified wait time for space to become available. + * + * @return <tt>true</tt> if successful, or <tt>false</tt> if + * the specified waiting time elapses before space is available. + * @throws InterruptedException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public boolean offer(E e, long timeout, TimeUnit unit) + throws InterruptedException { + + if (e == null) throw new NullPointerException(); + long nanos = unit.toNanos(timeout); + int c = -1; + final ReentrantLock putLock = this.putLock; + final AtomicInteger count = this.count; + putLock.lockInterruptibly(); + try { + for (;;) { + if (count.get() < capacity) { + insert(e); + c = count.getAndIncrement(); + if (c + 1 < capacity) + notFull.signal(); + break; + } + if (nanos <= 0) + return false; + try { + nanos = notFull.awaitNanos(nanos); + } catch (InterruptedException ie) { + notFull.signal(); // propagate to a non-interrupted thread + throw ie; + } + } + } finally { + putLock.unlock(); + } + if (c == 0) + signalNotEmpty(); + return true; + } + + /** + * Inserts the specified element at the tail of this queue if it is + * possible to do so immediately without exceeding the queue's capacity, + * returning <tt>true</tt> upon success and <tt>false</tt> if this queue + * is full. + * When using a capacity-restricted queue, this method is generally + * preferable to method {@link BlockingQueue#add add}, which can fail to + * insert an element only by throwing an exception. + * + * @throws NullPointerException if the specified element is null + */ + public boolean offer(E e) { + if (e == null) throw new NullPointerException(); + final AtomicInteger count = this.count; + if (count.get() == capacity) + return false; + int c = -1; + final ReentrantLock putLock = this.putLock; + putLock.lock(); + try { + if (count.get() < capacity) { + insert(e); + c = count.getAndIncrement(); + if (c + 1 < capacity) + notFull.signal(); + } + } finally { + putLock.unlock(); + } + if (c == 0) + signalNotEmpty(); + return c >= 0; + } + + + public E take() throws InterruptedException { + E x; + int c = -1; + final AtomicInteger count = this.count; + final ReentrantLock takeLock = this.takeLock; + takeLock.lockInterruptibly(); + try { + try { + while (count.get() == 0) + notEmpty.await(); + } catch (InterruptedException ie) { + notEmpty.signal(); // propagate to a non-interrupted thread + throw ie; + } + + x = extract(); + c = count.getAndDecrement(); + if (c > 1) + notEmpty.signal(); + } finally { + takeLock.unlock(); + } + if (c == capacity) + signalNotFull(); + return x; + } + + public E poll(long timeout, TimeUnit unit) throws InterruptedException { + E x = null; + int c = -1; + long nanos = unit.toNanos(timeout); + final AtomicInteger count = this.count; + final ReentrantLock takeLock = this.takeLock; + takeLock.lockInterruptibly(); + try { + for (;;) { + if (count.get() > 0) { + x = extract(); + c = count.getAndDecrement(); + if (c > 1) + notEmpty.signal(); + break; + } + if (nanos <= 0) + return null; + try { + nanos = notEmpty.awaitNanos(nanos); + } catch (InterruptedException ie) { + notEmpty.signal(); // propagate to a non-interrupted thread + throw ie; + } + } + } finally { + takeLock.unlock(); + } + if (c == capacity) + signalNotFull(); + return x; + } + + public E poll() { + final AtomicInteger count = this.count; + if (count.get() == 0) + return null; + E x = null; + int c = -1; + final ReentrantLock takeLock = this.takeLock; + takeLock.lock(); + try { + if (count.get() > 0) { + x = extract(); + c = count.getAndDecrement(); + if (c > 1) + notEmpty.signal(); + } + } finally { + takeLock.unlock(); + } + if (c == capacity) + signalNotFull(); + return x; + } + + + public E peek() { + if (count.get() == 0) + return null; + final ReentrantLock takeLock = this.takeLock; + takeLock.lock(); + try { + Node<E> first = head.next; + if (first == null) + return null; + else + return first.item; + } finally { + takeLock.unlock(); + } + } + + /** + * Removes a single instance of the specified element from this queue, + * if it is present. More formally, removes an element <tt>e</tt> such + * that <tt>o.equals(e)</tt>, if this queue contains one or more such + * elements. + * Returns <tt>true</tt> if this queue contained the specified element + * (or equivalently, if this queue changed as a result of the call). + * + * @param o element to be removed from this queue, if present + * @return <tt>true</tt> if this queue changed as a result of the call + */ + public boolean remove(Object o) { + if (o == null) return false; + boolean removed = false; + fullyLock(); + try { + Node<E> trail = head; + Node<E> p = head.next; + while (p != null) { + if (o.equals(p.item)) { + removed = true; + break; + } + trail = p; + p = p.next; + } + if (removed) { + p.item = null; + trail.next = p.next; + if (last == p) + last = trail; + if (count.getAndDecrement() == capacity) + notFull.signalAll(); + } + } finally { + fullyUnlock(); + } + return removed; + } + + /** + * 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() { + fullyLock(); + try { + int size = count.get(); + Object[] a = new Object[size]; + int k = 0; + for (Node<E> p = head.next; p != null; p = p.next) + a[k++] = p.item; + return a; + } finally { + fullyUnlock(); + } + } + + /** + * 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 + * <tt>null</tt>. + * + * <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 <tt>x</tt> is a queue known to contain only strings. + * The following code can be used to dump the queue into a newly + * allocated array of <tt>String</tt>: + * + * <pre> + * String[] y = x.toArray(new String[0]);</pre> + * + * Note that <tt>toArray(new Object[0])</tt> is identical in function to + * <tt>toArray()</tt>. + * + * @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 + */ + public <T> T[] toArray(T[] a) { + fullyLock(); + try { + int size = count.get(); + if (a.length < size) + a = (T[])java.lang.reflect.Array.newInstance + (a.getClass().getComponentType(), size); + + int k = 0; + for (Node p = head.next; p != null; p = p.next) + a[k++] = (T)p.item; + if (a.length > k) + a[k] = null; + return a; + } finally { + fullyUnlock(); + } + } + + public String toString() { + fullyLock(); + try { + return super.toString(); + } finally { + fullyUnlock(); + } + } + + /** + * Atomically removes all of the elements from this queue. + * The queue will be empty after this call returns. + */ + public void clear() { + fullyLock(); + try { + head.next = null; + assert head.item == null; + last = head; + if (count.getAndSet(0) == capacity) + notFull.signalAll(); + } finally { + fullyUnlock(); + } + } + + /** + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public int drainTo(Collection<? super E> c) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + Node<E> first; + fullyLock(); + try { + first = head.next; + head.next = null; + assert head.item == null; + last = head; + if (count.getAndSet(0) == capacity) + notFull.signalAll(); + } finally { + fullyUnlock(); + } + // Transfer the elements outside of locks + int n = 0; + for (Node<E> p = first; p != null; p = p.next) { + c.add(p.item); + p.item = null; + ++n; + } + return n; + } + + /** + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public int drainTo(Collection<? super E> c, int maxElements) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + fullyLock(); + try { + int n = 0; + Node<E> p = head.next; + while (p != null && n < maxElements) { + c.add(p.item); + p.item = null; + p = p.next; + ++n; + } + if (n != 0) { + head.next = p; + assert head.item == null; + if (p == null) + last = head; + if (count.getAndAdd(-n) == capacity) + notFull.signalAll(); + } + return n; + } finally { + fullyUnlock(); + } + } + + /** + * Returns an iterator over the elements in this queue in proper sequence. + * The returned <tt>Iterator</tt> is a "weakly consistent" iterator that + * will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + * + * @return an iterator over the elements in this queue in proper sequence + */ + public Iterator<E> iterator() { + return new Itr(); + } + + private class Itr implements Iterator<E> { + /* + * Basic weak-consistent iterator. At all times hold the next + * item to hand out so that if hasNext() reports true, we will + * still have it to return even if lost race with a take etc. + */ + private Node<E> current; + private Node<E> lastRet; + private E currentElement; + + Itr() { + final ReentrantLock putLock = LinkedBlockingQueue.this.putLock; + final ReentrantLock takeLock = LinkedBlockingQueue.this.takeLock; + putLock.lock(); + takeLock.lock(); + try { + current = head.next; + if (current != null) + currentElement = current.item; + } finally { + takeLock.unlock(); + putLock.unlock(); + } + } + + public boolean hasNext() { + return current != null; + } + + public E next() { + final ReentrantLock putLock = LinkedBlockingQueue.this.putLock; + final ReentrantLock takeLock = LinkedBlockingQueue.this.takeLock; + putLock.lock(); + takeLock.lock(); + try { + if (current == null) + throw new NoSuchElementException(); + E x = currentElement; + lastRet = current; + current = current.next; + if (current != null) + currentElement = current.item; + return x; + } finally { + takeLock.unlock(); + putLock.unlock(); + } + } + + public void remove() { + if (lastRet == null) + throw new IllegalStateException(); + final ReentrantLock putLock = LinkedBlockingQueue.this.putLock; + final ReentrantLock takeLock = LinkedBlockingQueue.this.takeLock; + putLock.lock(); + takeLock.lock(); + try { + Node<E> node = lastRet; + lastRet = null; + Node<E> trail = head; + Node<E> p = head.next; + while (p != null && p != node) { + trail = p; + p = p.next; + } + if (p == node) { + p.item = null; + trail.next = p.next; + if (last == p) + last = trail; + int c = count.getAndDecrement(); + if (c == capacity) + notFull.signalAll(); + } + } finally { + takeLock.unlock(); + putLock.unlock(); + } + } + } + + /** + * Save the state to a stream (that is, serialize it). + * + * @serialData The capacity is emitted (int), followed by all of + * its elements (each an <tt>Object</tt>) in the proper order, + * followed by a null + * @param s the stream + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + + fullyLock(); + try { + // Write out any hidden stuff, plus capacity + s.defaultWriteObject(); + + // Write out all elements in the proper order. + for (Node<E> p = head.next; p != null; p = p.next) + s.writeObject(p.item); + + // Use trailing null as sentinel + s.writeObject(null); + } finally { + fullyUnlock(); + } + } + + /** + * Reconstitute this queue instance from a stream (that is, + * deserialize it). + * @param s the stream + */ + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + // Read in capacity, and any hidden stuff + s.defaultReadObject(); + + count.set(0); + last = head = new Node<E>(null); + + // Read in all elements and place in queue + for (;;) { + E item = (E)s.readObject(); + if (item == null) + break; + add(item); + } + } +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/PriorityBlockingQueue.java b/libjava/classpath/external/jsr166/java/util/concurrent/PriorityBlockingQueue.java new file mode 100644 index 000000000..9466aa477 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/PriorityBlockingQueue.java @@ -0,0 +1,563 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; + +import java.util.concurrent.locks.*; +import java.util.*; + +/** + * An unbounded {@linkplain BlockingQueue blocking queue} that uses + * the same ordering rules as class {@link PriorityQueue} and supplies + * blocking retrieval operations. While this queue is logically + * unbounded, attempted additions may fail due to resource exhaustion + * (causing <tt>OutOfMemoryError</tt>). This class does not permit + * <tt>null</tt> elements. A priority queue relying on {@linkplain + * Comparable natural ordering} also does not permit insertion of + * non-comparable objects (doing so results in + * <tt>ClassCastException</tt>). + * + * <p>This class and its iterator implement all of the + * <em>optional</em> methods of the {@link Collection} and {@link + * Iterator} interfaces. The Iterator provided in method {@link + * #iterator()} is <em>not</em> guaranteed to traverse the elements of + * the PriorityBlockingQueue in any particular order. If you need + * ordered traversal, consider using + * <tt>Arrays.sort(pq.toArray())</tt>. Also, method <tt>drainTo</tt> + * can be used to <em>remove</em> some or all elements in priority + * order and place them in another collection. + * + * <p>Operations on this class make no guarantees about the ordering + * of elements with equal priority. If you need to enforce an + * ordering, you can define custom classes or comparators that use a + * secondary key to break ties in primary priority values. For + * example, here is a class that applies first-in-first-out + * tie-breaking to comparable elements. To use it, you would insert a + * <tt>new FIFOEntry(anEntry)</tt> instead of a plain entry object. + * + * <pre> + * class FIFOEntry<E extends Comparable<? super E>> + * implements Comparable<FIFOEntry<E>> { + * final static AtomicLong seq = new AtomicLong(); + * final long seqNum; + * final E entry; + * public FIFOEntry(E entry) { + * seqNum = seq.getAndIncrement(); + * this.entry = entry; + * } + * public E getEntry() { return entry; } + * public int compareTo(FIFOEntry<E> other) { + * int res = entry.compareTo(other.entry); + * if (res == 0 && other.entry != this.entry) + * res = (seqNum < other.seqNum ? -1 : 1); + * return res; + * } + * }</pre> + * + * <p>This class is a member of the + * <a href="{@docRoot}/../technotes/guides/collections/index.html"> + * Java Collections Framework</a>. + * + * @since 1.5 + * @author Doug Lea + * @param <E> the type of elements held in this collection + */ +public class PriorityBlockingQueue<E> extends AbstractQueue<E> + implements BlockingQueue<E>, java.io.Serializable { + private static final long serialVersionUID = 5595510919245408276L; + + private final PriorityQueue<E> q; + private final ReentrantLock lock = new ReentrantLock(true); + private final Condition notEmpty = lock.newCondition(); + + /** + * Creates a <tt>PriorityBlockingQueue</tt> with the default + * initial capacity (11) that orders its elements according to + * their {@linkplain Comparable natural ordering}. + */ + public PriorityBlockingQueue() { + q = new PriorityQueue<E>(); + } + + /** + * Creates a <tt>PriorityBlockingQueue</tt> with the specified + * initial capacity that orders its elements according to their + * {@linkplain Comparable natural ordering}. + * + * @param initialCapacity the initial capacity for this priority queue + * @throws IllegalArgumentException if <tt>initialCapacity</tt> is less + * than 1 + */ + public PriorityBlockingQueue(int initialCapacity) { + q = new PriorityQueue<E>(initialCapacity, null); + } + + /** + * Creates a <tt>PriorityBlockingQueue</tt> with the specified initial + * capacity that orders its elements according to the specified + * comparator. + * + * @param initialCapacity the initial capacity for this priority queue + * @param comparator the comparator that will be used to order this + * priority queue. If {@code null}, the {@linkplain Comparable + * natural ordering} of the elements will be used. + * @throws IllegalArgumentException if <tt>initialCapacity</tt> is less + * than 1 + */ + public PriorityBlockingQueue(int initialCapacity, + Comparator<? super E> comparator) { + q = new PriorityQueue<E>(initialCapacity, comparator); + } + + /** + * Creates a <tt>PriorityBlockingQueue</tt> containing the elements + * in the specified collection. If the specified collection is a + * {@link SortedSet} or a {@link PriorityQueue}, this + * priority queue will be ordered according to the same ordering. + * Otherwise, this priority queue will be ordered according to the + * {@linkplain Comparable natural ordering} of its elements. + * + * @param c the collection whose elements are to be placed + * into this priority queue + * @throws ClassCastException if elements of the specified collection + * cannot be compared to one another according to the priority + * queue's ordering + * @throws NullPointerException if the specified collection or any + * of its elements are null + */ + public PriorityBlockingQueue(Collection<? extends E> c) { + q = new PriorityQueue<E>(c); + } + + /** + * Inserts the specified element into this priority queue. + * + * @param e the element to add + * @return <tt>true</tt> (as specified by {@link Collection#add}) + * @throws ClassCastException if the specified element cannot be compared + * with elements currently in the priority queue according to the + * priority queue's ordering + * @throws NullPointerException if the specified element is null + */ + public boolean add(E e) { + return offer(e); + } + + /** + * Inserts the specified element into this priority queue. + * + * @param e the element to add + * @return <tt>true</tt> (as specified by {@link Queue#offer}) + * @throws ClassCastException if the specified element cannot be compared + * with elements currently in the priority queue according to the + * priority queue's ordering + * @throws NullPointerException if the specified element is null + */ + public boolean offer(E e) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + boolean ok = q.offer(e); + assert ok; + notEmpty.signal(); + return true; + } finally { + lock.unlock(); + } + } + + /** + * Inserts the specified element into this priority queue. As the queue is + * unbounded this method will never block. + * + * @param e the element to add + * @throws ClassCastException if the specified element cannot be compared + * with elements currently in the priority queue according to the + * priority queue's ordering + * @throws NullPointerException if the specified element is null + */ + public void put(E e) { + offer(e); // never need to block + } + + /** + * Inserts the specified element into this priority queue. As the queue is + * unbounded this method will never block. + * + * @param e the element to add + * @param timeout This parameter is ignored as the method never blocks + * @param unit This parameter is ignored as the method never blocks + * @return <tt>true</tt> + * @throws ClassCastException if the specified element cannot be compared + * with elements currently in the priority queue according to the + * priority queue's ordering + * @throws NullPointerException if the specified element is null + */ + public boolean offer(E e, long timeout, TimeUnit unit) { + return offer(e); // never need to block + } + + public E poll() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return q.poll(); + } finally { + lock.unlock(); + } + } + + public E take() throws InterruptedException { + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + try { + while (q.size() == 0) + notEmpty.await(); + } catch (InterruptedException ie) { + notEmpty.signal(); // propagate to non-interrupted thread + throw ie; + } + E x = q.poll(); + assert x != null; + return x; + } finally { + lock.unlock(); + } + } + + public E poll(long timeout, TimeUnit unit) throws InterruptedException { + long nanos = unit.toNanos(timeout); + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + for (;;) { + E x = q.poll(); + if (x != null) + return x; + if (nanos <= 0) + return null; + try { + nanos = notEmpty.awaitNanos(nanos); + } catch (InterruptedException ie) { + notEmpty.signal(); // propagate to non-interrupted thread + throw ie; + } + } + } finally { + lock.unlock(); + } + } + + public E peek() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return q.peek(); + } finally { + lock.unlock(); + } + } + + /** + * Returns the comparator used to order the elements in this queue, + * or <tt>null</tt> if this queue uses the {@linkplain Comparable + * natural ordering} of its elements. + * + * @return the comparator used to order the elements in this queue, + * or <tt>null</tt> if this queue uses the natural + * ordering of its elements + */ + public Comparator<? super E> comparator() { + return q.comparator(); + } + + public int size() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return q.size(); + } finally { + lock.unlock(); + } + } + + /** + * Always returns <tt>Integer.MAX_VALUE</tt> because + * a <tt>PriorityBlockingQueue</tt> is not capacity constrained. + * @return <tt>Integer.MAX_VALUE</tt> + */ + public int remainingCapacity() { + return Integer.MAX_VALUE; + } + + /** + * Removes a single instance of the specified element from this queue, + * if it is present. More formally, removes an element {@code e} such + * that {@code o.equals(e)}, if this queue contains one or more such + * elements. Returns {@code true} if and only if this queue contained + * the specified element (or equivalently, if this queue changed as a + * result of the call). + * + * @param o element to be removed from this queue, if present + * @return <tt>true</tt> if this queue changed as a result of the call + */ + public boolean remove(Object o) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return q.remove(o); + } finally { + lock.unlock(); + } + } + + /** + * Returns {@code true} if this queue contains the specified element. + * More formally, returns {@code true} if and only if this queue contains + * at least one element {@code e} such that {@code o.equals(e)}. + * + * @param o object to be checked for containment in this queue + * @return <tt>true</tt> if this queue contains the specified element + */ + public boolean contains(Object o) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return q.contains(o); + } finally { + lock.unlock(); + } + } + + /** + * 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 q.toArray(); + } finally { + lock.unlock(); + } + } + + + public String toString() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return q.toString(); + } finally { + lock.unlock(); + } + } + + /** + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public int drainTo(Collection<? super E> c) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + final ReentrantLock lock = this.lock; + lock.lock(); + try { + int n = 0; + E e; + while ( (e = q.poll()) != null) { + c.add(e); + ++n; + } + return n; + } finally { + lock.unlock(); + } + } + + /** + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public int drainTo(Collection<? super E> c, int maxElements) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + if (maxElements <= 0) + return 0; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + int n = 0; + E e; + while (n < maxElements && (e = q.poll()) != null) { + c.add(e); + ++n; + } + return n; + } finally { + lock.unlock(); + } + } + + /** + * Atomically removes all of the elements from this queue. + * The queue will be empty after this call returns. + */ + public void clear() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + q.clear(); + } finally { + lock.unlock(); + } + } + + /** + * Returns an array containing all of the elements in this queue; the + * runtime type of the returned array is that of the specified array. + * The returned array elements are in no particular order. + * 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 + * <tt>null</tt>. + * + * <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 <tt>x</tt> is a queue known to contain only strings. + * The following code can be used to dump the queue into a newly + * allocated array of <tt>String</tt>: + * + * <pre> + * String[] y = x.toArray(new String[0]);</pre> + * + * Note that <tt>toArray(new Object[0])</tt> is identical in function to + * <tt>toArray()</tt>. + * + * @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 + */ + public <T> T[] toArray(T[] a) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return q.toArray(a); + } finally { + lock.unlock(); + } + } + + /** + * Returns an iterator over the elements in this queue. The + * iterator does not return the elements in any particular order. + * The returned <tt>Iterator</tt> is a "weakly consistent" + * iterator that will never throw {@link + * ConcurrentModificationException}, and guarantees to traverse + * elements as they existed upon construction of the iterator, and + * may (but is not guaranteed to) reflect any modifications + * subsequent to construction. + * + * @return an iterator over the elements in this queue + */ + public Iterator<E> iterator() { + return new Itr(toArray()); + } + + /** + * Snapshot iterator that works off copy of underlying q array. + */ + private class Itr implements Iterator<E> { + final Object[] array; // Array of all elements + int cursor; // index of next element to return; + int lastRet; // index of last element, or -1 if no such + + Itr(Object[] array) { + lastRet = -1; + this.array = array; + } + + public boolean hasNext() { + return cursor < array.length; + } + + public E next() { + if (cursor >= array.length) + throw new NoSuchElementException(); + lastRet = cursor; + return (E)array[cursor++]; + } + + public void remove() { + if (lastRet < 0) + throw new IllegalStateException(); + Object x = array[lastRet]; + lastRet = -1; + // Traverse underlying queue to find == element, + // not just a .equals element. + lock.lock(); + try { + for (Iterator it = q.iterator(); it.hasNext(); ) { + if (it.next() == x) { + it.remove(); + return; + } + } + } finally { + lock.unlock(); + } + } + } + + /** + * Saves the state to a stream (that is, serializes it). This + * merely wraps default serialization within lock. The + * serialization strategy for items is left to underlying + * Queue. Note that locking is not needed on deserialization, so + * readObject is not defined, just relying on default. + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + lock.lock(); + try { + s.defaultWriteObject(); + } finally { + lock.unlock(); + } + } + +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/RejectedExecutionException.java b/libjava/classpath/external/jsr166/java/util/concurrent/RejectedExecutionException.java new file mode 100644 index 000000000..30b043d66 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/RejectedExecutionException.java @@ -0,0 +1,62 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; + +/** + * Exception thrown by an {@link Executor} when a task cannot be + * accepted for execution. + * + * @since 1.5 + * @author Doug Lea + */ +public class RejectedExecutionException extends RuntimeException { + private static final long serialVersionUID = -375805702767069545L; + + /** + * Constructs a <tt>RejectedExecutionException</tt> with no detail message. + * The cause is not initialized, and may subsequently be + * initialized by a call to {@link #initCause(Throwable) initCause}. + */ + public RejectedExecutionException() { } + + /** + * Constructs a <tt>RejectedExecutionException</tt> with the + * specified detail message. The cause is not initialized, and may + * subsequently be initialized by a call to {@link + * #initCause(Throwable) initCause}. + * + * @param message the detail message + */ + public RejectedExecutionException(String message) { + super(message); + } + + /** + * Constructs a <tt>RejectedExecutionException</tt> with the + * specified detail message and cause. + * + * @param message the detail message + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method) + */ + public RejectedExecutionException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructs a <tt>RejectedExecutionException</tt> with the + * specified cause. The detail message is set to: <pre> (cause == + * null ? null : cause.toString())</pre> (which typically contains + * the class and detail message of <tt>cause</tt>). + * + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method) + */ + public RejectedExecutionException(Throwable cause) { + super(cause); + } +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/RejectedExecutionHandler.java b/libjava/classpath/external/jsr166/java/util/concurrent/RejectedExecutionHandler.java new file mode 100644 index 000000000..4b4bbeab1 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/RejectedExecutionHandler.java @@ -0,0 +1,33 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; + +/** + * A handler for tasks that cannot be executed by a {@link + * ThreadPoolExecutor}. + * + * @since 1.5 + * @author Doug Lea + */ +public interface RejectedExecutionHandler { + + /** + * Method that may be invoked by a {@link ThreadPoolExecutor} when + * <tt>execute</tt> cannot accept a task. This may occur when no + * more threads or queue slots are available because their bounds + * would be exceeded, or upon shutdown of the Executor. + * + * In the absence other alternatives, the method may throw an + * unchecked {@link RejectedExecutionException}, which will be + * propagated to the caller of <tt>execute</tt>. + * + * @param r the runnable task requested to be executed + * @param executor the executor attempting to execute this task + * @throws RejectedExecutionException if there is no remedy + */ + void rejectedExecution(Runnable r, ThreadPoolExecutor executor); +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/RunnableFuture.java b/libjava/classpath/external/jsr166/java/util/concurrent/RunnableFuture.java new file mode 100644 index 000000000..d74211d13 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/RunnableFuture.java @@ -0,0 +1,25 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; + +/** + * A {@link Future} that is {@link Runnable}. Successful execution of + * the <tt>run</tt> method causes completion of the <tt>Future</tt> + * and allows access to its results. + * @see FutureTask + * @see Executor + * @since 1.6 + * @author Doug Lea + * @param <V> The result type returned by this Future's <tt>get</tt> method + */ +public interface RunnableFuture<V> extends Runnable, Future<V> { + /** + * Sets this Future to the result of its computation + * unless it has been cancelled. + */ + void run(); +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/RunnableScheduledFuture.java b/libjava/classpath/external/jsr166/java/util/concurrent/RunnableScheduledFuture.java new file mode 100644 index 000000000..0e8cc328c --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/RunnableScheduledFuture.java @@ -0,0 +1,29 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; + +/** + * A {@link ScheduledFuture} that is {@link Runnable}. Successful + * execution of the <tt>run</tt> method causes completion of the + * <tt>Future</tt> and allows access to its results. + * @see FutureTask + * @see Executor + * @since 1.6 + * @author Doug Lea + * @param <V> The result type returned by this Future's <tt>get</tt> method + */ +public interface RunnableScheduledFuture<V> extends RunnableFuture<V>, ScheduledFuture<V> { + + /** + * Returns true if this is a periodic task. A periodic task may + * re-run according to some schedule. A non-periodic task can be + * run only once. + * + * @return true if this task is periodic + */ + boolean isPeriodic(); +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/ScheduledExecutorService.java b/libjava/classpath/external/jsr166/java/util/concurrent/ScheduledExecutorService.java new file mode 100644 index 000000000..c170c4a52 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/ScheduledExecutorService.java @@ -0,0 +1,159 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.concurrent.atomic.*; +import java.util.*; + +/** + * An {@link ExecutorService} that can schedule commands to run after a given + * delay, or to execute periodically. + * + * <p> The <tt>schedule</tt> methods create tasks with various delays + * and return a task object that can be used to cancel or check + * execution. The <tt>scheduleAtFixedRate</tt> and + * <tt>scheduleWithFixedDelay</tt> methods create and execute tasks + * that run periodically until cancelled. + * + * <p> Commands submitted using the {@link Executor#execute} and + * {@link ExecutorService} <tt>submit</tt> methods are scheduled with + * a requested delay of zero. Zero and negative delays (but not + * periods) are also allowed in <tt>schedule</tt> methods, and are + * treated as requests for immediate execution. + * + * <p>All <tt>schedule</tt> methods accept <em>relative</em> delays and + * periods as arguments, not absolute times or dates. It is a simple + * matter to transform an absolute time represented as a {@link + * java.util.Date} to the required form. For example, to schedule at + * a certain future <tt>date</tt>, you can use: <tt>schedule(task, + * date.getTime() - System.currentTimeMillis(), + * TimeUnit.MILLISECONDS)</tt>. Beware however that expiration of a + * relative delay need not coincide with the current <tt>Date</tt> at + * which the task is enabled due to network time synchronization + * protocols, clock drift, or other factors. + * + * The {@link Executors} class provides convenient factory methods for + * the ScheduledExecutorService implementations provided in this package. + * + * <h3>Usage Example</h3> + * + * Here is a class with a method that sets up a ScheduledExecutorService + * to beep every ten seconds for an hour: + * + * <pre> + * import static java.util.concurrent.TimeUnit.*; + * class BeeperControl { + * private final ScheduledExecutorService scheduler = + * Executors.newScheduledThreadPool(1); + * + * public void beepForAnHour() { + * final Runnable beeper = new Runnable() { + * public void run() { System.out.println("beep"); } + * }; + * final ScheduledFuture<?> beeperHandle = + * scheduler.scheduleAtFixedRate(beeper, 10, 10, SECONDS); + * scheduler.schedule(new Runnable() { + * public void run() { beeperHandle.cancel(true); } + * }, 60 * 60, SECONDS); + * } + * } + * </pre> + * + * @since 1.5 + * @author Doug Lea + */ +public interface ScheduledExecutorService extends ExecutorService { + + /** + * Creates and executes a one-shot action that becomes enabled + * after the given delay. + * + * @param command the task to execute + * @param delay the time from now to delay execution + * @param unit the time unit of the delay parameter + * @return a ScheduledFuture representing pending completion of + * the task and whose <tt>get()</tt> method will return + * <tt>null</tt> upon completion + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + * @throws NullPointerException if command is null + */ + public ScheduledFuture<?> schedule(Runnable command, + long delay, TimeUnit unit); + + /** + * Creates and executes a ScheduledFuture that becomes enabled after the + * given delay. + * + * @param callable the function to execute + * @param delay the time from now to delay execution + * @param unit the time unit of the delay parameter + * @return a ScheduledFuture that can be used to extract result or cancel + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + * @throws NullPointerException if callable is null + */ + public <V> ScheduledFuture<V> schedule(Callable<V> callable, + long delay, TimeUnit unit); + + /** + * 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 + * <tt>initialDelay</tt> then <tt>initialDelay+period</tt>, then + * <tt>initialDelay + 2 * period</tt>, 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. + * + * @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 <tt>get()</tt> method will throw an + * exception upon cancellation + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + * @throws NullPointerException if command is null + * @throws IllegalArgumentException if period less than or equal to zero + */ + public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, + long initialDelay, + long period, + TimeUnit unit); + + /** + * 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. + * + * @param command the task to execute + * @param initialDelay the time to delay first execution + * @param delay the delay between the termination of one + * 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 <tt>get()</tt> method will throw an + * exception upon cancellation + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + * @throws NullPointerException if command is null + * @throws IllegalArgumentException if delay less than or equal to zero + */ + public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, + long initialDelay, + long delay, + TimeUnit unit); + +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/ScheduledFuture.java b/libjava/classpath/external/jsr166/java/util/concurrent/ScheduledFuture.java new file mode 100644 index 000000000..239d681f6 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/ScheduledFuture.java @@ -0,0 +1,19 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; + +/** + * A delayed result-bearing action that can be cancelled. + * Usually a scheduled future is the result of scheduling + * a task with a {@link ScheduledExecutorService}. + * + * @since 1.5 + * @author Doug Lea + * @param <V> The result type returned by this Future + */ +public interface ScheduledFuture<V> extends Delayed, Future<V> { +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/ScheduledThreadPoolExecutor.java b/libjava/classpath/external/jsr166/java/util/concurrent/ScheduledThreadPoolExecutor.java new file mode 100644 index 000000000..f08b9ac2e --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/ScheduledThreadPoolExecutor.java @@ -0,0 +1,626 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.concurrent.atomic.*; +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. + * + * <p> Delayed tasks execute no sooner than they are enabled, but + * without any real-time guarantees about when, after they are + * enabled, they will commence. Tasks scheduled for exactly the same + * execution time are enabled in first-in-first-out (FIFO) order of + * submission. + * + * <p>While this class inherits from {@link ThreadPoolExecutor}, a few + * of the inherited tuning methods are not useful for it. In + * particular, because it acts as a fixed-sized pool using + * <tt>corePoolSize</tt> threads and an unbounded queue, adjustments + * to <tt>maximumPoolSize</tt> have no useful effect. + * + * <p><b>Extension notes:</b> This class overrides {@link + * AbstractExecutorService} <tt>submit</tt> methods to generate + * internal objects to control per-task delays and scheduling. To + * preserve functionality, any further overrides of these methods in + * subclasses must invoke superclass versions, which effectively + * disables additional task customization. However, this class + * provides alternative protected extension method + * <tt>decorateTask</tt> (one version each for <tt>Runnable</tt> and + * <tt>Callable</tt>) that can be used to customize the concrete task + * types used to execute commands entered via <tt>execute</tt>, + * <tt>submit</tt>, <tt>schedule</tt>, <tt>scheduleAtFixedRate</tt>, + * and <tt>scheduleWithFixedDelay</tt>. By default, a + * <tt>ScheduledThreadPoolExecutor</tt> uses a task type extending + * {@link FutureTask}. However, this may be modified or replaced using + * subclasses of the form: + * + * <pre> + * public class CustomScheduledExecutor extends ScheduledThreadPoolExecutor { + * + * static class CustomTask<V> implements RunnableScheduledFuture<V> { ... } + * + * protected <V> RunnableScheduledFuture<V> decorateTask( + * Runnable r, RunnableScheduledFuture<V> task) { + * return new CustomTask<V>(r, task); + * } + * + * protected <V> RunnableScheduledFuture<V> decorateTask( + * Callable<V> c, RunnableScheduledFuture<V> task) { + * return new CustomTask<V>(c, task); + * } + * // ... add constructors, etc. + * } + * </pre> + * @since 1.5 + * @author Doug Lea + */ +public class ScheduledThreadPoolExecutor + extends ThreadPoolExecutor + implements ScheduledExecutorService { + + /** + * False if should cancel/suppress periodic tasks on shutdown. + */ + private volatile boolean continueExistingPeriodicTasksAfterShutdown; + + /** + * False if should cancel non-periodic tasks on shutdown. + */ + private volatile boolean executeExistingDelayedTasksAfterShutdown = true; + + /** + * Sequence number to break scheduling ties, and in turn to + * guarantee FIFO order among tied entries. + */ + private static final AtomicLong sequencer = new AtomicLong(0); + + /** Base of nanosecond timings, to avoid wrapping */ + private static final long NANO_ORIGIN = System.nanoTime(); + + /** + * Returns nanosecond time offset by origin + */ + final long now() { + return System.nanoTime() - NANO_ORIGIN; + } + + private class ScheduledFutureTask<V> + extends FutureTask<V> implements RunnableScheduledFuture<V> { + + /** Sequence number to break ties FIFO */ + private final long sequenceNumber; + /** The time the task is enabled to execute in nanoTime units */ + private 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. + */ + private final long period; + + /** + * Creates a one-shot action with given nanoTime-based trigger time. + */ + ScheduledFutureTask(Runnable r, V result, long ns) { + super(r, result); + this.time = ns; + this.period = 0; + this.sequenceNumber = sequencer.getAndIncrement(); + } + + /** + * Creates a periodic action with given nano time and period. + */ + ScheduledFutureTask(Runnable r, V result, long ns, long period) { + super(r, result); + this.time = ns; + this.period = period; + this.sequenceNumber = sequencer.getAndIncrement(); + } + + /** + * Creates a one-shot action with given nanoTime-based trigger. + */ + ScheduledFutureTask(Callable<V> callable, long ns) { + super(callable); + this.time = ns; + this.period = 0; + this.sequenceNumber = sequencer.getAndIncrement(); + } + + public long getDelay(TimeUnit unit) { + long d = unit.convert(time - now(), TimeUnit.NANOSECONDS); + return d; + } + + public int compareTo(Delayed other) { + if (other == this) // compare zero ONLY if same object + return 0; + if (other instanceof ScheduledFutureTask) { + ScheduledFutureTask<?> x = (ScheduledFutureTask<?>)other; + long diff = time - x.time; + if (diff < 0) + return -1; + else if (diff > 0) + return 1; + else if (sequenceNumber < x.sequenceNumber) + return -1; + else + return 1; + } + long d = (getDelay(TimeUnit.NANOSECONDS) - + other.getDelay(TimeUnit.NANOSECONDS)); + return (d == 0)? 0 : ((d < 0)? -1 : 1); + } + + /** + * Returns true if this is a periodic (not a one-shot) action. + * + * @return true if periodic + */ + public boolean isPeriodic() { + return period != 0; + } + + /** + * Runs a periodic task. + */ + private void runPeriodic() { + boolean ok = ScheduledFutureTask.super.runAndReset(); + boolean down = isShutdown(); + // Reschedule if not cancelled and not shutdown or policy allows + if (ok && (!down || + (getContinueExistingPeriodicTasksAfterShutdownPolicy() && + !isTerminating()))) { + long p = period; + if (p > 0) + time += p; + else + time = now() - p; + // Classpath local: ecj from eclipse 3.1 does not + // compile this. + // ScheduledThreadPoolExecutor.super.getQueue().add(this); + ScheduledThreadPoolExecutor.super.getQueue().add((Runnable) this); + } + // This might have been the final executed delayed + // task. Wake up threads to check. + else if (down) + interruptIdleWorkers(); + } + + /** + * Overrides FutureTask version so as to reset/requeue if periodic. + */ + public void run() { + if (isPeriodic()) + runPeriodic(); + else + ScheduledFutureTask.super.run(); + } + } + + /** + * Specialized variant of ThreadPoolExecutor.execute for delayed tasks. + */ + private void delayedExecute(Runnable command) { + if (isShutdown()) { + reject(command); + return; + } + // Prestart a thread if necessary. We cannot prestart it + // running the task because the task (probably) shouldn't be + // run yet, so thread will just idle until delay elapses. + if (getPoolSize() < getCorePoolSize()) + prestartCoreThread(); + + super.getQueue().add(command); + } + + /** + * Cancels and clears the queue of all tasks that should not be run + * due to shutdown policy. + */ + private void cancelUnwantedTasks() { + boolean keepDelayed = getExecuteExistingDelayedTasksAfterShutdownPolicy(); + boolean keepPeriodic = getContinueExistingPeriodicTasksAfterShutdownPolicy(); + if (!keepDelayed && !keepPeriodic) + super.getQueue().clear(); + else if (keepDelayed || keepPeriodic) { + Object[] entries = super.getQueue().toArray(); + for (int i = 0; i < entries.length; ++i) { + Object e = entries[i]; + if (e instanceof RunnableScheduledFuture) { + RunnableScheduledFuture<?> t = (RunnableScheduledFuture<?>)e; + if (t.isPeriodic()? !keepPeriodic : !keepDelayed) + t.cancel(false); + } + } + entries = null; + purge(); + } + } + + public boolean remove(Runnable task) { + if (!(task instanceof RunnableScheduledFuture)) + return false; + return getQueue().remove(task); + } + + /** + * Modifies or replaces the task used to execute a runnable. + * This method can be used to override the concrete + * class used for managing internal tasks. + * The default implementation simply returns the given task. + * + * @param runnable the submitted Runnable + * @param task the task created to execute the runnable + * @return a task that can execute the runnable + * @since 1.6 + */ + protected <V> RunnableScheduledFuture<V> decorateTask( + Runnable runnable, RunnableScheduledFuture<V> task) { + return task; + } + + /** + * Modifies or replaces the task used to execute a callable. + * This method can be used to override the concrete + * class used for managing internal tasks. + * The default implementation simply returns the given task. + * + * @param callable the submitted Callable + * @param task the task created to execute the callable + * @return a task that can execute the callable + * @since 1.6 + */ + protected <V> RunnableScheduledFuture<V> decorateTask( + Callable<V> callable, RunnableScheduledFuture<V> task) { + return task; + } + + /** + * Creates a new ScheduledThreadPoolExecutor with the given core + * pool size. + * + * @param corePoolSize the number of threads to keep in the pool, + * even if they are idle + * @throws IllegalArgumentException if <tt>corePoolSize < 0</tt> + */ + public ScheduledThreadPoolExecutor(int corePoolSize) { + super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS, + new DelayedWorkQueue()); + } + + /** + * Creates a new ScheduledThreadPoolExecutor with the given + * initial parameters. + * + * @param corePoolSize the number of threads to keep in the pool, + * even if they are idle + * @param threadFactory the factory to use when the executor + * creates a new thread + * @throws IllegalArgumentException if <tt>corePoolSize < 0</tt> + * @throws NullPointerException if threadFactory is null + */ + public ScheduledThreadPoolExecutor(int corePoolSize, + ThreadFactory threadFactory) { + super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS, + new DelayedWorkQueue(), threadFactory); + } + + /** + * Creates a new ScheduledThreadPoolExecutor with the given + * initial parameters. + * + * @param corePoolSize the number of threads to keep in the pool, + * even if they are idle + * @param handler the handler to use when execution is blocked + * because the thread bounds and queue capacities are reached + * @throws IllegalArgumentException if <tt>corePoolSize < 0</tt> + * @throws NullPointerException if handler is null + */ + public ScheduledThreadPoolExecutor(int corePoolSize, + RejectedExecutionHandler handler) { + super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS, + new DelayedWorkQueue(), handler); + } + + /** + * Creates a new ScheduledThreadPoolExecutor with the given + * initial parameters. + * + * @param corePoolSize the number of threads to keep in the pool, + * even if they are idle + * @param threadFactory the factory to use when the executor + * creates a new thread + * @param handler the handler to use when execution is blocked + * because the thread bounds and queue capacities are reached. + * @throws IllegalArgumentException if <tt>corePoolSize < 0</tt> + * @throws NullPointerException if threadFactory or handler is null + */ + public ScheduledThreadPoolExecutor(int corePoolSize, + ThreadFactory threadFactory, + RejectedExecutionHandler handler) { + super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS, + new DelayedWorkQueue(), threadFactory, handler); + } + + public ScheduledFuture<?> schedule(Runnable command, + long delay, + TimeUnit unit) { + if (command == null || unit == null) + throw new NullPointerException(); + long triggerTime = now() + unit.toNanos(delay); + RunnableScheduledFuture<?> t = decorateTask(command, + new ScheduledFutureTask<Boolean>(command, null, triggerTime)); + delayedExecute(t); + return t; + } + + public <V> ScheduledFuture<V> schedule(Callable<V> callable, + long delay, + TimeUnit unit) { + if (callable == null || unit == null) + throw new NullPointerException(); + if (delay < 0) delay = 0; + long triggerTime = now() + unit.toNanos(delay); + RunnableScheduledFuture<V> t = decorateTask(callable, + new ScheduledFutureTask<V>(callable, triggerTime)); + delayedExecute(t); + return t; + } + + public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, + long initialDelay, + long period, + TimeUnit unit) { + if (command == null || unit == null) + throw new NullPointerException(); + if (period <= 0) + throw new IllegalArgumentException(); + if (initialDelay < 0) initialDelay = 0; + long triggerTime = now() + unit.toNanos(initialDelay); + RunnableScheduledFuture<?> t = decorateTask(command, + new ScheduledFutureTask<Object>(command, + null, + triggerTime, + unit.toNanos(period))); + delayedExecute(t); + return t; + } + + public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, + long initialDelay, + long delay, + TimeUnit unit) { + if (command == null || unit == null) + throw new NullPointerException(); + if (delay <= 0) + throw new IllegalArgumentException(); + if (initialDelay < 0) initialDelay = 0; + long triggerTime = now() + unit.toNanos(initialDelay); + RunnableScheduledFuture<?> t = decorateTask(command, + new ScheduledFutureTask<Boolean>(command, + null, + triggerTime, + unit.toNanos(-delay))); + delayedExecute(t); + return t; + } + + + /** + * Executes command with zero required delay. This has effect + * equivalent to <tt>schedule(command, 0, anyUnit)</tt>. Note + * that inspections of the queue and of the list returned by + * <tt>shutdownNow</tt> will access the zero-delayed + * {@link ScheduledFuture}, not the <tt>command</tt> itself. + * + * @param command the task to execute + * @throws RejectedExecutionException at discretion of + * <tt>RejectedExecutionHandler</tt>, if task cannot be accepted + * for execution because the executor has been shut down. + * @throws NullPointerException if command is null + */ + public void execute(Runnable command) { + if (command == null) + throw new NullPointerException(); + schedule(command, 0, TimeUnit.NANOSECONDS); + } + + // Override AbstractExecutorService methods + + public Future<?> submit(Runnable task) { + return schedule(task, 0, TimeUnit.NANOSECONDS); + } + + public <T> Future<T> submit(Runnable task, T result) { + return schedule(Executors.callable(task, result), + 0, TimeUnit.NANOSECONDS); + } + + public <T> Future<T> submit(Callable<T> task) { + return schedule(task, 0, TimeUnit.NANOSECONDS); + } + + /** + * Sets the policy on whether to continue executing existing periodic + * tasks even when this executor has been <tt>shutdown</tt>. In + * this case, these tasks will only terminate upon + * <tt>shutdownNow</tt>, or after setting the policy to + * <tt>false</tt> when already shutdown. This value is by default + * false. + * + * @param value if true, continue after shutdown, else don't. + * @see #getContinueExistingPeriodicTasksAfterShutdownPolicy + */ + public void setContinueExistingPeriodicTasksAfterShutdownPolicy(boolean value) { + continueExistingPeriodicTasksAfterShutdown = value; + if (!value && isShutdown()) + cancelUnwantedTasks(); + } + + /** + * Gets the policy on whether to continue executing existing + * periodic tasks even when this executor has been + * <tt>shutdown</tt>. In this case, these tasks will only + * terminate upon <tt>shutdownNow</tt> or after setting the policy + * to <tt>false</tt> when already shutdown. This value is by + * default false. + * + * @return true if will continue after shutdown + * @see #setContinueExistingPeriodicTasksAfterShutdownPolicy + */ + public boolean getContinueExistingPeriodicTasksAfterShutdownPolicy() { + return continueExistingPeriodicTasksAfterShutdown; + } + + /** + * Sets the policy on whether to execute existing delayed + * tasks even when this executor has been <tt>shutdown</tt>. In + * this case, these tasks will only terminate upon + * <tt>shutdownNow</tt>, or after setting the policy to + * <tt>false</tt> when already shutdown. This value is by default + * true. + * + * @param value if true, execute after shutdown, else don't. + * @see #getExecuteExistingDelayedTasksAfterShutdownPolicy + */ + public void setExecuteExistingDelayedTasksAfterShutdownPolicy(boolean value) { + executeExistingDelayedTasksAfterShutdown = value; + if (!value && isShutdown()) + cancelUnwantedTasks(); + } + + /** + * Gets the policy on whether to execute existing delayed + * tasks even when this executor has been <tt>shutdown</tt>. In + * this case, these tasks will only terminate upon + * <tt>shutdownNow</tt>, or after setting the policy to + * <tt>false</tt> when already shutdown. This value is by default + * true. + * + * @return true if will execute after shutdown + * @see #setExecuteExistingDelayedTasksAfterShutdownPolicy + */ + public boolean getExecuteExistingDelayedTasksAfterShutdownPolicy() { + return executeExistingDelayedTasksAfterShutdown; + } + + + /** + * Initiates an orderly shutdown in which previously submitted + * tasks are executed, but no new tasks will be accepted. If the + * <tt>ExecuteExistingDelayedTasksAfterShutdownPolicy</tt> has + * been set <tt>false</tt>, existing delayed tasks whose delays + * have not yet elapsed are cancelled. And unless the + * <tt>ContinueExistingPeriodicTasksAfterShutdownPolicy</tt> has + * been set <tt>true</tt>, future executions of existing periodic + * tasks will be cancelled. + */ + public void shutdown() { + cancelUnwantedTasks(); + super.shutdown(); + } + + /** + * Attempts to stop all actively executing tasks, halts the + * processing of waiting tasks, and returns a list of the tasks + * that were awaiting execution. + * + * <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 + * 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 <tt>execute</tt>, which + * are for scheduling purposes used as the basis of a zero-delay + * <tt>ScheduledFuture</tt>. + * @throws SecurityException {@inheritDoc} + */ + public List<Runnable> shutdownNow() { + return super.shutdownNow(); + } + + /** + * Returns the task queue used by this executor. Each element of + * this queue is a {@link ScheduledFuture}, including those + * tasks submitted using <tt>execute</tt> which are for scheduling + * purposes used as the basis of a zero-delay + * <tt>ScheduledFuture</tt>. Iteration over this queue is + * <em>not</em> guaranteed to traverse tasks in the order in + * which they will execute. + * + * @return the task queue + */ + public BlockingQueue<Runnable> getQueue() { + return super.getQueue(); + } + + /** + * An annoying wrapper class to convince javac to use a + * DelayQueue<RunnableScheduledFuture> as a BlockingQueue<Runnable> + */ + private static class DelayedWorkQueue + extends AbstractCollection<Runnable> + implements BlockingQueue<Runnable> { + + private final DelayQueue<RunnableScheduledFuture> dq = new DelayQueue<RunnableScheduledFuture>(); + public Runnable poll() { return dq.poll(); } + public Runnable peek() { return dq.peek(); } + public Runnable take() throws InterruptedException { return dq.take(); } + public Runnable poll(long timeout, TimeUnit unit) throws InterruptedException { + return dq.poll(timeout, unit); + } + + public boolean add(Runnable x) { + return dq.add((RunnableScheduledFuture)x); + } + public boolean offer(Runnable x) { + return dq.offer((RunnableScheduledFuture)x); + } + public void put(Runnable x) { + dq.put((RunnableScheduledFuture)x); + } + public boolean offer(Runnable x, long timeout, TimeUnit unit) { + return dq.offer((RunnableScheduledFuture)x, timeout, unit); + } + + public Runnable remove() { return dq.remove(); } + public Runnable element() { return dq.element(); } + public void clear() { dq.clear(); } + public int drainTo(Collection<? super Runnable> c) { return dq.drainTo(c); } + public int drainTo(Collection<? super Runnable> c, int maxElements) { + return dq.drainTo(c, maxElements); + } + + public int remainingCapacity() { return dq.remainingCapacity(); } + public boolean remove(Object x) { return dq.remove(x); } + public boolean contains(Object x) { return dq.contains(x); } + public int size() { return dq.size(); } + public boolean isEmpty() { return dq.isEmpty(); } + public Object[] toArray() { return dq.toArray(); } + public <T> T[] toArray(T[] array) { return dq.toArray(array); } + public Iterator<Runnable> iterator() { + return new Iterator<Runnable>() { + private Iterator<RunnableScheduledFuture> it = dq.iterator(); + public boolean hasNext() { return it.hasNext(); } + public Runnable next() { return it.next(); } + public void remove() { it.remove(); } + }; + } + } +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/Semaphore.java b/libjava/classpath/external/jsr166/java/util/concurrent/Semaphore.java new file mode 100644 index 000000000..105236439 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/Semaphore.java @@ -0,0 +1,681 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.*; +import java.util.concurrent.locks.*; +import java.util.concurrent.atomic.*; + +/** + * A counting semaphore. Conceptually, a semaphore maintains a set of + * permits. Each {@link #acquire} blocks if necessary until a permit is + * available, and then takes it. Each {@link #release} adds a permit, + * potentially releasing a blocking acquirer. + * However, no actual permit objects are used; the {@code Semaphore} just + * keeps a count of the number available and acts accordingly. + * + * <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> + * class Pool { + * private static final int MAX_AVAILABLE = 100; + * private final Semaphore available = new Semaphore(MAX_AVAILABLE, true); + * + * public Object getItem() throws InterruptedException { + * available.acquire(); + * return getNextAvailableItem(); + * } + * + * public void putItem(Object x) { + * if (markAsUnused(x)) + * available.release(); + * } + * + * // Not a particularly efficient data structure; just for demo + * + * protected Object[] items = ... whatever kinds of items being managed + * protected boolean[] used = new boolean[MAX_AVAILABLE]; + * + * protected synchronized Object getNextAvailableItem() { + * for (int i = 0; i < MAX_AVAILABLE; ++i) { + * if (!used[i]) { + * used[i] = true; + * return items[i]; + * } + * } + * return null; // not reached + * } + * + * protected synchronized boolean markAsUnused(Object item) { + * for (int i = 0; i < MAX_AVAILABLE; ++i) { + * if (item == items[i]) { + * if (used[i]) { + * used[i] = false; + * return true; + * } else + * return false; + * } + * } + * return false; + * } + * + * } + * </pre> + * + * <p>Before obtaining an item each thread must acquire a permit from + * the semaphore, guaranteeing that an item is available for use. When + * the thread has finished with the item it is returned back to the + * pool and a permit is returned to the semaphore, allowing another + * thread to acquire that item. Note that no synchronization lock is + * held when {@link #acquire} is called as that would prevent an item + * from being returned to the pool. The semaphore encapsulates the + * synchronization needed to restrict access to the pool, separately + * from any synchronization needed to maintain the consistency of the + * pool itself. + * + * <p>A semaphore initialized to one, and which is used such that it + * only has at most one permit available, can serve as a mutual + * exclusion lock. This is more commonly known as a <em>binary + * semaphore</em>, because it only has two states: one permit + * available, or zero permits available. When used in this way, the + * binary semaphore has the property (unlike many {@link Lock} + * implementations), that the "lock" can be released by a + * thread other than the owner (as semaphores have no notion of + * ownership). This can be useful in some specialized contexts, such + * as deadlock recovery. + * + * <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 + * invoking {@link #acquire} can be allocated a permit ahead of a + * thread that has been waiting - logically the new thread places itself at + * the head of the queue of waiting threads. When fairness is set true, the + * semaphore guarantees that threads invoking any of the {@link + * #acquire() acquire} methods are selected to obtain permits in the order in + * which their invocation of those methods was processed + * (first-in-first-out; FIFO). Note that FIFO ordering necessarily + * applies to specific internal points of execution within these + * methods. So, it is possible for one thread to invoke + * {@code acquire} before another, but reach the ordering point after + * the other, and similarly upon return from the method. + * Also note that the untimed {@link #tryAcquire() tryAcquire} methods do not + * honor the fairness setting, but will take any permits that are + * available. + * + * <p>Generally, semaphores used to control resource access should be + * initialized as fair, to ensure that no thread is starved out from + * accessing a resource. When using semaphores for other kinds of + * synchronization control, the throughput advantages of non-fair + * ordering often outweigh fairness considerations. + * + * <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. + * + * <p>Memory consistency effects: Actions in a thread prior to calling + * a "release" method such as {@code release()} + * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a> + * actions following a successful "acquire" method such as {@code acquire()} + * in another thread. + * + * @since 1.5 + * @author Doug Lea + * + */ + +public class Semaphore implements java.io.Serializable { + private static final long serialVersionUID = -3222578661600680210L; + /** All mechanics via AbstractQueuedSynchronizer subclass */ + private final Sync sync; + + /** + * Synchronization implementation for semaphore. Uses AQS state + * to represent permits. Subclassed into fair and nonfair + * versions. + */ + abstract static class Sync extends AbstractQueuedSynchronizer { + private static final long serialVersionUID = 1192457210091910933L; + + Sync(int permits) { + setState(permits); + } + + final int getPermits() { + return getState(); + } + + final int nonfairTryAcquireShared(int acquires) { + for (;;) { + int available = getState(); + int remaining = available - acquires; + if (remaining < 0 || + compareAndSetState(available, remaining)) + return remaining; + } + } + + protected final boolean tryReleaseShared(int releases) { + for (;;) { + int p = getState(); + if (compareAndSetState(p, p + releases)) + return true; + } + } + + final void reducePermits(int reductions) { + for (;;) { + int current = getState(); + int next = current - reductions; + if (compareAndSetState(current, next)) + return; + } + } + + final int drainPermits() { + for (;;) { + int current = getState(); + if (current == 0 || compareAndSetState(current, 0)) + return current; + } + } + } + + /** + * NonFair version + */ + final static class NonfairSync extends Sync { + private static final long serialVersionUID = -2694183684443567898L; + + NonfairSync(int permits) { + super(permits); + } + + protected int tryAcquireShared(int acquires) { + return nonfairTryAcquireShared(acquires); + } + } + + /** + * Fair version + */ + final static class FairSync extends Sync { + private static final long serialVersionUID = 2014338818796000944L; + + FairSync(int permits) { + super(permits); + } + + protected int tryAcquireShared(int acquires) { + Thread current = Thread.currentThread(); + for (;;) { + Thread first = getFirstQueuedThread(); + if (first != null && first != current) + return -1; + int available = getState(); + int remaining = available - acquires; + if (remaining < 0 || + compareAndSetState(available, remaining)) + return remaining; + } + } + } + + /** + * Creates a {@code Semaphore} with the given number of + * permits and nonfair fairness setting. + * + * @param permits the initial number of permits available. + * This value may be negative, in which case releases + * must occur before any acquires will be granted. + */ + public Semaphore(int permits) { + sync = new NonfairSync(permits); + } + + /** + * Creates a {@code Semaphore} with the given number of + * permits and the given fairness setting. + * + * @param permits the initial number of permits available. + * This value may be negative, in which case releases + * must occur before any acquires will be granted. + * @param fair {@code true} if this semaphore will guarantee + * first-in first-out granting of permits under contention, + * else {@code false} + */ + public Semaphore(int permits, boolean fair) { + sync = (fair)? new FairSync(permits) : new NonfairSync(permits); + } + + /** + * Acquires a permit from this semaphore, blocking until one is + * available, or the thread is {@linkplain Thread#interrupt interrupted}. + * + * <p>Acquires a permit, if one is available and returns immediately, + * reducing the number of available permits by one. + * + * <p>If no permit is 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 the {@link #release} method for this + * semaphore and the current thread is next to be assigned a permit; or + * <li>Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread. + * </ul> + * + * <p>If the current thread: + * <ul> + * <li>has its interrupted status set on entry to this method; or + * <li>is {@linkplain Thread#interrupt interrupted} while waiting + * for a permit, + * </ul> + * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * + * @throws InterruptedException if the current thread is interrupted + */ + public void acquire() throws InterruptedException { + sync.acquireSharedInterruptibly(1); + } + + /** + * Acquires a permit from this semaphore, blocking until one is + * available. + * + * <p>Acquires a permit, if one is available and returns immediately, + * reducing the number of available permits by one. + * + * <p>If no permit is available then the current thread becomes + * disabled for thread scheduling purposes and lies dormant until + * some other thread invokes the {@link #release} method for this + * semaphore and the current thread is next to be assigned a permit. + * + * <p>If the current thread is {@linkplain Thread#interrupt interrupted} + * while waiting for a permit then it will continue to wait, but the + * time at which the thread is assigned a permit may change compared to + * the time it would have received the permit had no interruption + * occurred. When the thread does return from this method its interrupt + * status will be set. + */ + public void acquireUninterruptibly() { + sync.acquireShared(1); + } + + /** + * Acquires a permit from this semaphore, only if one is available at the + * time of invocation. + * + * <p>Acquires a permit, if one is available and returns immediately, + * with the value {@code true}, + * reducing the number of available permits by one. + * + * <p>If no permit is available then this method will return + * immediately with the value {@code false}. + * + * <p>Even when this semaphore has been set to use a + * fair ordering policy, a call to {@code tryAcquire()} <em>will</em> + * immediately acquire a permit if one is available, whether or not + * other threads are currently waiting. + * This "barging" behavior can be useful in certain + * circumstances, even though it breaks fairness. If you want to honor + * the fairness setting, then use + * {@link #tryAcquire(long, TimeUnit) tryAcquire(0, TimeUnit.SECONDS) } + * which is almost equivalent (it also detects interruption). + * + * @return {@code true} if a permit was acquired and {@code false} + * otherwise + */ + public boolean tryAcquire() { + return sync.nonfairTryAcquireShared(1) >= 0; + } + + /** + * Acquires a permit from this semaphore, if one becomes available + * within the given waiting time and the current thread has not + * been {@linkplain Thread#interrupt interrupted}. + * + * <p>Acquires a permit, if one is available and returns immediately, + * with the value {@code true}, + * reducing the number of available permits by one. + * + * <p>If no permit is available then the current thread becomes + * disabled for thread scheduling purposes and lies dormant until + * one of three things happens: + * <ul> + * <li>Some other thread invokes the {@link #release} method for this + * semaphore and the current thread is next to be assigned a permit; or + * <li>Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread; or + * <li>The specified waiting time elapses. + * </ul> + * + * <p>If a permit is acquired then the value {@code true} is returned. + * + * <p>If the current thread: + * <ul> + * <li>has its interrupted status set on entry to this method; or + * <li>is {@linkplain Thread#interrupt interrupted} while waiting + * to acquire a permit, + * </ul> + * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * + * <p>If the specified waiting time elapses then the value {@code false} + * is returned. If the time is less than or equal to zero, the method + * will not wait at all. + * + * @param timeout the maximum time to wait for a permit + * @param unit the time unit of the {@code timeout} argument + * @return {@code true} if a permit was acquired and {@code false} + * if the waiting time elapsed before a permit was acquired + * @throws InterruptedException if the current thread is interrupted + */ + public boolean tryAcquire(long timeout, TimeUnit unit) + throws InterruptedException { + return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout)); + } + + /** + * Releases a permit, returning it to the semaphore. + * + * <p>Releases a permit, increasing the number of available permits by + * one. If any threads are trying to acquire a permit, then one is + * selected and given the permit that was just released. That thread + * is (re)enabled for thread scheduling purposes. + * + * <p>There is no requirement that a thread that releases a permit must + * have acquired that permit by calling {@link #acquire}. + * Correct usage of a semaphore is established by programming convention + * in the application. + */ + public void release() { + sync.releaseShared(1); + } + + /** + * Acquires the given number of permits from this semaphore, + * blocking until all are available, + * or the thread is {@linkplain Thread#interrupt interrupted}. + * + * <p>Acquires the given number of permits, if they are available, + * and returns immediately, reducing the number of available permits + * by the given amount. + * + * <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 + * permits and the number of available permits satisfies this request; or + * <li>Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread. + * </ul> + * + * <p>If the current thread: + * <ul> + * <li>has its interrupted status set on entry to this method; or + * <li>is {@linkplain Thread#interrupt interrupted} while waiting + * for a permit, + * </ul> + * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * Any permits that were to be assigned to this thread are instead + * assigned to other threads trying to acquire permits, as if + * permits had been made available by a call to {@link #release()}. + * + * @param permits the number of permits to acquire + * @throws InterruptedException if the current thread is interrupted + * @throws IllegalArgumentException if {@code permits} is negative + */ + public void acquire(int permits) throws InterruptedException { + if (permits < 0) throw new IllegalArgumentException(); + sync.acquireSharedInterruptibly(permits); + } + + /** + * Acquires the given number of permits from this semaphore, + * blocking until all are available. + * + * <p>Acquires the given number of permits, if they are available, + * and returns immediately, reducing the number of available permits + * by the given amount. + * + * <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 + * permits and the number of available permits satisfies this request. + * + * <p>If the current thread is {@linkplain Thread#interrupt interrupted} + * while waiting for permits then it will continue to wait and its + * position in the queue is not affected. When the thread does return + * from this method its interrupt status will be set. + * + * @param permits the number of permits to acquire + * @throws IllegalArgumentException if {@code permits} is negative + * + */ + public void acquireUninterruptibly(int permits) { + if (permits < 0) throw new IllegalArgumentException(); + sync.acquireShared(permits); + } + + /** + * Acquires the given number of permits from this semaphore, only + * if all are available at the time of invocation. + * + * <p>Acquires the given number of permits, if they are available, and + * returns immediately, with the value {@code true}, + * reducing the number of available permits by the given amount. + * + * <p>If insufficient permits are available then this method will return + * immediately with the value {@code false} and the number of available + * permits is unchanged. + * + * <p>Even when this semaphore has been set to use a fair ordering + * policy, a call to {@code tryAcquire} <em>will</em> + * immediately acquire a permit if one is available, whether or + * not other threads are currently waiting. This + * "barging" behavior can be useful in certain + * circumstances, even though it breaks fairness. If you want to + * honor the fairness setting, then use {@link #tryAcquire(int, + * long, TimeUnit) tryAcquire(permits, 0, TimeUnit.SECONDS) } + * which is almost equivalent (it also detects interruption). + * + * @param permits the number of permits to acquire + * @return {@code true} if the permits were acquired and + * {@code false} otherwise + * @throws IllegalArgumentException if {@code permits} is negative + */ + public boolean tryAcquire(int permits) { + if (permits < 0) throw new IllegalArgumentException(); + return sync.nonfairTryAcquireShared(permits) >= 0; + } + + /** + * Acquires the given number of permits from this semaphore, if all + * become available within the given waiting time and the current + * thread has not been {@linkplain Thread#interrupt interrupted}. + * + * <p>Acquires the given number of permits, if they are available and + * returns immediately, with the value {@code true}, + * reducing the number of available permits by the given amount. + * + * <p>If insufficient permits are available then + * the current thread becomes disabled for thread scheduling + * 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 + * permits and the number of available permits satisfies this request; or + * <li>Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread; or + * <li>The specified waiting time elapses. + * </ul> + * + * <p>If the permits are acquired then the value {@code true} is returned. + * + * <p>If the current thread: + * <ul> + * <li>has its interrupted status set on entry to this method; or + * <li>is {@linkplain Thread#interrupt interrupted} while waiting + * to acquire the permits, + * </ul> + * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * Any permits that were to be assigned to this thread, are instead + * assigned to other threads trying to acquire permits, as if + * the permits had been made available by a call to {@link #release()}. + * + * <p>If the specified waiting time elapses then the value {@code false} + * is returned. If the time is less than or equal to zero, the method + * will not wait at all. Any permits that were to be assigned to this + * thread, are instead assigned to other threads trying to acquire + * permits, as if the permits had been made available by a call to + * {@link #release()}. + * + * @param permits the number of permits to acquire + * @param timeout the maximum time to wait for the permits + * @param unit the time unit of the {@code timeout} argument + * @return {@code true} if all permits were acquired and {@code false} + * if the waiting time elapsed before all permits were acquired + * @throws InterruptedException if the current thread is interrupted + * @throws IllegalArgumentException if {@code permits} is negative + */ + public boolean tryAcquire(int permits, long timeout, TimeUnit unit) + throws InterruptedException { + if (permits < 0) throw new IllegalArgumentException(); + return sync.tryAcquireSharedNanos(permits, unit.toNanos(timeout)); + } + + /** + * Releases the given number of permits, returning them to the semaphore. + * + * <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 + * 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; + * otherwise the thread will wait until sufficient permits are available. + * If there are still permits available + * after this thread's request has been satisfied, then those permits + * are assigned in turn to other threads trying to acquire permits. + * + * <p>There is no requirement that a thread that releases a permit must + * have acquired that permit by calling {@link Semaphore#acquire acquire}. + * Correct usage of a semaphore is established by programming convention + * in the application. + * + * @param permits the number of permits to release + * @throws IllegalArgumentException if {@code permits} is negative + */ + public void release(int permits) { + if (permits < 0) throw new IllegalArgumentException(); + sync.releaseShared(permits); + } + + /** + * Returns the current number of permits available in this semaphore. + * + * <p>This method is typically used for debugging and testing purposes. + * + * @return the number of permits available in this semaphore + */ + public int availablePermits() { + return sync.getPermits(); + } + + /** + * Acquires and returns all permits that are immediately available. + * + * @return the number of permits acquired + */ + public int drainPermits() { + return sync.drainPermits(); + } + + /** + * Shrinks the number of available permits by the indicated + * reduction. This method can be useful in subclasses that use + * semaphores to track resources that become unavailable. This + * method differs from {@code acquire} in that it does not block + * waiting for permits to become available. + * + * @param reduction the number of permits to remove + * @throws IllegalArgumentException if {@code reduction} is negative + */ + protected void reducePermits(int reduction) { + if (reduction < 0) throw new IllegalArgumentException(); + sync.reducePermits(reduction); + } + + /** + * Returns {@code true} if this semaphore has fairness set true. + * + * @return {@code true} if this semaphore has fairness set true + */ + public boolean isFair() { + return sync instanceof FairSync; + } + + /** + * Queries whether any threads are waiting to acquire. Note that + * because cancellations may occur at any time, a {@code true} + * return does not guarantee that any other thread will ever + * acquire. This method is designed primarily for use in + * monitoring of the system state. + * + * @return {@code true} if there may be other threads waiting to + * acquire the lock + */ + public final boolean hasQueuedThreads() { + return sync.hasQueuedThreads(); + } + + /** + * 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 + * system state, not for synchronization control. + * + * @return the estimated number of threads waiting for this lock + */ + public final int getQueueLength() { + return sync.getQueueLength(); + } + + /** + * Returns a collection containing threads that may be waiting to acquire. + * Because the actual set of threads may change dynamically while + * constructing this result, the returned collection is only a best-effort + * estimate. The elements of the returned collection are in no particular + * order. This method is designed to facilitate construction of + * subclasses that provide more extensive monitoring facilities. + * + * @return the collection of threads + */ + protected Collection<Thread> getQueuedThreads() { + return sync.getQueuedThreads(); + } + + /** + * Returns a string identifying this semaphore, as well as its state. + * The state, in brackets, includes the String {@code "Permits ="} + * followed by the number of permits. + * + * @return a string identifying this semaphore, as well as its state + */ + public String toString() { + return super.toString() + "[Permits = " + sync.getPermits() + "]"; + } +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/SynchronousQueue.java b/libjava/classpath/external/jsr166/java/util/concurrent/SynchronousQueue.java new file mode 100644 index 000000000..92f586ce8 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/SynchronousQueue.java @@ -0,0 +1,1127 @@ +/* + * Written by Doug Lea, Bill Scherer, and Michael Scott with + * assistance from members of JCP JSR-166 Expert Group and released to + * the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.concurrent.locks.*; +import java.util.concurrent.atomic.*; +import java.util.*; + +/** + * A {@linkplain BlockingQueue blocking queue} in which each insert + * operation must wait for a corresponding remove operation by another + * thread, and vice versa. A synchronous queue does not have any + * internal capacity, not even a capacity of one. You cannot + * <tt>peek</tt> at a synchronous queue because an element is only + * present when you try to remove it; you cannot insert an element + * (using any method) unless another thread is trying to remove it; + * you cannot iterate as there is nothing to iterate. The + * <em>head</em> of the queue is the element that the first queued + * inserting thread is trying to add to the queue; if there is no such + * queued thread then no element is available for removal and + * <tt>poll()</tt> will return <tt>null</tt>. For purposes of other + * <tt>Collection</tt> methods (for example <tt>contains</tt>), a + * <tt>SynchronousQueue</tt> acts as an empty collection. This queue + * does not permit <tt>null</tt> elements. + * + * <p>Synchronous queues are similar to rendezvous channels used in + * CSP and Ada. They are well suited for handoff designs, in which an + * object running in one thread must sync up with an object running + * in another thread in order to hand it some information, event, or + * task. + * + * <p> This class supports an optional fairness policy for ordering + * waiting producer and consumer threads. By default, this ordering + * is not guaranteed. However, a queue constructed with fairness set + * to <tt>true</tt> grants threads access in FIFO order. + * + * <p>This class and its iterator implement all of the + * <em>optional</em> methods of the {@link Collection} and {@link + * Iterator} interfaces. + * + * <p>This class is a member of the + * <a href="{@docRoot}/../technotes/guides/collections/index.html"> + * Java Collections Framework</a>. + * + * @since 1.5 + * @author Doug Lea and Bill Scherer and Michael Scott + * @param <E> the type of elements held in this collection + */ +public class SynchronousQueue<E> extends AbstractQueue<E> + implements BlockingQueue<E>, java.io.Serializable { + private static final long serialVersionUID = -3223113410248163686L; + + /* + * This class implements extensions of the dual stack and dual + * queue algorithms described in "Nonblocking Concurrent Objects + * with Condition Synchronization", by W. N. Scherer III and + * M. L. Scott. 18th Annual Conf. on Distributed Computing, + * Oct. 2004 (see also + * http://www.cs.rochester.edu/u/scott/synchronization/pseudocode/duals.html). + * The (Lifo) stack is used for non-fair mode, and the (Fifo) + * queue for fair mode. The performance of the two is generally + * similar. Fifo usually supports higher throughput under + * contention but Lifo maintains higher thread locality in common + * applications. + * + * A dual queue (and similarly stack) is one that at any given + * time either holds "data" -- items provided by put operations, + * or "requests" -- slots representing take operations, or is + * empty. A call to "fulfill" (i.e., a call requesting an item + * from a queue holding data or vice versa) dequeues a + * complementary node. The most interesting feature of these + * queues is that any operation can figure out which mode the + * queue is in, and act accordingly without needing locks. + * + * Both the queue and stack extend abstract class Transferer + * defining the single method transfer that does a put or a + * take. These are unified into a single method because in dual + * data structures, the put and take operations are symmetrical, + * so nearly all code can be combined. The resulting transfer + * methods are on the long side, but are easier to follow than + * they would be if broken up into nearly-duplicated parts. + * + * The queue and stack data structures share many conceptual + * similarities but very few concrete details. For simplicity, + * they are kept distinct so that they can later evolve + * separately. + * + * The algorithms here differ from the versions in the above paper + * in extending them for use in synchronous queues, as well as + * dealing with cancellation. The main differences include: + * + * 1. The original algorithms used bit-marked pointers, but + * the ones here use mode bits in nodes, leading to a number + * of further adaptations. + * 2. SynchronousQueues must block threads waiting to become + * fulfilled. + * 3. Support for cancellation via timeout and interrupts, + * including cleaning out cancelled nodes/threads + * from lists to avoid garbage retention and memory depletion. + * + * Blocking is mainly accomplished using LockSupport park/unpark, + * except that nodes that appear to be the next ones to become + * fulfilled first spin a bit (on multiprocessors only). On very + * busy synchronous queues, spinning can dramatically improve + * throughput. And on less busy ones, the amount of spinning is + * small enough not to be noticeable. + * + * Cleaning is done in different ways in queues vs stacks. For + * queues, we can almost always remove a node immediately in O(1) + * time (modulo retries for consistency checks) when it is + * cancelled. But if it may be pinned as the current tail, it must + * wait until some subsequent cancellation. For stacks, we need a + * potentially O(n) traversal to be sure that we can remove the + * node, but this can run concurrently with other threads + * accessing the stack. + * + * While garbage collection takes care of most node reclamation + * issues that otherwise complicate nonblocking algorithms, care + * is taken to "forget" references to data, other nodes, and + * threads that might be held on to long-term by blocked + * threads. In cases where setting to null would otherwise + * conflict with main algorithms, this is done by changing a + * node's link to now point to the node itself. This doesn't arise + * much for Stack nodes (because blocked threads do not hang on to + * old head pointers), but references in Queue nodes must be + * aggressively forgotten to avoid reachability of everything any + * node has ever referred to since arrival. + */ + + /** + * Shared internal API for dual stacks and queues. + */ + static abstract class Transferer { + /** + * Performs a put or take. + * + * @param e if non-null, the item to be handed to a consumer; + * if null, requests that transfer return an item + * offered by producer. + * @param timed if this operation should timeout + * @param nanos the timeout, in nanoseconds + * @return if non-null, the item provided or received; if null, + * the operation failed due to timeout or interrupt -- + * the caller can distinguish which of these occurred + * by checking Thread.interrupted. + */ + abstract Object transfer(Object 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 + * variety of processors and OSes. Empirically, the best value + * seems not to vary with number of CPUs (beyond 2) so is just + * a constant. + */ + static final int maxTimedSpins = (NCPUS < 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; + + /** + * 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; + + /** Dual stack */ + static final class TransferStack extends Transferer { + /* + * This extends Scherer-Scott dual stack algorithm, differing, + * among other ways, by using "covering" nodes rather than + * bit-marked pointers: Fulfilling operations push on marker + * nodes (with FULFILLING bit set in mode) to reserve a spot + * to match a waiting node. + */ + + /* Modes for SNodes, ORed together in node fields */ + /** Node represents an unfulfilled consumer */ + static final int REQUEST = 0; + /** Node represents an unfulfilled producer */ + static final int DATA = 1; + /** Node is fulfilling another unfulfilled DATA or REQUEST */ + static final int FULFILLING = 2; + + /** Return true if m has fulfilling bit set */ + static boolean isFulfilling(int m) { return (m & FULFILLING) != 0; } + + /** Node class for TransferStacks. */ + static final class SNode { + volatile SNode next; // next node in stack + volatile SNode match; // the node matched to this + volatile Thread waiter; // to control park/unpark + Object item; // data; or null for REQUESTs + int mode; + // Note: item and mode fields don't need to be volatile + // since they are always written before, and read after, + // other volatile/atomic operations. + + SNode(Object item) { + this.item = item; + } + + static final AtomicReferenceFieldUpdater<SNode, SNode> + nextUpdater = AtomicReferenceFieldUpdater.newUpdater + (SNode.class, SNode.class, "next"); + + boolean casNext(SNode cmp, SNode val) { + return (cmp == next && + nextUpdater.compareAndSet(this, cmp, val)); + } + + static final AtomicReferenceFieldUpdater<SNode, SNode> + matchUpdater = AtomicReferenceFieldUpdater.newUpdater + (SNode.class, SNode.class, "match"); + + /** + * Tries to match node s to this node, if so, waking up thread. + * Fulfillers call tryMatch to identify their waiters. + * Waiters block until they have been matched. + * + * @param s the node to match + * @return true if successfully matched to s + */ + boolean tryMatch(SNode s) { + if (match == null && + matchUpdater.compareAndSet(this, null, s)) { + Thread w = waiter; + if (w != null) { // waiters need at most one unpark + waiter = null; + LockSupport.unpark(w); + } + return true; + } + return match == s; + } + + /** + * Tries to cancel a wait by matching node to itself. + */ + void tryCancel() { + matchUpdater.compareAndSet(this, null, this); + } + + boolean isCancelled() { + return match == this; + } + } + + /** The head (top) of the stack */ + volatile SNode head; + + static final AtomicReferenceFieldUpdater<TransferStack, SNode> + headUpdater = AtomicReferenceFieldUpdater.newUpdater + (TransferStack.class, SNode.class, "head"); + + boolean casHead(SNode h, SNode nh) { + return h == head && headUpdater.compareAndSet(this, h, nh); + } + + /** + * Creates or resets fields of a node. Called only from transfer + * where the node to push on stack is lazily created and + * reused when possible to help reduce intervals between reads + * and CASes of head and to avoid surges of garbage when CASes + * to push nodes fail due to contention. + */ + static SNode snode(SNode s, Object e, SNode next, int mode) { + if (s == null) s = new SNode(e); + s.mode = mode; + s.next = next; + return s; + } + + /** + * Puts or takes an item. + */ + Object transfer(Object e, boolean timed, long nanos) { + /* + * Basic algorithm is to loop trying one of three actions: + * + * 1. If apparently empty or already containing nodes of same + * mode, try to push node on stack and wait for a match, + * returning it, or null if cancelled. + * + * 2. If apparently containing node of complementary mode, + * try to push a fulfilling node on to stack, match + * with corresponding waiting node, pop both from + * stack, and return matched item. The matching or + * unlinking might not actually be necessary because of + * other threads performing action 3: + * + * 3. If top of stack already holds another fulfilling node, + * help it out by doing its match and/or pop + * operations, and then continue. The code for helping + * is essentially the same as for fulfilling, except + * that it doesn't return the item. + */ + + SNode s = null; // constructed/reused as needed + int mode = (e == null)? REQUEST : DATA; + + for (;;) { + SNode h = head; + if (h == null || h.mode == mode) { // empty or same-mode + if (timed && nanos <= 0) { // can't wait + if (h != null && h.isCancelled()) + casHead(h, h.next); // pop cancelled node + else + return null; + } else if (casHead(h, s = snode(s, e, h, mode))) { + SNode m = awaitFulfill(s, timed, nanos); + if (m == s) { // wait was cancelled + clean(s); + return null; + } + if ((h = head) != null && h.next == s) + casHead(h, s.next); // help s's fulfiller + return mode == REQUEST? m.item : s.item; + } + } else if (!isFulfilling(h.mode)) { // try to fulfill + if (h.isCancelled()) // already cancelled + casHead(h, h.next); // pop and retry + else if (casHead(h, s=snode(s, e, h, FULFILLING|mode))) { + for (;;) { // loop until matched or waiters disappear + SNode m = s.next; // m is s's match + if (m == null) { // all waiters are gone + casHead(s, null); // pop fulfill node + s = null; // use new node next time + break; // restart main loop + } + SNode mn = m.next; + if (m.tryMatch(s)) { + casHead(s, mn); // pop both s and m + return (mode == REQUEST)? m.item : s.item; + } else // lost match + s.casNext(m, mn); // help unlink + } + } + } else { // help a fulfiller + SNode m = h.next; // m is h's match + if (m == null) // waiter is gone + casHead(h, null); // pop fulfilling node + else { + SNode mn = m.next; + if (m.tryMatch(h)) // help match + casHead(h, mn); // pop both h and m + else // lost match + h.casNext(m, mn); // help unlink + } + } + } + } + + /** + * Spins/blocks until node s is matched by a fulfill operation. + * + * @param s the waiting node + * @param timed true if timed wait + * @param nanos timeout value + * @return matched node, or s if cancelled + */ + SNode awaitFulfill(SNode s, boolean timed, long nanos) { + /* + * When a node/thread is about to block, it sets its waiter + * field and then rechecks state at least one more time + * before actually parking, thus covering race vs + * fulfiller noticing that waiter is non-null so should be + * woken. + * + * When invoked by nodes that appear at the point of call + * to be at the head of the stack, calls to park are + * preceded by spins to avoid blocking when producers and + * consumers are arriving very close in time. This can + * happen enough to bother only on multiprocessors. + * + * The order of checks for returning out of main loop + * reflects fact that interrupts have precedence over + * normal returns, which have precedence over + * timeouts. (So, on timeout, one last check for match is + * done before giving up.) Except that calls from untimed + * SynchronousQueue.{poll/offer} don't check interrupts + * and don't wait at all, so are trapped in transfer + * method rather than calling awaitFulfill. + */ + long lastTime = (timed)? System.nanoTime() : 0; + Thread w = Thread.currentThread(); + SNode h = head; + int spins = (shouldSpin(s)? + (timed? maxTimedSpins : maxUntimedSpins) : 0); + for (;;) { + if (w.isInterrupted()) + s.tryCancel(); + SNode m = s.match; + if (m != null) + return m; + if (timed) { + long now = System.nanoTime(); + nanos -= now - lastTime; + lastTime = now; + if (nanos <= 0) { + s.tryCancel(); + continue; + } + } + if (spins > 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) + LockSupport.parkNanos(this, nanos); + } + } + + /** + * Returns true if node s is at head or there is an active + * fulfiller. + */ + boolean shouldSpin(SNode s) { + SNode h = head; + return (h == s || h == null || isFulfilling(h.mode)); + } + + /** + * Unlinks s from the stack. + */ + void clean(SNode s) { + s.item = null; // forget item + s.waiter = null; // forget thread + + /* + * At worst we may need to traverse entire stack to unlink + * s. If there are multiple concurrent calls to clean, we + * might not see s if another thread has already removed + * it. But we can stop when we see any node known to + * follow s. We use s.next unless it too is cancelled, in + * which case we try the node one past. We don't check any + * further because we don't want to doubly traverse just to + * find sentinel. + */ + + SNode past = s.next; + if (past != null && past.isCancelled()) + past = past.next; + + // Absorb cancelled nodes at head + SNode p; + while ((p = head) != null && p != past && p.isCancelled()) + casHead(p, p.next); + + // Unsplice embedded nodes + while (p != null && p != past) { + SNode n = p.next; + if (n != null && n.isCancelled()) + p.casNext(n, n.next); + else + p = n; + } + } + } + + /** Dual Queue */ + static final class TransferQueue extends Transferer { + /* + * This extends Scherer-Scott dual queue algorithm, differing, + * among other ways, by using modes within nodes rather than + * marked pointers. The algorithm is a little simpler than + * that for stacks because fulfillers do not need explicit + * nodes, and matching is done by CAS'ing QNode.item field + * from non-null to null (for put) or vice versa (for take). + */ + + /** Node class for TransferQueue. */ + static final class QNode { + volatile QNode next; // next node in queue + volatile Object item; // CAS'ed to or from null + volatile Thread waiter; // to control park/unpark + final boolean isData; + + QNode(Object item, boolean isData) { + this.item = item; + this.isData = isData; + } + + static final AtomicReferenceFieldUpdater<QNode, QNode> + nextUpdater = AtomicReferenceFieldUpdater.newUpdater + (QNode.class, QNode.class, "next"); + + boolean casNext(QNode cmp, QNode val) { + return (next == cmp && + nextUpdater.compareAndSet(this, cmp, val)); + } + + static final AtomicReferenceFieldUpdater<QNode, Object> + itemUpdater = AtomicReferenceFieldUpdater.newUpdater + (QNode.class, Object.class, "item"); + + boolean casItem(Object cmp, Object val) { + return (item == cmp && + itemUpdater.compareAndSet(this, cmp, val)); + } + + /** + * Tries to cancel by CAS'ing ref to this as item. + */ + void tryCancel(Object cmp) { + itemUpdater.compareAndSet(this, cmp, this); + } + + boolean isCancelled() { + return item == this; + } + + /** + * Returns true if this node is known to be off the queue + * because its next pointer has been forgotten due to + * an advanceHead operation. + */ + boolean isOffList() { + return next == this; + } + } + + /** Head of queue */ + transient volatile QNode head; + /** Tail of queue */ + transient volatile QNode tail; + /** + * Reference to a cancelled node that might not yet have been + * unlinked from queue because it was the last inserted node + * when it cancelled. + */ + transient volatile QNode cleanMe; + + TransferQueue() { + QNode h = new QNode(null, false); // initialize to dummy node. + head = h; + tail = h; + } + + static final AtomicReferenceFieldUpdater<TransferQueue, QNode> + headUpdater = AtomicReferenceFieldUpdater.newUpdater + (TransferQueue.class, QNode.class, "head"); + + /** + * Tries to cas nh as new head; if successful, unlink + * old head's next node to avoid garbage retention. + */ + void advanceHead(QNode h, QNode nh) { + if (h == head && headUpdater.compareAndSet(this, h, nh)) + h.next = h; // forget old next + } + + static final AtomicReferenceFieldUpdater<TransferQueue, QNode> + tailUpdater = AtomicReferenceFieldUpdater.newUpdater + (TransferQueue.class, QNode.class, "tail"); + + /** + * Tries to cas nt as new tail. + */ + void advanceTail(QNode t, QNode nt) { + if (tail == t) + tailUpdater.compareAndSet(this, t, nt); + } + + static final AtomicReferenceFieldUpdater<TransferQueue, QNode> + cleanMeUpdater = AtomicReferenceFieldUpdater.newUpdater + (TransferQueue.class, QNode.class, "cleanMe"); + + /** + * Tries to CAS cleanMe slot. + */ + boolean casCleanMe(QNode cmp, QNode val) { + return (cleanMe == cmp && + cleanMeUpdater.compareAndSet(this, cmp, val)); + } + + /** + * Puts or takes an item. + */ + Object transfer(Object e, boolean timed, long nanos) { + /* Basic algorithm is to loop trying to take either of + * two actions: + * + * 1. If queue apparently empty or holding same-mode nodes, + * try to add node to queue of waiters, wait to be + * fulfilled (or cancelled) and return matching item. + * + * 2. If queue apparently contains waiting items, and this + * call is of complementary mode, try to fulfill by CAS'ing + * item field of waiting node and dequeuing it, and then + * returning matching item. + * + * In each case, along the way, check for and try to help + * advance head and tail on behalf of other stalled/slow + * threads. + * + * The loop starts off with a null check guarding against + * seeing uninitialized head or tail values. This never + * happens in current SynchronousQueue, but could if + * callers held non-volatile/final ref to the + * transferer. The check is here anyway because it places + * null checks at top of loop, which is usually faster + * than having them implicitly interspersed. + */ + + QNode s = null; // constructed/reused as needed + boolean isData = (e != null); + + for (;;) { + QNode t = tail; + QNode h = head; + if (t == null || h == null) // saw uninitialized value + continue; // spin + + if (h == t || t.isData == isData) { // empty or same-mode + QNode tn = t.next; + if (t != tail) // inconsistent read + continue; + if (tn != null) { // lagging tail + advanceTail(t, tn); + continue; + } + if (timed && nanos <= 0) // can't wait + return null; + if (s == null) + s = new QNode(e, isData); + if (!t.casNext(null, s)) // failed to link in + continue; + + advanceTail(t, s); // swing tail and wait + Object x = awaitFulfill(s, e, timed, nanos); + if (x == s) { // wait was cancelled + clean(t, s); + return null; + } + + if (!s.isOffList()) { // not already unlinked + advanceHead(t, s); // unlink if head + if (x != null) // and forget fields + s.item = s; + s.waiter = null; + } + return (x != null)? x : e; + + } else { // complementary-mode + QNode m = h.next; // node to fulfill + if (t != tail || m == null || h != head) + continue; // inconsistent read + + Object x = m.item; + if (isData == (x != null) || // m already fulfilled + x == m || // m cancelled + !m.casItem(x, e)) { // lost CAS + advanceHead(h, m); // dequeue and retry + continue; + } + + advanceHead(h, m); // successfully fulfilled + LockSupport.unpark(m.waiter); + return (x != null)? x : e; + } + } + } + + /** + * Spins/blocks until node s is fulfilled. + * + * @param s the waiting node + * @param e the comparison value for checking match + * @param timed true if timed wait + * @param nanos timeout value + * @return matched item, or s if cancelled + */ + Object awaitFulfill(QNode s, Object e, boolean timed, long nanos) { + /* Same idea as TransferStack.awaitFulfill */ + long lastTime = (timed)? System.nanoTime() : 0; + Thread w = Thread.currentThread(); + int spins = ((head.next == s) ? + (timed? maxTimedSpins : maxUntimedSpins) : 0); + for (;;) { + if (w.isInterrupted()) + s.tryCancel(e); + Object x = s.item; + if (x != e) + return x; + if (timed) { + long now = System.nanoTime(); + nanos -= now - lastTime; + lastTime = now; + if (nanos <= 0) { + s.tryCancel(e); + continue; + } + } + if (spins > 0) + --spins; + else if (s.waiter == null) + s.waiter = w; + else if (!timed) + LockSupport.park(this); + else if (nanos > spinForTimeoutThreshold) + LockSupport.parkNanos(this, nanos); + } + } + + /** + * Gets rid of cancelled node s with original predecessor pred. + */ + void clean(QNode pred, QNode s) { + s.waiter = null; // forget thread + /* + * At any given time, exactly one node on list cannot be + * deleted -- the last inserted node. To accommodate this, + * if we cannot delete s, we save its predecessor as + * "cleanMe", deleting the previously saved version + * first. At least one of node s or the node previously + * saved can always be deleted, so this always terminates. + */ + while (pred.next == s) { // Return early if already unlinked + QNode h = head; + QNode hn = h.next; // Absorb cancelled first node as head + if (hn != null && hn.isCancelled()) { + advanceHead(h, hn); + continue; + } + QNode t = tail; // Ensure consistent read for tail + if (t == h) + return; + QNode tn = t.next; + if (t != tail) + continue; + if (tn != null) { + advanceTail(t, tn); + continue; + } + if (s != t) { // If not tail, try to unsplice + QNode sn = s.next; + if (sn == s || pred.casNext(s, sn)) + return; + } + QNode dp = cleanMe; + if (dp != null) { // Try unlinking previous cancelled node + QNode d = dp.next; + QNode dn; + if (d == null || // d is gone or + d == dp || // d is off list or + !d.isCancelled() || // d not cancelled or + (d != t && // d not tail and + (dn = d.next) != null && // has successor + dn != d && // that is on list + dp.casNext(d, dn))) // d unspliced + casCleanMe(dp, null); + if (dp == pred) + return; // s is already saved node + } else if (casCleanMe(null, pred)) + return; // Postpone cleaning s + } + } + } + + /** + * The transferer. Set only in constructor, but cannot be declared + * as final without further complicating serialization. Since + * this is accessed only at most once per public method, there + * isn't a noticeable performance penalty for using volatile + * instead of final here. + */ + private transient volatile Transferer transferer; + + /** + * Creates a <tt>SynchronousQueue</tt> with nonfair access policy. + */ + public SynchronousQueue() { + this(false); + } + + /** + * Creates a <tt>SynchronousQueue</tt> with the specified fairness policy. + * + * @param fair if true, waiting threads contend in FIFO order for + * access; otherwise the order is unspecified. + */ + public SynchronousQueue(boolean fair) { + transferer = (fair)? new TransferQueue() : new TransferStack(); + } + + /** + * Adds the specified element to this queue, waiting if necessary for + * another thread to receive it. + * + * @throws InterruptedException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public void put(E o) throws InterruptedException { + if (o == null) throw new NullPointerException(); + if (transferer.transfer(o, false, 0) == null) { + Thread.interrupted(); + throw new InterruptedException(); + } + } + + /** + * Inserts the specified element into this queue, waiting if necessary + * up to the specified wait time for another thread to receive it. + * + * @return <tt>true</tt> if successful, or <tt>false</tt> if the + * specified waiting time elapses before a consumer appears. + * @throws InterruptedException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public boolean offer(E o, long timeout, TimeUnit unit) + throws InterruptedException { + if (o == null) throw new NullPointerException(); + if (transferer.transfer(o, true, unit.toNanos(timeout)) != null) + return true; + if (!Thread.interrupted()) + return false; + throw new InterruptedException(); + } + + /** + * Inserts the specified element into this queue, if another thread is + * waiting to receive it. + * + * @param e the element to add + * @return <tt>true</tt> if the element was added to this queue, else + * <tt>false</tt> + * @throws NullPointerException if the specified element is null + */ + public boolean offer(E e) { + if (e == null) throw new NullPointerException(); + return transferer.transfer(e, true, 0) != null; + } + + /** + * Retrieves and removes the head of this queue, waiting if necessary + * for another thread to insert it. + * + * @return the head of this queue + * @throws InterruptedException {@inheritDoc} + */ + public E take() throws InterruptedException { + Object e = transferer.transfer(null, false, 0); + if (e != null) + return (E)e; + Thread.interrupted(); + throw new InterruptedException(); + } + + /** + * Retrieves and removes the head of this queue, waiting + * if necessary up to the specified wait time, for another thread + * to insert it. + * + * @return the head of this queue, or <tt>null</tt> if the + * specified waiting time elapses before an element is present. + * @throws InterruptedException {@inheritDoc} + */ + public E poll(long timeout, TimeUnit unit) throws InterruptedException { + Object e = transferer.transfer(null, true, unit.toNanos(timeout)); + if (e != null || !Thread.interrupted()) + return (E)e; + throw new InterruptedException(); + } + + /** + * Retrieves and removes the head of this queue, if another thread + * is currently making an element available. + * + * @return the head of this queue, or <tt>null</tt> if no + * element is available. + */ + public E poll() { + return (E)transferer.transfer(null, true, 0); + } + + /** + * Always returns <tt>true</tt>. + * A <tt>SynchronousQueue</tt> has no internal capacity. + * + * @return <tt>true</tt> + */ + public boolean isEmpty() { + return true; + } + + /** + * Always returns zero. + * A <tt>SynchronousQueue</tt> has no internal capacity. + * + * @return zero. + */ + public int size() { + return 0; + } + + /** + * Always returns zero. + * A <tt>SynchronousQueue</tt> has no internal capacity. + * + * @return zero. + */ + public int remainingCapacity() { + return 0; + } + + /** + * Does nothing. + * A <tt>SynchronousQueue</tt> has no internal capacity. + */ + public void clear() { + } + + /** + * Always returns <tt>false</tt>. + * A <tt>SynchronousQueue</tt> has no internal capacity. + * + * @param o the element + * @return <tt>false</tt> + */ + public boolean contains(Object o) { + return false; + } + + /** + * Always returns <tt>false</tt>. + * A <tt>SynchronousQueue</tt> has no internal capacity. + * + * @param o the element to remove + * @return <tt>false</tt> + */ + public boolean remove(Object o) { + return false; + } + + /** + * Returns <tt>false</tt> unless the given collection is empty. + * A <tt>SynchronousQueue</tt> has no internal capacity. + * + * @param c the collection + * @return <tt>false</tt> unless given collection is empty + */ + public boolean containsAll(Collection<?> c) { + return c.isEmpty(); + } + + /** + * Always returns <tt>false</tt>. + * A <tt>SynchronousQueue</tt> has no internal capacity. + * + * @param c the collection + * @return <tt>false</tt> + */ + public boolean removeAll(Collection<?> c) { + return false; + } + + /** + * Always returns <tt>false</tt>. + * A <tt>SynchronousQueue</tt> has no internal capacity. + * + * @param c the collection + * @return <tt>false</tt> + */ + public boolean retainAll(Collection<?> c) { + return false; + } + + /** + * Always returns <tt>null</tt>. + * A <tt>SynchronousQueue</tt> does not return elements + * unless actively waited on. + * + * @return <tt>null</tt> + */ + public E peek() { + return null; + } + + static class EmptyIterator<E> implements Iterator<E> { + public boolean hasNext() { + return false; + } + public E next() { + throw new NoSuchElementException(); + } + public void remove() { + throw new IllegalStateException(); + } + } + + /** + * Returns an empty iterator in which <tt>hasNext</tt> always returns + * <tt>false</tt>. + * + * @return an empty iterator + */ + public Iterator<E> iterator() { + return new EmptyIterator<E>(); + } + + /** + * Returns a zero-length array. + * @return a zero-length array + */ + public Object[] toArray() { + return new Object[0]; + } + + /** + * Sets the zeroeth element of the specified array to <tt>null</tt> + * (if the array has non-zero length) and returns it. + * + * @param a the array + * @return the specified array + * @throws NullPointerException if the specified array is null + */ + public <T> T[] toArray(T[] a) { + if (a.length > 0) + a[0] = null; + return a; + } + + /** + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public int drainTo(Collection<? super E> c) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + int n = 0; + E e; + while ( (e = poll()) != null) { + c.add(e); + ++n; + } + return n; + } + + /** + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public int drainTo(Collection<? super E> c, int maxElements) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + int n = 0; + E e; + while (n < maxElements && (e = poll()) != null) { + c.add(e); + ++n; + } + return n; + } + + /* + * To cope with serialization strategy in the 1.5 version of + * SynchronousQueue, we declare some unused classes and fields + * that exist solely to enable serializability across versions. + * These fields are never used, so are initialized only if this + * object is ever serialized or deserialized. + */ + + static class WaitQueue implements java.io.Serializable { } + static class LifoWaitQueue extends WaitQueue { + private static final long serialVersionUID = -3633113410248163686L; + } + static class FifoWaitQueue extends WaitQueue { + private static final long serialVersionUID = -3623113410248163686L; + } + private ReentrantLock qlock; + private WaitQueue waitingProducers; + private WaitQueue waitingConsumers; + + /** + * Save the state to a stream (that is, serialize it). + * + * @param s the stream + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + boolean fair = transferer instanceof TransferQueue; + if (fair) { + qlock = new ReentrantLock(true); + waitingProducers = new FifoWaitQueue(); + waitingConsumers = new FifoWaitQueue(); + } + else { + qlock = new ReentrantLock(); + waitingProducers = new LifoWaitQueue(); + waitingConsumers = new LifoWaitQueue(); + } + s.defaultWriteObject(); + } + + private void readObject(final java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + if (waitingProducers instanceof FifoWaitQueue) + transferer = new TransferQueue(); + else + transferer = new TransferStack(); + } + +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/ThreadFactory.java b/libjava/classpath/external/jsr166/java/util/concurrent/ThreadFactory.java new file mode 100644 index 000000000..eca8dceb0 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/ThreadFactory.java @@ -0,0 +1,40 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; + +/** + * An object that creates new threads on demand. Using thread factories + * removes hardwiring of calls to {@link Thread#Thread(Runnable) new Thread}, + * enabling applications to use special thread subclasses, priorities, etc. + * + * <p> + * The simplest implementation of this interface is just: + * <pre> + * class SimpleThreadFactory implements ThreadFactory { + * public Thread newThread(Runnable r) { + * return new Thread(r); + * } + * } + * </pre> + * + * The {@link Executors#defaultThreadFactory} method provides a more + * useful simple implementation, that sets the created thread context + * to known values before returning it. + * @since 1.5 + * @author Doug Lea + */ +public interface ThreadFactory { + + /** + * Constructs a new <tt>Thread</tt>. Implementations may also initialize + * priority, name, daemon status, <tt>ThreadGroup</tt>, etc. + * + * @param r a runnable to be executed by new thread instance + * @return constructed thread + */ + Thread newThread(Runnable r); +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/ThreadPoolExecutor.java b/libjava/classpath/external/jsr166/java/util/concurrent/ThreadPoolExecutor.java new file mode 100644 index 000000000..e303f14a8 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/ThreadPoolExecutor.java @@ -0,0 +1,1605 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.concurrent.locks.*; +import java.util.*; + +/** + * An {@link ExecutorService} that executes each submitted task using + * one of possibly several pooled threads, normally configured + * using {@link Executors} factory methods. + * + * <p>Thread pools address two different problems: they usually + * provide improved performance when executing large numbers of + * asynchronous tasks, due to reduced per-task invocation overhead, + * and they provide a means of bounding and managing the resources, + * including threads, consumed when executing a collection of tasks. + * Each <tt>ThreadPoolExecutor</tt> also maintains some basic + * statistics, such as the number of completed tasks. + * + * <p>To be useful across a wide range of contexts, this class + * provides many adjustable parameters and extensibility + * hooks. However, programmers are urged to use the more convenient + * {@link Executors} factory methods {@link + * Executors#newCachedThreadPool} (unbounded thread pool, with + * automatic thread reclamation), {@link Executors#newFixedThreadPool} + * (fixed size thread pool) and {@link + * Executors#newSingleThreadExecutor} (single background thread), that + * preconfigure settings for the most common usage + * scenarios. Otherwise, use the following guide when manually + * configuring and tuning this class: + * + * <dl> + * + * <dt>Core and maximum pool sizes</dt> + * + * <dd>A <tt>ThreadPoolExecutor</tt> will automatically adjust the + * pool size + * (see {@link ThreadPoolExecutor#getPoolSize}) + * according to the bounds set by corePoolSize + * (see {@link ThreadPoolExecutor#getCorePoolSize}) + * and + * maximumPoolSize + * (see {@link ThreadPoolExecutor#getMaximumPoolSize}). + * When a new task is submitted in method {@link + * ThreadPoolExecutor#execute}, and fewer than corePoolSize threads + * are running, a new thread is created to handle the request, even if + * other worker threads are idle. If there are more than + * corePoolSize but less than maximumPoolSize threads running, a new + * thread will be created only if the queue is full. By setting + * corePoolSize and maximumPoolSize the same, you create a fixed-size + * thread pool. By setting maximumPoolSize to an essentially unbounded + * value such as <tt>Integer.MAX_VALUE</tt>, you allow the pool to + * accommodate an arbitrary number of concurrent tasks. Most typically, + * core and maximum pool sizes are set only upon construction, but they + * may also be changed dynamically using {@link + * ThreadPoolExecutor#setCorePoolSize} and {@link + * ThreadPoolExecutor#setMaximumPoolSize}. <dd> + * + * <dt> On-demand construction + * + * <dd> By default, even core threads are initially created and + * started only when new tasks arrive, but this can be overridden + * dynamically using method {@link + * ThreadPoolExecutor#prestartCoreThread} or + * {@link ThreadPoolExecutor#prestartAllCoreThreads}. + * You probably want to prestart threads if you construct the + * pool with a non-empty queue. </dd> + * + * <dt>Creating new threads</dt> + * + * <dd>New threads are created using a {@link + * java.util.concurrent.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 + * <tt>NORM_PRIORITY</tt> priority and non-daemon status. By supplying + * a different ThreadFactory, you can alter the thread's name, thread + * group, priority, daemon status, etc. If a <tt>ThreadFactory</tt> fails to create + * a thread when asked by returning null from <tt>newThread</tt>, + * the executor will continue, but might + * not be able to execute any tasks. </dd> + * + * <dt>Keep-alive times</dt> + * + * <dd>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 + * ThreadPoolExecutor#getKeepAliveTime}). This provides a means of + * reducing resource consumption when the pool is not being actively + * used. If the pool becomes more active later, new threads will be + * constructed. This parameter can also be changed dynamically using + * method {@link ThreadPoolExecutor#setKeepAliveTime}. Using a value + * of <tt>Long.MAX_VALUE</tt> {@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 corePoolSizeThreads. But method {@link + * ThreadPoolExecutor#allowCoreThreadTimeOut} 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 + * submitted tasks. The use of this queue interacts with pool sizing: + * + * <ul> + * + * <li> If fewer than corePoolSize threads are running, the Executor + * always prefers adding a new thread + * rather than queuing.</li> + * + * <li> If corePoolSize or more threads are running, the Executor + * always prefers queuing a request rather than adding a new + * thread.</li> + * + * <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> + * + * </ul> + * + * There are three general strategies for queuing: + * <ol> + * + * <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 + * new thread will be constructed. This policy avoids lockups when + * handling sets of requests that might have internal dependencies. + * 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> + * + * <li><em> Unbounded queues.</em> Using an unbounded queue (for + * example a {@link LinkedBlockingQueue} without a predefined + * capacity) will cause new tasks to wait in the queue when all + * corePoolSize threads are busy. Thus, no more than corePoolSize + * threads will ever be created. (And the value of the maximumPoolSize + * therefore doesn't have any effect.) This may be appropriate when + * each task is completely independent of others, so tasks cannot + * affect each others execution; for example, in a web page server. + * 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> + * + * <li><em>Bounded queues.</em> A bounded queue (for example, an + * {@link ArrayBlockingQueue}) helps prevent resource exhaustion when + * used with finite maximumPoolSizes, but can be more difficult to + * tune and control. Queue sizes and maximum pool sizes may be traded + * off for each other: Using large queues and small pools minimizes + * CPU usage, OS resources, and context-switching overhead, but can + * lead to artificially low throughput. If tasks frequently block (for + * example if they are I/O bound), a system may be able to schedule + * 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> + * + * </ol> + * + * </dd> + * + * <dt>Rejected tasks</dt> + * + * <dd> New tasks submitted in method {@link + * ThreadPoolExecutor#execute} 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 <tt>execute</tt> method invokes the + * {@link RejectedExecutionHandler#rejectedExecution} method of its + * {@link RejectedExecutionHandler}. Four predefined handler policies + * are provided: + * + * <ol> + * + * <li> In the + * default {@link ThreadPoolExecutor.AbortPolicy}, the handler throws a + * runtime {@link RejectedExecutionException} upon rejection. </li> + * + * <li> In {@link + * ThreadPoolExecutor.CallerRunsPolicy}, the thread that invokes + * <tt>execute</tt> itself runs the task. This provides a simple + * feedback control mechanism that will slow down the rate that new + * tasks are submitted. </li> + * + * <li> In {@link ThreadPoolExecutor.DiscardPolicy}, + * a task that cannot be executed is simply dropped. </li> + * + * <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> + * + * </ol> + * + * It is possible to define and use other kinds of {@link + * RejectedExecutionHandler} classes. Doing so requires some care + * especially when policies are designed to work only under particular + * capacity or queuing policies. </dd> + * + * <dt>Hook methods</dt> + * + * <dd>This class provides <tt>protected</tt> overridable {@link + * ThreadPoolExecutor#beforeExecute} and {@link + * ThreadPoolExecutor#afterExecute} methods that are called before and + * after execution of each task. These can be used to manipulate the + * execution environment; for example, reinitializing ThreadLocals, + * gathering statistics, or adding log entries. Additionally, method + * {@link ThreadPoolExecutor#terminated} can be overridden to perform + * 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> + * + * <dt>Queue maintenance</dt> + * + * <dd> Method {@link ThreadPoolExecutor#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 ThreadPoolExecutor#remove} and {@link + * ThreadPoolExecutor#purge} are available to assist in storage + * reclamation when large numbers of queued tasks become + * cancelled.</dd> + * + * <dt>Finalization</dt> + * + * <dd> A pool that is no longer referenced in a program <em>AND</em> + * has no remaining threads will be <tt>shutdown</tt> + * automatically. If you would like to ensure that unreferenced pools + * are reclaimed even if users forget to call {@link + * ThreadPoolExecutor#shutdown}, then you must arrange that unused + * threads eventually die, by setting appropriate keep-alive times, + * using a lower bound of zero core threads and/or setting {@link + * ThreadPoolExecutor#allowCoreThreadTimeOut}. </dd> </dl> + * + * <p> <b>Extension example</b>. Most extensions of this class + * override one or more of the protected hook methods. For example, + * here is a subclass that adds a simple pause/resume feature: + * + * <pre> + * class PausableThreadPoolExecutor extends ThreadPoolExecutor { + * private boolean isPaused; + * private ReentrantLock pauseLock = new ReentrantLock(); + * private Condition unpaused = pauseLock.newCondition(); + * + * public PausableThreadPoolExecutor(...) { super(...); } + * + * protected void beforeExecute(Thread t, Runnable r) { + * super.beforeExecute(t, r); + * pauseLock.lock(); + * try { + * while (isPaused) unpaused.await(); + * } catch (InterruptedException ie) { + * t.interrupt(); + * } finally { + * pauseLock.unlock(); + * } + * } + * + * public void pause() { + * pauseLock.lock(); + * try { + * isPaused = true; + * } finally { + * pauseLock.unlock(); + * } + * } + * + * public void resume() { + * pauseLock.lock(); + * try { + * isPaused = false; + * unpaused.signalAll(); + * } finally { + * pauseLock.unlock(); + * } + * } + * } + * </pre> + * @since 1.5 + * @author Doug Lea + */ +public class ThreadPoolExecutor extends AbstractExecutorService { + /** + * Only used to force toArray() to produce a Runnable[]. + */ + private static final Runnable[] EMPTY_RUNNABLE_ARRAY = new Runnable[0]; + + /** + * Permission for checking shutdown + */ + private static final RuntimePermission shutdownPerm = + new RuntimePermission("modifyThread"); + + /** + * Queue used for holding tasks and handing off to worker threads. + */ + private final BlockingQueue<Runnable> workQueue; + + /** + * Lock held on updates to poolSize, corePoolSize, maximumPoolSize, and + * workers set. + */ + private final ReentrantLock mainLock = new ReentrantLock(); + + /** + * Wait condition to support awaitTermination + */ + private final Condition termination = mainLock.newCondition(); + + /** + * Set containing all worker threads in pool. + */ + private final HashSet<Worker> workers = new HashSet<Worker>(); + + /** + * Timeout in nanoseconds for idle threads waiting for work. + * Threads use this timeout only when there are more than + * corePoolSize present. Otherwise they wait forever for new work. + */ + private volatile long keepAliveTime; + + /** + * If false (default) core threads stay alive even when idle. + * If true, core threads use keepAliveTime to time out waiting for work. + */ + private volatile boolean allowCoreThreadTimeOut; + + /** + * Core pool size, updated only while holding mainLock, + * but volatile to allow concurrent readability even + * during updates. + */ + private volatile int corePoolSize; + + /** + * Maximum pool size, updated only while holding mainLock + * but volatile to allow concurrent readability even + * during updates. + */ + private volatile int maximumPoolSize; + + /** + * Current pool size, updated only while holding mainLock + * but volatile to allow concurrent readability even + * during updates. + */ + private volatile int poolSize; + + /** + * Lifecycle state + */ + volatile int runState; + + // Special values for runState + /** Normal, not-shutdown mode */ + static final int RUNNING = 0; + /** Controlled shutdown mode */ + static final int SHUTDOWN = 1; + /** Immediate shutdown mode */ + static final int STOP = 2; + /** Final state */ + static final int TERMINATED = 3; + + /** + * Handler called when saturated or shutdown in execute. + */ + private volatile RejectedExecutionHandler handler; + + /** + * Factory for new threads. + */ + private volatile ThreadFactory threadFactory; + + /** + * Tracks largest attained pool size. + */ + private int largestPoolSize; + + /** + * Counter for completed tasks. Updated only on termination of + * worker threads. + */ + private long completedTaskCount; + + /** + * The default rejected execution handler + */ + private static final RejectedExecutionHandler defaultHandler = + new AbortPolicy(); + + /** + * Invokes the rejected execution handler for the given command. + */ + void reject(Runnable command) { + handler.rejectedExecution(command, this); + } + + /** + * Creates and returns a new thread running firstTask as its first + * task. Call only while holding mainLock. + * @param firstTask the task the new thread should run first (or + * null if none) + * @return the new thread, or null if threadFactory fails to create thread + */ + private Thread addThread(Runnable firstTask) { + if (runState == TERMINATED) // Don't create thread if terminated + return null; + Worker w = new Worker(firstTask); + Thread t = threadFactory.newThread(w); + if (t != null) { + w.thread = t; + workers.add(w); + int nt = ++poolSize; + if (nt > largestPoolSize) + largestPoolSize = nt; + } + return t; + } + + /** + * Creates and starts a new thread running firstTask as its first + * task, only if fewer than corePoolSize threads are running. + * @param firstTask the task the new thread should run first (or + * null if none) + * @return true if successful. + */ + private boolean addIfUnderCorePoolSize(Runnable firstTask) { + Thread t = null; + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + if (poolSize < corePoolSize) + t = addThread(firstTask); + } finally { + mainLock.unlock(); + } + if (t == null) + return false; + t.start(); + return true; + } + + /** + * Creates and starts a new thread only if fewer than maximumPoolSize + * threads are running. The new thread runs as its first task the + * next task in queue, or if there is none, the given task. + * @param firstTask the task the new thread should run first (or + * null if none) + * @return 0 if a new thread cannot be created, a positive number + * if firstTask will be run in a new thread, or a negative number + * if a new thread was created but is running some other task, in + * which case the caller must try some other way to run firstTask + * (perhaps by calling this method again). + */ + private int addIfUnderMaximumPoolSize(Runnable firstTask) { + Thread t = null; + int status = 0; + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + if (poolSize < maximumPoolSize) { + Runnable next = workQueue.poll(); + if (next == null) { + next = firstTask; + status = 1; + } else + status = -1; + t = addThread(next); + } + } finally { + mainLock.unlock(); + } + if (t == null) + return 0; + t.start(); + return status; + } + + + /** + * Gets the next task for a worker thread to run. + * @return the task + */ + Runnable getTask() { + for (;;) { + try { + switch (runState) { + case RUNNING: { + // untimed wait if core and not allowing core timeout + if (poolSize <= corePoolSize && !allowCoreThreadTimeOut) + return workQueue.take(); + + long timeout = keepAliveTime; + if (timeout <= 0) // die immediately for 0 timeout + return null; + Runnable r = workQueue.poll(timeout, TimeUnit.NANOSECONDS); + if (r != null) + return r; + if (poolSize > corePoolSize || allowCoreThreadTimeOut) + return null; // timed out + // Else, after timeout, the pool shrank. Retry + break; + } + + case SHUTDOWN: { + // Help drain queue + Runnable r = workQueue.poll(); + if (r != null) + return r; + + // Check if can terminate + if (workQueue.isEmpty()) { + interruptIdleWorkers(); + return null; + } + + // Else there could still be delayed tasks in queue. + return workQueue.take(); + } + + case STOP: + return null; + default: + assert false; + } + } catch (InterruptedException ie) { + // On interruption, re-check runstate + } + } + } + + /** + * Wakes up all threads that might be waiting for tasks. + */ + void interruptIdleWorkers() { + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + for (Worker w : workers) + w.interruptIfIdle(); + } finally { + mainLock.unlock(); + } + } + + /** + * Performs bookkeeping for a terminated worker thread. + * @param w the worker + */ + void workerDone(Worker w) { + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + completedTaskCount += w.completedTasks; + workers.remove(w); + if (--poolSize > 0) + return; + + // Else, this is the last thread. Deal with potential shutdown. + + int state = runState; + assert state != TERMINATED; + + if (state != STOP) { + // If there are queued tasks but no threads, create + // replacement thread. We must create it initially + // idle to avoid orphaned tasks in case addThread + // fails. This also handles case of delayed tasks + // that will sometime later become runnable. + if (!workQueue.isEmpty()) { + Thread t = addThread(null); + if (t != null) + t.start(); + return; + } + + // Otherwise, we can exit without replacement + if (state == RUNNING) + return; + } + + // Either state is STOP, or state is SHUTDOWN and there is + // no work to do. So we can terminate. + termination.signalAll(); + runState = TERMINATED; + // fall through to call terminate() outside of lock. + } finally { + mainLock.unlock(); + } + + assert runState == TERMINATED; + terminated(); + } + + /** + * Worker threads + */ + private class Worker implements Runnable { + + /** + * The runLock is acquired and released surrounding each task + * execution. It mainly protects against interrupts that are + * intended to cancel the worker thread from instead + * interrupting the task being run. + */ + private final ReentrantLock runLock = new ReentrantLock(); + + /** + * Initial task to run before entering run loop + */ + private Runnable firstTask; + + /** + * Per thread completed task counter; accumulated + * into completedTaskCount upon termination. + */ + volatile long completedTasks; + + /** + * Thread this worker is running in. Acts as a final field, + * but cannot be set until thread is created. + */ + Thread thread; + + Worker(Runnable firstTask) { + this.firstTask = firstTask; + } + + boolean isActive() { + return runLock.isLocked(); + } + + /** + * Interrupts thread if not running a task. + */ + void interruptIfIdle() { + final ReentrantLock runLock = this.runLock; + if (runLock.tryLock()) { + try { + thread.interrupt(); + } finally { + runLock.unlock(); + } + } + } + + /** + * Interrupts thread even if running a task. + */ + void interruptNow() { + thread.interrupt(); + } + + /** + * Runs a single task between before/after methods. + */ + private void runTask(Runnable task) { + final ReentrantLock runLock = this.runLock; + runLock.lock(); + try { + // If not shutting down then clear an outstanding interrupt. + if (runState != STOP && + Thread.interrupted() && + runState == STOP) // Re-interrupt if stopped after clearing + thread.interrupt(); + boolean ran = false; + beforeExecute(thread, task); + try { + task.run(); + ran = true; + afterExecute(task, null); + ++completedTasks; + } catch (RuntimeException ex) { + if (!ran) + afterExecute(task, ex); + // Else the exception occurred within + // afterExecute itself in which case we don't + // want to call it again. + throw ex; + } + } finally { + runLock.unlock(); + } + } + + /** + * Main run loop + */ + public void run() { + try { + Runnable task = firstTask; + firstTask = null; + while (task != null || (task = getTask()) != null) { + runTask(task); + task = null; // unnecessary but can help GC + } + } finally { + workerDone(this); + } + } + } + + // Public methods + + /** + * Creates a new <tt>ThreadPoolExecutor</tt> with the given initial + * parameters and default thread factory and rejected execution handler. + * It may be more convenient to use one of the {@link Executors} factory + * methods instead of this general purpose constructor. + * + * @param corePoolSize the number of threads to keep in the + * pool, even if they are idle. + * @param maximumPoolSize the maximum number of threads to allow in the + * pool. + * @param keepAliveTime when the number of threads is greater than + * the core, this is the maximum time that excess idle threads + * will wait for new tasks before terminating. + * @param unit the time unit for the keepAliveTime + * argument. + * @param workQueue the queue to use for holding tasks before they + * are executed. This queue will hold only the <tt>Runnable</tt> + * tasks submitted by the <tt>execute</tt> method. + * @throws IllegalArgumentException if corePoolSize, or + * keepAliveTime less than zero, or if maximumPoolSize less than or + * equal to zero, or if corePoolSize greater than maximumPoolSize. + * @throws NullPointerException if <tt>workQueue</tt> is null + */ + public ThreadPoolExecutor(int corePoolSize, + int maximumPoolSize, + long keepAliveTime, + TimeUnit unit, + BlockingQueue<Runnable> workQueue) { + this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, + Executors.defaultThreadFactory(), defaultHandler); + } + + /** + * Creates a new <tt>ThreadPoolExecutor</tt> with the given initial + * parameters and default rejected execution handler. + * + * @param corePoolSize the number of threads to keep in the + * pool, even if they are idle. + * @param maximumPoolSize the maximum number of threads to allow in the + * pool. + * @param keepAliveTime when the number of threads is greater than + * the core, this is the maximum time that excess idle threads + * will wait for new tasks before terminating. + * @param unit the time unit for the keepAliveTime + * argument. + * @param workQueue the queue to use for holding tasks before they + * are executed. This queue will hold only the <tt>Runnable</tt> + * tasks submitted by the <tt>execute</tt> method. + * @param threadFactory the factory to use when the executor + * creates a new thread. + * @throws IllegalArgumentException if corePoolSize, or + * keepAliveTime less than zero, or if maximumPoolSize less than or + * equal to zero, or if corePoolSize greater than maximumPoolSize. + * @throws NullPointerException if <tt>workQueue</tt> + * or <tt>threadFactory</tt> are null. + */ + public ThreadPoolExecutor(int corePoolSize, + int maximumPoolSize, + long keepAliveTime, + TimeUnit unit, + BlockingQueue<Runnable> workQueue, + ThreadFactory threadFactory) { + this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, + threadFactory, defaultHandler); + } + + /** + * Creates a new <tt>ThreadPoolExecutor</tt> with the given initial + * parameters and default thread factory. + * + * @param corePoolSize the number of threads to keep in the + * pool, even if they are idle. + * @param maximumPoolSize the maximum number of threads to allow in the + * pool. + * @param keepAliveTime when the number of threads is greater than + * the core, this is the maximum time that excess idle threads + * will wait for new tasks before terminating. + * @param unit the time unit for the keepAliveTime + * argument. + * @param workQueue the queue to use for holding tasks before they + * are executed. This queue will hold only the <tt>Runnable</tt> + * tasks submitted by the <tt>execute</tt> method. + * @param handler the handler to use when execution is blocked + * because the thread bounds and queue capacities are reached. + * @throws IllegalArgumentException if corePoolSize, or + * keepAliveTime less than zero, or if maximumPoolSize less than or + * equal to zero, or if corePoolSize greater than maximumPoolSize. + * @throws NullPointerException if <tt>workQueue</tt> + * or <tt>handler</tt> are null. + */ + public ThreadPoolExecutor(int corePoolSize, + int maximumPoolSize, + long keepAliveTime, + TimeUnit unit, + BlockingQueue<Runnable> workQueue, + RejectedExecutionHandler handler) { + this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, + Executors.defaultThreadFactory(), handler); + } + + /** + * Creates a new <tt>ThreadPoolExecutor</tt> with the given initial + * parameters. + * + * @param corePoolSize the number of threads to keep in the + * pool, even if they are idle. + * @param maximumPoolSize the maximum number of threads to allow in the + * pool. + * @param keepAliveTime when the number of threads is greater than + * the core, this is the maximum time that excess idle threads + * will wait for new tasks before terminating. + * @param unit the time unit for the keepAliveTime + * argument. + * @param workQueue the queue to use for holding tasks before they + * are executed. This queue will hold only the <tt>Runnable</tt> + * tasks submitted by the <tt>execute</tt> method. + * @param threadFactory the factory to use when the executor + * creates a new thread. + * @param handler the handler to use when execution is blocked + * because the thread bounds and queue capacities are reached. + * @throws IllegalArgumentException if corePoolSize, or + * keepAliveTime less than zero, or if maximumPoolSize less than or + * equal to zero, or if corePoolSize greater than maximumPoolSize. + * @throws NullPointerException if <tt>workQueue</tt> + * or <tt>threadFactory</tt> or <tt>handler</tt> are null. + */ + public ThreadPoolExecutor(int corePoolSize, + int maximumPoolSize, + long keepAliveTime, + TimeUnit unit, + BlockingQueue<Runnable> workQueue, + ThreadFactory threadFactory, + RejectedExecutionHandler handler) { + if (corePoolSize < 0 || + maximumPoolSize <= 0 || + maximumPoolSize < corePoolSize || + keepAliveTime < 0) + throw new IllegalArgumentException(); + if (workQueue == null || threadFactory == null || handler == null) + throw new NullPointerException(); + this.corePoolSize = corePoolSize; + this.maximumPoolSize = maximumPoolSize; + this.workQueue = workQueue; + this.keepAliveTime = unit.toNanos(keepAliveTime); + this.threadFactory = threadFactory; + this.handler = handler; + } + + + /** + * Executes the given task sometime in the future. The task + * may execute in a new thread or in an existing pooled thread. + * + * If the task cannot be submitted for execution, either because this + * executor has been shutdown or because its capacity has been reached, + * the task is handled by the current <tt>RejectedExecutionHandler</tt>. + * + * @param command the task to execute + * @throws RejectedExecutionException at discretion of + * <tt>RejectedExecutionHandler</tt>, if task cannot be accepted + * for execution + * @throws NullPointerException if command is null + */ + public void execute(Runnable command) { + if (command == null) + throw new NullPointerException(); + for (;;) { + if (runState != RUNNING) { + reject(command); + return; + } + if (poolSize < corePoolSize && addIfUnderCorePoolSize(command)) + return; + if (workQueue.offer(command)) + return; + int status = addIfUnderMaximumPoolSize(command); + if (status > 0) // created new thread + return; + if (status == 0) { // failed to create thread + reject(command); + return; + } + // Retry if created a new thread but it is busy with another task + } + } + + /** + * Initiates an orderly shutdown in which previously submitted + * tasks are executed, but no new tasks will be + * accepted. Invocation has no additional effect if already shut + * down. + * @throws SecurityException if a security manager exists and + * shutting down this ExecutorService may manipulate threads that + * the caller is not permitted to modify because it does not hold + * {@link java.lang.RuntimePermission}<tt>("modifyThread")</tt>, + * or the security manager's <tt>checkAccess</tt> method denies access. + */ + public void shutdown() { + // Fail if caller doesn't have modifyThread permission. + SecurityManager security = System.getSecurityManager(); + if (security != null) + security.checkPermission(shutdownPerm); + + boolean fullyTerminated = false; + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + if (workers.size() > 0) { + // Check if caller can modify worker threads. This + // might not be true even if passed above check, if + // the SecurityManager treats some threads specially. + if (security != null) { + for (Worker w: workers) + security.checkAccess(w.thread); + } + + int state = runState; + if (state == RUNNING) // don't override shutdownNow + runState = SHUTDOWN; + + try { + for (Worker w: workers) + w.interruptIfIdle(); + } catch (SecurityException se) { + // If SecurityManager allows above checks, but + // then unexpectedly throws exception when + // interrupting threads (which it ought not do), + // back out as cleanly as we can. Some threads may + // have been killed but we remain in non-shutdown + // state. + runState = state; + throw se; + } + } + else { // If no workers, trigger full termination now + fullyTerminated = true; + runState = TERMINATED; + termination.signalAll(); + } + } finally { + mainLock.unlock(); + } + if (fullyTerminated) + terminated(); + } + + + /** + * Attempts to stop all actively executing tasks, halts the + * processing of waiting tasks, and returns a list of the tasks + * that were awaiting execution. + * + * <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 + * fails to respond to interrupts may never terminate. + * + * @return list of tasks that never commenced execution + * @throws SecurityException if a security manager exists and + * shutting down this ExecutorService may manipulate threads that + * the caller is not permitted to modify because it does not hold + * {@link java.lang.RuntimePermission}<tt>("modifyThread")</tt>, + * or the security manager's <tt>checkAccess</tt> method denies access. + */ + public List<Runnable> shutdownNow() { + // Almost the same code as shutdown() + SecurityManager security = System.getSecurityManager(); + if (security != null) + security.checkPermission(shutdownPerm); + + boolean fullyTerminated = false; + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + if (workers.size() > 0) { + if (security != null) { + for (Worker w: workers) + security.checkAccess(w.thread); + } + + int state = runState; + if (state != TERMINATED) + runState = STOP; + try { + for (Worker w : workers) + w.interruptNow(); + } catch (SecurityException se) { + runState = state; // back out; + throw se; + } + } + else { // If no workers, trigger full termination now + fullyTerminated = true; + runState = TERMINATED; + termination.signalAll(); + } + } finally { + mainLock.unlock(); + } + if (fullyTerminated) + terminated(); + return Arrays.asList(workQueue.toArray(EMPTY_RUNNABLE_ARRAY)); + } + + public boolean isShutdown() { + return runState != RUNNING; + } + + /** + * Returns true if this executor is in the process of terminating + * after <tt>shutdown</tt> or <tt>shutdownNow</tt> but has not + * completely terminated. This method may be useful for + * debugging. A return of <tt>true</tt> reported a sufficient + * period after shutdown may indicate that submitted tasks have + * ignored or suppressed interruption, causing this executor not + * to properly terminate. + * @return true if terminating but not yet terminated. + */ + public boolean isTerminating() { + return runState == STOP; + } + + public boolean isTerminated() { + return runState == TERMINATED; + } + + public boolean awaitTermination(long timeout, TimeUnit unit) + throws InterruptedException { + long nanos = unit.toNanos(timeout); + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + for (;;) { + if (runState == TERMINATED) + return true; + if (nanos <= 0) + return false; + nanos = termination.awaitNanos(nanos); + } + } finally { + mainLock.unlock(); + } + } + + /** + * Invokes <tt>shutdown</tt> when this executor is no longer + * referenced. + */ + protected void finalize() { + shutdown(); + } + + /** + * Sets the thread factory used to create new threads. + * + * @param threadFactory the new thread factory + * @throws NullPointerException if threadFactory is null + * @see #getThreadFactory + */ + public void setThreadFactory(ThreadFactory threadFactory) { + if (threadFactory == null) + throw new NullPointerException(); + this.threadFactory = threadFactory; + } + + /** + * Returns the thread factory used to create new threads. + * + * @return the current thread factory + * @see #setThreadFactory + */ + public ThreadFactory getThreadFactory() { + return threadFactory; + } + + /** + * Sets a new handler for unexecutable tasks. + * + * @param handler the new handler + * @throws NullPointerException if handler is null + * @see #getRejectedExecutionHandler + */ + public void setRejectedExecutionHandler(RejectedExecutionHandler handler) { + if (handler == null) + throw new NullPointerException(); + this.handler = handler; + } + + /** + * Returns the current handler for unexecutable tasks. + * + * @return the current handler + * @see #setRejectedExecutionHandler + */ + public RejectedExecutionHandler getRejectedExecutionHandler() { + return handler; + } + + /** + * 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. + * + * @return the task queue + */ + public BlockingQueue<Runnable> getQueue() { + return workQueue; + } + + /** + * Removes this task from the executor's internal queue if it is + * present, thus causing it not to be run if it has not already + * started. + * + * <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 <tt>submit</tt> might be + * converted into a form that maintains <tt>Future</tt> status. + * However, in such cases, method {@link ThreadPoolExecutor#purge} + * may be used to remove those Futures that have been cancelled. + * + * @param task the task to remove + * @return true if the task was removed + */ + public boolean remove(Runnable task) { + return getQueue().remove(task); + } + + + /** + * Tries to remove from the work queue all {@link Future} + * tasks that have been cancelled. This method can be useful as a + * storage reclamation operation, that has no other impact on + * functionality. Cancelled tasks are never executed, but may + * accumulate in work queues until worker threads can actively + * remove them. Invoking this method instead tries to remove them now. + * However, this method may fail to remove tasks in + * the presence of interference by other threads. + */ + public void purge() { + // Fail if we encounter interference during traversal + try { + Iterator<Runnable> it = getQueue().iterator(); + while (it.hasNext()) { + Runnable r = it.next(); + if (r instanceof Future<?>) { + Future<?> c = (Future<?>)r; + if (c.isCancelled()) + it.remove(); + } + } + } + catch (ConcurrentModificationException ex) { + return; + } + } + + /** + * Sets the core number of threads. This overrides any value set + * in the constructor. If the new value is smaller than the + * current value, excess existing threads will be terminated when + * they next become idle. If larger, new threads will, if needed, + * be started to execute any queued tasks. + * + * @param corePoolSize the new core size + * @throws IllegalArgumentException if <tt>corePoolSize</tt> + * less than zero + * @see #getCorePoolSize + */ + public void setCorePoolSize(int corePoolSize) { + if (corePoolSize < 0) + throw new IllegalArgumentException(); + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + int extra = this.corePoolSize - corePoolSize; + this.corePoolSize = corePoolSize; + if (extra < 0) { + int n = workQueue.size(); + // We have to create initially-idle threads here + // because we otherwise have no recourse about + // what to do with a dequeued task if addThread fails. + while (extra++ < 0 && n-- > 0 && poolSize < corePoolSize ) { + Thread t = addThread(null); + if (t != null) + t.start(); + else + break; + } + } + else if (extra > 0 && poolSize > corePoolSize) { + Iterator<Worker> it = workers.iterator(); + while (it.hasNext() && + extra-- > 0 && + poolSize > corePoolSize && + workQueue.remainingCapacity() == 0) + it.next().interruptIfIdle(); + } + } finally { + mainLock.unlock(); + } + } + + /** + * Returns the core number of threads. + * + * @return the core number of threads + * @see #setCorePoolSize + */ + public int getCorePoolSize() { + return corePoolSize; + } + + /** + * Starts a core thread, causing it to idly wait for work. This + * overrides the default policy of starting core threads only when + * new tasks are executed. This method will return <tt>false</tt> + * if all core threads have already been started. + * @return true if a thread was started + */ + public boolean prestartCoreThread() { + return addIfUnderCorePoolSize(null); + } + + /** + * Starts all core threads, causing them to idly wait for work. This + * overrides the default policy of starting core threads only when + * new tasks are executed. + * @return the number of threads started. + */ + public int prestartAllCoreThreads() { + int n = 0; + while (addIfUnderCorePoolSize(null)) + ++n; + return n; + } + + /** + * Returns true if this pool allows core threads to time out and + * terminate if no tasks arrive within the keepAlive time, being + * replaced if needed when new tasks arrive. When true, the same + * keep-alive policy applying to non-core threads applies also to + * core threads. When false (the default), core threads are never + * terminated due to lack of incoming tasks. + * @return <tt>true</tt> if core threads are allowed to time out, + * else <tt>false</tt> + * + * @since 1.6 + */ + public boolean allowsCoreThreadTimeOut() { + return allowCoreThreadTimeOut; + } + + /** + * Sets the policy governing whether core threads may time out and + * terminate if no tasks arrive within the keep-alive time, being + * replaced if needed when new tasks arrive. When false, core + * threads are never terminated due to lack of incoming + * tasks. When true, the same keep-alive policy applying to + * non-core threads applies also to core threads. To avoid + * continual thread replacement, the keep-alive time must be + * greater than zero when setting <tt>true</tt>. This method + * should in general be called before the pool is actively used. + * @param value <tt>true</tt> if should time out, else <tt>false</tt> + * @throws IllegalArgumentException if value is <tt>true</tt> + * and the current keep-alive time is not greater than zero. + * + * @since 1.6 + */ + public void allowCoreThreadTimeOut(boolean value) { + if (value && keepAliveTime <= 0) + throw new IllegalArgumentException("Core threads must have nonzero keep alive times"); + + allowCoreThreadTimeOut = value; + } + + /** + * Sets the maximum allowed number of threads. This overrides any + * value set in the constructor. If the new value is smaller than + * the current value, excess existing threads will be + * terminated when they next become idle. + * + * @param maximumPoolSize the new maximum + * @throws IllegalArgumentException if the new maximum is + * less than or equal to zero, or + * less than the {@linkplain #getCorePoolSize core pool size} + * @see #getMaximumPoolSize + */ + public void setMaximumPoolSize(int maximumPoolSize) { + if (maximumPoolSize <= 0 || maximumPoolSize < corePoolSize) + throw new IllegalArgumentException(); + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + int extra = this.maximumPoolSize - maximumPoolSize; + this.maximumPoolSize = maximumPoolSize; + if (extra > 0 && poolSize > maximumPoolSize) { + Iterator<Worker> it = workers.iterator(); + while (it.hasNext() && + extra > 0 && + poolSize > maximumPoolSize) { + it.next().interruptIfIdle(); + --extra; + } + } + } finally { + mainLock.unlock(); + } + } + + /** + * Returns the maximum allowed number of threads. + * + * @return the maximum allowed number of threads + * @see #setMaximumPoolSize + */ + public int getMaximumPoolSize() { + return maximumPoolSize; + } + + /** + * 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. + * @param time the time to wait. A time value of zero will cause + * excess threads to terminate immediately after executing tasks. + * @param unit the time unit of the time argument + * @throws IllegalArgumentException if time less than zero or + * if time is zero and allowsCoreThreadTimeOut + * @see #getKeepAliveTime + */ + public void setKeepAliveTime(long time, TimeUnit unit) { + if (time < 0) + throw new IllegalArgumentException(); + if (time == 0 && allowsCoreThreadTimeOut()) + throw new IllegalArgumentException("Core threads must have nonzero keep alive times"); + this.keepAliveTime = unit.toNanos(time); + } + + /** + * Returns the thread keep-alive time, which is the amount of time + * which threads in excess of the core pool size may remain + * idle before being terminated. + * + * @param unit the desired time unit of the result + * @return the time limit + * @see #setKeepAliveTime + */ + public long getKeepAliveTime(TimeUnit unit) { + return unit.convert(keepAliveTime, TimeUnit.NANOSECONDS); + } + + /* Statistics */ + + /** + * Returns the current number of threads in the pool. + * + * @return the number of threads + */ + public int getPoolSize() { + return poolSize; + } + + /** + * Returns the approximate number of threads that are actively + * executing tasks. + * + * @return the number of threads + */ + public int getActiveCount() { + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + int n = 0; + for (Worker w : workers) { + if (w.isActive()) + ++n; + } + return n; + } finally { + mainLock.unlock(); + } + } + + /** + * Returns the largest number of threads that have ever + * simultaneously been in the pool. + * + * @return the number of threads + */ + public int getLargestPoolSize() { + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + return largestPoolSize; + } finally { + mainLock.unlock(); + } + } + + /** + * Returns the approximate total number of tasks that have been + * scheduled for execution. Because the states of tasks and + * threads may change dynamically during computation, the returned + * value is only an approximation, but one that does not ever + * decrease across successive calls. + * + * @return the number of tasks + */ + public long getTaskCount() { + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + long n = completedTaskCount; + for (Worker w : workers) { + n += w.completedTasks; + if (w.isActive()) + ++n; + } + return n + workQueue.size(); + } finally { + mainLock.unlock(); + } + } + + /** + * Returns the approximate total number of tasks that have + * completed execution. Because the states of tasks and threads + * may change dynamically during computation, the returned value + * is only an approximation, but one that does not ever decrease + * across successive calls. + * + * @return the number of tasks + */ + public long getCompletedTaskCount() { + final ReentrantLock mainLock = this.mainLock; + mainLock.lock(); + try { + long n = completedTaskCount; + for (Worker w : workers) + n += w.completedTasks; + return n; + } finally { + mainLock.unlock(); + } + } + + /** + * Method invoked prior to executing the given Runnable in the + * given thread. This method is invoked by thread <tt>t</tt> that + * will execute task <tt>r</tt>, and may be used to re-initialize + * ThreadLocals, or to perform logging. + * + * <p>This implementation does nothing, but may be customized in + * subclasses. Note: To properly nest multiple overridings, subclasses + * should generally invoke <tt>super.beforeExecute</tt> at the end of + * this method. + * + * @param t the thread that will run task r. + * @param r the task that will be executed. + */ + protected void beforeExecute(Thread t, Runnable r) { } + + /** + * Method invoked upon completion of execution of the given Runnable. + * This method is invoked by the thread that executed the task. If + * non-null, the Throwable is the uncaught <tt>RuntimeException</tt> + * or <tt>Error</tt> that caused execution to terminate abruptly. + * + * <p><b>Note:</b> When actions are enclosed in tasks (such as + * {@link FutureTask}) either explicitly or via methods such as + * <tt>submit</tt>, these task objects catch and maintain + * computational exceptions, and so they do not cause abrupt + * termination, and the internal exceptions are <em>not</em> + * passed to this method. + * + * <p>This implementation does nothing, but may be customized in + * subclasses. Note: To properly nest multiple overridings, subclasses + * should generally invoke <tt>super.afterExecute</tt> at the + * beginning of this method. + * + * @param r the runnable that has completed. + * @param t the exception that caused termination, or null if + * execution completed normally. + */ + protected void afterExecute(Runnable r, Throwable t) { } + + /** + * Method invoked when the Executor has terminated. Default + * implementation does nothing. Note: To properly nest multiple + * overridings, subclasses should generally invoke + * <tt>super.terminated</tt> within this method. + */ + protected void terminated() { } + + /** + * A handler for rejected tasks that runs the rejected task + * directly in the calling thread of the <tt>execute</tt> method, + * unless the executor has been shut down, in which case the task + * is discarded. + */ + public static class CallerRunsPolicy implements RejectedExecutionHandler { + /** + * Creates a <tt>CallerRunsPolicy</tt>. + */ + public CallerRunsPolicy() { } + + /** + * Executes task r in the caller's thread, unless the executor + * has been shut down, in which case the task is discarded. + * @param r the runnable task requested to be executed + * @param e the executor attempting to execute this task + */ + public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { + if (!e.isShutdown()) { + r.run(); + } + } + } + + /** + * A handler for rejected tasks that throws a + * <tt>RejectedExecutionException</tt>. + */ + public static class AbortPolicy implements RejectedExecutionHandler { + /** + * Creates an <tt>AbortPolicy</tt>. + */ + public AbortPolicy() { } + + /** + * Always throws RejectedExecutionException. + * @param r the runnable task requested to be executed + * @param e the executor attempting to execute this task + * @throws RejectedExecutionException always. + */ + public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { + throw new RejectedExecutionException(); + } + } + + /** + * A handler for rejected tasks that silently discards the + * rejected task. + */ + public static class DiscardPolicy implements RejectedExecutionHandler { + /** + * Creates a <tt>DiscardPolicy</tt>. + */ + public DiscardPolicy() { } + + /** + * Does nothing, which has the effect of discarding task r. + * @param r the runnable task requested to be executed + * @param e the executor attempting to execute this task + */ + public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { + } + } + + /** + * A handler for rejected tasks that discards the oldest unhandled + * request and then retries <tt>execute</tt>, unless the executor + * is shut down, in which case the task is discarded. + */ + public static class DiscardOldestPolicy implements RejectedExecutionHandler { + /** + * Creates a <tt>DiscardOldestPolicy</tt> for the given executor. + */ + public DiscardOldestPolicy() { } + + /** + * Obtains and ignores the next task that the executor + * would otherwise execute, if one is immediately available, + * and then retries execution of task r, unless the executor + * is shut down, in which case task r is instead discarded. + * @param r the runnable task requested to be executed + * @param e the executor attempting to execute this task + */ + public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { + if (!e.isShutdown()) { + e.getQueue().poll(); + e.execute(r); + } + } + } +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/TimeUnit.java b/libjava/classpath/external/jsr166/java/util/concurrent/TimeUnit.java new file mode 100644 index 000000000..2cd3d06ab --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/TimeUnit.java @@ -0,0 +1,331 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; + +/** + * A <tt>TimeUnit</tt> represents time durations at a given unit of + * granularity and provides utility methods to convert across units, + * and to perform timing and delay operations in these units. A + * <tt>TimeUnit</tt> does not maintain time information, but only + * helps organize and use time representations that may be maintained + * separately across various contexts. A nanosecond is defined as one + * thousandth of a microsecond, a microsecond as one thousandth of a + * millisecond, a millisecond as one thousandth of a second, a minute + * as sixty seconds, an hour as sixty minutes, and a day as twenty four + * hours. + * + * <p>A <tt>TimeUnit</tt> is mainly used to inform time-based methods + * how a given timing parameter should be interpreted. For example, + * the following code will timeout in 50 milliseconds if the {@link + * java.util.concurrent.locks.Lock lock} is not available: + * + * <pre> Lock lock = ...; + * if ( lock.tryLock(50L, TimeUnit.MILLISECONDS) ) ... + * </pre> + * while this code will timeout in 50 seconds: + * <pre> + * Lock lock = ...; + * if ( lock.tryLock(50L, TimeUnit.SECONDS) ) ... + * </pre> + * + * Note however, that there is no guarantee that a particular timeout + * implementation will be able to notice the passage of time at the + * same granularity as the given <tt>TimeUnit</tt>. + * + * @since 1.5 + * @author Doug Lea + */ +public enum TimeUnit { + NANOSECONDS { + public long toNanos(long d) { return d; } + public long toMicros(long d) { return d/(C1/C0); } + public long toMillis(long d) { return d/(C2/C0); } + public long toSeconds(long d) { return d/(C3/C0); } + public long toMinutes(long d) { return d/(C4/C0); } + public long toHours(long d) { return d/(C5/C0); } + public long toDays(long d) { return d/(C6/C0); } + public long convert(long d, TimeUnit u) { return u.toNanos(d); } + int excessNanos(long d, long m) { return (int)(d - (m*C2)); } + }, + MICROSECONDS { + public long toNanos(long d) { return x(d, C1/C0, MAX/(C1/C0)); } + public long toMicros(long d) { return d; } + public long toMillis(long d) { return d/(C2/C1); } + public long toSeconds(long d) { return d/(C3/C1); } + public long toMinutes(long d) { return d/(C4/C1); } + public long toHours(long d) { return d/(C5/C1); } + public long toDays(long d) { return d/(C6/C1); } + public long convert(long d, TimeUnit u) { return u.toMicros(d); } + int excessNanos(long d, long m) { return (int)((d*C1) - (m*C2)); } + }, + MILLISECONDS { + public long toNanos(long d) { return x(d, C2/C0, MAX/(C2/C0)); } + public long toMicros(long d) { return x(d, C2/C1, MAX/(C2/C1)); } + public long toMillis(long d) { return d; } + public long toSeconds(long d) { return d/(C3/C2); } + public long toMinutes(long d) { return d/(C4/C2); } + public long toHours(long d) { return d/(C5/C2); } + public long toDays(long d) { return d/(C6/C2); } + public long convert(long d, TimeUnit u) { return u.toMillis(d); } + int excessNanos(long d, long m) { return 0; } + }, + SECONDS { + public long toNanos(long d) { return x(d, C3/C0, MAX/(C3/C0)); } + public long toMicros(long d) { return x(d, C3/C1, MAX/(C3/C1)); } + public long toMillis(long d) { return x(d, C3/C2, MAX/(C3/C2)); } + public long toSeconds(long d) { return d; } + public long toMinutes(long d) { return d/(C4/C3); } + public long toHours(long d) { return d/(C5/C3); } + public long toDays(long d) { return d/(C6/C3); } + public long convert(long d, TimeUnit u) { return u.toSeconds(d); } + int excessNanos(long d, long m) { return 0; } + }, + MINUTES { + public long toNanos(long d) { return x(d, C4/C0, MAX/(C4/C0)); } + public long toMicros(long d) { return x(d, C4/C1, MAX/(C4/C1)); } + public long toMillis(long d) { return x(d, C4/C2, MAX/(C4/C2)); } + public long toSeconds(long d) { return x(d, C4/C3, MAX/(C4/C3)); } + public long toMinutes(long d) { return d; } + public long toHours(long d) { return d/(C5/C4); } + public long toDays(long d) { return d/(C6/C4); } + public long convert(long d, TimeUnit u) { return u.toMinutes(d); } + int excessNanos(long d, long m) { return 0; } + }, + HOURS { + public long toNanos(long d) { return x(d, C5/C0, MAX/(C5/C0)); } + public long toMicros(long d) { return x(d, C5/C1, MAX/(C5/C1)); } + public long toMillis(long d) { return x(d, C5/C2, MAX/(C5/C2)); } + public long toSeconds(long d) { return x(d, C5/C3, MAX/(C5/C3)); } + public long toMinutes(long d) { return x(d, C5/C4, MAX/(C5/C4)); } + public long toHours(long d) { return d; } + public long toDays(long d) { return d/(C6/C5); } + public long convert(long d, TimeUnit u) { return u.toHours(d); } + int excessNanos(long d, long m) { return 0; } + }, + DAYS { + public long toNanos(long d) { return x(d, C6/C0, MAX/(C6/C0)); } + public long toMicros(long d) { return x(d, C6/C1, MAX/(C6/C1)); } + public long toMillis(long d) { return x(d, C6/C2, MAX/(C6/C2)); } + public long toSeconds(long d) { return x(d, C6/C3, MAX/(C6/C3)); } + public long toMinutes(long d) { return x(d, C6/C4, MAX/(C6/C4)); } + public long toHours(long d) { return x(d, C6/C5, MAX/(C6/C5)); } + public long toDays(long d) { return d; } + public long convert(long d, TimeUnit u) { return u.toDays(d); } + int excessNanos(long d, long m) { return 0; } + }; + + // Handy constants for conversion methods + static final long C0 = 1L; + static final long C1 = C0 * 1000L; + static final long C2 = C1 * 1000L; + static final long C3 = C2 * 1000L; + static final long C4 = C3 * 60L; + static final long C5 = C4 * 60L; + static final long C6 = C5 * 24L; + + static final long MAX = Long.MAX_VALUE; + + /** + * Scale d by m, checking for overflow. + * 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.MIN_VALUE; + return d * m; + } + + // To maintain full signature compatibility with 1.5, and to improve the + // clarity of the generated javadoc (see 6287639: Abstract methods in + // enum classes should not be listed as abstract), method convert + // etc. are not declared abstract but otherwise act as abstract methods. + + /** + * Convert the given time duration in the given unit to this + * unit. Conversions from finer to coarser granularities + * truncate, so lose precision. For example converting + * <tt>999</tt> milliseconds to seconds results in + * <tt>0</tt>. Conversions from coarser to finer granularities + * with arguments that would numerically overflow saturate to + * <tt>Long.MIN_VALUE</tt> if negative or <tt>Long.MAX_VALUE</tt> + * if positive. + * + * <p>For example, to convert 10 minutes to milliseconds, use: + * <tt>TimeUnit.MILLISECONDS.convert(10L, TimeUnit.MINUTES)</tt> + * + * @param sourceDuration the time duration in the given <tt>sourceUnit</tt> + * @param sourceUnit the unit of the <tt>sourceDuration</tt> argument + * @return the converted duration in this unit, + * or <tt>Long.MIN_VALUE</tt> if conversion would negatively + * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow. + */ + public long convert(long sourceDuration, TimeUnit sourceUnit) { + throw new AbstractMethodError(); + } + + /** + * Equivalent to <tt>NANOSECONDS.convert(duration, this)</tt>. + * @param duration the duration + * @return the converted duration, + * or <tt>Long.MIN_VALUE</tt> if conversion would negatively + * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow. + * @see #convert + */ + public long toNanos(long duration) { + throw new AbstractMethodError(); + } + + /** + * Equivalent to <tt>MICROSECONDS.convert(duration, this)</tt>. + * @param duration the duration + * @return the converted duration, + * or <tt>Long.MIN_VALUE</tt> if conversion would negatively + * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow. + * @see #convert + */ + public long toMicros(long duration) { + throw new AbstractMethodError(); + } + + /** + * Equivalent to <tt>MILLISECONDS.convert(duration, this)</tt>. + * @param duration the duration + * @return the converted duration, + * or <tt>Long.MIN_VALUE</tt> if conversion would negatively + * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow. + * @see #convert + */ + public long toMillis(long duration) { + throw new AbstractMethodError(); + } + + /** + * Equivalent to <tt>SECONDS.convert(duration, this)</tt>. + * @param duration the duration + * @return the converted duration, + * or <tt>Long.MIN_VALUE</tt> if conversion would negatively + * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow. + * @see #convert + */ + public long toSeconds(long duration) { + throw new AbstractMethodError(); + } + + /** + * Equivalent to <tt>MINUTES.convert(duration, this)</tt>. + * @param duration the duration + * @return the converted duration, + * or <tt>Long.MIN_VALUE</tt> if conversion would negatively + * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow. + * @see #convert + * @since 1.6 + */ + public long toMinutes(long duration) { + throw new AbstractMethodError(); + } + + /** + * Equivalent to <tt>HOURS.convert(duration, this)</tt>. + * @param duration the duration + * @return the converted duration, + * or <tt>Long.MIN_VALUE</tt> if conversion would negatively + * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow. + * @see #convert + * @since 1.6 + */ + public long toHours(long duration) { + throw new AbstractMethodError(); + } + + /** + * Equivalent to <tt>DAYS.convert(duration, this)</tt>. + * @param duration the duration + * @return the converted duration + * @see #convert + * @since 1.6 + */ + public long toDays(long duration) { + throw new AbstractMethodError(); + } + + /** + * Utility to compute the excess-nanosecond argument to wait, + * sleep, join. + * @param d the duration + * @param m the number of milliseconds + * @return the number of nanoseconds + */ + abstract int excessNanos(long d, long m); + + /** + * Performs a timed <tt>Object.wait</tt> using this time unit. + * This is a convenience method that converts timeout arguments + * into the form required by the <tt>Object.wait</tt> method. + * + * <p>For example, you could implement a blocking <tt>poll</tt> + * method (see {@link BlockingQueue#poll BlockingQueue.poll}) + * using: + * + * <pre> public synchronized Object poll(long timeout, TimeUnit unit) throws InterruptedException { + * while (empty) { + * unit.timedWait(this, timeout); + * ... + * } + * }</pre> + * + * @param obj the object to wait on + * @param timeout the maximum time to wait. If less than + * or equal to zero, do not wait at all. + * @throws InterruptedException if interrupted while waiting. + * @see Object#wait(long, int) + */ + public void timedWait(Object obj, long timeout) + throws InterruptedException { + if (timeout > 0) { + long ms = toMillis(timeout); + int ns = excessNanos(timeout, ms); + obj.wait(ms, ns); + } + } + + /** + * Performs a timed <tt>Thread.join</tt> using this time unit. + * This is a convenience method that converts time arguments into the + * form required by the <tt>Thread.join</tt> method. + * @param thread the thread to wait for + * @param timeout the maximum time to wait. If less than + * or equal to zero, do not wait at all. + * @throws InterruptedException if interrupted while waiting. + * @see Thread#join(long, int) + */ + public void timedJoin(Thread thread, long timeout) + throws InterruptedException { + if (timeout > 0) { + long ms = toMillis(timeout); + int ns = excessNanos(timeout, ms); + thread.join(ms, ns); + } + } + + /** + * Performs a <tt>Thread.sleep</tt> using this unit. + * This is a convenience method that converts time arguments into the + * form required by the <tt>Thread.sleep</tt> method. + * @param timeout the minimum time to sleep. If less than + * or equal to zero, do not sleep at all. + * @throws InterruptedException if interrupted while sleeping. + * @see Thread#sleep + */ + public void sleep(long timeout) throws InterruptedException { + if (timeout > 0) { + long ms = toMillis(timeout); + int ns = excessNanos(timeout, ms); + Thread.sleep(ms, ns); + } + } + +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/TimeoutException.java b/libjava/classpath/external/jsr166/java/util/concurrent/TimeoutException.java new file mode 100644 index 000000000..8b84f28e5 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/TimeoutException.java @@ -0,0 +1,38 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent; + +/** + * Exception thrown when a blocking operation times out. Blocking + * operations for which a timeout is specified need a means to + * indicate that the timeout has occurred. For many such operations it + * is possible to return a value that indicates timeout; when that is + * not possible or desirable then <tt>TimeoutException</tt> should be + * declared and thrown. + * + * @since 1.5 + * @author Doug Lea + */ +public class TimeoutException extends Exception { + private static final long serialVersionUID = 1900926677490660714L; + + /** + * Constructs a <tt>TimeoutException</tt> with no specified detail + * message. + */ + public TimeoutException() {} + + /** + * Constructs a <tt>TimeoutException</tt> with the specified detail + * message. + * + * @param message the detail message + */ + public TimeoutException(String message) { + super(message); + } +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicBoolean.java b/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicBoolean.java new file mode 100644 index 000000000..bd823bd2c --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicBoolean.java @@ -0,0 +1,133 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.atomic; +import sun.misc.Unsafe; + +/** + * A <tt>boolean</tt> value that may be updated atomically. See the + * {@link java.util.concurrent.atomic} package specification for + * description of the properties of atomic variables. An + * <tt>AtomicBoolean</tt> is used in applications such as atomically + * updated flags, and cannot be used as a replacement for a + * {@link java.lang.Boolean}. + * + * @since 1.5 + * @author Doug Lea + */ +public class AtomicBoolean implements java.io.Serializable { + private static final long serialVersionUID = 4654671469794556979L; + // setup to use Unsafe.compareAndSwapInt for updates + private static final Unsafe unsafe = Unsafe.getUnsafe(); + private static final long valueOffset; + + static { + try { + valueOffset = unsafe.objectFieldOffset + (AtomicBoolean.class.getDeclaredField("value")); + } catch (Exception ex) { throw new Error(ex); } + } + + private volatile int value; + + /** + * Creates a new <tt>AtomicBoolean</tt> with the given initial value. + * + * @param initialValue the initial value + */ + public AtomicBoolean(boolean initialValue) { + value = initialValue ? 1 : 0; + } + + /** + * Creates a new <tt>AtomicBoolean</tt> with initial value <tt>false</tt>. + */ + public AtomicBoolean() { + } + + /** + * Returns the current value. + * + * @return the current value + */ + public final boolean get() { + return value != 0; + } + + /** + * Atomically sets the value to the given updated value + * if the current value <tt>==</tt> the expected value. + * + * @param expect the expected value + * @param update the new value + * @return true if successful. False return indicates that + * the actual value was not equal to the expected value. + */ + public final boolean compareAndSet(boolean expect, boolean update) { + int e = expect ? 1 : 0; + int u = update ? 1 : 0; + return unsafe.compareAndSwapInt(this, valueOffset, e, u); + } + + /** + * Atomically sets the value to the given updated value + * if the current value <tt>==</tt> the expected value. + * May fail spuriously and does not provide ordering guarantees, + * so is only rarely an appropriate alternative to <tt>compareAndSet</tt>. + * + * @param expect the expected value + * @param update the new value + * @return true if successful. + */ + public boolean weakCompareAndSet(boolean expect, boolean update) { + int e = expect ? 1 : 0; + int u = update ? 1 : 0; + return unsafe.compareAndSwapInt(this, valueOffset, e, u); + } + + /** + * Unconditionally sets to the given value. + * + * @param newValue the new value + */ + public final void set(boolean newValue) { + value = newValue ? 1 : 0; + } + + /** + * Eventually sets to the given value. + * + * @param newValue the new value + * @since 1.6 + */ + public final void lazySet(boolean newValue) { + int v = newValue ? 1 : 0; + unsafe.putOrderedInt(this, valueOffset, v); + } + + /** + * Atomically sets to the given value and returns the previous value. + * + * @param newValue the new value + * @return the previous value + */ + public final boolean getAndSet(boolean newValue) { + for (;;) { + boolean current = get(); + if (compareAndSet(current, newValue)) + return current; + } + } + + /** + * Returns the String representation of the current value. + * @return the String representation of the current value. + */ + public String toString() { + return Boolean.toString(get()); + } + +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicInteger.java b/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicInteger.java new file mode 100644 index 000000000..0f723f613 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicInteger.java @@ -0,0 +1,234 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.atomic; +import sun.misc.Unsafe; + +/** + * An <tt>int</tt> value that may be updated atomically. See the + * {@link java.util.concurrent.atomic} package specification for + * description of the properties of atomic variables. An + * <tt>AtomicInteger</tt> is used in applications such as atomically + * incremented counters, and cannot be used as a replacement for an + * {@link java.lang.Integer}. However, this class does extend + * <tt>Number</tt> to allow uniform access by tools and utilities that + * deal with numerically-based classes. + * + * @since 1.5 + * @author Doug Lea +*/ +public class AtomicInteger extends Number implements java.io.Serializable { + private static final long serialVersionUID = 6214790243416807050L; + + // setup to use Unsafe.compareAndSwapInt for updates + private static final Unsafe unsafe = Unsafe.getUnsafe(); + private static final long valueOffset; + + static { + try { + valueOffset = unsafe.objectFieldOffset + (AtomicInteger.class.getDeclaredField("value")); + } catch (Exception ex) { throw new Error(ex); } + } + + private volatile int value; + + /** + * Creates a new AtomicInteger with the given initial value. + * + * @param initialValue the initial value + */ + public AtomicInteger(int initialValue) { + value = initialValue; + } + + /** + * Creates a new AtomicInteger with initial value <tt>0</tt>. + */ + public AtomicInteger() { + } + + /** + * Gets the current value. + * + * @return the current value + */ + public final int get() { + return value; + } + + /** + * Sets to the given value. + * + * @param newValue the new value + */ + public final void set(int newValue) { + value = newValue; + } + + /** + * Eventually sets to the given value. + * + * @param newValue the new value + * @since 1.6 + */ + public final void lazySet(int newValue) { + unsafe.putOrderedInt(this, valueOffset, newValue); + } + + /** + * Atomically sets to the given value and returns the old value. + * + * @param newValue the new value + * @return the previous value + */ + public final int getAndSet(int newValue) { + for (;;) { + int current = get(); + if (compareAndSet(current, newValue)) + return current; + } + } + + /** + * Atomically sets the value to the given updated value + * if the current value <tt>==</tt> the expected value. + * + * @param expect the expected value + * @param update the new value + * @return true if successful. False return indicates that + * the actual value was not equal to the expected value. + */ + public final boolean compareAndSet(int expect, int update) { + return unsafe.compareAndSwapInt(this, valueOffset, expect, update); + } + + /** + * Atomically sets the value to the given updated value + * if the current value <tt>==</tt> the expected value. + * May fail spuriously and does not provide ordering guarantees, + * so is only rarely an appropriate alternative to <tt>compareAndSet</tt>. + * + * @param expect the expected value + * @param update the new value + * @return true if successful. + */ + public final boolean weakCompareAndSet(int expect, int update) { + return unsafe.compareAndSwapInt(this, valueOffset, expect, update); + } + + /** + * Atomically increments by one the current value. + * + * @return the previous value + */ + public final int getAndIncrement() { + for (;;) { + int current = get(); + int next = current + 1; + if (compareAndSet(current, next)) + return current; + } + } + + /** + * Atomically decrements by one the current value. + * + * @return the previous value + */ + public final int getAndDecrement() { + for (;;) { + int current = get(); + int next = current - 1; + if (compareAndSet(current, next)) + return current; + } + } + + /** + * Atomically adds the given value to the current value. + * + * @param delta the value to add + * @return the previous value + */ + public final int getAndAdd(int delta) { + for (;;) { + int current = get(); + int next = current + delta; + if (compareAndSet(current, next)) + return current; + } + } + + /** + * Atomically increments by one the current value. + * + * @return the updated value + */ + public final int incrementAndGet() { + for (;;) { + int current = get(); + int next = current + 1; + if (compareAndSet(current, next)) + return next; + } + } + + /** + * Atomically decrements by one the current value. + * + * @return the updated value + */ + public final int decrementAndGet() { + for (;;) { + int current = get(); + int next = current - 1; + if (compareAndSet(current, next)) + return next; + } + } + + /** + * Atomically adds the given value to the current value. + * + * @param delta the value to add + * @return the updated value + */ + public final int addAndGet(int delta) { + for (;;) { + int current = get(); + int next = current + delta; + if (compareAndSet(current, next)) + return next; + } + } + + /** + * Returns the String representation of the current value. + * @return the String representation of the current value. + */ + public String toString() { + return Integer.toString(get()); + } + + + public int intValue() { + return get(); + } + + public long longValue() { + return (long)get(); + } + + public float floatValue() { + return (float)get(); + } + + public double doubleValue() { + return (double)get(); + } + +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicIntegerArray.java b/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicIntegerArray.java new file mode 100644 index 000000000..2ad754fda --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicIntegerArray.java @@ -0,0 +1,255 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.atomic; +import sun.misc.Unsafe; +import java.util.*; + +/** + * An <tt>int</tt> array in which elements may be updated atomically. + * See the {@link java.util.concurrent.atomic} package + * specification for description of the properties of atomic + * variables. + * @since 1.5 + * @author Doug Lea + */ +public class AtomicIntegerArray implements java.io.Serializable { + private static final long serialVersionUID = 2862133569453604235L; + + // setup to use Unsafe.compareAndSwapInt for updates + private static final Unsafe unsafe = Unsafe.getUnsafe(); + private static final int base = unsafe.arrayBaseOffset(int[].class); + private static final int scale = unsafe.arrayIndexScale(int[].class); + private final int[] array; + + private long rawIndex(int i) { + if (i < 0 || i >= array.length) + throw new IndexOutOfBoundsException("index " + i); + return base + i * scale; + } + + /** + * Creates a new AtomicIntegerArray of given length. + * + * @param length the length of the array + */ + public AtomicIntegerArray(int length) { + array = new int[length]; + // must perform at least one volatile write to conform to JMM + if (length > 0) + unsafe.putIntVolatile(array, rawIndex(0), 0); + } + + /** + * Creates a new AtomicIntegerArray with the same length as, and + * all elements copied from, the given array. + * + * @param array the array to copy elements from + * @throws NullPointerException if array is null + */ + public AtomicIntegerArray(int[] array) { + if (array == null) + throw new NullPointerException(); + int length = array.length; + this.array = new int[length]; + if (length > 0) { + int last = length-1; + for (int i = 0; i < last; ++i) + this.array[i] = array[i]; + // Do the last write as volatile + unsafe.putIntVolatile(this.array, rawIndex(last), array[last]); + } + } + + /** + * Returns the length of the array. + * + * @return the length of the array + */ + public final int length() { + return array.length; + } + + /** + * Gets the current value at position <tt>i</tt>. + * + * @param i the index + * @return the current value + */ + public final int get(int i) { + return unsafe.getIntVolatile(array, rawIndex(i)); + } + + /** + * Sets the element at position <tt>i</tt> to the given value. + * + * @param i the index + * @param newValue the new value + */ + public final void set(int i, int newValue) { + unsafe.putIntVolatile(array, rawIndex(i), newValue); + } + + /** + * Eventually sets the element at position <tt>i</tt> to the given value. + * + * @param i the index + * @param newValue the new value + * @since 1.6 + */ + public final void lazySet(int i, int newValue) { + unsafe.putOrderedInt(array, rawIndex(i), newValue); + } + + /** + * Atomically sets the element at position <tt>i</tt> to the given + * value and returns the old value. + * + * @param i the index + * @param newValue the new value + * @return the previous value + */ + public final int getAndSet(int i, int newValue) { + while (true) { + int current = get(i); + if (compareAndSet(i, current, newValue)) + return current; + } + } + + /** + * Atomically sets the element at position <tt>i</tt> to the given + * updated value if the current value <tt>==</tt> the expected value. + * + * @param i the index + * @param expect the expected value + * @param update the new value + * @return true if successful. False return indicates that + * the actual value was not equal to the expected value. + */ + public final boolean compareAndSet(int i, int expect, int update) { + return unsafe.compareAndSwapInt(array, rawIndex(i), + expect, update); + } + + /** + * Atomically sets the element at position <tt>i</tt> to the given + * updated value if the current value <tt>==</tt> the expected value. + * May fail spuriously and does not provide ordering guarantees, + * so is only rarely an appropriate alternative to <tt>compareAndSet</tt>. + * + * @param i the index + * @param expect the expected value + * @param update the new value + * @return true if successful. + */ + public final boolean weakCompareAndSet(int i, int expect, int update) { + return compareAndSet(i, expect, update); + } + + /** + * Atomically increments by one the element at index <tt>i</tt>. + * + * @param i the index + * @return the previous value + */ + public final int getAndIncrement(int i) { + while (true) { + int current = get(i); + int next = current + 1; + if (compareAndSet(i, current, next)) + return current; + } + } + + /** + * Atomically decrements by one the element at index <tt>i</tt>. + * + * @param i the index + * @return the previous value + */ + public final int getAndDecrement(int i) { + while (true) { + int current = get(i); + int next = current - 1; + if (compareAndSet(i, current, next)) + return current; + } + } + + /** + * Atomically adds the given value to the element at index <tt>i</tt>. + * + * @param i the index + * @param delta the value to add + * @return the previous value + */ + public final int getAndAdd(int i, int delta) { + while (true) { + int current = get(i); + int next = current + delta; + if (compareAndSet(i, current, next)) + return current; + } + } + + /** + * Atomically increments by one the element at index <tt>i</tt>. + * + * @param i the index + * @return the updated value + */ + public final int incrementAndGet(int i) { + while (true) { + int current = get(i); + int next = current + 1; + if (compareAndSet(i, current, next)) + return next; + } + } + + /** + * Atomically decrements by one the element at index <tt>i</tt>. + * + * @param i the index + * @return the updated value + */ + public final int decrementAndGet(int i) { + while (true) { + int current = get(i); + int next = current - 1; + if (compareAndSet(i, current, next)) + return next; + } + } + + /** + * Atomically adds the given value to the element at index <tt>i</tt>. + * + * @param i the index + * @param delta the value to add + * @return the updated value + */ + public final int addAndGet(int i, int delta) { + while (true) { + int current = get(i); + int next = current + delta; + if (compareAndSet(i, current, next)) + return next; + } + } + + /** + * Returns the String representation of the current values of array. + * @return the String representation of the current values of array. + */ + public String toString() { + if (array.length > 0) // force volatile read + get(0); + return Arrays.toString(array); + } + +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java b/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java new file mode 100644 index 000000000..c957bbf3f --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java @@ -0,0 +1,316 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.atomic; +import sun.misc.Unsafe; +import java.lang.reflect.*; + +/** + * A reflection-based utility that enables atomic updates to + * designated <tt>volatile int</tt> fields of designated classes. + * This class is designed for use in atomic data structures in which + * several fields of the same node are independently subject to atomic + * updates. + * + * <p>Note that the guarantees of the {@code compareAndSet} + * method in this class are weaker than in other atomic classes. + * Because this class cannot ensure that all uses of the field + * are appropriate for purposes of atomic access, it can + * guarantee atomicity only with respect to other invocations of + * {@code compareAndSet} and {@code set} on the same updater. + * + * @since 1.5 + * @author Doug Lea + * @param <T> The type of the object holding the updatable field + */ +public abstract class AtomicIntegerFieldUpdater<T> { + /** + * Creates and returns an updater for objects with the given field. + * The Class argument is needed to check that reflective types and + * generic types match. + * + * @param tclass the class of the objects holding the field + * @param fieldName the name of the field to be updated + * @return the updater + * @throws IllegalArgumentException if the field is not a + * volatile integer type + * @throws RuntimeException with a nested reflection-based + * exception if the class does not hold field or is the wrong type + */ + public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) { + return new AtomicIntegerFieldUpdaterImpl<U>(tclass, fieldName); + } + + /** + * Protected do-nothing constructor for use by subclasses. + */ + protected AtomicIntegerFieldUpdater() { + } + + /** + * Atomically sets the field of the given object managed by this updater + * to the given updated value if the current value <tt>==</tt> the + * expected value. This method is guaranteed to be atomic with respect to + * other calls to <tt>compareAndSet</tt> and <tt>set</tt>, but not + * necessarily with respect to other changes in the field. + * + * @param obj An object whose field to conditionally set + * @param expect the expected value + * @param update the new value + * @return true if successful + * @throws ClassCastException if <tt>obj</tt> is not an instance + * of the class possessing the field established in the constructor + */ + public abstract boolean compareAndSet(T obj, int expect, int update); + + /** + * Atomically sets the field of the given object managed by this updater + * to the given updated value if the current value <tt>==</tt> the + * expected value. This method is guaranteed to be atomic with respect to + * other calls to <tt>compareAndSet</tt> and <tt>set</tt>, but not + * necessarily with respect to other changes in the field. + * May fail spuriously and does not provide ordering guarantees, + * so is only rarely an appropriate alternative to <tt>compareAndSet</tt>. + * + * @param obj An object whose field to conditionally set + * @param expect the expected value + * @param update the new value + * @return true if successful + * @throws ClassCastException if <tt>obj</tt> is not an instance + * of the class possessing the field established in the constructor + */ + public abstract boolean weakCompareAndSet(T obj, int expect, int update); + + /** + * Sets the field of the given object managed by this updater to the + * given updated value. This operation is guaranteed to act as a volatile + * store with respect to subsequent invocations of + * <tt>compareAndSet</tt>. + * + * @param obj An object whose field to set + * @param newValue the new value + */ + public abstract void set(T obj, int newValue); + + /** + * Eventually sets the field of the given object managed by this + * updater to the given updated value. + * + * @param obj An object whose field to set + * @param newValue the new value + * @since 1.6 + */ + public abstract void lazySet(T obj, int newValue); + + + /** + * Gets the current value held in the field of the given object managed + * by this updater. + * + * @param obj An object whose field to get + * @return the current value + */ + public abstract int get(T obj); + + /** + * Atomically sets the field of the given object managed by this updater + * to the given value and returns the old value. + * + * @param obj An object whose field to get and set + * @param newValue the new value + * @return the previous value + */ + public int getAndSet(T obj, int newValue) { + for (;;) { + int current = get(obj); + if (compareAndSet(obj, current, newValue)) + return current; + } + } + + /** + * Atomically increments by one the current value of the field of the + * given object managed by this updater. + * + * @param obj An object whose field to get and set + * @return the previous value + */ + public int getAndIncrement(T obj) { + for (;;) { + int current = get(obj); + int next = current + 1; + if (compareAndSet(obj, current, next)) + return current; + } + } + + /** + * Atomically decrements by one the current value of the field of the + * given object managed by this updater. + * + * @param obj An object whose field to get and set + * @return the previous value + */ + public int getAndDecrement(T obj) { + for (;;) { + int current = get(obj); + int next = current - 1; + if (compareAndSet(obj, current, next)) + return current; + } + } + + /** + * Atomically adds the given value to the current value of the field of + * the given object managed by this updater. + * + * @param obj An object whose field to get and set + * @param delta the value to add + * @return the previous value + */ + public int getAndAdd(T obj, int delta) { + for (;;) { + int current = get(obj); + int next = current + delta; + if (compareAndSet(obj, current, next)) + return current; + } + } + + /** + * Atomically increments by one the current value of the field of the + * given object managed by this updater. + * + * @param obj An object whose field to get and set + * @return the updated value + */ + public int incrementAndGet(T obj) { + for (;;) { + int current = get(obj); + int next = current + 1; + if (compareAndSet(obj, current, next)) + return next; + } + } + + /** + * Atomically decrements by one the current value of the field of the + * given object managed by this updater. + * + * @param obj An object whose field to get and set + * @return the updated value + */ + public int decrementAndGet(T obj) { + for (;;) { + int current = get(obj); + int next = current - 1; + if (compareAndSet(obj, current, next)) + return next; + } + } + + /** + * Atomically adds the given value to the current value of the field of + * the given object managed by this updater. + * + * @param obj An object whose field to get and set + * @param delta the value to add + * @return the updated value + */ + public int addAndGet(T obj, int delta) { + for (;;) { + int current = get(obj); + int next = current + delta; + if (compareAndSet(obj, current, next)) + return next; + } + } + + /** + * Standard hotspot implementation using intrinsics + */ + private static class AtomicIntegerFieldUpdaterImpl<T> extends AtomicIntegerFieldUpdater<T> { + private static final Unsafe unsafe = Unsafe.getUnsafe(); + private final long offset; + private final Class<T> tclass; + private final Class cclass; + + AtomicIntegerFieldUpdaterImpl(Class<T> tclass, String fieldName) { + Field field = null; + Class caller = null; + int modifiers = 0; + try { + field = tclass.getDeclaredField(fieldName); + caller = sun.reflect.Reflection.getCallerClass(3); + modifiers = field.getModifiers(); + sun.reflect.misc.ReflectUtil.ensureMemberAccess( + caller, tclass, null, modifiers); + sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); + } catch(Exception ex) { + throw new RuntimeException(ex); + } + + Class fieldt = field.getType(); + if (fieldt != int.class) + throw new IllegalArgumentException("Must be integer type"); + + if (!Modifier.isVolatile(modifiers)) + throw new IllegalArgumentException("Must be volatile type"); + + this.cclass = (Modifier.isProtected(modifiers) && + caller != tclass) ? caller : null; + this.tclass = tclass; + offset = unsafe.objectFieldOffset(field); + } + + private void fullCheck(T obj) { + if (!tclass.isInstance(obj)) + throw new ClassCastException(); + if (cclass != null) + ensureProtectedAccess(obj); + } + + public boolean compareAndSet(T obj, int expect, int update) { + if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); + return unsafe.compareAndSwapInt(obj, offset, expect, update); + } + + public boolean weakCompareAndSet(T obj, int expect, int update) { + if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); + return unsafe.compareAndSwapInt(obj, offset, expect, update); + } + + public void set(T obj, int newValue) { + if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); + unsafe.putIntVolatile(obj, offset, newValue); + } + + public void lazySet(T obj, int newValue) { + if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); + unsafe.putOrderedInt(obj, offset, newValue); + } + + public final int get(T obj) { + if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); + return unsafe.getIntVolatile(obj, offset); + } + + private void ensureProtectedAccess(T obj) { + if (cclass.isInstance(obj)) { + return; + } + throw new RuntimeException( + new IllegalAccessException("Class " + + cclass.getName() + + " can not access a protected member of class " + + tclass.getName() + + " using an instance of " + + obj.getClass().getName() + ) + ); + } + } +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicLong.java b/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicLong.java new file mode 100644 index 000000000..fa254ba62 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicLong.java @@ -0,0 +1,248 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.atomic; +import sun.misc.Unsafe; + +/** + * A <tt>long</tt> value that may be updated atomically. See the + * {@link java.util.concurrent.atomic} package specification for + * description of the properties of atomic variables. An + * <tt>AtomicLong</tt> is used in applications such as atomically + * incremented sequence numbers, and cannot be used as a replacement + * for a {@link java.lang.Long}. However, this class does extend + * <tt>Number</tt> to allow uniform access by tools and utilities that + * deal with numerically-based classes. + * + * @since 1.5 + * @author Doug Lea + */ +public class AtomicLong extends Number implements java.io.Serializable { + private static final long serialVersionUID = 1927816293512124184L; + + // setup to use Unsafe.compareAndSwapLong for updates + private static final Unsafe unsafe = Unsafe.getUnsafe(); + private static final long valueOffset; + + /** + * Records whether the underlying JVM supports lockless + * CompareAndSet for longs. While the unsafe.CompareAndSetLong + * method works in either case, some constructions should be + * handled at Java level to avoid locking user-visible locks. + */ + static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8(); + + /** + * Returns whether underlying JVM supports lockless CompareAndSet + * for longs. Called only once and cached in VM_SUPPORTS_LONG_CAS. + */ + private static native boolean VMSupportsCS8(); + + static { + try { + valueOffset = unsafe.objectFieldOffset + (AtomicLong.class.getDeclaredField("value")); + } catch (Exception ex) { throw new Error(ex); } + } + + private volatile long value; + + /** + * Creates a new AtomicLong with the given initial value. + * + * @param initialValue the initial value + */ + public AtomicLong(long initialValue) { + value = initialValue; + } + + /** + * Creates a new AtomicLong with initial value <tt>0</tt>. + */ + public AtomicLong() { + } + + /** + * Gets the current value. + * + * @return the current value + */ + public final long get() { + return value; + } + + /** + * Sets to the given value. + * + * @param newValue the new value + */ + public final void set(long newValue) { + value = newValue; + } + + /** + * Eventually sets to the given value. + * + * @param newValue the new value + * @since 1.6 + */ + public final void lazySet(long newValue) { + unsafe.putOrderedLong(this, valueOffset, newValue); + } + + /** + * Atomically sets to the given value and returns the old value. + * + * @param newValue the new value + * @return the previous value + */ + public final long getAndSet(long newValue) { + while (true) { + long current = get(); + if (compareAndSet(current, newValue)) + return current; + } + } + + /** + * Atomically sets the value to the given updated value + * if the current value <tt>==</tt> the expected value. + * + * @param expect the expected value + * @param update the new value + * @return true if successful. False return indicates that + * the actual value was not equal to the expected value. + */ + public final boolean compareAndSet(long expect, long update) { + return unsafe.compareAndSwapLong(this, valueOffset, expect, update); + } + + /** + * Atomically sets the value to the given updated value + * if the current value <tt>==</tt> the expected value. + * May fail spuriously and does not provide ordering guarantees, + * so is only rarely an appropriate alternative to <tt>compareAndSet</tt>. + * + * @param expect the expected value + * @param update the new value + * @return true if successful. + */ + public final boolean weakCompareAndSet(long expect, long update) { + return unsafe.compareAndSwapLong(this, valueOffset, expect, update); + } + + /** + * Atomically increments by one the current value. + * + * @return the previous value + */ + public final long getAndIncrement() { + while (true) { + long current = get(); + long next = current + 1; + if (compareAndSet(current, next)) + return current; + } + } + + /** + * Atomically decrements by one the current value. + * + * @return the previous value + */ + public final long getAndDecrement() { + while (true) { + long current = get(); + long next = current - 1; + if (compareAndSet(current, next)) + return current; + } + } + + /** + * Atomically adds the given value to the current value. + * + * @param delta the value to add + * @return the previous value + */ + public final long getAndAdd(long delta) { + while (true) { + long current = get(); + long next = current + delta; + if (compareAndSet(current, next)) + return current; + } + } + + /** + * Atomically increments by one the current value. + * + * @return the updated value + */ + public final long incrementAndGet() { + for (;;) { + long current = get(); + long next = current + 1; + if (compareAndSet(current, next)) + return next; + } + } + + /** + * Atomically decrements by one the current value. + * + * @return the updated value + */ + public final long decrementAndGet() { + for (;;) { + long current = get(); + long next = current - 1; + if (compareAndSet(current, next)) + return next; + } + } + + /** + * Atomically adds the given value to the current value. + * + * @param delta the value to add + * @return the updated value + */ + public final long addAndGet(long delta) { + for (;;) { + long current = get(); + long next = current + delta; + if (compareAndSet(current, next)) + return next; + } + } + + /** + * Returns the String representation of the current value. + * @return the String representation of the current value. + */ + public String toString() { + return Long.toString(get()); + } + + + public int intValue() { + return (int)get(); + } + + public long longValue() { + return (long)get(); + } + + public float floatValue() { + return (float)get(); + } + + public double doubleValue() { + return (double)get(); + } + +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicLongArray.java b/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicLongArray.java new file mode 100644 index 000000000..c582cba54 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicLongArray.java @@ -0,0 +1,255 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.atomic; +import sun.misc.Unsafe; +import java.util.*; + +/** + * A <tt>long</tt> array in which elements may be updated atomically. + * See the {@link java.util.concurrent.atomic} package specification + * for description of the properties of atomic variables. + * @since 1.5 + * @author Doug Lea + */ +public class AtomicLongArray implements java.io.Serializable { + private static final long serialVersionUID = -2308431214976778248L; + + // setup to use Unsafe.compareAndSwapInt for updates + private static final Unsafe unsafe = Unsafe.getUnsafe(); + private static final int base = unsafe.arrayBaseOffset(long[].class); + private static final int scale = unsafe.arrayIndexScale(long[].class); + private final long[] array; + + private long rawIndex(int i) { + if (i < 0 || i >= array.length) + throw new IndexOutOfBoundsException("index " + i); + return base + i * scale; + } + + /** + * Creates a new AtomicLongArray of given length. + * + * @param length the length of the array + */ + public AtomicLongArray(int length) { + array = new long[length]; + // must perform at least one volatile write to conform to JMM + if (length > 0) + unsafe.putLongVolatile(array, rawIndex(0), 0); + } + + /** + * Creates a new AtomicLongArray with the same length as, and + * all elements copied from, the given array. + * + * @param array the array to copy elements from + * @throws NullPointerException if array is null + */ + public AtomicLongArray(long[] array) { + if (array == null) + throw new NullPointerException(); + int length = array.length; + this.array = new long[length]; + if (length > 0) { + int last = length-1; + for (int i = 0; i < last; ++i) + this.array[i] = array[i]; + // Do the last write as volatile + unsafe.putLongVolatile(this.array, rawIndex(last), array[last]); + } + } + + /** + * Returns the length of the array. + * + * @return the length of the array + */ + public final int length() { + return array.length; + } + + /** + * Gets the current value at position <tt>i</tt>. + * + * @param i the index + * @return the current value + */ + public final long get(int i) { + return unsafe.getLongVolatile(array, rawIndex(i)); + } + + /** + * Sets the element at position <tt>i</tt> to the given value. + * + * @param i the index + * @param newValue the new value + */ + public final void set(int i, long newValue) { + unsafe.putLongVolatile(array, rawIndex(i), newValue); + } + + /** + * Eventually sets the element at position <tt>i</tt> to the given value. + * + * @param i the index + * @param newValue the new value + * @since 1.6 + */ + public final void lazySet(int i, long newValue) { + unsafe.putOrderedLong(array, rawIndex(i), newValue); + } + + + /** + * Atomically sets the element at position <tt>i</tt> to the given value + * and returns the old value. + * + * @param i the index + * @param newValue the new value + * @return the previous value + */ + public final long getAndSet(int i, long newValue) { + while (true) { + long current = get(i); + if (compareAndSet(i, current, newValue)) + return current; + } + } + + /** + * Atomically sets the value to the given updated value + * if the current value <tt>==</tt> the expected value. + * + * @param i the index + * @param expect the expected value + * @param update the new value + * @return true if successful. False return indicates that + * the actual value was not equal to the expected value. + */ + public final boolean compareAndSet(int i, long expect, long update) { + return unsafe.compareAndSwapLong(array, rawIndex(i), + expect, update); + } + + /** + * Atomically sets the value to the given updated value + * if the current value <tt>==</tt> the expected value. + * May fail spuriously and does not provide ordering guarantees, + * so is only rarely an appropriate alternative to <tt>compareAndSet</tt>. + * + * @param i the index + * @param expect the expected value + * @param update the new value + * @return true if successful. + */ + public final boolean weakCompareAndSet(int i, long expect, long update) { + return compareAndSet(i, expect, update); + } + + /** + * Atomically increments by one the element at index <tt>i</tt>. + * + * @param i the index + * @return the previous value + */ + public final long getAndIncrement(int i) { + while (true) { + long current = get(i); + long next = current + 1; + if (compareAndSet(i, current, next)) + return current; + } + } + + /** + * Atomically decrements by one the element at index <tt>i</tt>. + * + * @param i the index + * @return the previous value + */ + public final long getAndDecrement(int i) { + while (true) { + long current = get(i); + long next = current - 1; + if (compareAndSet(i, current, next)) + return current; + } + } + + /** + * Atomically adds the given value to the element at index <tt>i</tt>. + * + * @param i the index + * @param delta the value to add + * @return the previous value + */ + public final long getAndAdd(int i, long delta) { + while (true) { + long current = get(i); + long next = current + delta; + if (compareAndSet(i, current, next)) + return current; + } + } + + /** + * Atomically increments by one the element at index <tt>i</tt>. + * + * @param i the index + * @return the updated value + */ + public final long incrementAndGet(int i) { + while (true) { + long current = get(i); + long next = current + 1; + if (compareAndSet(i, current, next)) + return next; + } + } + + /** + * Atomically decrements by one the element at index <tt>i</tt>. + * + * @param i the index + * @return the updated value + */ + public final long decrementAndGet(int i) { + while (true) { + long current = get(i); + long next = current - 1; + if (compareAndSet(i, current, next)) + return next; + } + } + + /** + * Atomically adds the given value to the element at index <tt>i</tt>. + * + * @param i the index + * @param delta the value to add + * @return the updated value + */ + public long addAndGet(int i, long delta) { + while (true) { + long current = get(i); + long next = current + delta; + if (compareAndSet(i, current, next)) + return next; + } + } + + /** + * Returns the String representation of the current values of array. + * @return the String representation of the current values of array. + */ + public String toString() { + if (array.length > 0) // force volatile read + get(0); + return Arrays.toString(array); + } + +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicLongFieldUpdater.java b/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicLongFieldUpdater.java new file mode 100644 index 000000000..f6135d1fc --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicLongFieldUpdater.java @@ -0,0 +1,406 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.atomic; +import sun.misc.Unsafe; +import java.lang.reflect.*; + +/** + * A reflection-based utility that enables atomic updates to + * designated <tt>volatile long</tt> fields of designated classes. + * This class is designed for use in atomic data structures in which + * several fields of the same node are independently subject to atomic + * updates. + * + * <p>Note that the guarantees of the {@code compareAndSet} + * method in this class are weaker than in other atomic classes. + * Because this class cannot ensure that all uses of the field + * are appropriate for purposes of atomic access, it can + * guarantee atomicity only with respect to other invocations of + * {@code compareAndSet} and {@code set} on the same updater. + * + * @since 1.5 + * @author Doug Lea + * @param <T> The type of the object holding the updatable field + */ +public abstract class AtomicLongFieldUpdater<T> { + /** + * Creates and returns an updater for objects with the given field. + * The Class argument is needed to check that reflective types and + * generic types match. + * + * @param tclass the class of the objects holding the field + * @param fieldName the name of the field to be updated. + * @return the updater + * @throws IllegalArgumentException if the field is not a + * volatile long type. + * @throws RuntimeException with a nested reflection-based + * exception if the class does not hold field or is the wrong type. + */ + public static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) { + if (AtomicLong.VM_SUPPORTS_LONG_CAS) + return new CASUpdater<U>(tclass, fieldName); + else + return new LockedUpdater<U>(tclass, fieldName); + } + + /** + * Protected do-nothing constructor for use by subclasses. + */ + protected AtomicLongFieldUpdater() { + } + + /** + * Atomically sets the field of the given object managed by this updater + * to the given updated value if the current value <tt>==</tt> the + * expected value. This method is guaranteed to be atomic with respect to + * other calls to <tt>compareAndSet</tt> and <tt>set</tt>, but not + * necessarily with respect to other changes in the field. + * + * @param obj An object whose field to conditionally set + * @param expect the expected value + * @param update the new value + * @return true if successful. + * @throws ClassCastException if <tt>obj</tt> is not an instance + * of the class possessing the field established in the constructor. + */ + public abstract boolean compareAndSet(T obj, long expect, long update); + + /** + * Atomically sets the field of the given object managed by this updater + * to the given updated value if the current value <tt>==</tt> the + * expected value. This method is guaranteed to be atomic with respect to + * other calls to <tt>compareAndSet</tt> and <tt>set</tt>, but not + * necessarily with respect to other changes in the field. + * May fail spuriously and does not provide ordering guarantees, + * so is only rarely an appropriate alternative to <tt>compareAndSet</tt>. + * + * @param obj An object whose field to conditionally set + * @param expect the expected value + * @param update the new value + * @return true if successful. + * @throws ClassCastException if <tt>obj</tt> is not an instance + * of the class possessing the field established in the constructor. + */ + public abstract boolean weakCompareAndSet(T obj, long expect, long update); + + /** + * Sets the field of the given object managed by this updater to the + * given updated value. This operation is guaranteed to act as a volatile + * store with respect to subsequent invocations of + * <tt>compareAndSet</tt>. + * + * @param obj An object whose field to set + * @param newValue the new value + */ + public abstract void set(T obj, long newValue); + + /** + * Eventually sets the field of the given object managed by this + * updater to the given updated value. + * + * @param obj An object whose field to set + * @param newValue the new value + * @since 1.6 + */ + public abstract void lazySet(T obj, long newValue); + + /** + * Gets the current value held in the field of the given object managed + * by this updater. + * + * @param obj An object whose field to get + * @return the current value + */ + public abstract long get(T obj); + + /** + * Atomically sets the field of the given object managed by this updater + * to the given value and returns the old value. + * + * @param obj An object whose field to get and set + * @param newValue the new value + * @return the previous value + */ + public long getAndSet(T obj, long newValue) { + for (;;) { + long current = get(obj); + if (compareAndSet(obj, current, newValue)) + return current; + } + } + + /** + * Atomically increments by one the current value of the field of the + * given object managed by this updater. + * + * @param obj An object whose field to get and set + * @return the previous value + */ + public long getAndIncrement(T obj) { + for (;;) { + long current = get(obj); + long next = current + 1; + if (compareAndSet(obj, current, next)) + return current; + } + } + + /** + * Atomically decrements by one the current value of the field of the + * given object managed by this updater. + * + * @param obj An object whose field to get and set + * @return the previous value + */ + public long getAndDecrement(T obj) { + for (;;) { + long current = get(obj); + long next = current - 1; + if (compareAndSet(obj, current, next)) + return current; + } + } + + /** + * Atomically adds the given value to the current value of the field of + * the given object managed by this updater. + * + * @param obj An object whose field to get and set + * @param delta the value to add + * @return the previous value + */ + public long getAndAdd(T obj, long delta) { + for (;;) { + long current = get(obj); + long next = current + delta; + if (compareAndSet(obj, current, next)) + return current; + } + } + + /** + * Atomically increments by one the current value of the field of the + * given object managed by this updater. + * + * @param obj An object whose field to get and set + * @return the updated value + */ + public long incrementAndGet(T obj) { + for (;;) { + long current = get(obj); + long next = current + 1; + if (compareAndSet(obj, current, next)) + return next; + } + } + + /** + * Atomically decrements by one the current value of the field of the + * given object managed by this updater. + * + * @param obj An object whose field to get and set + * @return the updated value + */ + public long decrementAndGet(T obj) { + for (;;) { + long current = get(obj); + long next = current - 1; + if (compareAndSet(obj, current, next)) + return next; + } + } + + /** + * Atomically adds the given value to the current value of the field of + * the given object managed by this updater. + * + * @param obj An object whose field to get and set + * @param delta the value to add + * @return the updated value + */ + public long addAndGet(T obj, long delta) { + for (;;) { + long current = get(obj); + long next = current + delta; + if (compareAndSet(obj, current, next)) + return next; + } + } + + private static class CASUpdater<T> extends AtomicLongFieldUpdater<T> { + private static final Unsafe unsafe = Unsafe.getUnsafe(); + private final long offset; + private final Class<T> tclass; + private final Class cclass; + + CASUpdater(Class<T> tclass, String fieldName) { + Field field = null; + Class caller = null; + int modifiers = 0; + try { + field = tclass.getDeclaredField(fieldName); + caller = sun.reflect.Reflection.getCallerClass(3); + modifiers = field.getModifiers(); + sun.reflect.misc.ReflectUtil.ensureMemberAccess( + caller, tclass, null, modifiers); + sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); + } catch(Exception ex) { + throw new RuntimeException(ex); + } + + Class fieldt = field.getType(); + if (fieldt != long.class) + throw new IllegalArgumentException("Must be long type"); + + if (!Modifier.isVolatile(modifiers)) + throw new IllegalArgumentException("Must be volatile type"); + + this.cclass = (Modifier.isProtected(modifiers) && + caller != tclass) ? caller : null; + this.tclass = tclass; + offset = unsafe.objectFieldOffset(field); + } + + private void fullCheck(T obj) { + if (!tclass.isInstance(obj)) + throw new ClassCastException(); + if (cclass != null) + ensureProtectedAccess(obj); + } + + public boolean compareAndSet(T obj, long expect, long update) { + if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); + return unsafe.compareAndSwapLong(obj, offset, expect, update); + } + + public boolean weakCompareAndSet(T obj, long expect, long update) { + if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); + return unsafe.compareAndSwapLong(obj, offset, expect, update); + } + + public void set(T obj, long newValue) { + if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); + unsafe.putLongVolatile(obj, offset, newValue); + } + + public void lazySet(T obj, long newValue) { + if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); + unsafe.putOrderedLong(obj, offset, newValue); + } + + public long get(T obj) { + if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); + return unsafe.getLongVolatile(obj, offset); + } + + private void ensureProtectedAccess(T obj) { + if (cclass.isInstance(obj)) { + return; + } + throw new RuntimeException ( + new IllegalAccessException("Class " + + cclass.getName() + + " can not access a protected member of class " + + tclass.getName() + + " using an instance of " + + obj.getClass().getName() + ) + ); + } + } + + + private static class LockedUpdater<T> extends AtomicLongFieldUpdater<T> { + private static final Unsafe unsafe = Unsafe.getUnsafe(); + private final long offset; + private final Class<T> tclass; + private final Class cclass; + + LockedUpdater(Class<T> tclass, String fieldName) { + Field field = null; + Class caller = null; + int modifiers = 0; + try { + field = tclass.getDeclaredField(fieldName); + caller = sun.reflect.Reflection.getCallerClass(3); + modifiers = field.getModifiers(); + sun.reflect.misc.ReflectUtil.ensureMemberAccess( + caller, tclass, null, modifiers); + sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); + } catch(Exception ex) { + throw new RuntimeException(ex); + } + + Class fieldt = field.getType(); + if (fieldt != long.class) + throw new IllegalArgumentException("Must be long type"); + + if (!Modifier.isVolatile(modifiers)) + throw new IllegalArgumentException("Must be volatile type"); + + this.cclass = (Modifier.isProtected(modifiers) && + caller != tclass) ? caller : null; + this.tclass = tclass; + offset = unsafe.objectFieldOffset(field); + } + + private void fullCheck(T obj) { + if (!tclass.isInstance(obj)) + throw new ClassCastException(); + if (cclass != null) + ensureProtectedAccess(obj); + } + + public boolean compareAndSet(T obj, long expect, long update) { + if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); + synchronized(this) { + long v = unsafe.getLong(obj, offset); + if (v != expect) + return false; + unsafe.putLong(obj, offset, update); + return true; + } + } + + public boolean weakCompareAndSet(T obj, long expect, long update) { + return compareAndSet(obj, expect, update); + } + + public void set(T obj, long newValue) { + if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); + synchronized(this) { + unsafe.putLong(obj, offset, newValue); + } + } + + public void lazySet(T obj, long newValue) { + set(obj, newValue); + } + + public long get(T obj) { + if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); + synchronized(this) { + return unsafe.getLong(obj, offset); + } + } + + private void ensureProtectedAccess(T obj) { + if (cclass.isInstance(obj)) { + return; + } + throw new RuntimeException ( + new IllegalAccessException("Class " + + cclass.getName() + + " can not access a protected member of class " + + tclass.getName() + + " using an instance of " + + obj.getClass().getName() + ) + ); + } + } +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicMarkableReference.java b/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicMarkableReference.java new file mode 100644 index 000000000..85335b737 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicMarkableReference.java @@ -0,0 +1,161 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.atomic; + +/** + * An <tt>AtomicMarkableReference</tt> maintains an object reference + * along with a mark bit, that can be updated atomically. + * <p> + * <p> Implementation note. This implementation maintains markable + * references by creating internal objects representing "boxed" + * [reference, boolean] pairs. + * + * @since 1.5 + * @author Doug Lea + * @param <V> The type of object referred to by this reference + */ +public class AtomicMarkableReference<V> { + + private static class ReferenceBooleanPair<T> { + private final T reference; + private final boolean bit; + ReferenceBooleanPair(T r, boolean i) { + reference = r; bit = i; + } + } + + private final AtomicReference<ReferenceBooleanPair<V>> atomicRef; + + /** + * Creates a new <tt>AtomicMarkableReference</tt> with the given + * initial values. + * + * @param initialRef the initial reference + * @param initialMark the initial mark + */ + public AtomicMarkableReference(V initialRef, boolean initialMark) { + atomicRef = new AtomicReference<ReferenceBooleanPair<V>> (new ReferenceBooleanPair<V>(initialRef, initialMark)); + } + + /** + * Returns the current value of the reference. + * + * @return the current value of the reference + */ + public V getReference() { + return atomicRef.get().reference; + } + + /** + * Returns the current value of the mark. + * + * @return the current value of the mark + */ + public boolean isMarked() { + return atomicRef.get().bit; + } + + /** + * Returns the current values of both the reference and the mark. + * Typical usage is <tt>boolean[1] holder; ref = v.get(holder); </tt>. + * + * @param markHolder an array of size of at least one. On return, + * <tt>markholder[0]</tt> will hold the value of the mark. + * @return the current value of the reference + */ + public V get(boolean[] markHolder) { + ReferenceBooleanPair<V> p = atomicRef.get(); + markHolder[0] = p.bit; + return p.reference; + } + + /** + * Atomically sets the value of both the reference and mark + * to the given update values if the + * current reference is <tt>==</tt> to the expected reference + * and the current mark is equal to the expected mark. + * May fail spuriously and does not provide ordering guarantees, + * so is only rarely an appropriate alternative to <tt>compareAndSet</tt>. + * + * @param expectedReference the expected value of the reference + * @param newReference the new value for the reference + * @param expectedMark the expected value of the mark + * @param newMark the new value for the mark + * @return true if successful + */ + public boolean weakCompareAndSet(V expectedReference, + V newReference, + boolean expectedMark, + boolean newMark) { + ReferenceBooleanPair<V> current = atomicRef.get(); + return expectedReference == current.reference && + expectedMark == current.bit && + ((newReference == current.reference && newMark == current.bit) || + atomicRef.weakCompareAndSet(current, + new ReferenceBooleanPair<V>(newReference, + newMark))); + } + + /** + * Atomically sets the value of both the reference and mark + * to the given update values if the + * current reference is <tt>==</tt> to the expected reference + * and the current mark is equal to the expected mark. + * + * @param expectedReference the expected value of the reference + * @param newReference the new value for the reference + * @param expectedMark the expected value of the mark + * @param newMark the new value for the mark + * @return true if successful + */ + public boolean compareAndSet(V expectedReference, + V newReference, + boolean expectedMark, + boolean newMark) { + ReferenceBooleanPair<V> current = atomicRef.get(); + return expectedReference == current.reference && + expectedMark == current.bit && + ((newReference == current.reference && newMark == current.bit) || + atomicRef.compareAndSet(current, + new ReferenceBooleanPair<V>(newReference, + newMark))); + } + + /** + * Unconditionally sets the value of both the reference and mark. + * + * @param newReference the new value for the reference + * @param newMark the new value for the mark + */ + public void set(V newReference, boolean newMark) { + ReferenceBooleanPair<V> current = atomicRef.get(); + if (newReference != current.reference || newMark != current.bit) + atomicRef.set(new ReferenceBooleanPair<V>(newReference, newMark)); + } + + /** + * Atomically sets the value of the mark to the given update value + * if the current reference is <tt>==</tt> to the expected + * reference. Any given invocation of this operation may fail + * (return <tt>false</tt>) spuriously, but repeated invocation + * when the current value holds the expected value and no other + * thread is also attempting to set the value will eventually + * succeed. + * + * @param expectedReference the expected value of the reference + * @param newMark the new value for the mark + * @return true if successful + */ + public boolean attemptMark(V expectedReference, boolean newMark) { + ReferenceBooleanPair<V> current = atomicRef.get(); + return expectedReference == current.reference && + (newMark == current.bit || + atomicRef.compareAndSet + (current, new ReferenceBooleanPair<V>(expectedReference, + newMark))); + } +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicReference.java b/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicReference.java new file mode 100644 index 000000000..e7c989c2b --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicReference.java @@ -0,0 +1,124 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.atomic; +import sun.misc.Unsafe; + +/** + * An object reference that may be updated atomically. See the {@link + * java.util.concurrent.atomic} package specification for description + * of the properties of atomic variables. + * @since 1.5 + * @author Doug Lea + * @param <V> The type of object referred to by this reference + */ +public class AtomicReference<V> implements java.io.Serializable { + private static final long serialVersionUID = -1848883965231344442L; + + private static final Unsafe unsafe = Unsafe.getUnsafe(); + private static final long valueOffset; + + static { + try { + valueOffset = unsafe.objectFieldOffset + (AtomicReference.class.getDeclaredField("value")); + } catch (Exception ex) { throw new Error(ex); } + } + + private volatile V value; + + /** + * Creates a new AtomicReference with the given initial value. + * + * @param initialValue the initial value + */ + public AtomicReference(V initialValue) { + value = initialValue; + } + + /** + * Creates a new AtomicReference with null initial value. + */ + public AtomicReference() { + } + + /** + * Gets the current value. + * + * @return the current value + */ + public final V get() { + return value; + } + + /** + * Sets to the given value. + * + * @param newValue the new value + */ + public final void set(V newValue) { + value = newValue; + } + + /** + * Eventually sets to the given value. + * + * @param newValue the new value + * @since 1.6 + */ + public final void lazySet(V newValue) { + unsafe.putOrderedObject(this, valueOffset, newValue); + } + + /** + * Atomically sets the value to the given updated value + * if the current value <tt>==</tt> the expected value. + * @param expect the expected value + * @param update the new value + * @return true if successful. False return indicates that + * the actual value was not equal to the expected value. + */ + public final boolean compareAndSet(V expect, V update) { + return unsafe.compareAndSwapObject(this, valueOffset, expect, update); + } + + /** + * Atomically sets the value to the given updated value + * if the current value <tt>==</tt> the expected value. + * May fail spuriously and does not provide ordering guarantees, + * so is only rarely an appropriate alternative to <tt>compareAndSet</tt>. + * + * @param expect the expected value + * @param update the new value + * @return true if successful. + */ + public final boolean weakCompareAndSet(V expect, V update) { + return unsafe.compareAndSwapObject(this, valueOffset, expect, update); + } + + /** + * Atomically sets to the given value and returns the old value. + * + * @param newValue the new value + * @return the previous value + */ + public final V getAndSet(V newValue) { + while (true) { + V x = get(); + if (compareAndSet(x, newValue)) + return x; + } + } + + /** + * Returns the String representation of the current value. + * @return the String representation of the current value. + */ + public String toString() { + return String.valueOf(get()); + } + +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicReferenceArray.java b/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicReferenceArray.java new file mode 100644 index 000000000..91b601ed9 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicReferenceArray.java @@ -0,0 +1,163 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.atomic; +import sun.misc.Unsafe; +import java.util.*; + +/** + * An array of object references in which elements may be updated + * atomically. See the {@link java.util.concurrent.atomic} package + * specification for description of the properties of atomic + * variables. + * @since 1.5 + * @author Doug Lea + * @param <E> The base class of elements held in this array + */ +public class AtomicReferenceArray<E> implements java.io.Serializable { + private static final long serialVersionUID = -6209656149925076980L; + + private static final Unsafe unsafe = Unsafe.getUnsafe(); + private static final int base = unsafe.arrayBaseOffset(Object[].class); + private static final int scale = unsafe.arrayIndexScale(Object[].class); + private final Object[] array; + + private long rawIndex(int i) { + if (i < 0 || i >= array.length) + throw new IndexOutOfBoundsException("index " + i); + return base + i * scale; + } + + /** + * Creates a new AtomicReferenceArray of given length. + * @param length the length of the array + */ + public AtomicReferenceArray(int length) { + array = new Object[length]; + // must perform at least one volatile write to conform to JMM + if (length > 0) + unsafe.putObjectVolatile(array, rawIndex(0), null); + } + + /** + * Creates a new AtomicReferenceArray with the same length as, and + * all elements copied from, the given array. + * + * @param array the array to copy elements from + * @throws NullPointerException if array is null + */ + public AtomicReferenceArray(E[] array) { + if (array == null) + throw new NullPointerException(); + int length = array.length; + this.array = new Object[length]; + if (length > 0) { + int last = length-1; + for (int i = 0; i < last; ++i) + this.array[i] = array[i]; + // Do the last write as volatile + E e = array[last]; + unsafe.putObjectVolatile(this.array, rawIndex(last), e); + } + } + + /** + * Returns the length of the array. + * + * @return the length of the array + */ + public final int length() { + return array.length; + } + + /** + * Gets the current value at position <tt>i</tt>. + * + * @param i the index + * @return the current value + */ + public final E get(int i) { + return (E) unsafe.getObjectVolatile(array, rawIndex(i)); + } + + /** + * Sets the element at position <tt>i</tt> to the given value. + * + * @param i the index + * @param newValue the new value + */ + public final void set(int i, E newValue) { + unsafe.putObjectVolatile(array, rawIndex(i), newValue); + } + + /** + * Eventually sets the element at position <tt>i</tt> to the given value. + * + * @param i the index + * @param newValue the new value + * @since 1.6 + */ + public final void lazySet(int i, E newValue) { + unsafe.putOrderedObject(array, rawIndex(i), newValue); + } + + + /** + * Atomically sets the element at position <tt>i</tt> to the given + * value and returns the old value. + * + * @param i the index + * @param newValue the new value + * @return the previous value + */ + public final E getAndSet(int i, E newValue) { + while (true) { + E current = get(i); + if (compareAndSet(i, current, newValue)) + return current; + } + } + + /** + * Atomically sets the element at position <tt>i</tt> to the given + * updated value if the current value <tt>==</tt> the expected value. + * @param i the index + * @param expect the expected value + * @param update the new value + * @return true if successful. False return indicates that + * the actual value was not equal to the expected value. + */ + public final boolean compareAndSet(int i, E expect, E update) { + return unsafe.compareAndSwapObject(array, rawIndex(i), + expect, update); + } + + /** + * Atomically sets the element at position <tt>i</tt> to the given + * updated value if the current value <tt>==</tt> the expected value. + * May fail spuriously and does not provide ordering guarantees, + * so is only rarely an appropriate alternative to <tt>compareAndSet</tt>. + * + * @param i the index + * @param expect the expected value + * @param update the new value + * @return true if successful. + */ + public final boolean weakCompareAndSet(int i, E expect, E update) { + return compareAndSet(i, expect, update); + } + + /** + * Returns the String representation of the current values of array. + * @return the String representation of the current values of array. + */ + public String toString() { + if (array.length > 0) // force volatile read + get(0); + return Arrays.toString(array); + } + +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java b/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java new file mode 100644 index 000000000..24014a9df --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java @@ -0,0 +1,275 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.atomic; +import sun.misc.Unsafe; +import java.lang.reflect.*; + +/** + * A reflection-based utility that enables atomic updates to + * designated <tt>volatile</tt> reference fields of designated + * classes. This class is designed for use in atomic data structures + * in which several reference fields of the same node are + * independently subject to atomic updates. For example, a tree node + * might be declared as + * + * <pre> + * class Node { + * private volatile Node left, right; + * + * private static final AtomicReferenceFieldUpdater<Node, Node> leftUpdater = + * AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "left"); + * private static AtomicReferenceFieldUpdater<Node, Node> rightUpdater = + * AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "right"); + * + * Node getLeft() { return left; } + * boolean compareAndSetLeft(Node expect, Node update) { + * return leftUpdater.compareAndSet(this, expect, update); + * } + * // ... and so on + * } + * </pre> + * + * <p>Note that the guarantees of the {@code compareAndSet} + * method in this class are weaker than in other atomic classes. + * Because this class cannot ensure that all uses of the field + * are appropriate for purposes of atomic access, it can + * guarantee atomicity only with respect to other invocations of + * {@code compareAndSet} and {@code set} on the same updater. + * + * @since 1.5 + * @author Doug Lea + * @param <T> The type of the object holding the updatable field + * @param <V> The type of the field + */ +public abstract class AtomicReferenceFieldUpdater<T, V> { + + /** + * Creates and returns an updater for objects with the given field. + * The Class arguments are needed to check that reflective types and + * generic types match. + * + * @param tclass the class of the objects holding the field. + * @param vclass the class of the field + * @param fieldName the name of the field to be updated. + * @return the updater + * @throws IllegalArgumentException if the field is not a volatile reference type. + * @throws RuntimeException with a nested reflection-based + * exception if the class does not hold field or is the wrong type. + */ + public static <U, W> AtomicReferenceFieldUpdater<U,W> newUpdater(Class<U> tclass, Class<W> vclass, String fieldName) { + return new AtomicReferenceFieldUpdaterImpl<U,W>(tclass, + vclass, + fieldName); + } + + /** + * Protected do-nothing constructor for use by subclasses. + */ + protected AtomicReferenceFieldUpdater() { + } + + /** + * Atomically sets the field of the given object managed by this updater + * to the given updated value if the current value <tt>==</tt> the + * expected value. This method is guaranteed to be atomic with respect to + * other calls to <tt>compareAndSet</tt> and <tt>set</tt>, but not + * necessarily with respect to other changes in the field. + * + * @param obj An object whose field to conditionally set + * @param expect the expected value + * @param update the new value + * @return true if successful. + */ + public abstract boolean compareAndSet(T obj, V expect, V update); + + /** + * Atomically sets the field of the given object managed by this updater + * to the given updated value if the current value <tt>==</tt> the + * expected value. This method is guaranteed to be atomic with respect to + * other calls to <tt>compareAndSet</tt> and <tt>set</tt>, but not + * necessarily with respect to other changes in the field. + * May fail spuriously and does not provide ordering guarantees, + * so is only rarely an appropriate alternative to <tt>compareAndSet</tt>. + * + * @param obj An object whose field to conditionally set + * @param expect the expected value + * @param update the new value + * @return true if successful. + */ + public abstract boolean weakCompareAndSet(T obj, V expect, V update); + + /** + * Sets the field of the given object managed by this updater to the + * given updated value. This operation is guaranteed to act as a volatile + * store with respect to subsequent invocations of + * <tt>compareAndSet</tt>. + * + * @param obj An object whose field to set + * @param newValue the new value + */ + public abstract void set(T obj, V newValue); + + /** + * Eventually sets the field of the given object managed by this + * updater to the given updated value. + * + * @param obj An object whose field to set + * @param newValue the new value + * @since 1.6 + */ + public abstract void lazySet(T obj, V newValue); + + /** + * Gets the current value held in the field of the given object managed + * by this updater. + * + * @param obj An object whose field to get + * @return the current value + */ + public abstract V get(T obj); + + /** + * Atomically sets the field of the given object managed by this updater + * to the given value and returns the old value. + * + * @param obj An object whose field to get and set + * @param newValue the new value + * @return the previous value + */ + public V getAndSet(T obj, V newValue) { + for (;;) { + V current = get(obj); + if (compareAndSet(obj, current, newValue)) + return current; + } + } + + private static final class AtomicReferenceFieldUpdaterImpl<T,V> + extends AtomicReferenceFieldUpdater<T,V> { + private static final Unsafe unsafe = Unsafe.getUnsafe(); + private final long offset; + private final Class<T> tclass; + private final Class<V> vclass; + private final Class cclass; + + /* + * Internal type checks within all update methods contain + * internal inlined optimizations checking for the common + * cases where the class is final (in which case a simple + * getClass comparison suffices) or is of type Object (in + * which case no check is needed because all objects are + * instances of Object). The Object case is handled simply by + * setting vclass to null in constructor. The targetCheck and + * updateCheck methods are invoked when these faster + * screenings fail. + */ + + AtomicReferenceFieldUpdaterImpl(Class<T> tclass, + Class<V> vclass, + String fieldName) { + Field field = null; + Class fieldClass = null; + Class caller = null; + int modifiers = 0; + try { + field = tclass.getDeclaredField(fieldName); + caller = sun.reflect.Reflection.getCallerClass(3); + modifiers = field.getModifiers(); + sun.reflect.misc.ReflectUtil.ensureMemberAccess( + caller, tclass, null, modifiers); + sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); + fieldClass = field.getType(); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + + if (vclass != fieldClass) + throw new ClassCastException(); + + if (!Modifier.isVolatile(modifiers)) + throw new IllegalArgumentException("Must be volatile type"); + + this.cclass = (Modifier.isProtected(modifiers) && + caller != tclass) ? caller : null; + this.tclass = tclass; + if (vclass == Object.class) + this.vclass = null; + else + this.vclass = vclass; + offset = unsafe.objectFieldOffset(field); + } + + void targetCheck(T obj) { + if (!tclass.isInstance(obj)) + throw new ClassCastException(); + if (cclass != null) + ensureProtectedAccess(obj); + } + + void updateCheck(T obj, V update) { + if (!tclass.isInstance(obj) || + (update != null && vclass != null && !vclass.isInstance(update))) + throw new ClassCastException(); + if (cclass != null) + ensureProtectedAccess(obj); + } + + public boolean compareAndSet(T obj, V expect, V update) { + if (obj == null || obj.getClass() != tclass || cclass != null || + (update != null && vclass != null && + vclass != update.getClass())) + updateCheck(obj, update); + return unsafe.compareAndSwapObject(obj, offset, expect, update); + } + + public boolean weakCompareAndSet(T obj, V expect, V update) { + // same implementation as strong form for now + if (obj == null || obj.getClass() != tclass || cclass != null || + (update != null && vclass != null && + vclass != update.getClass())) + updateCheck(obj, update); + return unsafe.compareAndSwapObject(obj, offset, expect, update); + } + + public void set(T obj, V newValue) { + if (obj == null || obj.getClass() != tclass || cclass != null || + (newValue != null && vclass != null && + vclass != newValue.getClass())) + updateCheck(obj, newValue); + unsafe.putObjectVolatile(obj, offset, newValue); + } + + public void lazySet(T obj, V newValue) { + if (obj == null || obj.getClass() != tclass || cclass != null || + (newValue != null && vclass != null && + vclass != newValue.getClass())) + updateCheck(obj, newValue); + unsafe.putOrderedObject(obj, offset, newValue); + } + + public V get(T obj) { + if (obj == null || obj.getClass() != tclass || cclass != null) + targetCheck(obj); + return (V)unsafe.getObjectVolatile(obj, offset); + } + + private void ensureProtectedAccess(T obj) { + if (cclass.isInstance(obj)) { + return; + } + throw new RuntimeException ( + new IllegalAccessException("Class " + + cclass.getName() + + " can not access a protected member of class " + + tclass.getName() + + " using an instance of " + + obj.getClass().getName() + ) + ); + } + } +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicStampedReference.java b/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicStampedReference.java new file mode 100644 index 000000000..558808216 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/atomic/AtomicStampedReference.java @@ -0,0 +1,165 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.atomic; + +/** + * An <tt>AtomicStampedReference</tt> maintains an object reference + * along with an integer "stamp", that can be updated atomically. + * + * <p> Implementation note. This implementation maintains stamped + * references by creating internal objects representing "boxed" + * [reference, integer] pairs. + * + * @since 1.5 + * @author Doug Lea + * @param <V> The type of object referred to by this reference + */ +public class AtomicStampedReference<V> { + + private static class ReferenceIntegerPair<T> { + private final T reference; + private final int integer; + ReferenceIntegerPair(T r, int i) { + reference = r; integer = i; + } + } + + private final AtomicReference<ReferenceIntegerPair<V>> atomicRef; + + /** + * Creates a new <tt>AtomicStampedReference</tt> with the given + * initial values. + * + * @param initialRef the initial reference + * @param initialStamp the initial stamp + */ + public AtomicStampedReference(V initialRef, int initialStamp) { + atomicRef = new AtomicReference<ReferenceIntegerPair<V>> + (new ReferenceIntegerPair<V>(initialRef, initialStamp)); + } + + /** + * Returns the current value of the reference. + * + * @return the current value of the reference + */ + public V getReference() { + return atomicRef.get().reference; + } + + /** + * Returns the current value of the stamp. + * + * @return the current value of the stamp + */ + public int getStamp() { + return atomicRef.get().integer; + } + + /** + * Returns the current values of both the reference and the stamp. + * Typical usage is <tt>int[1] holder; ref = v.get(holder); </tt>. + * + * @param stampHolder an array of size of at least one. On return, + * <tt>stampholder[0]</tt> will hold the value of the stamp. + * @return the current value of the reference + */ + public V get(int[] stampHolder) { + ReferenceIntegerPair<V> p = atomicRef.get(); + stampHolder[0] = p.integer; + return p.reference; + } + + /** + * Atomically sets the value of both the reference and stamp + * to the given update values if the + * current reference is <tt>==</tt> to the expected reference + * and the current stamp is equal to the expected stamp. + * May fail spuriously and does not provide ordering guarantees, + * so is only rarely an appropriate alternative to <tt>compareAndSet</tt>. + * + * @param expectedReference the expected value of the reference + * @param newReference the new value for the reference + * @param expectedStamp the expected value of the stamp + * @param newStamp the new value for the stamp + * @return true if successful + */ + public boolean weakCompareAndSet(V expectedReference, + V newReference, + int expectedStamp, + int newStamp) { + ReferenceIntegerPair<V> current = atomicRef.get(); + return expectedReference == current.reference && + expectedStamp == current.integer && + ((newReference == current.reference && + newStamp == current.integer) || + atomicRef.weakCompareAndSet(current, + new ReferenceIntegerPair<V>(newReference, + newStamp))); + } + + /** + * Atomically sets the value of both the reference and stamp + * to the given update values if the + * current reference is <tt>==</tt> to the expected reference + * and the current stamp is equal to the expected stamp. + * + * @param expectedReference the expected value of the reference + * @param newReference the new value for the reference + * @param expectedStamp the expected value of the stamp + * @param newStamp the new value for the stamp + * @return true if successful + */ + public boolean compareAndSet(V expectedReference, + V newReference, + int expectedStamp, + int newStamp) { + ReferenceIntegerPair<V> current = atomicRef.get(); + return expectedReference == current.reference && + expectedStamp == current.integer && + ((newReference == current.reference && + newStamp == current.integer) || + atomicRef.compareAndSet(current, + new ReferenceIntegerPair<V>(newReference, + newStamp))); + } + + + /** + * Unconditionally sets the value of both the reference and stamp. + * + * @param newReference the new value for the reference + * @param newStamp the new value for the stamp + */ + public void set(V newReference, int newStamp) { + ReferenceIntegerPair<V> current = atomicRef.get(); + if (newReference != current.reference || newStamp != current.integer) + atomicRef.set(new ReferenceIntegerPair<V>(newReference, newStamp)); + } + + /** + * Atomically sets the value of the stamp to the given update value + * if the current reference is <tt>==</tt> to the expected + * reference. Any given invocation of this operation may fail + * (return <tt>false</tt>) spuriously, but repeated invocation + * when the current value holds the expected value and no other + * thread is also attempting to set the value will eventually + * succeed. + * + * @param expectedReference the expected value of the reference + * @param newStamp the new value for the stamp + * @return true if successful + */ + public boolean attemptStamp(V expectedReference, int newStamp) { + ReferenceIntegerPair<V> current = atomicRef.get(); + return expectedReference == current.reference && + (newStamp == current.integer || + atomicRef.compareAndSet(current, + new ReferenceIntegerPair<V>(expectedReference, + newStamp))); + } +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/locks/AbstractOwnableSynchronizer.java b/libjava/classpath/external/jsr166/java/util/concurrent/locks/AbstractOwnableSynchronizer.java new file mode 100644 index 000000000..f3780e5a6 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/locks/AbstractOwnableSynchronizer.java @@ -0,0 +1,57 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.locks; + +/** + * A synchronizer that may be exclusively owned by a thread. This + * class provides a basis for creating locks and related synchronizers + * that may entail a notion of ownership. The + * <tt>AbstractOwnableSynchronizer</tt> class itself does not manage or + * use this information. However, subclasses and tools may use + * appropriately maintained values to help control and monitor access + * and provide diagnostics. + * + * @since 1.6 + * @author Doug Lea + */ +public abstract class AbstractOwnableSynchronizer + implements java.io.Serializable { + + /** Use serial ID even though all fields transient. */ + private static final long serialVersionUID = 3737899427754241961L; + + /** + * Empty constructor for use by subclasses. + */ + protected AbstractOwnableSynchronizer() { } + + /** + * The current owner of exclusive mode synchronization. + */ + private transient Thread exclusiveOwnerThread; + + /** + * Sets the thread that currently owns exclusive access. A + * <tt>null</tt> argument indicates that no thread owns access. + * This method does not otherwise impose any synchronization or + * <tt>volatile</tt> field accesses. + */ + protected final void setExclusiveOwnerThread(Thread t) { + exclusiveOwnerThread = t; + } + + /** + * Returns the thread last set by + * <tt>setExclusiveOwnerThread</tt>, or <tt>null</tt> if never + * set. This method does not otherwise impose any synchronization + * or <tt>volatile</tt> field accesses. + * @return the owner thread + */ + protected final Thread getExclusiveOwnerThread() { + return exclusiveOwnerThread; + } +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java b/libjava/classpath/external/jsr166/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java new file mode 100644 index 000000000..45d744bb8 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java @@ -0,0 +1,1934 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.locks; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; +import sun.misc.Unsafe; + +/** + * A version of {@link AbstractQueuedSynchronizer} in + * which synchronization state is maintained as a <tt>long</tt>. + * This class has exactly the same structure, properties, and methods + * as <tt>AbstractQueuedSynchronizer</tt> with the exception + * that all state-related parameters and results are defined + * as <tt>long</tt> rather than <tt>int</tt>. This class + * may be useful when creating synchronizers such as + * multilevel locks and barriers that require + * 64 bits of state. + * + * <p>See {@link AbstractQueuedSynchronizer} for usage + * notes and examples. + * + * @since 1.6 + * @author Doug Lea + */ +public abstract class AbstractQueuedLongSynchronizer + extends AbstractOwnableSynchronizer + implements java.io.Serializable { + + private static final long serialVersionUID = 7373984972572414692L; + + /* + To keep sources in sync, the remainder of this source file is + exactly cloned from AbstractQueuedSynchronizer, replacing class + name and changing ints related with sync state to longs. Please + keep it that way. + */ + + /** + * Creates a new <tt>AbstractQueuedLongSynchronizer</tt> instance + * with initial synchronization state of zero. + */ + 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, dequeing + * 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. + * + * <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 { + /** 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; + /** 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; + + /** + * 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. (Use of this value here + * has nothing to do with the other uses + * of the field, but simplifies mechanics.) + * 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 only using + * CAS. + */ + volatile int waitStatus; + + /** + * Link to predecessor node that current node/thread relies on + * for checking waitStatus. Assigned during enqueing, 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 once during enqueuing, and + * nulled out (for sake of GC) when no longer needed. Upon + * cancellation, we cannot adjust this field, but can notice + * status and bypass the node if cancelled. 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. + */ + 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. + * @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: + * If head exists, its waitStatus is guaranteed not to be + * CANCELLED. + */ + private transient volatile Node head; + + /** + * Tail of the wait queue, lazily initialized. Modified only via + * method enq to add new wait node. + */ + private transient volatile Node tail; + + /** + * The synchronization state. + */ + private volatile long state; + + /** + * Returns the current value of synchronization state. + * This operation has memory semantics of a <tt>volatile</tt> read. + * @return current state value + */ + protected final long getState() { + return state; + } + + /** + * Sets the value of synchronization state. + * This operation has memory semantics of a <tt>volatile</tt> write. + * @param newState the new state value + */ + protected final void setState(long newState) { + state = newState; + } + + /** + * Atomically sets synchronization state to the given updated + * value if the current state value equals the expected value. + * This operation has memory semantics of a <tt>volatile</tt> read + * and write. + * + * @param expect the expected value + * @param update the new value + * @return true if successful. False return indicates that the actual + * 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); + } + + // Queuing utilities + + /** + * The number of nanoseconds for which it is faster to spin + * rather than to use timed park. A rough estimate suffices + * to improve responsiveness with very short timeouts. + */ + static final long spinForTimeoutThreshold = 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) { + for (;;) { + Node t = tail; + if (t == null) { // Must initialize + Node h = new Node(); // Dummy header + h.next = node; + node.prev = h; + if (compareAndSetHead(h)) { + tail = node; + return h; + } + } + else { + node.prev = t; + if (compareAndSetTail(t, node)) { + t.next = node; + return t; + } + } + } + } + + /** + * Creates and enqueues node for given thread and mode. + * + * @param current the thread + * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared + * @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; + } + } + enq(node); + return node; + } + + /** + * Sets head of queue to be node, thus dequeuing. Called only by + * acquire methods. Also nulls out unused fields for sake of GC + * and to suppress unnecessary signals and traversals. + * + * @param node the node + */ + private void setHead(Node node) { + head = node; + node.thread = null; + node.prev = null; + } + + /** + * Wakes up node's successor, if one exists. + * + * @param node the node + */ + private void unparkSuccessor(Node node) { + /* + * Try to clear status in anticipation of signalling. It is + * OK if this fails or if status is changed by waiting thread. + */ + compareAndSetWaitStatus(node, Node.SIGNAL, 0); + + /* + * Thread to unpark is held in successor, which is normally + * just the next node. But if cancelled or apparently null, + * traverse backwards from tail to find the actual + * non-cancelled successor. + */ + 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; + } + if (s != null) + LockSupport.unpark(s.thread); + } + + /** + * Sets head of queue, and checks if successor may be waiting + * in shared mode, if so propagating if propagate > 0. + * + * @param pred the node holding waitStatus for node + * @param node the node + * @param propagate the return value from a tryAcquireShared + */ + private void setHeadAndPropagate(Node node, long propagate) { + setHead(node); + if (propagate > 0 && node.waitStatus != 0) { + /* + * Don't bother fully figuring out successor. If it + * looks null, call unparkSuccessor anyway to be safe. + */ + Node s = node.next; + if (s == null || s.isShared()) + unparkSuccessor(node); + } + } + + // Utilities for various versions of acquire + + /** + * Cancels an ongoing attempt to acquire. + * + * @param node the node + */ + private void cancelAcquire(Node node) { + if (node != null) { // Ignore if node doesn't exist + node.thread = null; + // Can use unconditional write instead of CAS here + node.waitStatus = Node.CANCELLED; + unparkSuccessor(node); + } + } + + /** + * Checks and updates status for a node that failed to acquire. + * Returns true if thread should block. This is the main signal + * control in all acquire loops. Requires that pred == node.prev + * + * @param pred node's predecessor holding status + * @param node the node + * @return {@code true} if thread should block + */ + private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) { + int s = pred.waitStatus; + if (s < 0) + /* + * This node has already set status asking a release + * to signal it, so it can safely park + */ + return true; + if (s > 0) + /* + * Predecessor was cancelled. Move up to its predecessor + * and indicate retry. + */ + node.prev = pred.prev; + else + /* + * Indicate that we need a signal, but don't park yet. Caller + * will need to retry to make sure it cannot acquire before + * parking. + */ + compareAndSetWaitStatus(pred, 0, Node.SIGNAL); + return false; + } + + /** + * Convenience method to interrupt current thread. + */ + private static void selfInterrupt() { + Thread.currentThread().interrupt(); + } + + /** + * Convenience method to park and then check if interrupted + * + * @return {@code true} if interrupted + */ + private final boolean parkAndCheckInterrupt() { + LockSupport.park(this); + return Thread.interrupted(); + } + + /* + * Various flavors of acquire, varying in exclusive/shared and + * control modes. Each is mostly the same, but annoyingly + * different. Only a little bit of factoring is possible due to + * interactions of exception mechanics (including ensuring that we + * cancel if tryAcquire throws exception) and other control, at + * least not without hurting performance too much. + */ + + /** + * Acquires in exclusive uninterruptible mode for thread already in + * queue. Used by condition wait methods as well as acquire. + * + * @param node the node + * @param arg the acquire argument + * @return {@code true} if interrupted while waiting + */ + final boolean acquireQueued(final Node node, long arg) { + try { + boolean interrupted = false; + for (;;) { + final Node p = node.predecessor(); + if (p == head && tryAcquire(arg)) { + setHead(node); + p.next = null; // help GC + return interrupted; + } + if (shouldParkAfterFailedAcquire(p, node) && + parkAndCheckInterrupt()) + interrupted = true; + } + } catch (RuntimeException ex) { + cancelAcquire(node); + throw ex; + } + } + + /** + * Acquires in exclusive interruptible mode. + * @param arg the acquire argument + */ + private void doAcquireInterruptibly(long arg) + throws InterruptedException { + final Node node = addWaiter(Node.EXCLUSIVE); + try { + for (;;) { + final Node p = node.predecessor(); + if (p == head && tryAcquire(arg)) { + setHead(node); + p.next = null; // help GC + return; + } + if (shouldParkAfterFailedAcquire(p, node) && + parkAndCheckInterrupt()) + break; + } + } catch (RuntimeException ex) { + cancelAcquire(node); + throw ex; + } + // Arrive here only if interrupted + cancelAcquire(node); + throw new InterruptedException(); + } + + /** + * Acquires in exclusive timed mode. + * + * @param arg the acquire argument + * @param nanosTimeout max wait time + * @return {@code true} if acquired + */ + private boolean doAcquireNanos(long arg, long nanosTimeout) + throws InterruptedException { + long lastTime = System.nanoTime(); + final Node node = addWaiter(Node.EXCLUSIVE); + try { + for (;;) { + final Node p = node.predecessor(); + if (p == head && tryAcquire(arg)) { + setHead(node); + p.next = null; // help GC + return true; + } + if (nanosTimeout <= 0) { + cancelAcquire(node); + return false; + } + if (nanosTimeout > spinForTimeoutThreshold && + shouldParkAfterFailedAcquire(p, node)) + LockSupport.parkNanos(this, nanosTimeout); + long now = System.nanoTime(); + nanosTimeout -= now - lastTime; + lastTime = now; + if (Thread.interrupted()) + break; + } + } catch (RuntimeException ex) { + cancelAcquire(node); + throw ex; + } + // Arrive here only if interrupted + cancelAcquire(node); + throw new InterruptedException(); + } + + /** + * Acquires in shared uninterruptible mode. + * @param arg the acquire argument + */ + private void doAcquireShared(long arg) { + final Node node = addWaiter(Node.SHARED); + try { + boolean interrupted = false; + for (;;) { + final Node p = node.predecessor(); + if (p == head) { + long r = tryAcquireShared(arg); + if (r >= 0) { + setHeadAndPropagate(node, r); + p.next = null; // help GC + if (interrupted) + selfInterrupt(); + return; + } + } + if (shouldParkAfterFailedAcquire(p, node) && + parkAndCheckInterrupt()) + interrupted = true; + } + } catch (RuntimeException ex) { + cancelAcquire(node); + throw ex; + } + } + + /** + * Acquires in shared interruptible mode. + * @param arg the acquire argument + */ + private void doAcquireSharedInterruptibly(long arg) + throws InterruptedException { + final Node node = addWaiter(Node.SHARED); + try { + for (;;) { + final Node p = node.predecessor(); + if (p == head) { + long r = tryAcquireShared(arg); + if (r >= 0) { + setHeadAndPropagate(node, r); + p.next = null; // help GC + return; + } + } + if (shouldParkAfterFailedAcquire(p, node) && + parkAndCheckInterrupt()) + break; + } + } catch (RuntimeException ex) { + cancelAcquire(node); + throw ex; + } + // Arrive here only if interrupted + cancelAcquire(node); + throw new InterruptedException(); + } + + /** + * Acquires in shared timed mode. + * + * @param arg the acquire argument + * @param nanosTimeout max wait time + * @return {@code true} if acquired + */ + private boolean doAcquireSharedNanos(long arg, long nanosTimeout) + throws InterruptedException { + + long lastTime = System.nanoTime(); + final Node node = addWaiter(Node.SHARED); + try { + for (;;) { + final Node p = node.predecessor(); + if (p == head) { + long r = tryAcquireShared(arg); + if (r >= 0) { + setHeadAndPropagate(node, r); + p.next = null; // help GC + return true; + } + } + if (nanosTimeout <= 0) { + cancelAcquire(node); + return false; + } + if (nanosTimeout > spinForTimeoutThreshold && + shouldParkAfterFailedAcquire(p, node)) + LockSupport.parkNanos(this, nanosTimeout); + long now = System.nanoTime(); + nanosTimeout -= now - lastTime; + lastTime = now; + if (Thread.interrupted()) + break; + } + } catch (RuntimeException ex) { + cancelAcquire(node); + throw ex; + } + // Arrive here only if interrupted + cancelAcquire(node); + throw new InterruptedException(); + } + + // Main exported methods + + /** + * Attempts to acquire in exclusive mode. This method should query + * if the state of the object permits it to be acquired in the + * exclusive mode, and if so to acquire it. + * + * <p>This method is always invoked by the thread performing + * acquire. If this method reports failure, the acquire method + * may queue the thread, if it is not already queued, until it is + * signalled by a release from some other thread. This can be used + * to implement method {@link Lock#tryLock()}. + * + * <p>The default + * implementation throws {@link UnsupportedOperationException}. + * + * @param arg the acquire argument. This value is always the one + * passed to an acquire method, or is the value saved on entry + * to a condition wait. The value is otherwise uninterpreted + * and can represent anything you like. + * @return {@code true} if successful. Upon success, this object has + * been acquired. + * @throws IllegalMonitorStateException if acquiring would place this + * synchronizer in an illegal state. This exception must be + * thrown in a consistent fashion for synchronization to work + * correctly. + * @throws UnsupportedOperationException if exclusive mode is not supported + */ + protected boolean tryAcquire(long arg) { + throw new UnsupportedOperationException(); + } + + /** + * Attempts to set the state to reflect a release in exclusive + * mode. + * + * <p>This method is always invoked by the thread performing release. + * + * <p>The default implementation throws + * {@link UnsupportedOperationException}. + * + * @param arg the release argument. This value is always the one + * passed to a release method, or the current state value upon + * entry to a condition wait. The value is otherwise + * uninterpreted and can represent anything you like. + * @return {@code true} if this object is now in a fully released + * state, so that any waiting threads may attempt to acquire; + * and {@code false} otherwise. + * @throws IllegalMonitorStateException if releasing would place this + * synchronizer in an illegal state. This exception must be + * thrown in a consistent fashion for synchronization to work + * correctly. + * @throws UnsupportedOperationException if exclusive mode is not supported + */ + protected boolean tryRelease(long arg) { + throw new UnsupportedOperationException(); + } + + /** + * Attempts to acquire in shared mode. This method should query if + * the state of the object permits it to be acquired in the shared + * mode, and if so to acquire it. + * + * <p>This method is always invoked by the thread performing + * acquire. If this method reports failure, the acquire method + * may queue the thread, if it is not already queued, until it is + * signalled by a release from some other thread. + * + * <p>The default implementation throws {@link + * UnsupportedOperationException}. + * + * @param arg the acquire argument. This value is always the one + * passed to an acquire method, or is the value saved on entry + * to a condition wait. The value is otherwise uninterpreted + * and can represent anything you like. + * @return a negative value on failure; zero if acquisition in shared + * mode succeeded but no subsequent shared-mode acquire can + * succeed; and a positive value if acquisition in shared + * mode succeeded and subsequent shared-mode acquires might + * also succeed, in which case a subsequent waiting thread + * must check availability. (Support for three different + * return values enables this method to be used in contexts + * where acquires only sometimes act exclusively.) Upon + * success, this object has been acquired. + * @throws IllegalMonitorStateException if acquiring would place this + * synchronizer in an illegal state. This exception must be + * thrown in a consistent fashion for synchronization to work + * correctly. + * @throws UnsupportedOperationException if shared mode is not supported + */ + protected long tryAcquireShared(long arg) { + throw new UnsupportedOperationException(); + } + + /** + * Attempts to set the state to reflect a release in shared mode. + * + * <p>This method is always invoked by the thread performing release. + * + * <p>The default implementation throws + * {@link UnsupportedOperationException}. + * + * @param arg the release argument. This value is always the one + * passed to a release method, or the current state value upon + * entry to a condition wait. The value is otherwise + * uninterpreted and can represent anything you like. + * @return {@code true} if this release of shared mode may permit a + * waiting acquire (shared or exclusive) to succeed; and + * {@code false} otherwise + * @throws IllegalMonitorStateException if releasing would place this + * synchronizer in an illegal state. This exception must be + * thrown in a consistent fashion for synchronization to work + * correctly. + * @throws UnsupportedOperationException if shared mode is not supported + */ + protected boolean tryReleaseShared(long arg) { + throw new UnsupportedOperationException(); + } + + /** + * Returns {@code true} if synchronization is held exclusively with + * respect to the current (calling) thread. This method is invoked + * upon each call to a non-waiting {@link ConditionObject} method. + * (Waiting methods instead invoke {@link #release}.) + * + * <p>The default implementation throws {@link + * UnsupportedOperationException}. This method is invoked + * internally only within {@link ConditionObject} methods, so need + * not be defined if conditions are not used. + * + * @return {@code true} if synchronization is held exclusively; + * {@code false} otherwise + * @throws UnsupportedOperationException if conditions are not supported + */ + protected boolean isHeldExclusively() { + throw new UnsupportedOperationException(); + } + + /** + * Acquires in exclusive mode, ignoring interrupts. Implemented + * by invoking at least once {@link #tryAcquire}, + * returning on success. Otherwise the thread is queued, possibly + * repeatedly blocking and unblocking, invoking {@link + * #tryAcquire} until success. This method can be used + * to implement method {@link Lock#lock}. + * + * @param arg the acquire argument. This value is conveyed to + * {@link #tryAcquire} but is otherwise uninterpreted and + * can represent anything you like. + */ + public final void acquire(long arg) { + if (!tryAcquire(arg) && + acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) + selfInterrupt(); + } + + /** + * Acquires in exclusive mode, aborting if interrupted. + * Implemented by first checking interrupt status, then invoking + * at least once {@link #tryAcquire}, returning on + * success. Otherwise the thread is queued, possibly repeatedly + * blocking and unblocking, invoking {@link #tryAcquire} + * until success or the thread is interrupted. This method can be + * used to implement method {@link Lock#lockInterruptibly}. + * + * @param arg the acquire argument. This value is conveyed to + * {@link #tryAcquire} but is otherwise uninterpreted and + * can represent anything you like. + * @throws InterruptedException if the current thread is interrupted + */ + public final void acquireInterruptibly(long arg) throws InterruptedException { + if (Thread.interrupted()) + throw new InterruptedException(); + if (!tryAcquire(arg)) + doAcquireInterruptibly(arg); + } + + /** + * Attempts to acquire in exclusive mode, aborting if interrupted, + * and failing if the given timeout elapses. Implemented by first + * checking interrupt status, then invoking at least once {@link + * #tryAcquire}, returning on success. Otherwise, the thread is + * queued, possibly repeatedly blocking and unblocking, invoking + * {@link #tryAcquire} until success or the thread is interrupted + * or the timeout elapses. This method can be used to implement + * method {@link Lock#tryLock(long, TimeUnit)}. + * + * @param arg the acquire argument. This value is conveyed to + * {@link #tryAcquire} but is otherwise uninterpreted and + * can represent anything you like. + * @param nanosTimeout the maximum number of nanoseconds to wait + * @return {@code true} if acquired; {@code false} if timed out + * @throws InterruptedException if the current thread is interrupted + */ + public final boolean tryAcquireNanos(long arg, long nanosTimeout) throws InterruptedException { + if (Thread.interrupted()) + throw new InterruptedException(); + return tryAcquire(arg) || + doAcquireNanos(arg, nanosTimeout); + } + + /** + * Releases in exclusive mode. Implemented by unblocking one or + * more threads if {@link #tryRelease} returns true. + * This method can be used to implement method {@link Lock#unlock}. + * + * @param arg the release argument. This value is conveyed to + * {@link #tryRelease} but is otherwise uninterpreted and + * can represent anything you like. + * @return the value returned from {@link #tryRelease} + */ + public final boolean release(long arg) { + if (tryRelease(arg)) { + Node h = head; + if (h != null && h.waitStatus != 0) + unparkSuccessor(h); + return true; + } + return false; + } + + /** + * Acquires in shared mode, ignoring interrupts. Implemented by + * first invoking at least once {@link #tryAcquireShared}, + * returning on success. Otherwise the thread is queued, possibly + * repeatedly blocking and unblocking, invoking {@link + * #tryAcquireShared} until success. + * + * @param arg the acquire argument. This value is conveyed to + * {@link #tryAcquireShared} but is otherwise uninterpreted + * and can represent anything you like. + */ + public final void acquireShared(long arg) { + if (tryAcquireShared(arg) < 0) + doAcquireShared(arg); + } + + /** + * Acquires in shared mode, aborting if interrupted. Implemented + * by first checking interrupt status, then invoking at least once + * {@link #tryAcquireShared}, returning on success. Otherwise the + * thread is queued, possibly repeatedly blocking and unblocking, + * invoking {@link #tryAcquireShared} until success or the thread + * is interrupted. + * @param arg the acquire argument. + * This value is conveyed to {@link #tryAcquireShared} but is + * otherwise uninterpreted and can represent anything + * you like. + * @throws InterruptedException if the current thread is interrupted + */ + public final void acquireSharedInterruptibly(long arg) throws InterruptedException { + if (Thread.interrupted()) + throw new InterruptedException(); + if (tryAcquireShared(arg) < 0) + doAcquireSharedInterruptibly(arg); + } + + /** + * Attempts to acquire in shared mode, aborting if interrupted, and + * failing if the given timeout elapses. Implemented by first + * checking interrupt status, then invoking at least once {@link + * #tryAcquireShared}, returning on success. Otherwise, the + * thread is queued, possibly repeatedly blocking and unblocking, + * invoking {@link #tryAcquireShared} until success or the thread + * is interrupted or the timeout elapses. + * + * @param arg the acquire argument. This value is conveyed to + * {@link #tryAcquireShared} but is otherwise uninterpreted + * and can represent anything you like. + * @param nanosTimeout the maximum number of nanoseconds to wait + * @return {@code true} if acquired; {@code false} if timed out + * @throws InterruptedException if the current thread is interrupted + */ + public final boolean tryAcquireSharedNanos(long arg, long nanosTimeout) throws InterruptedException { + if (Thread.interrupted()) + throw new InterruptedException(); + return tryAcquireShared(arg) >= 0 || + doAcquireSharedNanos(arg, nanosTimeout); + } + + /** + * Releases in shared mode. Implemented by unblocking one or more + * threads if {@link #tryReleaseShared} returns true. + * + * @param arg the release argument. This value is conveyed to + * {@link #tryReleaseShared} but is otherwise uninterpreted + * and can represent anything you like. + * @return the value returned from {@link #tryReleaseShared} + */ + public final boolean releaseShared(long arg) { + if (tryReleaseShared(arg)) { + Node h = head; + if (h != null && h.waitStatus != 0) + unparkSuccessor(h); + return true; + } + return false; + } + + // Queue inspection methods + + /** + * Queries whether any threads are waiting to acquire. Note that + * because cancellations due to interrupts and timeouts may occur + * at any time, a {@code true} return does not guarantee that any + * other thread will ever acquire. + * + * <p>In this implementation, this operation returns in + * constant time. + * + * @return {@code true} if there may be other threads waiting to acquire + */ + public final boolean hasQueuedThreads() { + return head != tail; + } + + /** + * Queries whether any threads have ever contended to acquire this + * synchronizer; that is if an acquire method has ever blocked. + * + * <p>In this implementation, this operation returns in + * constant time. + * + * @return {@code true} if there has ever been contention + */ + public final boolean hasContended() { + return head != null; + } + + /** + * Returns the first (longest-waiting) thread in the queue, or + * {@code null} if no threads are currently queued. + * + * <p>In this implementation, this operation normally returns in + * constant time, but may iterate upon contention if other threads are + * concurrently modifying the queue. + * + * @return the first (longest-waiting) thread in the queue, or + * {@code null} if no threads are currently queued + */ + public final Thread getFirstQueuedThread() { + // handle only fast path, else relay + return (head == tail)? null : fullGetFirstQueuedThread(); + } + + /** + * Version of getFirstQueuedThread called when fastpath fails + */ + private Thread fullGetFirstQueuedThread() { + /* + * The first node is normally h.next. Try to get its + * thread field, ensuring consistent reads: If thread + * field is nulled out or s.prev is no longer head, then + * some other thread(s) concurrently performed setHead in + * between some of our reads. We try this twice before + * resorting to traversal. + */ + Node h, s; + Thread st; + if (((h = head) != null && (s = h.next) != null && + s.prev == head && (st = s.thread) != null) || + ((h = head) != null && (s = h.next) != null && + s.prev == head && (st = s.thread) != null)) + return st; + + /* + * Head's next field might not have been set yet, or may have + * been unset after setHead. So we must check to see if tail + * is actually first node. If not, we continue on, safely + * traversing from tail back to head to find first, + * guaranteeing termination. + */ + + Node t = tail; + Thread firstThread = null; + while (t != null && t != head) { + Thread tt = t.thread; + if (tt != null) + firstThread = tt; + t = t.prev; + } + return firstThread; + } + + /** + * Returns true if the given thread is currently queued. + * + * <p>This implementation traverses the queue to determine + * presence of the given thread. + * + * @param thread the thread + * @return {@code true} if the given thread is on the queue + * @throws NullPointerException if the thread is null + */ + public final boolean isQueued(Thread thread) { + if (thread == null) + throw new NullPointerException(); + for (Node p = tail; p != null; p = p.prev) + if (p.thread == thread) + return true; + return false; + } + + /** + * Return {@code true} if the apparent first queued thread, if one + * exists, is not waiting in exclusive mode. Used only as a heuristic + * in ReentrantReadWriteLock. + */ + final boolean apparentlyFirstQueuedIsExclusive() { + Node h, s; + return ((h = head) != null && (s = h.next) != null && + s.nextWaiter != Node.SHARED); + } + + /** + * Return {@code true} if the queue is empty or if the given thread + * is at the head of the queue. This is reliable only if + * <tt>current</tt> is actually Thread.currentThread() of caller. + */ + final boolean isFirst(Thread current) { + Node h, s; + return ((h = head) == null || + ((s = h.next) != null && s.thread == current) || + fullIsFirst(current)); + } + + final boolean fullIsFirst(Thread current) { + // same idea as fullGetFirstQueuedThread + Node h, s; + Thread firstThread = null; + if (((h = head) != null && (s = h.next) != null && + s.prev == head && (firstThread = s.thread) != null)) + return firstThread == current; + Node t = tail; + while (t != null && t != head) { + Thread tt = t.thread; + if (tt != null) + firstThread = tt; + t = t.prev; + } + return firstThread == current || firstThread == null; + } + + + // Instrumentation and monitoring methods + + /** + * 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 system state, not for synchronization + * control. + * + * @return the estimated number of threads waiting to acquire + */ + public final int getQueueLength() { + int n = 0; + for (Node p = tail; p != null; p = p.prev) { + if (p.thread != null) + ++n; + } + return n; + } + + /** + * Returns a collection containing threads that may be waiting to + * acquire. Because the actual set of threads may change + * dynamically while constructing this result, the returned + * collection is only a best-effort estimate. The elements of the + * returned collection are in no particular order. This method is + * designed to facilitate construction of subclasses that provide + * more extensive monitoring facilities. + * + * @return the collection of threads + */ + public final Collection<Thread> getQueuedThreads() { + ArrayList<Thread> list = new ArrayList<Thread>(); + for (Node p = tail; p != null; p = p.prev) { + Thread t = p.thread; + if (t != null) + list.add(t); + } + return list; + } + + /** + * Returns a collection containing threads that may be waiting to + * acquire in exclusive mode. This has the same properties + * as {@link #getQueuedThreads} except that it only returns + * those threads waiting due to an exclusive acquire. + * + * @return the collection of threads + */ + public final Collection<Thread> getExclusiveQueuedThreads() { + ArrayList<Thread> list = new ArrayList<Thread>(); + for (Node p = tail; p != null; p = p.prev) { + if (!p.isShared()) { + Thread t = p.thread; + if (t != null) + list.add(t); + } + } + return list; + } + + /** + * Returns a collection containing threads that may be waiting to + * acquire in shared mode. This has the same properties + * as {@link #getQueuedThreads} except that it only returns + * those threads waiting due to a shared acquire. + * + * @return the collection of threads + */ + public final Collection<Thread> getSharedQueuedThreads() { + ArrayList<Thread> list = new ArrayList<Thread>(); + for (Node p = tail; p != null; p = p.prev) { + if (p.isShared()) { + Thread t = p.thread; + if (t != null) + list.add(t); + } + } + return list; + } + + /** + * Returns a string identifying this synchronizer, as well as its state. + * The state, in brackets, includes the String {@code "State ="} + * followed by the current value of {@link #getState}, and either + * {@code "nonempty"} or {@code "empty"} depending on whether the + * queue is empty. + * + * @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]"; + } + + + // Internal support methods for Conditions + + /** + * Returns true if a node, always one that was initially placed on + * a condition queue, is now waiting to reacquire on sync queue. + * @param node the node + * @return true if is reacquiring + */ + final boolean isOnSyncQueue(Node node) { + if (node.waitStatus == Node.CONDITION || node.prev == null) + return false; + if (node.next != null) // If has successor, it must be on queue + return true; + /* + * node.prev can be non-null, but not yet on queue because + * the CAS to place it on queue can fail. So we have to + * traverse from tail to make sure it actually made it. It + * will always be near the tail in calls to this method, and + * unless the CAS failed (which is unlikely), it will be + * there, so we hardly ever traverse much. + */ + return findNodeFromTail(node); + } + + /** + * Returns true if node is on sync queue by searching backwards from tail. + * Called only when needed by isOnSyncQueue. + * @return true if present + */ + private boolean findNodeFromTail(Node node) { + Node t = tail; + for (;;) { + if (t == node) + return true; + if (t == null) + return false; + t = t.prev; + } + } + + /** + * Transfers a node from a condition queue onto sync queue. + * Returns true if successful. + * @param node the node + * @return true if successfully transferred (else the node was + * cancelled before signal). + */ + final boolean transferForSignal(Node node) { + /* + * If cannot change waitStatus, the node has been cancelled. + */ + if (!compareAndSetWaitStatus(node, Node.CONDITION, 0)) + return false; + + /* + * Splice onto queue and try to set waitStatus of predecessor to + * indicate that thread is (probably) waiting. If cancelled or + * attempt to set waitStatus fails, wake up to resync (in which + * case the waitStatus can be transiently and harmlessly wrong). + */ + Node p = enq(node); + int c = p.waitStatus; + if (c > 0 || !compareAndSetWaitStatus(p, c, Node.SIGNAL)) + LockSupport.unpark(node.thread); + return true; + } + + /** + * Transfers node, if necessary, to sync queue after a cancelled + * wait. Returns true if thread was cancelled before being + * signalled. + * @param current the waiting thread + * @param node its node + * @return true if cancelled before the node was signalled. + */ + final boolean transferAfterCancelledWait(Node node) { + if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) { + enq(node); + return true; + } + /* + * If we lost out to a signal(), then we can't proceed + * until it finishes its enq(). Cancelling during an + * incomplete transfer is both rare and transient, so just + * spin. + */ + while (!isOnSyncQueue(node)) + Thread.yield(); + return false; + } + + /** + * Invokes release with current state value; returns saved state. + * Cancels node and throws exception on failure. + * @param node the condition node for this wait + * @return previous sync state + */ + final long fullyRelease(Node node) { + try { + long savedState = getState(); + if (release(savedState)) + return savedState; + } catch (RuntimeException ex) { + node.waitStatus = Node.CANCELLED; + throw ex; + } + // reach here if release fails + node.waitStatus = Node.CANCELLED; + throw new IllegalMonitorStateException(); + } + + // Instrumentation methods for conditions + + /** + * Queries whether the given ConditionObject + * uses this synchronizer as its lock. + * + * @param condition the condition + * @return <tt>true</tt> if owned + * @throws NullPointerException if the condition is null + */ + public final boolean owns(ConditionObject condition) { + if (condition == null) + throw new NullPointerException(); + return condition.isOwnedBy(this); + } + + /** + * Queries whether any threads are waiting on the given condition + * associated with this synchronizer. Note that because timeouts + * and interrupts may occur at any time, a <tt>true</tt> return + * does not guarantee that a future <tt>signal</tt> will awaken + * any threads. This method is designed primarily for use in + * monitoring of the system state. + * + * @param condition the condition + * @return <tt>true</tt> if there are any waiting threads + * @throws IllegalMonitorStateException if exclusive synchronization + * is not held + * @throws IllegalArgumentException if the given condition is + * not associated with this synchronizer + * @throws NullPointerException if the condition is null + */ + public final boolean hasWaiters(ConditionObject condition) { + if (!owns(condition)) + throw new IllegalArgumentException("Not owner"); + return condition.hasWaiters(); + } + + /** + * Returns an estimate of the number of threads waiting on the + * 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. + * + * @param condition the condition + * @return the estimated number of waiting threads + * @throws IllegalMonitorStateException if exclusive synchronization + * is not held + * @throws IllegalArgumentException if the given condition is + * not associated with this synchronizer + * @throws NullPointerException if the condition is null + */ + public final int getWaitQueueLength(ConditionObject condition) { + if (!owns(condition)) + throw new IllegalArgumentException("Not owner"); + return condition.getWaitQueueLength(); + } + + /** + * Returns a collection containing those threads that may be + * waiting on the given condition associated with this + * synchronizer. Because the actual set of threads may change + * dynamically while constructing this result, the returned + * collection is only a best-effort estimate. The elements of the + * returned collection are in no particular order. + * + * @param condition the condition + * @return the collection of threads + * @throws IllegalMonitorStateException if exclusive synchronization + * is not held + * @throws IllegalArgumentException if the given condition is + * not associated with this synchronizer + * @throws NullPointerException if the condition is null + */ + public final Collection<Thread> getWaitingThreads(ConditionObject condition) { + if (!owns(condition)) + throw new IllegalArgumentException("Not owner"); + return condition.getWaitingThreads(); + } + + /** + * Condition implementation for a {@link + * AbstractQueuedLongSynchronizer} serving as the basis of a {@link + * Lock} implementation. + * + * <p>Method documentation for this class describes mechanics, + * not behavioral specifications from the point of view of Lock + * and Condition users. Exported versions of this class will in + * general need to be accompanied by documentation describing + * condition semantics that rely on those of the associated + * <tt>AbstractQueuedLongSynchronizer</tt>. + * + * <p>This class is Serializable, but all fields are transient, + * so deserialized conditions have no waiters. + * + * @since 1.6 + */ + public class ConditionObject implements Condition, java.io.Serializable { + private static final long serialVersionUID = 1173984872572414699L; + /** First node of condition queue. */ + private transient Node firstWaiter; + /** Last node of condition queue. */ + private transient Node lastWaiter; + + /** + * Creates a new <tt>ConditionObject</tt> instance. + */ + public ConditionObject() { } + + // Internal methods + + /** + * Adds a new waiter to wait queue. + * @return its new wait node + */ + private Node addConditionWaiter() { + Node node = new Node(Thread.currentThread(), Node.CONDITION); + Node t = lastWaiter; + if (t == null) + firstWaiter = node; + else + t.nextWaiter = node; + lastWaiter = node; + return node; + } + + /** + * Removes and transfers nodes until hit non-cancelled one or + * null. Split out from signal in part to encourage compilers + * to inline the case of no waiters. + * @param first (non-null) the first node on condition queue + */ + private void doSignal(Node first) { + do { + if ( (firstWaiter = first.nextWaiter) == null) + lastWaiter = null; + first.nextWaiter = null; + } while (!transferForSignal(first) && + (first = firstWaiter) != null); + } + + /** + * Removes and transfers all nodes. + * @param first (non-null) the first node on condition queue + */ + private void doSignalAll(Node first) { + lastWaiter = firstWaiter = null; + do { + Node next = first.nextWaiter; + first.nextWaiter = null; + transferForSignal(first); + first = next; + } while (first != null); + } + + /** + * Returns true if given node is on this condition queue. + * Call only when holding lock. + */ + private boolean isOnConditionQueue(Node node) { + return node.next != null || node == lastWaiter; + } + + /** + * Unlinks a cancelled waiter node from condition queue. This + * is called when cancellation occurred during condition wait, + * not lock wait, and is called only after lock has been + * re-acquired by a cancelled waiter and the node is not known + * to already have been dequeued. It is needed to avoid + * garbage retention in the absence of signals. So even though + * it may require a full traversal, it comes into play only + * when timeouts or cancellations occur in the absence of + * signals. + */ + private void unlinkCancelledWaiter(Node node) { + Node t = firstWaiter; + Node trail = null; + while (t != null) { + if (t == node) { + Node next = t.nextWaiter; + if (trail == null) + firstWaiter = next; + else + trail.nextWaiter = next; + if (lastWaiter == node) + lastWaiter = trail; + break; + } + trail = t; + t = t.nextWaiter; + } + } + + // public methods + + /** + * Moves the longest-waiting thread, if one exists, from the + * wait queue for this condition to the wait queue for the + * owning lock. + * + * @throws IllegalMonitorStateException if {@link #isHeldExclusively} + * returns {@code false} + */ + public final void signal() { + if (!isHeldExclusively()) + throw new IllegalMonitorStateException(); + Node first = firstWaiter; + if (first != null) + doSignal(first); + } + + /** + * Moves all threads from the wait queue for this condition to + * the wait queue for the owning lock. + * + * @throws IllegalMonitorStateException if {@link #isHeldExclusively} + * returns {@code false} + */ + public final void signalAll() { + if (!isHeldExclusively()) + throw new IllegalMonitorStateException(); + Node first = firstWaiter; + if (first != null) + doSignalAll(first); + } + + /** + * 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. + * </ol> + */ + public final void awaitUninterruptibly() { + Node node = addConditionWaiter(); + long savedState = fullyRelease(node); + boolean interrupted = false; + while (!isOnSyncQueue(node)) { + LockSupport.park(this); + if (Thread.interrupted()) + interrupted = true; + } + if (acquireQueued(node, savedState) || interrupted) + selfInterrupt(); + } + + /* + * For interruptible waits, we need to track whether to throw + * InterruptedException, if interrupted while blocked on + * condition, versus reinterrupt current thread, if + * interrupted while blocked waiting to re-acquire. + */ + + /** Mode meaning to reinterrupt on exit from wait */ + private static final int REINTERRUPT = 1; + /** Mode meaning to throw InterruptedException on exit from wait */ + private static final int THROW_IE = -1; + + /** + * Checks for interrupt, returning THROW_IE if interrupted + * before signalled, REINTERRUPT if after signalled, or + * 0 if not interrupted. + */ + private int checkInterruptWhileWaiting(Node node) { + return (Thread.interrupted()) ? + ((transferAfterCancelledWait(node))? THROW_IE : REINTERRUPT) : + 0; + } + + /** + * Throws InterruptedException, reinterrupts current thread, or + * does nothing, depending on mode. + */ + private void reportInterruptAfterWait(int interruptMode) + throws InterruptedException { + if (interruptMode == THROW_IE) + throw new InterruptedException(); + else if (interruptMode == REINTERRUPT) + selfInterrupt(); + } + + /** + * 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 exception + * </ol> + */ + public final void await() throws InterruptedException { + if (Thread.interrupted()) + throw new InterruptedException(); + Node node = addConditionWaiter(); + long savedState = fullyRelease(node); + int interruptMode = 0; + while (!isOnSyncQueue(node)) { + LockSupport.park(this); + if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) + break; + } + if (acquireQueued(node, savedState) && interruptMode != THROW_IE) + interruptMode = REINTERRUPT; + if (isOnConditionQueue(node)) + unlinkCancelledWaiter(node); + if (interruptMode != 0) + reportInterruptAfterWait(interruptMode); + } + + /** + * 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 + * </ol> + */ + public final long awaitNanos(long nanosTimeout) throws InterruptedException { + if (Thread.interrupted()) + throw new InterruptedException(); + Node node = addConditionWaiter(); + long savedState = fullyRelease(node); + long lastTime = System.nanoTime(); + int interruptMode = 0; + while (!isOnSyncQueue(node)) { + if (nanosTimeout <= 0L) { + transferAfterCancelledWait(node); + break; + } + LockSupport.parkNanos(this, nanosTimeout); + if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) + break; + + long now = System.nanoTime(); + nanosTimeout -= now - lastTime; + lastTime = now; + } + if (acquireQueued(node, savedState) && interruptMode != THROW_IE) + interruptMode = REINTERRUPT; + if (isOnConditionQueue(node)) + unlinkCancelledWaiter(node); + if (interruptMode != 0) + reportInterruptAfterWait(interruptMode); + return nanosTimeout - (System.nanoTime() - lastTime); + } + + /** + * 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 + * </ol> + */ + public final boolean awaitUntil(Date deadline) throws InterruptedException { + if (deadline == null) + throw new NullPointerException(); + long abstime = deadline.getTime(); + if (Thread.interrupted()) + throw new InterruptedException(); + Node node = addConditionWaiter(); + long savedState = fullyRelease(node); + boolean timedout = false; + int interruptMode = 0; + while (!isOnSyncQueue(node)) { + if (System.currentTimeMillis() > abstime) { + timedout = transferAfterCancelledWait(node); + break; + } + LockSupport.parkUntil(this, abstime); + if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) + break; + } + if (acquireQueued(node, savedState) && interruptMode != THROW_IE) + interruptMode = REINTERRUPT; + if (isOnConditionQueue(node)) + unlinkCancelledWaiter(node); + if (interruptMode != 0) + reportInterruptAfterWait(interruptMode); + return !timedout; + } + + /** + * 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 + * </ol> + */ + public final boolean await(long time, TimeUnit unit) throws InterruptedException { + if (unit == null) + throw new NullPointerException(); + long nanosTimeout = unit.toNanos(time); + if (Thread.interrupted()) + throw new InterruptedException(); + Node node = addConditionWaiter(); + long savedState = fullyRelease(node); + long lastTime = System.nanoTime(); + boolean timedout = false; + int interruptMode = 0; + while (!isOnSyncQueue(node)) { + if (nanosTimeout <= 0L) { + timedout = transferAfterCancelledWait(node); + break; + } + LockSupport.parkNanos(this, nanosTimeout); + if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) + break; + long now = System.nanoTime(); + nanosTimeout -= now - lastTime; + lastTime = now; + } + if (acquireQueued(node, savedState) && interruptMode != THROW_IE) + interruptMode = REINTERRUPT; + if (isOnConditionQueue(node)) + unlinkCancelledWaiter(node); + if (interruptMode != 0) + reportInterruptAfterWait(interruptMode); + return !timedout; + } + + // support for instrumentation + + /** + * Returns true if this condition was created by the given + * synchronization object. + * + * @return {@code true} if owned + */ + final boolean isOwnedBy(AbstractQueuedLongSynchronizer sync) { + return sync == AbstractQueuedLongSynchronizer.this; + } + + /** + * Queries whether any threads are waiting on this condition. + * Implements {@link AbstractQueuedLongSynchronizer#hasWaiters}. + * + * @return {@code true} if there are any waiting threads + * @throws IllegalMonitorStateException if {@link #isHeldExclusively} + * returns {@code false} + */ + protected final boolean hasWaiters() { + if (!isHeldExclusively()) + throw new IllegalMonitorStateException(); + for (Node w = firstWaiter; w != null; w = w.nextWaiter) { + if (w.waitStatus == Node.CONDITION) + return true; + } + return false; + } + + /** + * Returns an estimate of the number of threads waiting on + * this condition. + * Implements {@link AbstractQueuedLongSynchronizer#getWaitQueueLength}. + * + * @return the estimated number of waiting threads + * @throws IllegalMonitorStateException if {@link #isHeldExclusively} + * returns {@code false} + */ + protected final int getWaitQueueLength() { + if (!isHeldExclusively()) + throw new IllegalMonitorStateException(); + int n = 0; + for (Node w = firstWaiter; w != null; w = w.nextWaiter) { + if (w.waitStatus == Node.CONDITION) + ++n; + } + return n; + } + + /** + * Returns a collection containing those threads that may be + * waiting on this Condition. + * Implements {@link AbstractQueuedLongSynchronizer#getWaitingThreads}. + * + * @return the collection of threads + * @throws IllegalMonitorStateException if {@link #isHeldExclusively} + * returns {@code false} + */ + protected final Collection<Thread> getWaitingThreads() { + if (!isHeldExclusively()) + throw new IllegalMonitorStateException(); + ArrayList<Thread> list = new ArrayList<Thread>(); + for (Node w = firstWaiter; w != null; w = w.nextWaiter) { + if (w.waitStatus == Node.CONDITION) { + Thread t = w.thread; + if (t != null) + list.add(t); + } + } + return list; + } + } + + /** + * Setup to support compareAndSet. We need to natively implement + * this here: For the sake of permitting future enhancements, we + * cannot explicitly subclass AtomicLong, which would be + * efficient and useful otherwise. So, as the lesser of evils, we + * natively implement using hotspot intrinsics API. And while we + * 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; + + static { + try { + stateOffset = unsafe.objectFieldOffset + (AbstractQueuedLongSynchronizer.class.getDeclaredField("state")); + headOffset = unsafe.objectFieldOffset + (AbstractQueuedLongSynchronizer.class.getDeclaredField("head")); + tailOffset = unsafe.objectFieldOffset + (AbstractQueuedLongSynchronizer.class.getDeclaredField("tail")); + waitStatusOffset = unsafe.objectFieldOffset + (Node.class.getDeclaredField("waitStatus")); + + } catch (Exception ex) { throw new Error(ex); } + } + + /** + * CAS head field. Used only by enq + */ + private final boolean compareAndSetHead(Node update) { + return unsafe.compareAndSwapObject(this, headOffset, null, update); + } + + /** + * CAS tail field. Used only by enq + */ + private final boolean compareAndSetTail(Node expect, Node update) { + return unsafe.compareAndSwapObject(this, tailOffset, expect, update); + } + + /** + * CAS waitStatus field of a node. + */ + private final static boolean compareAndSetWaitStatus(Node node, + int expect, + int update) { + return unsafe.compareAndSwapInt(node, waitStatusOffset, + expect, update); + } +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/locks/AbstractQueuedSynchronizer.java b/libjava/classpath/external/jsr166/java/util/concurrent/locks/AbstractQueuedSynchronizer.java new file mode 100644 index 000000000..647f4fcbc --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/locks/AbstractQueuedSynchronizer.java @@ -0,0 +1,2159 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.locks; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; +import sun.misc.Unsafe; + +/** + * Provides a framework for implementing blocking locks and related + * synchronizers (semaphores, events, etc) that rely on + * first-in-first-out (FIFO) wait queues. This class is designed to + * be a useful basis for most kinds of synchronizers that rely on a + * single atomic <tt>int</tt> value to represent state. Subclasses + * must define the protected methods that change this state, and which + * define what that state means in terms of this object being acquired + * or released. Given these, the other methods in this class carry + * out all queuing and blocking mechanics. Subclasses can maintain + * other state fields, but only the atomically updated <tt>int</tt> + * value manipulated using methods {@link #getState}, {@link + * #setState} and {@link #compareAndSetState} is tracked with respect + * to synchronization. + * + * <p>Subclasses should be defined as non-public internal helper + * classes that are used to implement the synchronization properties + * of their enclosing class. Class + * <tt>AbstractQueuedSynchronizer</tt> does not implement any + * synchronization interface. Instead it defines methods such as + * {@link #acquireInterruptibly} that can be invoked as + * appropriate by concrete locks and related synchronizers to + * implement their public methods. + * + * <p>This class supports either or both a default <em>exclusive</em> + * mode and a <em>shared</em> mode. When acquired in exclusive mode, + * attempted acquires by other threads cannot succeed. Shared mode + * acquires by multiple threads may (but need not) succeed. This class + * does not "understand" these differences except in the + * mechanical sense that when a shared mode acquire succeeds, the next + * waiting thread (if one exists) must also determine whether it can + * acquire as well. Threads waiting in the different modes share the + * same FIFO queue. Usually, implementation subclasses support only + * one of these modes, but both can come into play for example in a + * {@link ReadWriteLock}. Subclasses that support only exclusive or + * only shared modes need not define the methods supporting the unused mode. + * + * <p>This class defines a nested {@link ConditionObject} class that + * can be used as a {@link Condition} implementation by subclasses + * supporting exclusive mode for which method {@link + * #isHeldExclusively} reports whether synchronization is exclusively + * held with respect to the current thread, method {@link #release} + * invoked with the current {@link #getState} value fully releases + * this object, and {@link #acquire}, given this saved state value, + * eventually restores this object to its previous acquired state. No + * <tt>AbstractQueuedSynchronizer</tt> method otherwise creates such a + * condition, so if this constraint cannot be met, do not use it. The + * behavior of {@link ConditionObject} depends of course on the + * semantics of its synchronizer implementation. + * + * <p>This class provides inspection, instrumentation, and monitoring + * methods for the internal queue, as well as similar methods for + * condition objects. These can be exported as desired into classes + * using an <tt>AbstractQueuedSynchronizer</tt> for their + * synchronization mechanics. + * + * <p>Serialization of this class stores only the underlying atomic + * integer maintaining state, so deserialized objects have empty + * thread queues. Typical subclasses requiring serializability will + * define a <tt>readObject</tt> method that restores this to a known + * initial state upon deserialization. + * + * <h3>Usage</h3> + * + * <p>To use this class as the basis of a synchronizer, redefine the + * following methods, as applicable, by inspecting and/or modifying + * the synchronization state using {@link #getState}, {@link + * #setState} and/or {@link #compareAndSetState}: + * + * <ul> + * <li> {@link #tryAcquire} + * <li> {@link #tryRelease} + * <li> {@link #tryAcquireShared} + * <li> {@link #tryReleaseShared} + * <li> {@link #isHeldExclusively} + *</ul> + * + * Each of these methods by default throws {@link + * UnsupportedOperationException}. Implementations of these methods + * must be internally thread-safe, and should in general be short and + * not block. Defining these methods is the <em>only</em> supported + * means of using this class. All other methods are declared + * <tt>final</tt> because they cannot be independently varied. + * + * <p>You may also find the inherited methods from {@link + * AbstractOwnableSynchronizer} useful to keep track of the thread + * owning an exclusive synchronizer. You are encouraged to use them + * -- this enables monitoring and diagnostic tools to assist users in + * determining which threads hold locks. + * + * <p>Even though this class is based on an internal FIFO queue, it + * does not automatically enforce FIFO acquisition policies. The core + * of exclusive synchronization takes the form: + * + * <pre> + * Acquire: + * while (!tryAcquire(arg)) { + * <em>enqueue thread if it is not already queued</em>; + * <em>possibly block current thread</em>; + * } + * + * Release: + * if (tryRelease(arg)) + * <em>unblock the first queued thread</em>; + * </pre> + * + * (Shared mode is similar but may involve cascading signals.) + * + * <p>Because checks in acquire are invoked before enqueuing, a newly + * acquiring thread may <em>barge</em> ahead of others that are + * blocked and queued. However, you can, if desired, define + * <tt>tryAcquire</tt> and/or <tt>tryAcquireShared</tt> to disable + * barging by internally invoking one or more of the inspection + * methods. In particular, a strict FIFO lock can define + * <tt>tryAcquire</tt> to immediately return <tt>false</tt> if {@link + * #getFirstQueuedThread} does not return the current thread. A + * normally preferable non-strict fair version can immediately return + * <tt>false</tt> only if {@link #hasQueuedThreads} returns + * <tt>true</tt> and <tt>getFirstQueuedThread</tt> is not the current + * thread; or equivalently, that <tt>getFirstQueuedThread</tt> is both + * non-null and not the current thread. Further variations are + * possible. + * + * <p>Throughput and scalability are generally highest for the + * default barging (also known as <em>greedy</em>, + * <em>renouncement</em>, and <em>convoy-avoidance</em>) strategy. + * While this is not guaranteed to be fair or starvation-free, earlier + * queued threads are allowed to recontend before later queued + * threads, and each recontention has an unbiased chance to succeed + * against incoming threads. Also, while acquires do not + * "spin" in the usual sense, they may perform multiple + * invocations of <tt>tryAcquire</tt> interspersed with other + * computations before blocking. This gives most of the benefits of + * spins when exclusive synchronization is only briefly held, without + * most of the liabilities when it isn't. If so desired, you can + * augment this by preceding calls to acquire methods with + * "fast-path" checks, possibly prechecking {@link #hasContended} + * and/or {@link #hasQueuedThreads} to only do so if the synchronizer + * is likely not to be contended. + * + * <p>This class provides an efficient and scalable basis for + * synchronization in part by specializing its range of use to + * synchronizers that can rely on <tt>int</tt> state, acquire, and + * release parameters, and an internal FIFO wait queue. When this does + * not suffice, you can build synchronizers from a lower level using + * {@link java.util.concurrent.atomic atomic} classes, your own custom + * {@link java.util.Queue} classes, and {@link LockSupport} blocking + * support. + * + * <h3>Usage Examples</h3> + * + * <p>Here is a non-reentrant mutual exclusion lock class that uses + * the value zero to represent the unlocked state, and one to + * represent the locked state. While a non-reentrant lock + * does not strictly require recording of the current owner + * thread, this class does so anyway to make usage easier to monitor. + * It also supports conditions and exposes + * one of the instrumentation methods: + * + * <pre> + * class Mutex implements Lock, java.io.Serializable { + * + * // Our internal helper class + * private static class Sync extends AbstractQueuedSynchronizer { + * // Report whether in locked state + * protected boolean isHeldExclusively() { + * return getState() == 1; + * } + * + * // Acquire the lock if state is zero + * public boolean tryAcquire(int acquires) { + * assert acquires == 1; // Otherwise unused + * if (compareAndSetState(0, 1)) { + * setExclusiveOwnerThread(Thread.currentThread()); + * return true; + * } + * return false; + * } + * + * // Release the lock by setting state to zero + * protected boolean tryRelease(int releases) { + * assert releases == 1; // Otherwise unused + * if (getState() == 0) throw new IllegalMonitorStateException(); + * setExclusiveOwnerThread(null); + * setState(0); + * return true; + * } + * + * // Provide a Condition + * Condition newCondition() { return new ConditionObject(); } + * + * // Deserialize properly + * private void readObject(ObjectInputStream s) + * throws IOException, ClassNotFoundException { + * s.defaultReadObject(); + * setState(0); // reset to unlocked state + * } + * } + * + * // The sync object does all the hard work. We just forward to it. + * private final Sync sync = new Sync(); + * + * public void lock() { sync.acquire(1); } + * public boolean tryLock() { return sync.tryAcquire(1); } + * public void unlock() { sync.release(1); } + * public Condition newCondition() { return sync.newCondition(); } + * public boolean isLocked() { return sync.isHeldExclusively(); } + * public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); } + * public void lockInterruptibly() throws InterruptedException { + * sync.acquireInterruptibly(1); + * } + * public boolean tryLock(long timeout, TimeUnit unit) + * throws InterruptedException { + * return sync.tryAcquireNanos(1, unit.toNanos(timeout)); + * } + * } + * </pre> + * + * <p>Here is a latch class that is like a {@link CountDownLatch} + * except that it only requires a single <tt>signal</tt> to + * fire. Because a latch is non-exclusive, it uses the <tt>shared</tt> + * acquire and release methods. + * + * <pre> + * class BooleanLatch { + * + * private static class Sync extends AbstractQueuedSynchronizer { + * boolean isSignalled() { return getState() != 0; } + * + * protected int tryAcquireShared(int ignore) { + * return isSignalled()? 1 : -1; + * } + * + * protected boolean tryReleaseShared(int ignore) { + * setState(1); + * return true; + * } + * } + * + * private final Sync sync = new Sync(); + * public boolean isSignalled() { return sync.isSignalled(); } + * public void signal() { sync.releaseShared(1); } + * public void await() throws InterruptedException { + * sync.acquireSharedInterruptibly(1); + * } + * } + * </pre> + * + * @since 1.5 + * @author Doug Lea + */ +public abstract class AbstractQueuedSynchronizer + extends AbstractOwnableSynchronizer + implements java.io.Serializable { + + private static final long serialVersionUID = 7373984972572414691L; + + /** + * Creates a new <tt>AbstractQueuedSynchronizer</tt> instance + * with initial synchronization state of zero. + */ + protected AbstractQueuedSynchronizer() { } + + /** + * 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, dequeing + * 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. + * + * <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 { + /** 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; + /** 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; + + /** + * 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. (Use of this value here + * has nothing to do with the other uses + * of the field, but simplifies mechanics.) + * 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 only using + * CAS. + */ + volatile int waitStatus; + + /** + * Link to predecessor node that current node/thread relies on + * for checking waitStatus. Assigned during enqueing, 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 once during enqueuing, and + * nulled out (for sake of GC) when no longer needed. Upon + * cancellation, we cannot adjust this field, but can notice + * status and bypass the node if cancelled. 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. + */ + 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. + * @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: + * If head exists, its waitStatus is guaranteed not to be + * CANCELLED. + */ + private transient volatile Node head; + + /** + * Tail of the wait queue, lazily initialized. Modified only via + * method enq to add new wait node. + */ + private transient volatile Node tail; + + /** + * The synchronization state. + */ + private volatile int state; + + /** + * Returns the current value of synchronization state. + * This operation has memory semantics of a <tt>volatile</tt> read. + * @return current state value + */ + protected final int getState() { + return state; + } + + /** + * Sets the value of synchronization state. + * This operation has memory semantics of a <tt>volatile</tt> write. + * @param newState the new state value + */ + protected final void setState(int newState) { + state = newState; + } + + /** + * Atomically sets synchronization state to the given updated + * value if the current state value equals the expected value. + * This operation has memory semantics of a <tt>volatile</tt> read + * and write. + * + * @param expect the expected value + * @param update the new value + * @return true if successful. False return indicates that the actual + * 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); + } + + // Queuing utilities + + /** + * The number of nanoseconds for which it is faster to spin + * rather than to use timed park. A rough estimate suffices + * to improve responsiveness with very short timeouts. + */ + static final long spinForTimeoutThreshold = 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) { + for (;;) { + Node t = tail; + if (t == null) { // Must initialize + Node h = new Node(); // Dummy header + h.next = node; + node.prev = h; + if (compareAndSetHead(h)) { + tail = node; + return h; + } + } + else { + node.prev = t; + if (compareAndSetTail(t, node)) { + t.next = node; + return t; + } + } + } + } + + /** + * Creates and enqueues node for given thread and mode. + * + * @param current the thread + * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared + * @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; + } + } + enq(node); + return node; + } + + /** + * Sets head of queue to be node, thus dequeuing. Called only by + * acquire methods. Also nulls out unused fields for sake of GC + * and to suppress unnecessary signals and traversals. + * + * @param node the node + */ + private void setHead(Node node) { + head = node; + node.thread = null; + node.prev = null; + } + + /** + * Wakes up node's successor, if one exists. + * + * @param node the node + */ + private void unparkSuccessor(Node node) { + /* + * Try to clear status in anticipation of signalling. It is + * OK if this fails or if status is changed by waiting thread. + */ + compareAndSetWaitStatus(node, Node.SIGNAL, 0); + + /* + * Thread to unpark is held in successor, which is normally + * just the next node. But if cancelled or apparently null, + * traverse backwards from tail to find the actual + * non-cancelled successor. + */ + 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; + } + if (s != null) + LockSupport.unpark(s.thread); + } + + /** + * Sets head of queue, and checks if successor may be waiting + * in shared mode, if so propagating if propagate > 0. + * + * @param pred the node holding waitStatus for node + * @param node the node + * @param propagate the return value from a tryAcquireShared + */ + private void setHeadAndPropagate(Node node, int propagate) { + setHead(node); + if (propagate > 0 && node.waitStatus != 0) { + /* + * Don't bother fully figuring out successor. If it + * looks null, call unparkSuccessor anyway to be safe. + */ + Node s = node.next; + if (s == null || s.isShared()) + unparkSuccessor(node); + } + } + + // Utilities for various versions of acquire + + /** + * Cancels an ongoing attempt to acquire. + * + * @param node the node + */ + private void cancelAcquire(Node node) { + if (node != null) { // Ignore if node doesn't exist + node.thread = null; + // Can use unconditional write instead of CAS here + node.waitStatus = Node.CANCELLED; + unparkSuccessor(node); + } + } + + /** + * Checks and updates status for a node that failed to acquire. + * Returns true if thread should block. This is the main signal + * control in all acquire loops. Requires that pred == node.prev + * + * @param pred node's predecessor holding status + * @param node the node + * @return {@code true} if thread should block + */ + private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) { + int s = pred.waitStatus; + if (s < 0) + /* + * This node has already set status asking a release + * to signal it, so it can safely park + */ + return true; + if (s > 0) + /* + * Predecessor was cancelled. Move up to its predecessor + * and indicate retry. + */ + node.prev = pred.prev; + else + /* + * Indicate that we need a signal, but don't park yet. Caller + * will need to retry to make sure it cannot acquire before + * parking. + */ + compareAndSetWaitStatus(pred, 0, Node.SIGNAL); + return false; + } + + /** + * Convenience method to interrupt current thread. + */ + private static void selfInterrupt() { + Thread.currentThread().interrupt(); + } + + /** + * Convenience method to park and then check if interrupted + * + * @return {@code true} if interrupted + */ + private final boolean parkAndCheckInterrupt() { + LockSupport.park(this); + return Thread.interrupted(); + } + + /* + * Various flavors of acquire, varying in exclusive/shared and + * control modes. Each is mostly the same, but annoyingly + * different. Only a little bit of factoring is possible due to + * interactions of exception mechanics (including ensuring that we + * cancel if tryAcquire throws exception) and other control, at + * least not without hurting performance too much. + */ + + /** + * Acquires in exclusive uninterruptible mode for thread already in + * queue. Used by condition wait methods as well as acquire. + * + * @param node the node + * @param arg the acquire argument + * @return {@code true} if interrupted while waiting + */ + final boolean acquireQueued(final Node node, int arg) { + try { + boolean interrupted = false; + for (;;) { + final Node p = node.predecessor(); + if (p == head && tryAcquire(arg)) { + setHead(node); + p.next = null; // help GC + return interrupted; + } + if (shouldParkAfterFailedAcquire(p, node) && + parkAndCheckInterrupt()) + interrupted = true; + } + } catch (RuntimeException ex) { + cancelAcquire(node); + throw ex; + } + } + + /** + * Acquires in exclusive interruptible mode. + * @param arg the acquire argument + */ + private void doAcquireInterruptibly(int arg) + throws InterruptedException { + final Node node = addWaiter(Node.EXCLUSIVE); + try { + for (;;) { + final Node p = node.predecessor(); + if (p == head && tryAcquire(arg)) { + setHead(node); + p.next = null; // help GC + return; + } + if (shouldParkAfterFailedAcquire(p, node) && + parkAndCheckInterrupt()) + break; + } + } catch (RuntimeException ex) { + cancelAcquire(node); + throw ex; + } + // Arrive here only if interrupted + cancelAcquire(node); + throw new InterruptedException(); + } + + /** + * Acquires in exclusive timed mode. + * + * @param arg the acquire argument + * @param nanosTimeout max wait time + * @return {@code true} if acquired + */ + private boolean doAcquireNanos(int arg, long nanosTimeout) + throws InterruptedException { + long lastTime = System.nanoTime(); + final Node node = addWaiter(Node.EXCLUSIVE); + try { + for (;;) { + final Node p = node.predecessor(); + if (p == head && tryAcquire(arg)) { + setHead(node); + p.next = null; // help GC + return true; + } + if (nanosTimeout <= 0) { + cancelAcquire(node); + return false; + } + if (nanosTimeout > spinForTimeoutThreshold && + shouldParkAfterFailedAcquire(p, node)) + LockSupport.parkNanos(this, nanosTimeout); + long now = System.nanoTime(); + nanosTimeout -= now - lastTime; + lastTime = now; + if (Thread.interrupted()) + break; + } + } catch (RuntimeException ex) { + cancelAcquire(node); + throw ex; + } + // Arrive here only if interrupted + cancelAcquire(node); + throw new InterruptedException(); + } + + /** + * Acquires in shared uninterruptible mode. + * @param arg the acquire argument + */ + private void doAcquireShared(int arg) { + final Node node = addWaiter(Node.SHARED); + try { + boolean interrupted = false; + for (;;) { + final Node p = node.predecessor(); + if (p == head) { + int r = tryAcquireShared(arg); + if (r >= 0) { + setHeadAndPropagate(node, r); + p.next = null; // help GC + if (interrupted) + selfInterrupt(); + return; + } + } + if (shouldParkAfterFailedAcquire(p, node) && + parkAndCheckInterrupt()) + interrupted = true; + } + } catch (RuntimeException ex) { + cancelAcquire(node); + throw ex; + } + } + + /** + * Acquires in shared interruptible mode. + * @param arg the acquire argument + */ + private void doAcquireSharedInterruptibly(int arg) + throws InterruptedException { + final Node node = addWaiter(Node.SHARED); + try { + for (;;) { + final Node p = node.predecessor(); + if (p == head) { + int r = tryAcquireShared(arg); + if (r >= 0) { + setHeadAndPropagate(node, r); + p.next = null; // help GC + return; + } + } + if (shouldParkAfterFailedAcquire(p, node) && + parkAndCheckInterrupt()) + break; + } + } catch (RuntimeException ex) { + cancelAcquire(node); + throw ex; + } + // Arrive here only if interrupted + cancelAcquire(node); + throw new InterruptedException(); + } + + /** + * Acquires in shared timed mode. + * + * @param arg the acquire argument + * @param nanosTimeout max wait time + * @return {@code true} if acquired + */ + private boolean doAcquireSharedNanos(int arg, long nanosTimeout) + throws InterruptedException { + + long lastTime = System.nanoTime(); + final Node node = addWaiter(Node.SHARED); + try { + for (;;) { + final Node p = node.predecessor(); + if (p == head) { + int r = tryAcquireShared(arg); + if (r >= 0) { + setHeadAndPropagate(node, r); + p.next = null; // help GC + return true; + } + } + if (nanosTimeout <= 0) { + cancelAcquire(node); + return false; + } + if (nanosTimeout > spinForTimeoutThreshold && + shouldParkAfterFailedAcquire(p, node)) + LockSupport.parkNanos(this, nanosTimeout); + long now = System.nanoTime(); + nanosTimeout -= now - lastTime; + lastTime = now; + if (Thread.interrupted()) + break; + } + } catch (RuntimeException ex) { + cancelAcquire(node); + throw ex; + } + // Arrive here only if interrupted + cancelAcquire(node); + throw new InterruptedException(); + } + + // Main exported methods + + /** + * Attempts to acquire in exclusive mode. This method should query + * if the state of the object permits it to be acquired in the + * exclusive mode, and if so to acquire it. + * + * <p>This method is always invoked by the thread performing + * acquire. If this method reports failure, the acquire method + * may queue the thread, if it is not already queued, until it is + * signalled by a release from some other thread. This can be used + * to implement method {@link Lock#tryLock()}. + * + * <p>The default + * implementation throws {@link UnsupportedOperationException}. + * + * @param arg the acquire argument. This value is always the one + * passed to an acquire method, or is the value saved on entry + * to a condition wait. The value is otherwise uninterpreted + * and can represent anything you like. + * @return {@code true} if successful. Upon success, this object has + * been acquired. + * @throws IllegalMonitorStateException if acquiring would place this + * synchronizer in an illegal state. This exception must be + * thrown in a consistent fashion for synchronization to work + * correctly. + * @throws UnsupportedOperationException if exclusive mode is not supported + */ + protected boolean tryAcquire(int arg) { + throw new UnsupportedOperationException(); + } + + /** + * Attempts to set the state to reflect a release in exclusive + * mode. + * + * <p>This method is always invoked by the thread performing release. + * + * <p>The default implementation throws + * {@link UnsupportedOperationException}. + * + * @param arg the release argument. This value is always the one + * passed to a release method, or the current state value upon + * entry to a condition wait. The value is otherwise + * uninterpreted and can represent anything you like. + * @return {@code true} if this object is now in a fully released + * state, so that any waiting threads may attempt to acquire; + * and {@code false} otherwise. + * @throws IllegalMonitorStateException if releasing would place this + * synchronizer in an illegal state. This exception must be + * thrown in a consistent fashion for synchronization to work + * correctly. + * @throws UnsupportedOperationException if exclusive mode is not supported + */ + protected boolean tryRelease(int arg) { + throw new UnsupportedOperationException(); + } + + /** + * Attempts to acquire in shared mode. This method should query if + * the state of the object permits it to be acquired in the shared + * mode, and if so to acquire it. + * + * <p>This method is always invoked by the thread performing + * acquire. If this method reports failure, the acquire method + * may queue the thread, if it is not already queued, until it is + * signalled by a release from some other thread. + * + * <p>The default implementation throws {@link + * UnsupportedOperationException}. + * + * @param arg the acquire argument. This value is always the one + * passed to an acquire method, or is the value saved on entry + * to a condition wait. The value is otherwise uninterpreted + * and can represent anything you like. + * @return a negative value on failure; zero if acquisition in shared + * mode succeeded but no subsequent shared-mode acquire can + * succeed; and a positive value if acquisition in shared + * mode succeeded and subsequent shared-mode acquires might + * also succeed, in which case a subsequent waiting thread + * must check availability. (Support for three different + * return values enables this method to be used in contexts + * where acquires only sometimes act exclusively.) Upon + * success, this object has been acquired. + * @throws IllegalMonitorStateException if acquiring would place this + * synchronizer in an illegal state. This exception must be + * thrown in a consistent fashion for synchronization to work + * correctly. + * @throws UnsupportedOperationException if shared mode is not supported + */ + protected int tryAcquireShared(int arg) { + throw new UnsupportedOperationException(); + } + + /** + * Attempts to set the state to reflect a release in shared mode. + * + * <p>This method is always invoked by the thread performing release. + * + * <p>The default implementation throws + * {@link UnsupportedOperationException}. + * + * @param arg the release argument. This value is always the one + * passed to a release method, or the current state value upon + * entry to a condition wait. The value is otherwise + * uninterpreted and can represent anything you like. + * @return {@code true} if this release of shared mode may permit a + * waiting acquire (shared or exclusive) to succeed; and + * {@code false} otherwise + * @throws IllegalMonitorStateException if releasing would place this + * synchronizer in an illegal state. This exception must be + * thrown in a consistent fashion for synchronization to work + * correctly. + * @throws UnsupportedOperationException if shared mode is not supported + */ + protected boolean tryReleaseShared(int arg) { + throw new UnsupportedOperationException(); + } + + /** + * Returns {@code true} if synchronization is held exclusively with + * respect to the current (calling) thread. This method is invoked + * upon each call to a non-waiting {@link ConditionObject} method. + * (Waiting methods instead invoke {@link #release}.) + * + * <p>The default implementation throws {@link + * UnsupportedOperationException}. This method is invoked + * internally only within {@link ConditionObject} methods, so need + * not be defined if conditions are not used. + * + * @return {@code true} if synchronization is held exclusively; + * {@code false} otherwise + * @throws UnsupportedOperationException if conditions are not supported + */ + protected boolean isHeldExclusively() { + throw new UnsupportedOperationException(); + } + + /** + * Acquires in exclusive mode, ignoring interrupts. Implemented + * by invoking at least once {@link #tryAcquire}, + * returning on success. Otherwise the thread is queued, possibly + * repeatedly blocking and unblocking, invoking {@link + * #tryAcquire} until success. This method can be used + * to implement method {@link Lock#lock}. + * + * @param arg the acquire argument. This value is conveyed to + * {@link #tryAcquire} but is otherwise uninterpreted and + * can represent anything you like. + */ + public final void acquire(int arg) { + if (!tryAcquire(arg) && + acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) + selfInterrupt(); + } + + /** + * Acquires in exclusive mode, aborting if interrupted. + * Implemented by first checking interrupt status, then invoking + * at least once {@link #tryAcquire}, returning on + * success. Otherwise the thread is queued, possibly repeatedly + * blocking and unblocking, invoking {@link #tryAcquire} + * until success or the thread is interrupted. This method can be + * used to implement method {@link Lock#lockInterruptibly}. + * + * @param arg the acquire argument. This value is conveyed to + * {@link #tryAcquire} but is otherwise uninterpreted and + * can represent anything you like. + * @throws InterruptedException if the current thread is interrupted + */ + public final void acquireInterruptibly(int arg) throws InterruptedException { + if (Thread.interrupted()) + throw new InterruptedException(); + if (!tryAcquire(arg)) + doAcquireInterruptibly(arg); + } + + /** + * Attempts to acquire in exclusive mode, aborting if interrupted, + * and failing if the given timeout elapses. Implemented by first + * checking interrupt status, then invoking at least once {@link + * #tryAcquire}, returning on success. Otherwise, the thread is + * queued, possibly repeatedly blocking and unblocking, invoking + * {@link #tryAcquire} until success or the thread is interrupted + * or the timeout elapses. This method can be used to implement + * method {@link Lock#tryLock(long, TimeUnit)}. + * + * @param arg the acquire argument. This value is conveyed to + * {@link #tryAcquire} but is otherwise uninterpreted and + * can represent anything you like. + * @param nanosTimeout the maximum number of nanoseconds to wait + * @return {@code true} if acquired; {@code false} if timed out + * @throws InterruptedException if the current thread is interrupted + */ + public final boolean tryAcquireNanos(int arg, long nanosTimeout) throws InterruptedException { + if (Thread.interrupted()) + throw new InterruptedException(); + return tryAcquire(arg) || + doAcquireNanos(arg, nanosTimeout); + } + + /** + * Releases in exclusive mode. Implemented by unblocking one or + * more threads if {@link #tryRelease} returns true. + * This method can be used to implement method {@link Lock#unlock}. + * + * @param arg the release argument. This value is conveyed to + * {@link #tryRelease} but is otherwise uninterpreted and + * can represent anything you like. + * @return the value returned from {@link #tryRelease} + */ + public final boolean release(int arg) { + if (tryRelease(arg)) { + Node h = head; + if (h != null && h.waitStatus != 0) + unparkSuccessor(h); + return true; + } + return false; + } + + /** + * Acquires in shared mode, ignoring interrupts. Implemented by + * first invoking at least once {@link #tryAcquireShared}, + * returning on success. Otherwise the thread is queued, possibly + * repeatedly blocking and unblocking, invoking {@link + * #tryAcquireShared} until success. + * + * @param arg the acquire argument. This value is conveyed to + * {@link #tryAcquireShared} but is otherwise uninterpreted + * and can represent anything you like. + */ + public final void acquireShared(int arg) { + if (tryAcquireShared(arg) < 0) + doAcquireShared(arg); + } + + /** + * Acquires in shared mode, aborting if interrupted. Implemented + * by first checking interrupt status, then invoking at least once + * {@link #tryAcquireShared}, returning on success. Otherwise the + * thread is queued, possibly repeatedly blocking and unblocking, + * invoking {@link #tryAcquireShared} until success or the thread + * is interrupted. + * @param arg the acquire argument. + * This value is conveyed to {@link #tryAcquireShared} but is + * otherwise uninterpreted and can represent anything + * you like. + * @throws InterruptedException if the current thread is interrupted + */ + public final void acquireSharedInterruptibly(int arg) throws InterruptedException { + if (Thread.interrupted()) + throw new InterruptedException(); + if (tryAcquireShared(arg) < 0) + doAcquireSharedInterruptibly(arg); + } + + /** + * Attempts to acquire in shared mode, aborting if interrupted, and + * failing if the given timeout elapses. Implemented by first + * checking interrupt status, then invoking at least once {@link + * #tryAcquireShared}, returning on success. Otherwise, the + * thread is queued, possibly repeatedly blocking and unblocking, + * invoking {@link #tryAcquireShared} until success or the thread + * is interrupted or the timeout elapses. + * + * @param arg the acquire argument. This value is conveyed to + * {@link #tryAcquireShared} but is otherwise uninterpreted + * and can represent anything you like. + * @param nanosTimeout the maximum number of nanoseconds to wait + * @return {@code true} if acquired; {@code false} if timed out + * @throws InterruptedException if the current thread is interrupted + */ + public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout) throws InterruptedException { + if (Thread.interrupted()) + throw new InterruptedException(); + return tryAcquireShared(arg) >= 0 || + doAcquireSharedNanos(arg, nanosTimeout); + } + + /** + * Releases in shared mode. Implemented by unblocking one or more + * threads if {@link #tryReleaseShared} returns true. + * + * @param arg the release argument. This value is conveyed to + * {@link #tryReleaseShared} but is otherwise uninterpreted + * and can represent anything you like. + * @return the value returned from {@link #tryReleaseShared} + */ + public final boolean releaseShared(int arg) { + if (tryReleaseShared(arg)) { + Node h = head; + if (h != null && h.waitStatus != 0) + unparkSuccessor(h); + return true; + } + return false; + } + + // Queue inspection methods + + /** + * Queries whether any threads are waiting to acquire. Note that + * because cancellations due to interrupts and timeouts may occur + * at any time, a {@code true} return does not guarantee that any + * other thread will ever acquire. + * + * <p>In this implementation, this operation returns in + * constant time. + * + * @return {@code true} if there may be other threads waiting to acquire + */ + public final boolean hasQueuedThreads() { + return head != tail; + } + + /** + * Queries whether any threads have ever contended to acquire this + * synchronizer; that is if an acquire method has ever blocked. + * + * <p>In this implementation, this operation returns in + * constant time. + * + * @return {@code true} if there has ever been contention + */ + public final boolean hasContended() { + return head != null; + } + + /** + * Returns the first (longest-waiting) thread in the queue, or + * {@code null} if no threads are currently queued. + * + * <p>In this implementation, this operation normally returns in + * constant time, but may iterate upon contention if other threads are + * concurrently modifying the queue. + * + * @return the first (longest-waiting) thread in the queue, or + * {@code null} if no threads are currently queued + */ + public final Thread getFirstQueuedThread() { + // handle only fast path, else relay + return (head == tail)? null : fullGetFirstQueuedThread(); + } + + /** + * Version of getFirstQueuedThread called when fastpath fails + */ + private Thread fullGetFirstQueuedThread() { + /* + * The first node is normally h.next. Try to get its + * thread field, ensuring consistent reads: If thread + * field is nulled out or s.prev is no longer head, then + * some other thread(s) concurrently performed setHead in + * between some of our reads. We try this twice before + * resorting to traversal. + */ + Node h, s; + Thread st; + if (((h = head) != null && (s = h.next) != null && + s.prev == head && (st = s.thread) != null) || + ((h = head) != null && (s = h.next) != null && + s.prev == head && (st = s.thread) != null)) + return st; + + /* + * Head's next field might not have been set yet, or may have + * been unset after setHead. So we must check to see if tail + * is actually first node. If not, we continue on, safely + * traversing from tail back to head to find first, + * guaranteeing termination. + */ + + Node t = tail; + Thread firstThread = null; + while (t != null && t != head) { + Thread tt = t.thread; + if (tt != null) + firstThread = tt; + t = t.prev; + } + return firstThread; + } + + /** + * Returns true if the given thread is currently queued. + * + * <p>This implementation traverses the queue to determine + * presence of the given thread. + * + * @param thread the thread + * @return {@code true} if the given thread is on the queue + * @throws NullPointerException if the thread is null + */ + public final boolean isQueued(Thread thread) { + if (thread == null) + throw new NullPointerException(); + for (Node p = tail; p != null; p = p.prev) + if (p.thread == thread) + return true; + return false; + } + + /** + * Return {@code true} if the apparent first queued thread, if one + * exists, is not waiting in exclusive mode. Used only as a heuristic + * in ReentrantReadWriteLock. + */ + final boolean apparentlyFirstQueuedIsExclusive() { + Node h, s; + return ((h = head) != null && (s = h.next) != null && + s.nextWaiter != Node.SHARED); + } + + /** + * Return {@code true} if the queue is empty or if the given thread + * is at the head of the queue. This is reliable only if + * <tt>current</tt> is actually Thread.currentThread() of caller. + */ + final boolean isFirst(Thread current) { + Node h, s; + return ((h = head) == null || + ((s = h.next) != null && s.thread == current) || + fullIsFirst(current)); + } + + final boolean fullIsFirst(Thread current) { + // same idea as fullGetFirstQueuedThread + Node h, s; + Thread firstThread = null; + if (((h = head) != null && (s = h.next) != null && + s.prev == head && (firstThread = s.thread) != null)) + return firstThread == current; + Node t = tail; + while (t != null && t != head) { + Thread tt = t.thread; + if (tt != null) + firstThread = tt; + t = t.prev; + } + return firstThread == current || firstThread == null; + } + + + // Instrumentation and monitoring methods + + /** + * 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 system state, not for synchronization + * control. + * + * @return the estimated number of threads waiting to acquire + */ + public final int getQueueLength() { + int n = 0; + for (Node p = tail; p != null; p = p.prev) { + if (p.thread != null) + ++n; + } + return n; + } + + /** + * Returns a collection containing threads that may be waiting to + * acquire. Because the actual set of threads may change + * dynamically while constructing this result, the returned + * collection is only a best-effort estimate. The elements of the + * returned collection are in no particular order. This method is + * designed to facilitate construction of subclasses that provide + * more extensive monitoring facilities. + * + * @return the collection of threads + */ + public final Collection<Thread> getQueuedThreads() { + ArrayList<Thread> list = new ArrayList<Thread>(); + for (Node p = tail; p != null; p = p.prev) { + Thread t = p.thread; + if (t != null) + list.add(t); + } + return list; + } + + /** + * Returns a collection containing threads that may be waiting to + * acquire in exclusive mode. This has the same properties + * as {@link #getQueuedThreads} except that it only returns + * those threads waiting due to an exclusive acquire. + * + * @return the collection of threads + */ + public final Collection<Thread> getExclusiveQueuedThreads() { + ArrayList<Thread> list = new ArrayList<Thread>(); + for (Node p = tail; p != null; p = p.prev) { + if (!p.isShared()) { + Thread t = p.thread; + if (t != null) + list.add(t); + } + } + return list; + } + + /** + * Returns a collection containing threads that may be waiting to + * acquire in shared mode. This has the same properties + * as {@link #getQueuedThreads} except that it only returns + * those threads waiting due to a shared acquire. + * + * @return the collection of threads + */ + public final Collection<Thread> getSharedQueuedThreads() { + ArrayList<Thread> list = new ArrayList<Thread>(); + for (Node p = tail; p != null; p = p.prev) { + if (p.isShared()) { + Thread t = p.thread; + if (t != null) + list.add(t); + } + } + return list; + } + + /** + * Returns a string identifying this synchronizer, as well as its state. + * The state, in brackets, includes the String {@code "State ="} + * followed by the current value of {@link #getState}, and either + * {@code "nonempty"} or {@code "empty"} depending on whether the + * queue is empty. + * + * @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]"; + } + + + // Internal support methods for Conditions + + /** + * Returns true if a node, always one that was initially placed on + * a condition queue, is now waiting to reacquire on sync queue. + * @param node the node + * @return true if is reacquiring + */ + final boolean isOnSyncQueue(Node node) { + if (node.waitStatus == Node.CONDITION || node.prev == null) + return false; + if (node.next != null) // If has successor, it must be on queue + return true; + /* + * node.prev can be non-null, but not yet on queue because + * the CAS to place it on queue can fail. So we have to + * traverse from tail to make sure it actually made it. It + * will always be near the tail in calls to this method, and + * unless the CAS failed (which is unlikely), it will be + * there, so we hardly ever traverse much. + */ + return findNodeFromTail(node); + } + + /** + * Returns true if node is on sync queue by searching backwards from tail. + * Called only when needed by isOnSyncQueue. + * @return true if present + */ + private boolean findNodeFromTail(Node node) { + Node t = tail; + for (;;) { + if (t == node) + return true; + if (t == null) + return false; + t = t.prev; + } + } + + /** + * Transfers a node from a condition queue onto sync queue. + * Returns true if successful. + * @param node the node + * @return true if successfully transferred (else the node was + * cancelled before signal). + */ + final boolean transferForSignal(Node node) { + /* + * If cannot change waitStatus, the node has been cancelled. + */ + if (!compareAndSetWaitStatus(node, Node.CONDITION, 0)) + return false; + + /* + * Splice onto queue and try to set waitStatus of predecessor to + * indicate that thread is (probably) waiting. If cancelled or + * attempt to set waitStatus fails, wake up to resync (in which + * case the waitStatus can be transiently and harmlessly wrong). + */ + Node p = enq(node); + int c = p.waitStatus; + if (c > 0 || !compareAndSetWaitStatus(p, c, Node.SIGNAL)) + LockSupport.unpark(node.thread); + return true; + } + + /** + * Transfers node, if necessary, to sync queue after a cancelled + * wait. Returns true if thread was cancelled before being + * signalled. + * @param current the waiting thread + * @param node its node + * @return true if cancelled before the node was signalled. + */ + final boolean transferAfterCancelledWait(Node node) { + if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) { + enq(node); + return true; + } + /* + * If we lost out to a signal(), then we can't proceed + * until it finishes its enq(). Cancelling during an + * incomplete transfer is both rare and transient, so just + * spin. + */ + while (!isOnSyncQueue(node)) + Thread.yield(); + return false; + } + + /** + * Invokes release with current state value; returns saved state. + * Cancels node and throws exception on failure. + * @param node the condition node for this wait + * @return previous sync state + */ + final int fullyRelease(Node node) { + try { + int savedState = getState(); + if (release(savedState)) + return savedState; + } catch (RuntimeException ex) { + node.waitStatus = Node.CANCELLED; + throw ex; + } + // reach here if release fails + node.waitStatus = Node.CANCELLED; + throw new IllegalMonitorStateException(); + } + + // Instrumentation methods for conditions + + /** + * Queries whether the given ConditionObject + * uses this synchronizer as its lock. + * + * @param condition the condition + * @return <tt>true</tt> if owned + * @throws NullPointerException if the condition is null + */ + public final boolean owns(ConditionObject condition) { + if (condition == null) + throw new NullPointerException(); + return condition.isOwnedBy(this); + } + + /** + * Queries whether any threads are waiting on the given condition + * associated with this synchronizer. Note that because timeouts + * and interrupts may occur at any time, a <tt>true</tt> return + * does not guarantee that a future <tt>signal</tt> will awaken + * any threads. This method is designed primarily for use in + * monitoring of the system state. + * + * @param condition the condition + * @return <tt>true</tt> if there are any waiting threads + * @throws IllegalMonitorStateException if exclusive synchronization + * is not held + * @throws IllegalArgumentException if the given condition is + * not associated with this synchronizer + * @throws NullPointerException if the condition is null + */ + public final boolean hasWaiters(ConditionObject condition) { + if (!owns(condition)) + throw new IllegalArgumentException("Not owner"); + return condition.hasWaiters(); + } + + /** + * Returns an estimate of the number of threads waiting on the + * 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. + * + * @param condition the condition + * @return the estimated number of waiting threads + * @throws IllegalMonitorStateException if exclusive synchronization + * is not held + * @throws IllegalArgumentException if the given condition is + * not associated with this synchronizer + * @throws NullPointerException if the condition is null + */ + public final int getWaitQueueLength(ConditionObject condition) { + if (!owns(condition)) + throw new IllegalArgumentException("Not owner"); + return condition.getWaitQueueLength(); + } + + /** + * Returns a collection containing those threads that may be + * waiting on the given condition associated with this + * synchronizer. Because the actual set of threads may change + * dynamically while constructing this result, the returned + * collection is only a best-effort estimate. The elements of the + * returned collection are in no particular order. + * + * @param condition the condition + * @return the collection of threads + * @throws IllegalMonitorStateException if exclusive synchronization + * is not held + * @throws IllegalArgumentException if the given condition is + * not associated with this synchronizer + * @throws NullPointerException if the condition is null + */ + public final Collection<Thread> getWaitingThreads(ConditionObject condition) { + if (!owns(condition)) + throw new IllegalArgumentException("Not owner"); + return condition.getWaitingThreads(); + } + + /** + * Condition implementation for a {@link + * AbstractQueuedSynchronizer} serving as the basis of a {@link + * Lock} implementation. + * + * <p>Method documentation for this class describes mechanics, + * not behavioral specifications from the point of view of Lock + * and Condition users. Exported versions of this class will in + * general need to be accompanied by documentation describing + * condition semantics that rely on those of the associated + * <tt>AbstractQueuedSynchronizer</tt>. + * + * <p>This class is Serializable, but all fields are transient, + * so deserialized conditions have no waiters. + */ + public class ConditionObject implements Condition, java.io.Serializable { + private static final long serialVersionUID = 1173984872572414699L; + /** First node of condition queue. */ + private transient Node firstWaiter; + /** Last node of condition queue. */ + private transient Node lastWaiter; + + /** + * Creates a new <tt>ConditionObject</tt> instance. + */ + public ConditionObject() { } + + // Internal methods + + /** + * Adds a new waiter to wait queue. + * @return its new wait node + */ + private Node addConditionWaiter() { + Node node = new Node(Thread.currentThread(), Node.CONDITION); + Node t = lastWaiter; + if (t == null) + firstWaiter = node; + else + t.nextWaiter = node; + lastWaiter = node; + return node; + } + + /** + * Removes and transfers nodes until hit non-cancelled one or + * null. Split out from signal in part to encourage compilers + * to inline the case of no waiters. + * @param first (non-null) the first node on condition queue + */ + private void doSignal(Node first) { + do { + if ( (firstWaiter = first.nextWaiter) == null) + lastWaiter = null; + first.nextWaiter = null; + } while (!transferForSignal(first) && + (first = firstWaiter) != null); + } + + /** + * Removes and transfers all nodes. + * @param first (non-null) the first node on condition queue + */ + private void doSignalAll(Node first) { + lastWaiter = firstWaiter = null; + do { + Node next = first.nextWaiter; + first.nextWaiter = null; + transferForSignal(first); + first = next; + } while (first != null); + } + + /** + * Returns true if given node is on this condition queue. + * Call only when holding lock. + */ + private boolean isOnConditionQueue(Node node) { + return node.next != null || node == lastWaiter; + } + + /** + * Unlinks a cancelled waiter node from condition queue. This + * is called when cancellation occurred during condition wait, + * not lock wait, and is called only after lock has been + * re-acquired by a cancelled waiter and the node is not known + * to already have been dequeued. It is needed to avoid + * garbage retention in the absence of signals. So even though + * it may require a full traversal, it comes into play only + * when timeouts or cancellations occur in the absence of + * signals. + */ + private void unlinkCancelledWaiter(Node node) { + Node t = firstWaiter; + Node trail = null; + while (t != null) { + if (t == node) { + Node next = t.nextWaiter; + if (trail == null) + firstWaiter = next; + else + trail.nextWaiter = next; + if (lastWaiter == node) + lastWaiter = trail; + break; + } + trail = t; + t = t.nextWaiter; + } + } + + // public methods + + /** + * Moves the longest-waiting thread, if one exists, from the + * wait queue for this condition to the wait queue for the + * owning lock. + * + * @throws IllegalMonitorStateException if {@link #isHeldExclusively} + * returns {@code false} + */ + public final void signal() { + if (!isHeldExclusively()) + throw new IllegalMonitorStateException(); + Node first = firstWaiter; + if (first != null) + doSignal(first); + } + + /** + * Moves all threads from the wait queue for this condition to + * the wait queue for the owning lock. + * + * @throws IllegalMonitorStateException if {@link #isHeldExclusively} + * returns {@code false} + */ + public final void signalAll() { + if (!isHeldExclusively()) + throw new IllegalMonitorStateException(); + Node first = firstWaiter; + if (first != null) + doSignalAll(first); + } + + /** + * 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. + * </ol> + */ + public final void awaitUninterruptibly() { + Node node = addConditionWaiter(); + int savedState = fullyRelease(node); + boolean interrupted = false; + while (!isOnSyncQueue(node)) { + LockSupport.park(this); + if (Thread.interrupted()) + interrupted = true; + } + if (acquireQueued(node, savedState) || interrupted) + selfInterrupt(); + } + + /* + * For interruptible waits, we need to track whether to throw + * InterruptedException, if interrupted while blocked on + * condition, versus reinterrupt current thread, if + * interrupted while blocked waiting to re-acquire. + */ + + /** Mode meaning to reinterrupt on exit from wait */ + private static final int REINTERRUPT = 1; + /** Mode meaning to throw InterruptedException on exit from wait */ + private static final int THROW_IE = -1; + + /** + * Checks for interrupt, returning THROW_IE if interrupted + * before signalled, REINTERRUPT if after signalled, or + * 0 if not interrupted. + */ + private int checkInterruptWhileWaiting(Node node) { + return (Thread.interrupted()) ? + ((transferAfterCancelledWait(node))? THROW_IE : REINTERRUPT) : + 0; + } + + /** + * Throws InterruptedException, reinterrupts current thread, or + * does nothing, depending on mode. + */ + private void reportInterruptAfterWait(int interruptMode) + throws InterruptedException { + if (interruptMode == THROW_IE) + throw new InterruptedException(); + else if (interruptMode == REINTERRUPT) + selfInterrupt(); + } + + /** + * 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 exception + * </ol> + */ + public final void await() throws InterruptedException { + if (Thread.interrupted()) + throw new InterruptedException(); + Node node = addConditionWaiter(); + int savedState = fullyRelease(node); + int interruptMode = 0; + while (!isOnSyncQueue(node)) { + LockSupport.park(this); + if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) + break; + } + if (acquireQueued(node, savedState) && interruptMode != THROW_IE) + interruptMode = REINTERRUPT; + if (isOnConditionQueue(node)) + unlinkCancelledWaiter(node); + if (interruptMode != 0) + reportInterruptAfterWait(interruptMode); + } + + /** + * 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 + * </ol> + */ + public final long awaitNanos(long nanosTimeout) throws InterruptedException { + if (Thread.interrupted()) + throw new InterruptedException(); + Node node = addConditionWaiter(); + int savedState = fullyRelease(node); + long lastTime = System.nanoTime(); + int interruptMode = 0; + while (!isOnSyncQueue(node)) { + if (nanosTimeout <= 0L) { + transferAfterCancelledWait(node); + break; + } + LockSupport.parkNanos(this, nanosTimeout); + if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) + break; + + long now = System.nanoTime(); + nanosTimeout -= now - lastTime; + lastTime = now; + } + if (acquireQueued(node, savedState) && interruptMode != THROW_IE) + interruptMode = REINTERRUPT; + if (isOnConditionQueue(node)) + unlinkCancelledWaiter(node); + if (interruptMode != 0) + reportInterruptAfterWait(interruptMode); + return nanosTimeout - (System.nanoTime() - lastTime); + } + + /** + * 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 + * </ol> + */ + public final boolean awaitUntil(Date deadline) throws InterruptedException { + if (deadline == null) + throw new NullPointerException(); + long abstime = deadline.getTime(); + if (Thread.interrupted()) + throw new InterruptedException(); + Node node = addConditionWaiter(); + int savedState = fullyRelease(node); + boolean timedout = false; + int interruptMode = 0; + while (!isOnSyncQueue(node)) { + if (System.currentTimeMillis() > abstime) { + timedout = transferAfterCancelledWait(node); + break; + } + LockSupport.parkUntil(this, abstime); + if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) + break; + } + if (acquireQueued(node, savedState) && interruptMode != THROW_IE) + interruptMode = REINTERRUPT; + if (isOnConditionQueue(node)) + unlinkCancelledWaiter(node); + if (interruptMode != 0) + reportInterruptAfterWait(interruptMode); + return !timedout; + } + + /** + * 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 + * </ol> + */ + public final boolean await(long time, TimeUnit unit) throws InterruptedException { + if (unit == null) + throw new NullPointerException(); + long nanosTimeout = unit.toNanos(time); + if (Thread.interrupted()) + throw new InterruptedException(); + Node node = addConditionWaiter(); + int savedState = fullyRelease(node); + long lastTime = System.nanoTime(); + boolean timedout = false; + int interruptMode = 0; + while (!isOnSyncQueue(node)) { + if (nanosTimeout <= 0L) { + timedout = transferAfterCancelledWait(node); + break; + } + LockSupport.parkNanos(this, nanosTimeout); + if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) + break; + long now = System.nanoTime(); + nanosTimeout -= now - lastTime; + lastTime = now; + } + if (acquireQueued(node, savedState) && interruptMode != THROW_IE) + interruptMode = REINTERRUPT; + if (isOnConditionQueue(node)) + unlinkCancelledWaiter(node); + if (interruptMode != 0) + reportInterruptAfterWait(interruptMode); + return !timedout; + } + + // support for instrumentation + + /** + * Returns true if this condition was created by the given + * synchronization object. + * + * @return {@code true} if owned + */ + final boolean isOwnedBy(AbstractQueuedSynchronizer sync) { + return sync == AbstractQueuedSynchronizer.this; + } + + /** + * Queries whether any threads are waiting on this condition. + * Implements {@link AbstractQueuedSynchronizer#hasWaiters}. + * + * @return {@code true} if there are any waiting threads + * @throws IllegalMonitorStateException if {@link #isHeldExclusively} + * returns {@code false} + */ + protected final boolean hasWaiters() { + if (!isHeldExclusively()) + throw new IllegalMonitorStateException(); + for (Node w = firstWaiter; w != null; w = w.nextWaiter) { + if (w.waitStatus == Node.CONDITION) + return true; + } + return false; + } + + /** + * Returns an estimate of the number of threads waiting on + * this condition. + * Implements {@link AbstractQueuedSynchronizer#getWaitQueueLength}. + * + * @return the estimated number of waiting threads + * @throws IllegalMonitorStateException if {@link #isHeldExclusively} + * returns {@code false} + */ + protected final int getWaitQueueLength() { + if (!isHeldExclusively()) + throw new IllegalMonitorStateException(); + int n = 0; + for (Node w = firstWaiter; w != null; w = w.nextWaiter) { + if (w.waitStatus == Node.CONDITION) + ++n; + } + return n; + } + + /** + * Returns a collection containing those threads that may be + * waiting on this Condition. + * Implements {@link AbstractQueuedSynchronizer#getWaitingThreads}. + * + * @return the collection of threads + * @throws IllegalMonitorStateException if {@link #isHeldExclusively} + * returns {@code false} + */ + protected final Collection<Thread> getWaitingThreads() { + if (!isHeldExclusively()) + throw new IllegalMonitorStateException(); + ArrayList<Thread> list = new ArrayList<Thread>(); + for (Node w = firstWaiter; w != null; w = w.nextWaiter) { + if (w.waitStatus == Node.CONDITION) { + Thread t = w.thread; + if (t != null) + list.add(t); + } + } + return list; + } + } + + /** + * Setup to support compareAndSet. We need to natively implement + * this here: For the sake of permitting future enhancements, we + * cannot explicitly subclass AtomicInteger, which would be + * efficient and useful otherwise. So, as the lesser of evils, we + * natively implement using hotspot intrinsics API. And while we + * 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; + + static { + try { + stateOffset = unsafe.objectFieldOffset + (AbstractQueuedSynchronizer.class.getDeclaredField("state")); + headOffset = unsafe.objectFieldOffset + (AbstractQueuedSynchronizer.class.getDeclaredField("head")); + tailOffset = unsafe.objectFieldOffset + (AbstractQueuedSynchronizer.class.getDeclaredField("tail")); + waitStatusOffset = unsafe.objectFieldOffset + (Node.class.getDeclaredField("waitStatus")); + + } catch (Exception ex) { throw new Error(ex); } + } + + /** + * CAS head field. Used only by enq + */ + private final boolean compareAndSetHead(Node update) { + return unsafe.compareAndSwapObject(this, headOffset, null, update); + } + + /** + * CAS tail field. Used only by enq + */ + private final boolean compareAndSetTail(Node expect, Node update) { + return unsafe.compareAndSwapObject(this, tailOffset, expect, update); + } + + /** + * CAS waitStatus field of a node. + */ + private final static boolean compareAndSetWaitStatus(Node node, + int expect, + int update) { + return unsafe.compareAndSwapInt(node, waitStatusOffset, + expect, update); + } +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/locks/Condition.java b/libjava/classpath/external/jsr166/java/util/concurrent/locks/Condition.java new file mode 100644 index 000000000..5d24128e1 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/locks/Condition.java @@ -0,0 +1,435 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.locks; +import java.util.concurrent.*; +import java.util.Date; + +/** + * {@code Condition} factors out the {@code Object} monitor + * methods ({@link Object#wait() wait}, {@link Object#notify notify} + * and {@link Object#notifyAll notifyAll}) into distinct objects to + * give the effect of having multiple wait-sets per object, by + * combining them with the use of arbitrary {@link Lock} implementations. + * Where a {@code Lock} replaces the use of {@code synchronized} methods + * and statements, a {@code Condition} replaces the use of the Object + * monitor methods. + * + * <p>Conditions (also known as <em>condition queues</em> or + * <em>condition variables</em>) provide a means for one thread to + * suspend execution (to "wait") until notified by another + * thread that some state condition may now be true. Because access + * to this shared state information occurs in different threads, it + * must be protected, so a lock of some form is associated with the + * condition. The key property that waiting for a condition provides + * is that it <em>atomically</em> releases the associated lock and + * suspends the current thread, just like {@code Object.wait}. + * + * <p>A {@code Condition} instance is intrinsically bound to a lock. + * To obtain a {@code Condition} instance for a particular {@link Lock} + * instance use its {@link Lock#newCondition newCondition()} method. + * + * <p>As an example, suppose we have a bounded buffer which supports + * {@code put} and {@code take} methods. If a + * {@code take} is attempted on an empty buffer, then the thread will block + * until an item becomes available; if a {@code put} is attempted on a + * full buffer, then the thread will block until a space becomes available. + * We would like to keep waiting {@code put} threads and {@code take} + * threads in separate wait-sets so that we can use the optimization of + * only notifying a single thread at a time when items or spaces become + * available in the buffer. This can be achieved using two + * {@link Condition} instances. + * <pre> + * class BoundedBuffer { + * <b>final Lock lock = new ReentrantLock();</b> + * final Condition notFull = <b>lock.newCondition(); </b> + * final Condition notEmpty = <b>lock.newCondition(); </b> + * + * final Object[] items = new Object[100]; + * int putptr, takeptr, count; + * + * public void put(Object x) throws InterruptedException { + * <b>lock.lock(); + * try {</b> + * while (count == items.length) + * <b>notFull.await();</b> + * items[putptr] = x; + * if (++putptr == items.length) putptr = 0; + * ++count; + * <b>notEmpty.signal();</b> + * <b>} finally { + * lock.unlock(); + * }</b> + * } + * + * public Object take() throws InterruptedException { + * <b>lock.lock(); + * try {</b> + * while (count == 0) + * <b>notEmpty.await();</b> + * Object x = items[takeptr]; + * if (++takeptr == items.length) takeptr = 0; + * --count; + * <b>notFull.signal();</b> + * return x; + * <b>} finally { + * lock.unlock(); + * }</b> + * } + * } + * </pre> + * + * (The {@link java.util.concurrent.ArrayBlockingQueue} class provides + * this functionality, so there is no reason to implement this + * sample usage class.) + * + * <p>A {@code Condition} implementation can provide behavior and semantics + * that is + * different from that of the {@code Object} monitor methods, such as + * guaranteed ordering for notifications, or not requiring a lock to be held + * when performing notifications. + * If an implementation provides such specialized semantics then the + * implementation must document those semantics. + * + * <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. + * 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 + * {@linkplain #await waiting} and {@linkplain #signal signalling} methods. + * It is recommended that to avoid confusion you never use {@code Condition} + * instances in this way, except perhaps within their own implementation. + * + * <p>Except where noted, passing a {@code null} value for any parameter + * will result in a {@link NullPointerException} being thrown. + * + * <h3>Implementation Considerations</h3> + * + * <p>When waiting upon a {@code Condition}, a "<em>spurious + * wakeup</em>" is permitted to occur, in + * general, as a concession to the underlying platform semantics. + * This has little practical impact on most application programs as a + * {@code Condition} should always be waited upon in a loop, testing + * the state predicate that is being waited for. An implementation is + * free to remove the possibility of spurious wakeups but it is + * recommended that applications programmers always assume that they can + * occur and so always wait in a loop. + * + * <p>The three forms of condition waiting + * (interruptible, non-interruptible, and timed) may differ in their ease of + * implementation on some platforms and in their performance characteristics. + * In particular, it may be difficult to provide these features and maintain + * specific semantics such as ordering guarantees. + * Further, the ability to interrupt the actual suspension of the thread may + * not always be feasible to implement on all platforms. + * + * <p>Consequently, an implementation is not required to define exactly the + * same guarantees or semantics for all three forms of waiting, nor is it + * required to support interruption of the actual suspension of the thread. + * + * <p>An implementation is required to + * clearly document the semantics and guarantees provided by each of the + * waiting methods, and when an implementation does support interruption of + * thread suspension then it must obey the interruption semantics as defined + * in this interface. + * + * <p>As interruption generally implies cancellation, and checks for + * interruption are often infrequent, an implementation can favor responding + * to an interrupt over normal method return. This is true even if it can be + * shown that the interrupt occurred after another action may have unblocked + * the thread. An implementation should document this behavior. + * + * @since 1.5 + * @author Doug Lea + */ +public interface Condition { + + /** + * Causes the current thread to wait until it is signalled or + * {@linkplain Thread#interrupt interrupted}. + * + * <p>The lock associated with this {@code Condition} is atomically + * released and the current thread becomes disabled for thread scheduling + * purposes and lies dormant until <em>one</em> of four things happens: + * <ul> + * <li>Some other thread invokes the {@link #signal} method for this + * {@code Condition} and the current thread happens to be chosen as the + * thread to be awakened; or + * <li>Some other thread invokes the {@link #signalAll} method for this + * {@code Condition}; or + * <li>Some other thread {@linkplain Thread#interrupt interrupts} the + * current thread, and interruption of thread suspension is supported; or + * <li>A "<em>spurious wakeup</em>" occurs. + * </ul> + * + * <p>In all cases, before this method can return the current thread must + * re-acquire the lock associated with this condition. When the + * thread returns it is <em>guaranteed</em> to hold this lock. + * + * <p>If the current thread: + * <ul> + * <li>has its interrupted status set on entry to this method; or + * <li>is {@linkplain Thread#interrupt interrupted} while waiting + * and interruption of thread suspension is supported, + * </ul> + * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. It is not specified, in the first + * case, whether or not the test for interruption occurs before the lock + * is released. + * + * <p><b>Implementation Considerations</b> + * + * <p>The current thread is assumed to hold the lock associated with this + * {@code Condition} when this method is called. + * It is up to the implementation to determine if this is + * the case and if not, how to respond. Typically, an exception will be + * thrown (such as {@link IllegalMonitorStateException}) and the + * implementation must document that fact. + * + * <p>An implementation can favor responding to an interrupt over normal + * method return in response to a signal. In that case the implementation + * must ensure that the signal is redirected to another waiting thread, if + * there is one. + * + * @throws InterruptedException if the current thread is interrupted + * (and interruption of thread suspension is supported) + */ + void await() throws InterruptedException; + + /** + * Causes the current thread to wait until it is signalled. + * + * <p>The lock associated with this condition is atomically + * released and the current thread becomes disabled for thread scheduling + * purposes and lies dormant until <em>one</em> of three things happens: + * <ul> + * <li>Some other thread invokes the {@link #signal} method for this + * {@code Condition} and the current thread happens to be chosen as the + * thread to be awakened; or + * <li>Some other thread invokes the {@link #signalAll} method for this + * {@code Condition}; or + * <li>A "<em>spurious wakeup</em>" occurs. + * </ul> + * + * <p>In all cases, before this method can return the current thread must + * re-acquire the lock associated with this condition. When the + * thread returns it is <em>guaranteed</em> to hold this lock. + * + * <p>If the current thread's interrupted status is set when it enters + * this method, or it is {@linkplain Thread#interrupt interrupted} + * while waiting, it will continue to wait until signalled. When it finally + * returns from this method its interrupted status will still + * be set. + * + * <p><b>Implementation Considerations</b> + * + * <p>The current thread is assumed to hold the lock associated with this + * {@code Condition} when this method is called. + * It is up to the implementation to determine if this is + * the case and if not, how to respond. Typically, an exception will be + * thrown (such as {@link IllegalMonitorStateException}) and the + * implementation must document that fact. + */ + void awaitUninterruptibly(); + + /** + * Causes the current thread to wait until it is signalled or interrupted, + * or the specified waiting time elapses. + * + * <p>The lock associated with this condition is atomically + * released and the current thread becomes disabled for thread scheduling + * purposes and lies dormant until <em>one</em> of five things happens: + * <ul> + * <li>Some other thread invokes the {@link #signal} method for this + * {@code Condition} and the current thread happens to be chosen as the + * thread to be awakened; or + * <li>Some other thread invokes the {@link #signalAll} method for this + * {@code Condition}; or + * <li>Some other thread {@linkplain Thread#interrupt interrupts} the + * current thread, and interruption of thread suspension is supported; or + * <li>The specified waiting time elapses; or + * <li>A "<em>spurious wakeup</em>" occurs. + * </ul> + * + * <p>In all cases, before this method can return the current thread must + * re-acquire the lock associated with this condition. When the + * thread returns it is <em>guaranteed</em> to hold this lock. + * + * <p>If the current thread: + * <ul> + * <li>has its interrupted status set on entry to this method; or + * <li>is {@linkplain Thread#interrupt interrupted} while waiting + * and interruption of thread suspension is supported, + * </ul> + * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. It is not specified, in the first + * case, whether or not the test for interruption occurs before the lock + * is released. + * + * <p>The method returns an estimate of the number of nanoseconds + * remaining to wait given the supplied {@code nanosTimeout} + * value upon return, or a value less than or equal to zero if it + * timed out. This value can be used to determine whether and how + * long to re-wait in cases where the wait returns but an awaited + * condition still does not hold. Typical uses of this method take + * the following form: + * + * <pre> + * synchronized boolean aMethod(long timeout, TimeUnit unit) { + * long nanosTimeout = unit.toNanos(timeout); + * while (!conditionBeingWaitedFor) { + * if (nanosTimeout > 0) + * nanosTimeout = theCondition.awaitNanos(nanosTimeout); + * else + * return false; + * } + * // ... + * } + * </pre> + * + * <p> Design note: This method requires a nanosecond argument so + * as to avoid truncation errors in reporting remaining times. + * Such precision loss would make it difficult for programmers to + * ensure that total waiting times are not systematically shorter + * than specified when re-waits occur. + * + * <p><b>Implementation Considerations</b> + * + * <p>The current thread is assumed to hold the lock associated with this + * {@code Condition} when this method is called. + * It is up to the implementation to determine if this is + * the case and if not, how to respond. Typically, an exception will be + * thrown (such as {@link IllegalMonitorStateException}) and the + * implementation must document that fact. + * + * <p>An implementation can favor responding to an interrupt over normal + * method return in response to a signal, or over indicating the elapse + * of the specified waiting time. In either case the implementation + * must ensure that the signal is redirected to another waiting thread, if + * there is one. + * + * @param nanosTimeout the maximum time to wait, in nanoseconds + * @return an estimate of the {@code nanosTimeout} value minus + * the time spent waiting upon return from this method. + * A positive value may be used as the argument to a + * subsequent call to this method to finish waiting out + * the desired time. A value less than or equal to zero + * indicates that no time remains. + * @throws InterruptedException if the current thread is interrupted + * (and interruption of thread suspension is supported) + */ + long awaitNanos(long nanosTimeout) throws InterruptedException; + + /** + * Causes the current thread to wait until it is signalled or interrupted, + * or the specified waiting time elapses. This method is behaviorally + * equivalent to:<br> + * <pre> + * awaitNanos(unit.toNanos(time)) > 0 + * </pre> + * @param time the maximum time to wait + * @param unit the time unit of the {@code time} argument + * @return {@code false} if the waiting time detectably elapsed + * before return from the method, else {@code true} + * @throws InterruptedException if the current thread is interrupted + * (and interruption of thread suspension is supported) + */ + boolean await(long time, TimeUnit unit) throws InterruptedException; + + /** + * Causes the current thread to wait until it is signalled or interrupted, + * or the specified deadline elapses. + * + * <p>The lock associated with this condition is atomically + * released and the current thread becomes disabled for thread scheduling + * purposes and lies dormant until <em>one</em> of five things happens: + * <ul> + * <li>Some other thread invokes the {@link #signal} method for this + * {@code Condition} and the current thread happens to be chosen as the + * thread to be awakened; or + * <li>Some other thread invokes the {@link #signalAll} method for this + * {@code Condition}; or + * <li>Some other thread {@linkplain Thread#interrupt interrupts} the + * current thread, and interruption of thread suspension is supported; or + * <li>The specified deadline elapses; or + * <li>A "<em>spurious wakeup</em>" occurs. + * </ul> + * + * <p>In all cases, before this method can return the current thread must + * re-acquire the lock associated with this condition. When the + * thread returns it is <em>guaranteed</em> to hold this lock. + * + * + * <p>If the current thread: + * <ul> + * <li>has its interrupted status set on entry to this method; or + * <li>is {@linkplain Thread#interrupt interrupted} while waiting + * and interruption of thread suspension is supported, + * </ul> + * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. It is not specified, in the first + * case, whether or not the test for interruption occurs before the lock + * is released. + * + * + * <p>The return value indicates whether the deadline has elapsed, + * which can be used as follows: + * <pre> + * synchronized boolean aMethod(Date deadline) { + * boolean stillWaiting = true; + * while (!conditionBeingWaitedFor) { + * if (stillWaiting) + * stillWaiting = theCondition.awaitUntil(deadline); + * else + * return false; + * } + * // ... + * } + * </pre> + * + * <p><b>Implementation Considerations</b> + * + * <p>The current thread is assumed to hold the lock associated with this + * {@code Condition} when this method is called. + * It is up to the implementation to determine if this is + * the case and if not, how to respond. Typically, an exception will be + * thrown (such as {@link IllegalMonitorStateException}) and the + * implementation must document that fact. + * + * <p>An implementation can favor responding to an interrupt over normal + * method return in response to a signal, or over indicating the passing + * of the specified deadline. In either case the implementation + * must ensure that the signal is redirected to another waiting thread, if + * there is one. + * + * @param deadline the absolute time to wait until + * @return {@code false} if the deadline has elapsed upon return, else + * {@code true} + * @throws InterruptedException if the current thread is interrupted + * (and interruption of thread suspension is supported) + */ + boolean awaitUntil(Date deadline) throws InterruptedException; + + /** + * Wakes up one waiting thread. + * + * <p>If any threads are waiting on this condition then one + * is selected for waking up. That thread must then re-acquire the + * lock before returning from {@code await}. + */ + void signal(); + + /** + * Wakes up all waiting threads. + * + * <p>If any threads are waiting on this condition then they are + * all woken up. Each thread must re-acquire the lock before it can + * return from {@code await}. + */ + void signalAll(); +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/locks/Lock.java b/libjava/classpath/external/jsr166/java/util/concurrent/locks/Lock.java new file mode 100644 index 000000000..4b9abd665 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/locks/Lock.java @@ -0,0 +1,327 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.locks; +import java.util.concurrent.TimeUnit; + +/** + * {@code Lock} implementations provide more extensive locking + * operations than can be obtained using {@code synchronized} methods + * and statements. They allow more flexible structuring, may have + * quite different properties, and may support multiple associated + * {@link Condition} objects. + * + * <p>A lock is a tool for controlling access to a shared resource by + * multiple threads. Commonly, a lock provides exclusive access to a + * shared resource: only one thread at a time can acquire the lock and + * all access to the shared resource requires that the lock be + * acquired first. However, some locks may allow concurrent access to + * a shared resource, such as the read lock of a {@link ReadWriteLock}. + * + * <p>The use of {@code synchronized} methods or statements provides + * access to the implicit monitor lock associated with every object, but + * forces all lock acquisition and release to occur in a block-structured way: + * when multiple locks are acquired they must be released in the opposite + * order, and all locks must be released in the same lexical scope in which + * they were acquired. + * + * <p>While the scoping mechanism for {@code synchronized} methods + * and statements makes it much easier to program with monitor locks, + * and helps avoid many common programming errors involving locks, + * there are occasions where you need to work with locks in a more + * flexible way. For example, some algorithms for traversing + * concurrently accessed data structures require the use of + * "hand-over-hand" or "chain locking": you + * acquire the lock of node A, then node B, then release A and acquire + * C, then release B and acquire D and so on. Implementations of the + * {@code Lock} interface enable the use of such techniques by + * allowing a lock to be acquired and released in different scopes, + * and allowing multiple locks to be acquired and released in any + * order. + * + * <p>With this increased flexibility comes additional + * responsibility. The absence of block-structured locking removes the + * automatic release of locks that occurs with {@code synchronized} + * methods and statements. In most cases, the following idiom + * should be used: + * + * <pre><tt> Lock l = ...; + * l.lock(); + * try { + * // access the resource protected by this lock + * } finally { + * l.unlock(); + * } + * </tt></pre> + * + * When locking and unlocking occur in different scopes, care must be + * taken to ensure that all code that is executed while the lock is + * held is protected by try-finally or try-catch to ensure that the + * lock is released when necessary. + * + * <p>{@code Lock} implementations provide additional functionality + * over the use of {@code synchronized} methods and statements by + * providing a non-blocking attempt to acquire a lock ({@link + * #tryLock()}), an attempt to acquire the lock that can be + * interrupted ({@link #lockInterruptibly}, and an attempt to acquire + * the lock that can timeout ({@link #tryLock(long, TimeUnit)}). + * + * <p>A {@code Lock} class can also provide behavior and semantics + * that is quite different from that of the implicit monitor lock, + * such as guaranteed ordering, non-reentrant usage, or deadlock + * detection. If an implementation provides such specialized semantics + * then the implementation must document those semantics. + * + * <p>Note that {@code Lock} instances are just normal objects and can + * themselves be used as the target in a {@code synchronized} statement. + * Acquiring the + * monitor lock of a {@code Lock} instance has no specified relationship + * with invoking any of the {@link #lock} methods of that instance. + * It is recommended that to avoid confusion you never use {@code Lock} + * instances in this way, except within their own implementation. + * + * <p>Except where noted, passing a {@code null} value for any + * parameter will result in a {@link NullPointerException} being + * thrown. + * + * <h3>Memory Synchronization</h3> + * + * <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://java.sun.com/docs/books/jls/"> + * The Java Language Specification, Third Edition (17.4 Memory Model)</a>: + * <ul> + * <li>A successful {@code lock} operation has the same memory + * synchronization effects as a successful <em>Lock</em> action. + * <li>A successful {@code unlock} operation has the same + * memory synchronization effects as a successful <em>Unlock</em> action. + * </ul> + * + * Unsuccessful locking and unlocking operations, and reentrant + * locking/unlocking operations, do not require any memory + * synchronization effects. + * + * <h3>Implementation Considerations</h3> + * + * <p> The three forms of lock acquisition (interruptible, + * non-interruptible, and timed) may differ in their performance + * characteristics, ordering guarantees, or other implementation + * qualities. Further, the ability to interrupt the <em>ongoing</em> + * acquisition of a lock may not be available in a given {@code Lock} + * class. Consequently, an implementation is not required to define + * exactly the same guarantees or semantics for all three forms of + * lock acquisition, nor is it required to support interruption of an + * ongoing lock acquisition. An implementation is required to clearly + * document the semantics and guarantees provided by each of the + * locking methods. It must also obey the interruption semantics as + * defined in this interface, to the extent that interruption of lock + * acquisition is supported: which is either totally, or only on + * method entry. + * + * <p>As interruption generally implies cancellation, and checks for + * interruption are often infrequent, an implementation can favor responding + * to an interrupt over normal method return. This is true even if it can be + * shown that the interrupt occurred after another action may have unblocked + * the thread. An implementation should document this behavior. + * + * @see ReentrantLock + * @see Condition + * @see ReadWriteLock + * + * @since 1.5 + * @author Doug Lea + */ +public interface Lock { + + /** + * Acquires the lock. + * + * <p>If the lock is not available then the current thread becomes + * disabled for thread scheduling purposes and lies dormant until the + * lock has been acquired. + * + * <p><b>Implementation Considerations</b> + * + * <p>A {@code Lock} implementation may be able to detect erroneous use + * of the lock, such as an invocation that would cause deadlock, and + * may throw an (unchecked) exception in such circumstances. The + * circumstances and the exception type must be documented by that + * {@code Lock} implementation. + */ + void lock(); + + /** + * Acquires the lock unless the current thread is + * {@linkplain Thread#interrupt interrupted}. + * + * <p>Acquires the lock if it is available and returns immediately. + * + * <p>If the lock is not available then the current thread becomes + * disabled for thread scheduling purposes and lies dormant until + * one of two things happens: + * + * <ul> + * <li>The lock is acquired by the current thread; or + * <li>Some other thread {@linkplain Thread#interrupt interrupts} the + * current thread, and interruption of lock acquisition is supported. + * </ul> + * + * <p>If the current thread: + * <ul> + * <li>has its interrupted status set on entry to this method; or + * <li>is {@linkplain Thread#interrupt interrupted} while acquiring the + * lock, and interruption of lock acquisition is supported, + * </ul> + * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * + * <p><b>Implementation Considerations</b> + * + * <p>The ability to interrupt a lock acquisition in some + * implementations may not be possible, and if possible may be an + * expensive operation. The programmer should be aware that this + * may be the case. An implementation should document when this is + * the case. + * + * <p>An implementation can favor responding to an interrupt over + * normal method return. + * + * <p>A {@code Lock} implementation may be able to detect + * erroneous use of the lock, such as an invocation that would + * cause deadlock, and may throw an (unchecked) exception in such + * circumstances. The circumstances and the exception type must + * be documented by that {@code Lock} implementation. + * + * @throws InterruptedException if the current thread is + * interrupted while acquiring the lock (and interruption + * of lock acquisition is supported). + */ + void lockInterruptibly() throws InterruptedException; + + /** + * Acquires the lock only if it is free at the time of invocation. + * + * <p>Acquires the lock if it is available and returns immediately + * with the value {@code true}. + * If the lock is not available then this method will return + * immediately with the value {@code false}. + * + * <p>A typical usage idiom for this method would be: + * <pre> + * Lock lock = ...; + * if (lock.tryLock()) { + * try { + * // manipulate protected state + * } finally { + * lock.unlock(); + * } + * } else { + * // perform alternative actions + * } + * </pre> + * This usage ensures that the lock is unlocked if it was acquired, and + * doesn't try to unlock if the lock was not acquired. + * + * @return {@code true} if the lock was acquired and + * {@code false} otherwise + */ + boolean tryLock(); + + /** + * Acquires the lock if it is free within the given waiting time and the + * current thread has not been {@linkplain Thread#interrupt interrupted}. + * + * <p>If the lock is available this method returns immediately + * with the value {@code true}. + * If the lock is not available then + * the current thread becomes disabled for thread scheduling + * purposes and lies dormant until one of three things happens: + * <ul> + * <li>The lock is acquired by the current thread; or + * <li>Some other thread {@linkplain Thread#interrupt interrupts} the + * current thread, and interruption of lock acquisition is supported; or + * <li>The specified waiting time elapses + * </ul> + * + * <p>If the lock is acquired then the value {@code true} is returned. + * + * <p>If the current thread: + * <ul> + * <li>has its interrupted status set on entry to this method; or + * <li>is {@linkplain Thread#interrupt interrupted} while acquiring + * the lock, and interruption of lock acquisition is supported, + * </ul> + * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * + * <p>If the specified waiting time elapses then the value {@code false} + * is returned. + * If the time is + * less than or equal to zero, the method will not wait at all. + * + * <p><b>Implementation Considerations</b> + * + * <p>The ability to interrupt a lock acquisition in some implementations + * may not be possible, and if possible may + * be an expensive operation. + * The programmer should be aware that this may be the case. An + * implementation should document when this is the case. + * + * <p>An implementation can favor responding to an interrupt over normal + * method return, or reporting a timeout. + * + * <p>A {@code Lock} implementation may be able to detect + * erroneous use of the lock, such as an invocation that would cause + * deadlock, and may throw an (unchecked) exception in such circumstances. + * The circumstances and the exception type must be documented by that + * {@code Lock} implementation. + * + * @param time the maximum time to wait for the lock + * @param unit the time unit of the {@code time} argument + * @return {@code true} if the lock was acquired and {@code false} + * if the waiting time elapsed before the lock was acquired + * + * @throws InterruptedException if the current thread is interrupted + * while acquiring the lock (and interruption of lock + * acquisition is supported) + */ + boolean tryLock(long time, TimeUnit unit) throws InterruptedException; + + /** + * Releases the lock. + * + * <p><b>Implementation Considerations</b> + * + * <p>A {@code Lock} implementation will usually impose + * restrictions on which thread can release a lock (typically only the + * holder of the lock can release it) and may throw + * an (unchecked) exception if the restriction is violated. + * Any restrictions and the exception + * type must be documented by that {@code Lock} implementation. + */ + void unlock(); + + /** + * Returns a new {@link Condition} instance that is bound to this + * {@code Lock} instance. + * + * <p>Before waiting on the condition the lock must be held by the + * current thread. + * A call to {@link Condition#await()} will atomically release the lock + * before waiting and re-acquire the lock before the wait returns. + * + * <p><b>Implementation Considerations</b> + * + * <p>The exact operation of the {@link Condition} instance depends on + * the {@code Lock} implementation and must be documented by that + * implementation. + * + * @return A new {@link Condition} instance for this {@code Lock} instance + * @throws UnsupportedOperationException if this {@code Lock} + * implementation does not support conditions + */ + Condition newCondition(); +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/locks/LockSupport.java b/libjava/classpath/external/jsr166/java/util/concurrent/locks/LockSupport.java new file mode 100644 index 000000000..28728ae2b --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/locks/LockSupport.java @@ -0,0 +1,352 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.locks; +import java.util.concurrent.*; +import sun.misc.Unsafe; + + +/** + * Basic thread blocking primitives for creating locks and other + * synchronization classes. + * + * <p>This class associates, with each thread that uses it, a permit + * (in the sense of the {@link java.util.concurrent.Semaphore + * Semaphore} class). A call to {@code park} will return immediately + * if the permit is available, consuming it in the process; otherwise + * 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.) + * + * <p>Methods {@code park} and {@code unpark} provide efficient + * means of blocking and unblocking threads that do not encounter the + * problems that cause the deprecated methods {@code Thread.suspend} + * and {@code Thread.resume} to be unusable for such purposes: Races + * between one thread invoking {@code park} and another thread trying + * to {@code unpark} it will preserve liveness, due to the + * permit. Additionally, {@code park} will return if the caller's + * thread was interrupted, and timeout versions are supported. The + * {@code park} method may also return at any other time, for "no + * reason", so in general must be invoked within a loop that rechecks + * conditions upon return. In this sense {@code park} serves as an + * optimization of a "busy wait" that does not waste as much time + * spinning, but must be paired with an {@code unpark} to be + * effective. + * + * <p>The three forms of {@code park} each also support a + * {@code blocker} object parameter. This object is recorded while + * the thread is blocked to permit monitoring and diagnostic tools to + * identify the reasons that threads are blocked. (Such tools may + * access blockers using method {@link #getBlocker}.) The use of these + * forms rather than the original forms without this parameter is + * strongly encouraged. The normal argument to supply as a + * {@code blocker} within a lock implementation is {@code this}. + * + * <p>These methods are designed to be used as tools for creating + * higher-level synchronization utilities, and are not in themselves + * useful for most concurrency control applications. The {@code park} + * method is designed for use only in constructions of the form: + * <pre>while (!canProceed()) { ... LockSupport.park(this); }</pre> + * where neither {@code canProceed} nor any other actions prior to the + * call to {@code park} entail locking or blocking. Because only one + * permit is associated with each thread, any intermediary uses of + * {@code park} could interfere with its intended effects. + * + * <p><b>Sample Usage.</b> Here is a sketch of a first-in-first-out + * non-reentrant lock class: + * <pre>{@code + * class FIFOMutex { + * private final AtomicBoolean locked = new AtomicBoolean(false); + * private final Queue<Thread> waiters + * = new ConcurrentLinkedQueue<Thread>(); + * + * public void lock() { + * boolean wasInterrupted = false; + * Thread current = Thread.currentThread(); + * waiters.add(current); + * + * // Block while not first in queue or cannot acquire lock + * while (waiters.peek() != current || + * !locked.compareAndSet(false, true)) { + * LockSupport.park(this); + * if (Thread.interrupted()) // ignore interrupts while waiting + * wasInterrupted = true; + * } + * + * waiters.remove(); + * if (wasInterrupted) // reassert interrupt status on exit + * current.interrupt(); + * } + * + * public void unlock() { + * locked.set(false); + * LockSupport.unpark(waiters.peek()); + * } + * }}</pre> + */ + +public class LockSupport { + private LockSupport() {} // Cannot be instantiated. + + // Hotspot implementation via intrinsics API + private static final Unsafe unsafe = Unsafe.getUnsafe(); + private static final long parkBlockerOffset; + + static { + try { + parkBlockerOffset = unsafe.objectFieldOffset + (java.lang.Thread.class.getDeclaredField("parkBlocker")); + } catch (Exception ex) { throw new Error(ex); } + } + + private static void setBlocker(Thread t, Object arg) { + // Even though volatile, hotspot doesn't need a write barrier here. + unsafe.putObject(t, parkBlockerOffset, arg); + } + + /** + * Makes available the permit for the given thread, if it + * was not already available. If the thread was blocked on + * {@code park} then it will unblock. Otherwise, its next call + * to {@code park} is guaranteed not to block. This operation + * is not guaranteed to have any effect at all if the given + * thread has not been started. + * + * @param thread the thread to unpark, or {@code null}, in which case + * this operation has no effect + */ + public static void unpark(Thread thread) { + if (thread != null) + unsafe.unpark(thread); + } + + /** + * Disables the current thread for thread scheduling purposes unless the + * permit is available. + * + * <p>If the permit is available then it is consumed and the call returns + * immediately; otherwise + * the current thread becomes disabled for thread scheduling + * purposes and lies dormant until one of three things happens: + * + * <ul> + * <li>Some other thread invokes {@link #unpark unpark} with the + * current thread as the target; or + * + * <li>Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread; or + * + * <li>The call spuriously (that is, for no reason) returns. + * </ul> + * + * <p>This method does <em>not</em> report which of these caused the + * method to return. Callers should re-check the conditions which caused + * the thread to park in the first place. Callers may also determine, + * for example, the interrupt status of the thread upon return. + * + * @param blocker the synchronization object responsible for this + * thread parking + * @since 1.6 + */ + public static void park(Object blocker) { + Thread t = Thread.currentThread(); + setBlocker(t, blocker); + unsafe.park(false, 0L); + setBlocker(t, null); + } + + /** + * Disables the current thread for thread scheduling purposes, for up to + * the specified waiting time, unless the permit is available. + * + * <p>If the permit is available then it is consumed and the call + * returns immediately; otherwise the current thread becomes disabled + * for thread scheduling purposes and lies dormant until one of four + * things happens: + * + * <ul> + * <li>Some other thread invokes {@link #unpark unpark} with the + * current thread as the target; or + * + * <li>Some other thread {@linkplain Thread#interrupt interrupts} the current + * thread; or + * + * <li>The specified waiting time elapses; or + * + * <li>The call spuriously (that is, for no reason) returns. + * </ul> + * + * <p>This method does <em>not</em> report which of these caused the + * method to return. Callers should re-check the conditions which caused + * the thread to park in the first place. Callers may also determine, + * for example, the interrupt status of the thread, or the elapsed time + * upon return. + * + * @param blocker the synchronization object responsible for this + * thread parking + * @param nanos the maximum number of nanoseconds to wait + * @since 1.6 + */ + public static void parkNanos(Object blocker, long nanos) { + if (nanos > 0) { + Thread t = Thread.currentThread(); + setBlocker(t, blocker); + unsafe.park(false, nanos); + setBlocker(t, null); + } + } + + /** + * Disables the current thread for thread scheduling purposes, until + * the specified deadline, unless the permit is available. + * + * <p>If the permit is available then it is consumed and the call + * returns immediately; otherwise the current thread becomes disabled + * for thread scheduling purposes and lies dormant until one of four + * things happens: + * + * <ul> + * <li>Some other thread invokes {@link #unpark unpark} with the + * current thread as the target; or + * + * <li>Some other thread {@linkplain Thread#interrupt interrupts} the + * current thread; or + * + * <li>The specified deadline passes; or + * + * <li>The call spuriously (that is, for no reason) returns. + * </ul> + * + * <p>This method does <em>not</em> report which of these caused the + * method to return. Callers should re-check the conditions which caused + * the thread to park in the first place. Callers may also determine, + * for example, the interrupt status of the thread, or the current time + * upon return. + * + * @param blocker the synchronization object responsible for this + * thread parking + * @param deadline the absolute time, in milliseconds from the Epoch, + * to wait until + * @since 1.6 + */ + public static void parkUntil(Object blocker, long deadline) { + Thread t = Thread.currentThread(); + setBlocker(t, blocker); + unsafe.park(true, deadline); + setBlocker(t, null); + } + + /** + * Returns the blocker object supplied to the most recent + * invocation of a park method that has not yet unblocked, or null + * if not blocked. The value returned is just a momentary + * snapshot -- the thread may have since unblocked or blocked on a + * different blocker object. + * + * @return the blocker + * @since 1.6 + */ + public static Object getBlocker(Thread t) { + return unsafe.getObjectVolatile(t, parkBlockerOffset); + } + + /** + * Disables the current thread for thread scheduling purposes unless the + * permit is available. + * + * <p>If the permit is available then it is consumed and the call + * returns immediately; otherwise the current thread becomes disabled + * for thread scheduling purposes and lies dormant until one of three + * things happens: + * + * <ul> + * + * <li>Some other thread invokes {@link #unpark unpark} with the + * current thread as the target; or + * + * <li>Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread; or + * + * <li>The call spuriously (that is, for no reason) returns. + * </ul> + * + * <p>This method does <em>not</em> report which of these caused the + * method to return. Callers should re-check the conditions which caused + * the thread to park in the first place. Callers may also determine, + * for example, the interrupt status of the thread upon return. + */ + public static void park() { + unsafe.park(false, 0L); + } + + /** + * Disables the current thread for thread scheduling purposes, for up to + * the specified waiting time, unless the permit is available. + * + * <p>If the permit is available then it is consumed and the call + * returns immediately; otherwise the current thread becomes disabled + * for thread scheduling purposes and lies dormant until one of four + * things happens: + * + * <ul> + * <li>Some other thread invokes {@link #unpark unpark} with the + * current thread as the target; or + * + * <li>Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread; or + * + * <li>The specified waiting time elapses; or + * + * <li>The call spuriously (that is, for no reason) returns. + * </ul> + * + * <p>This method does <em>not</em> report which of these caused the + * method to return. Callers should re-check the conditions which caused + * the thread to park in the first place. Callers may also determine, + * for example, the interrupt status of the thread, or the elapsed time + * upon return. + * + * @param nanos the maximum number of nanoseconds to wait + */ + public static void parkNanos(long nanos) { + if (nanos > 0) + unsafe.park(false, nanos); + } + + /** + * Disables the current thread for thread scheduling purposes, until + * the specified deadline, unless the permit is available. + * + * <p>If the permit is available then it is consumed and the call + * returns immediately; otherwise the current thread becomes disabled + * for thread scheduling purposes and lies dormant until one of four + * things happens: + * + * <ul> + * <li>Some other thread invokes {@link #unpark unpark} with the + * current thread as the target; or + * + * <li>Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread; or + * + * <li>The specified deadline passes; or + * + * <li>The call spuriously (that is, for no reason) returns. + * </ul> + * + * <p>This method does <em>not</em> report which of these caused the + * method to return. Callers should re-check the conditions which caused + * the thread to park in the first place. Callers may also determine, + * for example, the interrupt status of the thread, or the current time + * upon return. + * + * @param deadline the absolute time, in milliseconds from the Epoch, + * to wait until + */ + public static void parkUntil(long deadline) { + unsafe.park(true, deadline); + } +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/locks/ReadWriteLock.java b/libjava/classpath/external/jsr166/java/util/concurrent/locks/ReadWriteLock.java new file mode 100644 index 000000000..484f68d15 --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/locks/ReadWriteLock.java @@ -0,0 +1,104 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.locks; + +/** + * A <tt>ReadWriteLock</tt> 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. + * + * <p>All <tt>ReadWriteLock</tt> implementations must guarantee that + * the memory synchronization effects of <tt>writeLock</tt> operations + * (as specified in the {@link Lock} interface) also hold with respect + * to the associated <tt>readLock</tt>. That is, a thread successfully + * acquiring the read lock will see all updates made upon previous + * release of the write lock. + * + * <p>A read-write lock allows for a greater level of concurrency in + * accessing shared data than that permitted by a mutual exclusion lock. + * It exploits the fact that while only a single thread at a time (a + * <em>writer</em> thread) can modify the shared data, in many cases any + * number of threads can concurrently read the data (hence <em>reader</em> + * threads). + * In theory, the increase in concurrency permitted by the use of a read-write + * lock will lead to performance improvements over the use of a mutual + * exclusion lock. In practice this increase in concurrency will only be fully + * realized on a multi-processor, and then only if the access patterns for + * the shared data are suitable. + * + * <p>Whether or not a read-write lock will improve performance over the use + * of a mutual exclusion lock depends on the frequency that the data is + * read compared to being modified, the duration of the read and write + * operations, and the contention for the data - that is, the number of + * threads that will try to read or write the data at the same time. + * For example, a collection that is initially populated with data and + * thereafter infrequently modified, while being frequently searched + * (such as a directory of some kind) is an ideal candidate for the use of + * a read-write lock. However, if updates become frequent then the data + * spends most of its time being exclusively locked and there is little, if any + * increase in concurrency. Further, if the read operations are too short + * the overhead of the read-write lock implementation (which is inherently + * more complex than a mutual exclusion lock) can dominate the execution + * cost, particularly as many read-write lock implementations still serialize + * all threads through a small section of code. Ultimately, only profiling + * and measurement will establish whether the use of a read-write lock is + * suitable for your application. + * + * + * <p>Although the basic operation of a read-write lock is straight-forward, + * there are many policy decisions that an implementation must make, which + * may affect the effectiveness of the read-write lock in a given application. + * Examples of these policies include: + * <ul> + * <li>Determining whether to grant the read lock or the write lock, when + * both readers and writers are waiting, at the time that a writer releases + * the write lock. Writer preference is common, as writes are expected to be + * short and infrequent. Reader preference is less common as it can lead to + * lengthy delays for a write if the readers are frequent and long-lived as + * expected. Fair, or "in-order" implementations are also possible. + * + * <li>Determining whether readers that request the read lock while a + * reader is active and a writer is waiting, are granted the read lock. + * Preference to the reader can delay the writer indefinitely, while + * preference to the writer can reduce the potential for concurrency. + * + * <li>Determining whether the locks are reentrant: can a thread with the + * write lock reacquire it? Can it acquire a read lock while holding the + * write lock? Is the read lock itself reentrant? + * + * <li>Can the write lock be downgraded to a read lock without allowing + * an intervening writer? Can a read lock be upgraded to a write lock, + * in preference to other waiting readers or writers? + * + * </ul> + * You should consider all of these things when evaluating the suitability + * of a given implementation for your application. + * + * @see ReentrantReadWriteLock + * @see Lock + * @see ReentrantLock + * + * @since 1.5 + * @author Doug Lea + */ +public interface ReadWriteLock { + /** + * Returns the lock used for reading. + * + * @return the lock used for reading. + */ + Lock readLock(); + + /** + * Returns the lock used for writing. + * + * @return the lock used for writing. + */ + Lock writeLock(); +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/locks/ReentrantLock.java b/libjava/classpath/external/jsr166/java/util/concurrent/locks/ReentrantLock.java new file mode 100644 index 000000000..4a2fc175c --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/locks/ReentrantLock.java @@ -0,0 +1,740 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.locks; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; + +/** + * A reentrant mutual exclusion {@link Lock} with the same basic + * behavior and semantics as the implicit monitor lock accessed using + * {@code synchronized} methods and statements, but with extended + * capabilities. + * + * <p>A {@code ReentrantLock} is <em>owned</em> by the thread last + * successfully locking, but not yet unlocking it. A thread invoking + * {@code lock} will return, successfully acquiring the lock, when + * the lock is not owned by another thread. The method will return + * immediately if the current thread already owns the lock. This can + * be checked using methods {@link #isHeldByCurrentThread}, and {@link + * #getHoldCount}. + * + * <p>The constructor for this class accepts an optional + * <em>fairness</em> parameter. When set {@code true}, under + * contention, locks favor granting access to the longest-waiting + * thread. Otherwise this lock does not guarantee any particular + * access order. Programs using fair locks accessed by many threads + * may display lower overall throughput (i.e., are slower; often much + * slower) than those using the default setting, but have smaller + * variances in times to obtain locks and guarantee lack of + * starvation. Note however, that fairness of locks does not guarantee + * fairness of thread scheduling. Thus, one of many threads using a + * fair lock may obtain it multiple times in succession while other + * active threads are not progressing and not currently holding the + * lock. + * Also note that the untimed {@link #tryLock() tryLock} method does not + * honor the fairness setting. It will succeed if the lock + * is available even if other threads are waiting. + * + * <p>It is recommended practice to <em>always</em> immediately + * follow a call to {@code lock} with a {@code try} block, most + * typically in a before/after construction such as: + * + * <pre> + * class X { + * private final ReentrantLock lock = new ReentrantLock(); + * // ... + * + * public void m() { + * lock.lock(); // block until condition holds + * try { + * // ... method body + * } finally { + * lock.unlock() + * } + * } + * } + * </pre> + * + * <p>In addition to implementing the {@link Lock} interface, this + * class defines methods {@code isLocked} and + * {@code getLockQueueLength}, as well as some associated + * {@code protected} access methods that may be useful for + * instrumentation and monitoring. + * + * <p>Serialization of this class behaves in the same way as built-in + * locks: a deserialized lock is in the unlocked state, regardless of + * its state when serialized. + * + * <p>This lock supports a maximum of 2147483647 recursive locks by + * the same thread. Attempts to exceed this limit result in + * {@link Error} throws from locking methods. + * + * @since 1.5 + * @author Doug Lea + */ +public class ReentrantLock implements Lock, java.io.Serializable { + private static final long serialVersionUID = 7373984872572414699L; + /** Synchronizer providing all implementation mechanics */ + private final Sync sync; + + /** + * Base of synchronization control for this lock. Subclassed + * into fair and nonfair versions below. Uses AQS state to + * represent the number of holds on the lock. + */ + static abstract class Sync extends AbstractQueuedSynchronizer { + private static final long serialVersionUID = -5179523762034025860L; + + /** + * Performs {@link Lock#lock}. The main reason for subclassing + * is to allow fast path for nonfair version. + */ + abstract void lock(); + + /** + * Performs non-fair tryLock. tryAcquire is + * implemented in subclasses, but both need nonfair + * try for trylock method. + */ + final boolean nonfairTryAcquire(int acquires) { + final Thread current = Thread.currentThread(); + int c = getState(); + if (c == 0) { + if (compareAndSetState(0, acquires)) { + setExclusiveOwnerThread(current); + return true; + } + } + else if (current == getExclusiveOwnerThread()) { + int nextc = c + acquires; + if (nextc < 0) // overflow + throw new Error("Maximum lock count exceeded"); + setState(nextc); + return true; + } + return false; + } + + protected final boolean tryRelease(int releases) { + int c = getState() - releases; + if (Thread.currentThread() != getExclusiveOwnerThread()) + throw new IllegalMonitorStateException(); + boolean free = false; + if (c == 0) { + free = true; + setExclusiveOwnerThread(null); + } + setState(c); + return free; + } + + protected final boolean isHeldExclusively() { + // While we must in general read state before owner, + // we don't need to do so to check if current thread is owner + return getExclusiveOwnerThread() == Thread.currentThread(); + } + + final ConditionObject newCondition() { + return new ConditionObject(); + } + + // Methods relayed from outer class + + final Thread getOwner() { + return getState() == 0 ? null : getExclusiveOwnerThread(); + } + + final int getHoldCount() { + return isHeldExclusively() ? getState() : 0; + } + + final boolean isLocked() { + return getState() != 0; + } + + /** + * Reconstitutes this lock instance from a stream. + * @param s the stream + */ + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + setState(0); // reset to unlocked state + } + } + + /** + * Sync object for non-fair locks + */ + final static class NonfairSync extends Sync { + private static final long serialVersionUID = 7316153563782823691L; + + /** + * Performs lock. Try immediate barge, backing up to normal + * acquire on failure. + */ + final void lock() { + if (compareAndSetState(0, 1)) + setExclusiveOwnerThread(Thread.currentThread()); + else + acquire(1); + } + + protected final boolean tryAcquire(int acquires) { + return nonfairTryAcquire(acquires); + } + } + + /** + * Sync object for fair locks + */ + final static class FairSync extends Sync { + private static final long serialVersionUID = -3000897897090466540L; + + final void lock() { + acquire(1); + } + + /** + * Fair version of tryAcquire. Don't grant access unless + * recursive call or no waiters or is first. + */ + protected final boolean tryAcquire(int acquires) { + final Thread current = Thread.currentThread(); + int c = getState(); + if (c == 0) { + if (isFirst(current) && + compareAndSetState(0, acquires)) { + setExclusiveOwnerThread(current); + return true; + } + } + else if (current == getExclusiveOwnerThread()) { + int nextc = c + acquires; + if (nextc < 0) + throw new Error("Maximum lock count exceeded"); + setState(nextc); + return true; + } + return false; + } + } + + /** + * Creates an instance of {@code ReentrantLock}. + * This is equivalent to using {@code ReentrantLock(false)}. + */ + public ReentrantLock() { + sync = new NonfairSync(); + } + + /** + * Creates an instance of {@code ReentrantLock} with the + * given fairness policy. + * + * @param fair {@code true} if this lock should use a fair ordering policy + */ + public ReentrantLock(boolean fair) { + sync = (fair)? new FairSync() : new NonfairSync(); + } + + /** + * Acquires the lock. + * + * <p>Acquires the lock if it is not held by another thread and returns + * immediately, setting the lock hold count to one. + * + * <p>If the current thread already holds the lock then the hold + * count is incremented by one and the method returns immediately. + * + * <p>If the lock is held by another thread then the + * current thread becomes disabled for thread scheduling + * purposes and lies dormant until the lock has been acquired, + * at which time the lock hold count is set to one. + */ + public void lock() { + sync.lock(); + } + + /** + * Acquires the lock unless the current thread is + * {@linkplain Thread#interrupt interrupted}. + * + * <p>Acquires the lock if it is not held by another thread and returns + * immediately, setting the lock hold count to one. + * + * <p>If the current thread already holds this lock then the hold count + * is incremented by one and the method returns immediately. + * + * <p>If the lock is held by another thread then the + * current thread becomes disabled for thread scheduling + * purposes and lies dormant until one of two things happens: + * + * <ul> + * + * <li>The lock is acquired by the current thread; or + * + * <li>Some other thread {@linkplain Thread#interrupt interrupts} the + * current thread. + * + * </ul> + * + * <p>If the lock is acquired by the current thread then the lock hold + * count is set to one. + * + * <p>If the current thread: + * + * <ul> + * + * <li>has its interrupted status set on entry to this method; or + * + * <li>is {@linkplain Thread#interrupt interrupted} while acquiring + * the lock, + * + * </ul> + * + * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * + * <p>In this implementation, as this method is an explicit + * interruption point, preference is given to responding to the + * interrupt over normal or reentrant acquisition of the lock. + * + * @throws InterruptedException if the current thread is interrupted + */ + public void lockInterruptibly() throws InterruptedException { + sync.acquireInterruptibly(1); + } + + /** + * Acquires the lock only if it is not held by another thread at the time + * of invocation. + * + * <p>Acquires the lock if it is not held by another thread and + * returns immediately with the value {@code true}, setting the + * lock hold count to one. Even when this lock has been set to use a + * fair ordering policy, a call to {@code tryLock()} <em>will</em> + * immediately acquire the lock if it is available, whether or not + * other threads are currently waiting for the lock. + * This "barging" behavior can be useful in certain + * circumstances, even though it breaks fairness. If you want to honor + * the fairness setting for this lock, then use + * {@link #tryLock(long, TimeUnit) tryLock(0, TimeUnit.SECONDS) } + * which is almost equivalent (it also detects interruption). + * + * <p> If the current thread already holds this lock then the hold + * count is incremented by one and the method returns {@code true}. + * + * <p>If the lock is held by another thread then this method will return + * immediately with the value {@code false}. + * + * @return {@code true} if the lock was free and was acquired by the + * current thread, or the lock was already held by the current + * thread; and {@code false} otherwise + */ + public boolean tryLock() { + return sync.nonfairTryAcquire(1); + } + + /** + * Acquires the lock if it is not held by another thread within the given + * waiting time and the current thread has not been + * {@linkplain Thread#interrupt interrupted}. + * + * <p>Acquires the lock if it is not held by another thread and returns + * immediately with the value {@code true}, setting the lock hold count + * to one. If this lock has been set to use a fair ordering policy then + * an available lock <em>will not</em> be acquired if any other threads + * are waiting for the lock. This is in contrast to the {@link #tryLock()} + * 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>if (lock.tryLock() || lock.tryLock(timeout, unit) ) { ... } + * </pre> + * + * <p>If the current thread + * already holds this lock then the hold count is incremented by one and + * the method returns {@code true}. + * + * <p>If the lock is held by another thread then the + * current thread becomes disabled for thread scheduling + * purposes and lies dormant until one of three things happens: + * + * <ul> + * + * <li>The lock is acquired by the current thread; or + * + * <li>Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread; or + * + * <li>The specified waiting time elapses + * + * </ul> + * + * <p>If the lock is acquired then the value {@code true} is returned and + * the lock hold count is set to one. + * + * <p>If the current thread: + * + * <ul> + * + * <li>has its interrupted status set on entry to this method; or + * + * <li>is {@linkplain Thread#interrupt interrupted} while + * acquiring the lock, + * + * </ul> + * then {@link InterruptedException} is thrown and the current thread's + * interrupted status is cleared. + * + * <p>If the specified waiting time elapses then the value {@code false} + * is returned. If the time is less than or equal to zero, the method + * will not wait at all. + * + * <p>In this implementation, as this method is an explicit + * interruption point, preference is given to responding to the + * interrupt over normal or reentrant acquisition of the lock, and + * over reporting the elapse of the waiting time. + * + * @param timeout the time to wait for the lock + * @param unit the time unit of the timeout argument + * @return {@code true} if the lock was free and was acquired by the + * current thread, or the lock was already held by the current + * thread; and {@code false} if the waiting time elapsed before + * the lock could be acquired + * @throws InterruptedException if the current thread is interrupted + * @throws NullPointerException if the time unit is null + * + */ + public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { + return sync.tryAcquireNanos(1, unit.toNanos(timeout)); + } + + /** + * Attempts to release this lock. + * + * <p>If the current thread is the holder of this lock then the hold + * count is decremented. If the hold count is now zero then the lock + * is released. If the current thread is not the holder of this + * lock then {@link IllegalMonitorStateException} is thrown. + * + * @throws IllegalMonitorStateException if the current thread does not + * hold this lock + */ + public void unlock() { + sync.release(1); + } + + /** + * Returns a {@link Condition} instance for use with this + * {@link Lock} instance. + * + * <p>The returned {@link Condition} instance supports the same + * usages as do the {@link Object} monitor methods ({@link + * Object#wait() wait}, {@link Object#notify notify}, and {@link + * Object#notifyAll notifyAll}) when used with the built-in + * monitor lock. + * + * <ul> + * + * <li>If this lock is not held when any of the {@link Condition} + * {@linkplain Condition#await() waiting} or {@linkplain + * Condition#signal signalling} methods are called, then an {@link + * IllegalMonitorStateException} is thrown. + * + * <li>When the condition {@linkplain Condition#await() waiting} + * methods are called the lock is released and, before they + * return, the lock is reacquired and the lock hold count restored + * to what it was when the method was called. + * + * <li>If a thread is {@linkplain Thread#interrupt interrupted} + * while waiting then the wait will terminate, an {@link + * InterruptedException} will be thrown, and the thread's + * interrupted status will be cleared. + * + * <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 + * acquiring the lock, which is in the default case not specified, + * but for <em>fair</em> locks favors those threads that have been + * waiting the longest. + * + * </ul> + * + * @return the Condition object + */ + public Condition newCondition() { + return sync.newCondition(); + } + + /** + * Queries the number of holds on this lock by the current thread. + * + * <p>A thread has a hold on a lock for each lock action that is not + * matched by an unlock action. + * + * <p>The hold count information is typically only used for testing and + * debugging purposes. For example, if a certain section of code should + * not be entered with the lock already held then we can assert that + * fact: + * + * <pre> + * class X { + * ReentrantLock lock = new ReentrantLock(); + * // ... + * public void m() { + * assert lock.getHoldCount() == 0; + * lock.lock(); + * try { + * // ... method body + * } finally { + * lock.unlock(); + * } + * } + * } + * </pre> + * + * @return the number of holds on this lock by the current thread, + * or zero if this lock is not held by the current thread + */ + public int getHoldCount() { + return sync.getHoldCount(); + } + + /** + * Queries if this lock is held by the current thread. + * + * <p>Analogous to the {@link Thread#holdsLock} method for built-in + * monitor locks, this method is typically used for 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> + * class X { + * ReentrantLock lock = new ReentrantLock(); + * // ... + * + * public void m() { + * assert lock.isHeldByCurrentThread(); + * // ... method body + * } + * } + * </pre> + * + * <p>It can also be used to ensure that a reentrant lock is used + * in a non-reentrant manner, for example: + * + * <pre> + * class X { + * ReentrantLock lock = new ReentrantLock(); + * // ... + * + * public void m() { + * assert !lock.isHeldByCurrentThread(); + * lock.lock(); + * try { + * // ... method body + * } finally { + * lock.unlock(); + * } + * } + * } + * </pre> + * + * @return {@code true} if current thread holds this lock and + * {@code false} otherwise + */ + public boolean isHeldByCurrentThread() { + return sync.isHeldExclusively(); + } + + /** + * Queries if this lock is held by any thread. This method is + * designed for use in monitoring of the system state, + * not for synchronization control. + * + * @return {@code true} if any thread holds this lock and + * {@code false} otherwise + */ + public boolean isLocked() { + return sync.isLocked(); + } + + /** + * Returns {@code true} if this lock has fairness set true. + * + * @return {@code true} if this lock has fairness set true + */ + public final boolean isFair() { + return sync instanceof FairSync; + } + + /** + * Returns the thread that currently owns this lock, or + * {@code null} if not owned. When this method is called by a + * thread that is not the owner, the return value reflects a + * best-effort approximation of current lock status. For example, + * the owner may be momentarily {@code null} even if there are + * threads trying to acquire the lock but have not yet done so. + * This method is designed to facilitate construction of + * subclasses that provide more extensive lock monitoring + * facilities. + * + * @return the owner, or {@code null} if not owned + */ + protected Thread getOwner() { + return sync.getOwner(); + } + + /** + * Queries whether any threads are waiting to acquire this lock. Note that + * because cancellations may occur at any time, a {@code true} + * return does not guarantee that any other thread will ever + * acquire this lock. This method is designed primarily for use in + * monitoring of the system state. + * + * @return {@code true} if there may be other threads waiting to + * acquire the lock + */ + public final boolean hasQueuedThreads() { + return sync.hasQueuedThreads(); + } + + + /** + * Queries whether the given thread is waiting to acquire this + * lock. Note that because cancellations may occur at any time, a + * {@code true} return does not guarantee that this thread + * will ever acquire this lock. This method is designed primarily for use + * in monitoring of the system state. + * + * @param thread the thread + * @return {@code true} if the given thread is queued waiting for this lock + * @throws NullPointerException if the thread is null + */ + public final boolean hasQueuedThread(Thread thread) { + return sync.isQueued(thread); + } + + + /** + * 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. + * + * @return the estimated number of threads waiting for this lock + */ + public final int getQueueLength() { + return sync.getQueueLength(); + } + + /** + * Returns a collection containing threads that may be waiting to + * acquire this lock. Because the actual set of threads may change + * dynamically while constructing this result, the returned + * collection is only a best-effort estimate. The elements of the + * returned collection are in no particular order. This method is + * designed to facilitate construction of subclasses that provide + * more extensive monitoring facilities. + * + * @return the collection of threads + */ + protected Collection<Thread> getQueuedThreads() { + return sync.getQueuedThreads(); + } + + /** + * Queries whether any threads are waiting on the given condition + * associated with this lock. Note that because timeouts and + * interrupts may occur at any time, a {@code true} return does + * not guarantee that a future {@code signal} will awaken any + * threads. This method is designed primarily for use in + * monitoring of the system state. + * + * @param condition the condition + * @return {@code true} if there are any waiting threads + * @throws IllegalMonitorStateException if this lock is not held + * @throws IllegalArgumentException if the given condition is + * not associated with this lock + * @throws NullPointerException if the condition is null + */ + public boolean hasWaiters(Condition condition) { + if (condition == null) + throw new NullPointerException(); + if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) + throw new IllegalArgumentException("not owner"); + return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition); + } + + /** + * Returns an estimate of the number of threads waiting on the + * given condition associated with this lock. 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. + * + * @param condition the condition + * @return the estimated number of waiting threads + * @throws IllegalMonitorStateException if this lock is not held + * @throws IllegalArgumentException if the given condition is + * not associated with this lock + * @throws NullPointerException if the condition is null + */ + public int getWaitQueueLength(Condition condition) { + if (condition == null) + throw new NullPointerException(); + if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) + throw new IllegalArgumentException("not owner"); + return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition); + } + + /** + * Returns a collection containing those threads that may be + * waiting on the given condition associated with this lock. + * Because the actual set of threads may change dynamically while + * constructing this result, the returned collection is only a + * best-effort estimate. The elements of the returned collection + * are in no particular order. This method is designed to + * facilitate construction of subclasses that provide more + * extensive condition monitoring facilities. + * + * @param condition the condition + * @return the collection of threads + * @throws IllegalMonitorStateException if this lock is not held + * @throws IllegalArgumentException if the given condition is + * not associated with this lock + * @throws NullPointerException if the condition is null + */ + protected Collection<Thread> getWaitingThreads(Condition condition) { + if (condition == null) + throw new NullPointerException(); + if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) + throw new IllegalArgumentException("not owner"); + return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition); + } + + /** + * Returns a string identifying this lock, as well as its lock state. + * The state, in brackets, includes either the String {@code "Unlocked"} + * or the String {@code "Locked by"} followed by the + * {@linkplain Thread#getName name} of the owning thread. + * + * @return a string identifying this lock, as well as its lock state + */ + public String toString() { + Thread o = sync.getOwner(); + return super.toString() + ((o == null) ? + "[Unlocked]" : + "[Locked by thread " + o.getName() + "]"); + } +} diff --git a/libjava/classpath/external/jsr166/java/util/concurrent/locks/ReentrantReadWriteLock.java b/libjava/classpath/external/jsr166/java/util/concurrent/locks/ReentrantReadWriteLock.java new file mode 100644 index 000000000..a6eadff5b --- /dev/null +++ b/libjava/classpath/external/jsr166/java/util/concurrent/locks/ReentrantReadWriteLock.java @@ -0,0 +1,1346 @@ +/* + * 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/licenses/publicdomain + */ + +package java.util.concurrent.locks; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; +import java.util.*; + +/** + * An implementation of {@link ReadWriteLock} supporting similar + * semantics to {@link ReentrantLock}. + * <p>This class has the following properties: + * + * <ul> + * <li><b>Acquisition order</b> + * + * <p> This class does not impose a reader or writer preference + * ordering for lock access. However, it does support an optional + * <em>fairness</em> policy. + * + * <dl> + * <dt><b><i>Non-fair mode (default)</i></b> + * <dd>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 continously contended may + * indefinitely postpone one or more reader or writer threads, but + * will normally have higher throughput than a fair lock. + * <p> + * + * <dt><b><i>Fair mode</i></b> + * <dd> When constructed as fair, threads contend for entry using an + * 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 + * waiting longer than all waiting writer threads, that group will be + * assigned the read lock. + * + * <p>A thread that tries to acquire a fair read lock (non-reentrantly) + * will block if either the write lock is held, or there is a waiting + * writer thread. The thread will not acquire the read lock until + * after the oldest currently waiting writer thread has acquired and + * released the write lock. Of course, if a waiting writer abandons + * its wait, leaving one or more reader threads as the longest waiters + * in the queue with the write lock free, then those readers will be + * assigned the read lock. + * + * <p>A thread that tries to acquire a fair write lock (non-reentrantly) + * will block unless both the read lock and write lock are free (which + * implies there are no waiting threads). (Note that the non-blocking + * {@link ReadLock#tryLock()} and {@link WriteLock#tryLock()} methods + * do not honor this fair setting and will acquire the lock if it is + * possible, regardless of waiting threads.) + * <p> + * </dl> + * + * <li><b>Reentrancy</b> + * + * <p>This lock allows both readers and writers to reacquire read or + * write locks in the style of a {@link ReentrantLock}. Non-reentrant + * readers are not allowed until all write locks held by the writing + * thread have been released. + * + * <p>Additionally, a writer can acquire the read lock, but not + * vice-versa. Among other applications, reentrancy can be useful + * when write locks are held during calls or callbacks to methods that + * perform reads under read locks. If a reader tries to acquire the + * write lock it will never succeed. + * + * <li><b>Lock downgrading</b> + * <p>Reentrancy also allows downgrading from the write lock to a read lock, + * by acquiring the write lock, then the read lock and then releasing the + * write lock. However, upgrading from a read lock to the write lock is + * <b>not</b> possible. + * + * <li><b>Interruption of lock acquisition</b> + * <p>The read lock and write lock both support interruption during lock + * acquisition. + * + * <li><b>{@link Condition} support</b> + * <p>The write lock provides a {@link Condition} implementation that + * behaves in the same way, with respect to the write lock, as the + * {@link Condition} implementation provided by + * {@link ReentrantLock#newCondition} does for {@link ReentrantLock}. + * This {@link Condition} can, of course, only be used with the write lock. + * + * <p>The read lock does not support a {@link Condition} and + * {@code readLock().newCondition()} throws + * {@code UnsupportedOperationException}. + * + * <li><b>Instrumentation</b> + * <p>This class supports methods to determine whether locks + * are held or contended. These methods are designed for monitoring + * system state, not for synchronization control. + * </ul> + * + * <p>Serialization of this class behaves in the same way as built-in + * locks: a deserialized lock is in the unlocked state, regardless of + * its state when serialized. + * + * <p><b>Sample usages</b>. Here is a code sketch showing how to exploit + * reentrancy to perform lock downgrading after updating a cache (exception + * handling is elided for simplicity): + * <pre> + * class CachedData { + * Object data; + * volatile boolean cacheValid; + * ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); + * + * void processCachedData() { + * rwl.readLock().lock(); + * if (!cacheValid) { + * // Must release read lock before acquiring write lock + * rwl.readLock().unlock(); + * rwl.writeLock().lock(); + * // Recheck state because another thread might have acquired + * // write lock and changed state before we did. + * if (!cacheValid) { + * data = ... + * cacheValid = true; + * } + * // Downgrade by acquiring read lock before releasing write lock + * rwl.readLock().lock(); + * rwl.writeLock().unlock(); // Unlock write, still hold read + * } + * + * use(data); + * rwl.readLock().unlock(); + * } + * } + * </pre> + * + * ReentrantReadWriteLocks can be used to improve concurrency in some + * uses of some kinds of Collections. This is typically worthwhile + * only when the collections are expected to be large, accessed by + * more reader threads than writer threads, and entail operations with + * overhead that outweighs synchronization overhead. For example, here + * is a class using a TreeMap that is expected to be large and + * concurrently accessed. + * + * <pre>{@code + * class RWDictionary { + * private final Map<String, Data> m = new TreeMap<String, Data>(); + * private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); + * private final Lock r = rwl.readLock(); + * private final Lock w = rwl.writeLock(); + * + * public Data get(String key) { + * r.lock(); + * try { return m.get(key); } + * finally { r.unlock(); } + * } + * public String[] allKeys() { + * r.lock(); + * try { return m.keySet().toArray(); } + * finally { r.unlock(); } + * } + * public Data put(String key, Data value) { + * w.lock(); + * try { return m.put(key, value); } + * finally { w.unlock(); } + * } + * public void clear() { + * w.lock(); + * try { m.clear(); } + * finally { w.unlock(); } + * } + * }}</pre> + * + * <h3>Implementation Notes</h3> + * + * <p>This lock supports a maximum of 65535 recursive write locks + * and 65535 read locks. Attempts to exceed these limits result in + * {@link Error} throws from locking methods. + * + * @since 1.5 + * @author Doug Lea + * + */ +public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable { + private static final long serialVersionUID = -6992448646407690164L; + /** Inner class providing readlock */ + private final ReentrantReadWriteLock.ReadLock readerLock; + /** Inner class providing writelock */ + private final ReentrantReadWriteLock.WriteLock writerLock; + /** Performs all synchronization mechanics */ + private final Sync sync; + + /** + * Creates a new {@code ReentrantReadWriteLock} with + * default (nonfair) ordering properties. + */ + public ReentrantReadWriteLock() { + this(false); + } + + /** + * Creates a new {@code ReentrantReadWriteLock} with + * the given fairness policy. + * + * @param fair {@code true} if this lock should use a fair ordering policy + */ + public ReentrantReadWriteLock(boolean fair) { + sync = (fair)? new FairSync() : new NonfairSync(); + readerLock = new ReadLock(this); + writerLock = new WriteLock(this); + } + + public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock; } + public ReentrantReadWriteLock.ReadLock readLock() { return readerLock; } + + /** + * Synchronization implementation for ReentrantReadWriteLock. + * Subclassed into fair and nonfair versions. + */ + static abstract class Sync extends AbstractQueuedSynchronizer { + private static final long serialVersionUID = 6317671515068378041L; + + /* + * Read vs write count extraction constants and functions. + * Lock state is logically divided into two shorts: The lower + * one representing the exclusive (writer) lock hold count, + * and the upper the shared (reader) hold count. + */ + + static final int SHARED_SHIFT = 16; + static final int SHARED_UNIT = (1 << SHARED_SHIFT); + 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 */ + static int sharedCount(int c) { return c >>> SHARED_SHIFT; } + /** 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 + */ + static final class HoldCounter { + int count; + // Use id, not reference, to avoid garbage retention + final long tid = Thread.currentThread().getId(); + /** Decrement if positive; return previous value */ + int tryDecrement() { + int c = count; + if (c > 0) + count = c - 1; + return c; + } + } + + /** + * ThreadLocal subclass. Easiest to explicitly define for sake + * of deserialization mechanics. + */ + static final class ThreadLocalHoldCounter + extends ThreadLocal<HoldCounter> { + public HoldCounter initialValue() { + return new HoldCounter(); + } + } + + /** + * The number of read locks held by current thread. + * Initialized only in constructor and readObject. + */ + transient ThreadLocalHoldCounter readHolds; + + /** + * The hold count of the last thread to successfully acquire + * readLock. This saves ThreadLocal lookup in the common case + * where the next thread to release is the last one to + * acquire. This is non-volatile since it is just used + * as a heuristic, and would be great for threads to cache. + */ + transient HoldCounter cachedHoldCounter; + + Sync() { + readHolds = new ThreadLocalHoldCounter(); + setState(getState()); // ensures visibility of readHolds + } + + /* + * Acquires and releases use the same code for fair and + * nonfair locks, but differ in whether/how they allow barging + * when queues are non-empty. + */ + + /** + * Return true if a reader thread that is otherwise + * eligible for lock should block because of policy + * for overtaking other waiting threads. + */ + abstract boolean readerShouldBlock(Thread current); + + /** + * Return true if a writer thread that is otherwise + * eligible for lock should block because of policy + * for overtaking other waiting threads. + */ + abstract boolean writerShouldBlock(Thread current); + + /* + * Note that tryRelease and tryAcquire can be called by + * Conditions. So it is possible that their arguments contain + * both read and write holds that are all released during a + * condition wait and re-established in tryAcquire. + */ + + protected final boolean tryRelease(int releases) { + int nextc = getState() - releases; + if (Thread.currentThread() != getExclusiveOwnerThread()) + throw new IllegalMonitorStateException(); + if (exclusiveCount(nextc) == 0) { + setExclusiveOwnerThread(null); + setState(nextc); + return true; + } else { + setState(nextc); + return false; + } + } + + protected final boolean tryAcquire(int acquires) { + /* + * Walkthrough: + * 1. if read count nonzero or write count nonzero + * and owner is a different thread, fail. + * 2. If count would saturate, fail. (This can only + * happen if count is already nonzero.) + * 3. Otherwise, this thread is eligible for lock if + * it is either a reentrant acquire or + * queue policy allows it. If so, update state + * and set owner. + */ + Thread current = Thread.currentThread(); + int c = getState(); + int w = exclusiveCount(c); + if (c != 0) { + // (Note: if c != 0 and w == 0 then shared count != 0) + if (w == 0 || current != getExclusiveOwnerThread()) + return false; + if (w + exclusiveCount(acquires) > MAX_COUNT) + throw new Error("Maximum lock count exceeded"); + } + if ((w == 0 && writerShouldBlock(current)) || + !compareAndSetState(c, c + acquires)) + return false; + setExclusiveOwnerThread(current); + return true; + } + + protected final boolean tryReleaseShared(int unused) { + HoldCounter rh = cachedHoldCounter; + Thread current = Thread.currentThread(); + if (rh == null || rh.tid != current.getId()) + rh = readHolds.get(); + if (rh.tryDecrement() <= 0) + throw new IllegalMonitorStateException(); + for (;;) { + int c = getState(); + int nextc = c - SHARED_UNIT; + if (compareAndSetState(c, nextc)) + return nextc == 0; + } + } + + protected final int tryAcquireShared(int unused) { + /* + * Walkthrough: + * 1. If write lock held by another thread, fail + * 2. If count saturated, throw error + * 3. Otherwise, this thread is eligible for + * lock wrt state, so ask if it should block + * because of queue policy. If not, try + * to grant by CASing state and updating count. + * Note that step does not check for reentrant + * acquires, which is postponed to full version + * to avoid having to check hold count in + * the more typical non-reentrant case. + * 4. If step 3 fails either because thread + * apparently not eligible or CAS fails, + * chain to version with full retry loop. + */ + Thread current = Thread.currentThread(); + int c = getState(); + if (exclusiveCount(c) != 0 && + getExclusiveOwnerThread() != current) + return -1; + if (sharedCount(c) == MAX_COUNT) + throw new Error("Maximum lock count exceeded"); + if (!readerShouldBlock(current) && + compareAndSetState(c, c + SHARED_UNIT)) { + HoldCounter rh = cachedHoldCounter; + if (rh == null || rh.tid != current.getId()) + cachedHoldCounter = rh = readHolds.get(); + rh.count++; + return 1; + } + return fullTryAcquireShared(current); + } + + /** + * Full version of acquire for reads, that handles CAS misses + * and reentrant reads not dealt with in tryAcquireShared. + */ + final int fullTryAcquireShared(Thread current) { + /* + * This code is in part redundant with that in + * tryAcquireShared but is simpler overall by not + * complicating tryAcquireShared with interactions between + * retries and lazily reading hold counts. + */ + HoldCounter rh = cachedHoldCounter; + if (rh == null || rh.tid != current.getId()) + rh = readHolds.get(); + for (;;) { + int c = getState(); + int w = exclusiveCount(c); + if ((w != 0 && getExclusiveOwnerThread() != current) || + ((rh.count | w) == 0 && readerShouldBlock(current))) + return -1; + if (sharedCount(c) == MAX_COUNT) + throw new Error("Maximum lock count exceeded"); + if (compareAndSetState(c, c + SHARED_UNIT)) { + cachedHoldCounter = rh; // cache for release + rh.count++; + return 1; + } + } + } + + /** + * Performs tryLock for write, enabling barging in both modes. + * This is identical in effect to tryAcquire except for lack + * of calls to writerShouldBlock + */ + final boolean tryWriteLock() { + Thread current = Thread.currentThread(); + int c = getState(); + if (c != 0) { + int w = exclusiveCount(c); + if (w == 0 ||current != getExclusiveOwnerThread()) + return false; + if (w == MAX_COUNT) + throw new Error("Maximum lock count exceeded"); + } + if (!compareAndSetState(c, c + 1)) + return false; + setExclusiveOwnerThread(current); + return true; + } + + /** + * Performs tryLock for read, enabling barging in both modes. + * This is identical in effect to tryAcquireShared except for + * lack of calls to readerShouldBlock + */ + final boolean tryReadLock() { + Thread current = Thread.currentThread(); + for (;;) { + int c = getState(); + if (exclusiveCount(c) != 0 && + getExclusiveOwnerThread() != current) + return false; + if (sharedCount(c) == MAX_COUNT) + throw new Error("Maximum lock count exceeded"); + if (compareAndSetState(c, c + SHARED_UNIT)) { + HoldCounter rh = cachedHoldCounter; + if (rh == null || rh.tid != current.getId()) + cachedHoldCounter = rh = readHolds.get(); + rh.count++; + return true; + } + } + } + + protected final boolean isHeldExclusively() { + // While we must in general read state before owner, + // we don't need to do so to check if current thread is owner + return getExclusiveOwnerThread() == Thread.currentThread(); + } + + // Methods relayed to outer class + + final ConditionObject newCondition() { + return new ConditionObject(); + } + + final Thread getOwner() { + // Must read state before owner to ensure memory consistency + return ((exclusiveCount(getState()) == 0)? + null : + getExclusiveOwnerThread()); + } + + final int getReadLockCount() { + return sharedCount(getState()); + } + + final boolean isWriteLocked() { + return exclusiveCount(getState()) != 0; + } + + final int getWriteHoldCount() { + return isHeldExclusively() ? exclusiveCount(getState()) : 0; + } + + final int getReadHoldCount() { + return getReadLockCount() == 0? 0 : readHolds.get().count; + } + + /** + * Reconstitute this lock instance from a stream + * @param s the stream + */ + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + readHolds = new ThreadLocalHoldCounter(); + setState(0); // reset to unlocked state + } + + final int getCount() { return getState(); } + } + + /** + * Nonfair version of Sync + */ + final static class NonfairSync extends Sync { + private static final long serialVersionUID = -8159625535654395037L; + final boolean writerShouldBlock(Thread current) { + return false; // writers can always barge + } + final boolean readerShouldBlock(Thread current) { + /* As a heuristic to avoid indefinite writer starvation, + * block if the thread that momentarily appears to be head + * of queue, if one exists, is a waiting writer. This is + * only a probablistic effect since a new reader will not + * block if there is a waiting writer behind other enabled + * readers that have not yet drained from the queue. + */ + return apparentlyFirstQueuedIsExclusive(); + } + } + + /** + * Fair version of Sync + */ + final static class FairSync extends Sync { + private static final long serialVersionUID = -2274990926593161451L; + final boolean writerShouldBlock(Thread current) { + // only proceed if queue is empty or current thread at head + return !isFirst(current); + } + final boolean readerShouldBlock(Thread current) { + // only proceed if queue is empty or current thread at head + return !isFirst(current); + } + } + + /** + * The lock returned by method {@link ReentrantReadWriteLock#readLock}. + */ + public static class ReadLock implements Lock, java.io.Serializable { + private static final long serialVersionUID = -5992448646407690164L; + private final Sync sync; + + /** + * Constructor for use by subclasses + * + * @param lock the outer lock object + * @throws NullPointerException if the lock is null + */ + protected ReadLock(ReentrantReadWriteLock lock) { + sync = lock.sync; + } + + /** + * Acquires the read lock. + * + * <p>Acquires the read lock if the write lock is not held by + * another thread and returns immediately. + * + * <p>If the write lock is held by another thread then + * the current thread becomes disabled for thread scheduling + * purposes and lies dormant until the read lock has been acquired. + */ + public void lock() { + sync.acquireShared(1); + } + + /** + * Acquires the read lock unless the current thread is + * {@linkplain Thread#interrupt interrupted}. + * + * <p>Acquires the read lock if the write lock is not held + * by another thread and returns immediately. + * + * <p>If the write lock is held by another thread then the + * current thread becomes disabled for thread scheduling + * purposes and lies dormant until one of two things happens: + * + * <ul> + * + * <li>The read lock is acquired by the current thread; or + * + * <li>Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread. + * + * </ul> + * + * <p>If the current thread: + * + * <ul> + * + * <li>has its interrupted status set on entry to this method; or + * + * <li>is {@linkplain Thread#interrupt interrupted} while + * acquiring the read lock, + * + * </ul> + * + * then {@link InterruptedException} is thrown and the current + * thread's interrupted status is cleared. + * + * <p>In this implementation, as this method is an explicit + * interruption point, preference is given to responding to + * the interrupt over normal or reentrant acquisition of the + * lock. + * + * @throws InterruptedException if the current thread is interrupted + */ + public void lockInterruptibly() throws InterruptedException { + sync.acquireSharedInterruptibly(1); + } + + /** + * Acquires the read lock only if the write lock is not held by + * another thread at the time of invocation. + * + * <p>Acquires the read lock if the write lock is not held by + * another thread and returns immediately with the value + * {@code true}. Even when this lock has been set to use a + * fair ordering policy, a call to {@code tryLock()} + * <em>will</em> immediately acquire the read lock if it is + * available, whether or not other threads are currently + * waiting for the read lock. This "barging" behavior + * can be useful in certain circumstances, even though it + * breaks fairness. If you want to honor the fairness setting + * for this lock, then use {@link #tryLock(long, TimeUnit) + * tryLock(0, TimeUnit.SECONDS) } which is almost equivalent + * (it also detects interruption). + * + * <p>If the write lock is held by another thread then + * this method will return immediately with the value + * {@code false}. + * + * @return {@code true} if the read lock was acquired + */ + public boolean tryLock() { + return sync.tryReadLock(); + } + + /** + * Acquires the read lock if the write lock is not held by + * another thread within the given waiting time and the + * current thread has not been {@linkplain Thread#interrupt + * interrupted}. + * + * <p>Acquires the read lock if the write lock is not held by + * another thread and returns immediately with the value + * {@code true}. If this lock has been set to use a fair + * ordering policy then an available lock <em>will not</em> be + * acquired if any other threads are waiting for the + * lock. This is in contrast to the {@link #tryLock()} + * 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>if (lock.tryLock() || lock.tryLock(timeout, unit) ) { ... } + * </pre> + * + * <p>If the write lock is held by another thread then the + * current thread becomes disabled for thread scheduling + * purposes and lies dormant until one of three things happens: + * + * <ul> + * + * <li>The read lock is acquired by the current thread; or + * + * <li>Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread; or + * + * <li>The specified waiting time elapses. + * + * </ul> + * + * <p>If the read lock is acquired then the value {@code true} is + * returned. + * + * <p>If the current thread: + * + * <ul> + * + * <li>has its interrupted status set on entry to this method; or + * + * <li>is {@linkplain Thread#interrupt interrupted} while + * acquiring the read lock, + * + * </ul> then {@link InterruptedException} is thrown and the + * current thread's interrupted status is cleared. + * + * <p>If the specified waiting time elapses then the value + * {@code false} is returned. If the time is less than or + * equal to zero, the method will not wait at all. + * + * <p>In this implementation, as this method is an explicit + * interruption point, preference is given to responding to + * the interrupt over normal or reentrant acquisition of the + * lock, and over reporting the elapse of the waiting time. + * + * @param timeout the time to wait for the read lock + * @param unit the time unit of the timeout argument + * @return {@code true} if the read lock was acquired + * @throws InterruptedException if the current thread is interrupted + * @throws NullPointerException if the time unit is null + * + */ + public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { + return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout)); + } + + /** + * Attempts to release this lock. + * + * <p> If the number of readers is now zero then the lock + * is made available for write lock attempts. + */ + public void unlock() { + sync.releaseShared(1); + } + + /** + * Throws {@code UnsupportedOperationException} because + * {@code ReadLocks} do not support conditions. + * + * @throws UnsupportedOperationException always + */ + public Condition newCondition() { + throw new UnsupportedOperationException(); + } + + /** + * Returns a string identifying this lock, as well as its lock state. + * The state, in brackets, includes the String {@code "Read locks ="} + * followed by the number of held read locks. + * + * @return a string identifying this lock, as well as its lock state + */ + public String toString() { + int r = sync.getReadLockCount(); + return super.toString() + + "[Read locks = " + r + "]"; + } + } + + /** + * The lock returned by method {@link ReentrantReadWriteLock#writeLock}. + */ + public static class WriteLock implements Lock, java.io.Serializable { + private static final long serialVersionUID = -4992448646407690164L; + private final Sync sync; + + /** + * Constructor for use by subclasses + * + * @param lock the outer lock object + * @throws NullPointerException if the lock is null + */ + protected WriteLock(ReentrantReadWriteLock lock) { + sync = lock.sync; + } + + /** + * Acquires the write lock. + * + * <p>Acquires the write lock if neither the read nor write lock + * are held by another thread + * and returns immediately, setting the write lock hold count to + * one. + * + * <p>If the current thread already holds the write lock then the + * hold count is incremented by one and the method returns + * immediately. + * + * <p>If the lock is held by another thread then the current + * thread becomes disabled for thread scheduling purposes and + * lies dormant until the write lock has been acquired, at which + * time the write lock hold count is set to one. + */ + public void lock() { + sync.acquire(1); + } + + /** + * Acquires the write lock unless the current thread is + * {@linkplain Thread#interrupt interrupted}. + * + * <p>Acquires the write lock if neither the read nor write lock + * are held by another thread + * and returns immediately, setting the write lock hold count to + * one. + * + * <p>If the current thread already holds this lock then the + * hold count is incremented by one and the method returns + * immediately. + * + * <p>If the lock is held by another thread then the current + * thread becomes disabled for thread scheduling purposes and + * lies dormant until one of two things happens: + * + * <ul> + * + * <li>The write lock is acquired by the current thread; or + * + * <li>Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread. + * + * </ul> + * + * <p>If the write lock is acquired by the current thread then the + * lock hold count is set to one. + * + * <p>If the current thread: + * + * <ul> + * + * <li>has its interrupted status set on entry to this method; + * or + * + * <li>is {@linkplain Thread#interrupt interrupted} while + * acquiring the write lock, + * + * </ul> + * + * then {@link InterruptedException} is thrown and the current + * thread's interrupted status is cleared. + * + * <p>In this implementation, as this method is an explicit + * interruption point, preference is given to responding to + * the interrupt over normal or reentrant acquisition of the + * lock. + * + * @throws InterruptedException if the current thread is interrupted + */ + public void lockInterruptibly() throws InterruptedException { + sync.acquireInterruptibly(1); + } + + /** + * Acquires the write lock only if it is not held by another thread + * at the time of invocation. + * + * <p>Acquires the write lock if neither the read nor write lock + * are held by another thread + * and returns immediately with the value {@code true}, + * setting the write lock hold count to one. Even when this lock has + * been set to use a fair ordering policy, a call to + * {@code tryLock()} <em>will</em> immediately acquire the + * lock if it is available, whether or not other threads are + * currently waiting for the write lock. This "barging" + * behavior can be useful in certain circumstances, even + * though it breaks fairness. If you want to honor the + * fairness setting for this lock, then use {@link + * #tryLock(long, TimeUnit) tryLock(0, TimeUnit.SECONDS) } + * which is almost equivalent (it also detects interruption). + * + * <p> If the current thread already holds this lock then the + * hold count is incremented by one and the method returns + * {@code true}. + * + * <p>If the lock is held by another thread then this method + * will return immediately with the value {@code false}. + * + * @return {@code true} if the lock was free and was acquired + * by the current thread, or the write lock was already held + * by the current thread; and {@code false} otherwise. + */ + public boolean tryLock( ) { + return sync.tryWriteLock(); + } + + /** + * Acquires the write lock if it is not held by another thread + * within the given waiting time and the current thread has + * not been {@linkplain Thread#interrupt interrupted}. + * + * <p>Acquires the write lock if neither the read nor write lock + * are held by another thread + * and returns immediately with the value {@code true}, + * setting the write lock hold count to one. If this lock has been + * set to use a fair ordering policy then an available lock + * <em>will not</em> be acquired if any other threads are + * waiting for the write lock. This is in contrast to the {@link + * #tryLock()} 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>if (lock.tryLock() || lock.tryLock(timeout, unit) ) { ... } + * </pre> + * + * <p>If the current thread already holds this lock then the + * hold count is incremented by one and the method returns + * {@code true}. + * + * <p>If the lock is held by another thread then the current + * thread becomes disabled for thread scheduling purposes and + * lies dormant until one of three things happens: + * + * <ul> + * + * <li>The write lock is acquired by the current thread; or + * + * <li>Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread; or + * + * <li>The specified waiting time elapses + * + * </ul> + * + * <p>If the write lock is acquired then the value {@code true} is + * returned and the write lock hold count is set to one. + * + * <p>If the current thread: + * + * <ul> + * + * <li>has its interrupted status set on entry to this method; + * or + * + * <li>is {@linkplain Thread#interrupt interrupted} while + * acquiring the write lock, + * + * </ul> + * + * then {@link InterruptedException} is thrown and the current + * thread's interrupted status is cleared. + * + * <p>If the specified waiting time elapses then the value + * {@code false} is returned. If the time is less than or + * equal to zero, the method will not wait at all. + * + * <p>In this implementation, as this method is an explicit + * interruption point, preference is given to responding to + * the interrupt over normal or reentrant acquisition of the + * lock, and over reporting the elapse of the waiting time. + * + * @param timeout the time to wait for the write lock + * @param unit the time unit of the timeout argument + * + * @return {@code true} if the lock was free and was acquired + * by the current thread, or the write lock was already held by the + * current thread; and {@code false} if the waiting time + * elapsed before the lock could be acquired. + * + * @throws InterruptedException if the current thread is interrupted + * @throws NullPointerException if the time unit is null + * + */ + public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { + return sync.tryAcquireNanos(1, unit.toNanos(timeout)); + } + + /** + * Attempts to release this lock. + * + * <p>If the current thread is the holder of this lock then + * the hold count is decremented. If the hold count is now + * zero then the lock is released. If the current thread is + * not the holder of this lock then {@link + * IllegalMonitorStateException} is thrown. + * + * @throws IllegalMonitorStateException if the current thread does not + * hold this lock. + */ + public void unlock() { + sync.release(1); + } + + /** + * Returns a {@link Condition} instance for use with this + * {@link Lock} instance. + * <p>The returned {@link Condition} instance supports the same + * usages as do the {@link Object} monitor methods ({@link + * Object#wait() wait}, {@link Object#notify notify}, and {@link + * Object#notifyAll notifyAll}) when used with the built-in + * monitor lock. + * + * <ul> + * + * <li>If this write lock is not held when any {@link + * Condition} method is called then an {@link + * IllegalMonitorStateException} is thrown. (Read locks are + * held independently of write locks, so are not checked or + * affected. However it is essentially always an error to + * invoke a condition waiting method when the current thread + * has also acquired read locks, since other threads that + * could unblock it will not be able to acquire the write + * lock.) + * + * <li>When the condition {@linkplain Condition#await() waiting} + * methods are called the write lock is released and, before + * they return, the write lock is reacquired and the lock hold + * count restored to what it was when the method was called. + * + * <li>If a thread is {@linkplain Thread#interrupt interrupted} while + * waiting then the wait will terminate, an {@link + * InterruptedException} will be thrown, and the thread's + * interrupted status will be cleared. + * + * <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 + * acquiring the lock, which is in the default case not specified, + * but for <em>fair</em> locks favors those threads that have been + * waiting the longest. + * + * </ul> + * + * @return the Condition object + */ + public Condition newCondition() { + return sync.newCondition(); + } + + /** + * Returns a string identifying this lock, as well as its lock + * state. The state, in brackets includes either the String + * {@code "Unlocked"} or the String {@code "Locked by"} + * followed by the {@linkplain Thread#getName name} of the owning thread. + * + * @return a string identifying this lock, as well as its lock state + */ + public String toString() { + Thread o = sync.getOwner(); + return super.toString() + ((o == null) ? + "[Unlocked]" : + "[Locked by thread " + o.getName() + "]"); + } + + /** + * Queries if this write lock is held by the current thread. + * Identical in effect to {@link + * ReentrantReadWriteLock#isWriteLockedByCurrentThread}. + * + * @return {@code true} if the current thread holds this lock and + * {@code false} otherwise + * @since 1.6 + */ + public boolean isHeldByCurrentThread() { + return sync.isHeldExclusively(); + } + + /** + * Queries the number of holds on this write lock by the current + * thread. A thread has a hold on a lock for each lock action + * that is not matched by an unlock action. Identical in effect + * to {@link ReentrantReadWriteLock#getWriteHoldCount}. + * + * @return the number of holds on this lock by the current thread, + * or zero if this lock is not held by the current thread + * @since 1.6 + */ + public int getHoldCount() { + return sync.getWriteHoldCount(); + } + } + + // Instrumentation and status + + /** + * Returns {@code true} if this lock has fairness set true. + * + * @return {@code true} if this lock has fairness set true + */ + public final boolean isFair() { + return sync instanceof FairSync; + } + + /** + * Returns the thread that currently owns the write lock, or + * {@code null} if not owned. When this method is called by a + * thread that is not the owner, the return value reflects a + * best-effort approximation of current lock status. For example, + * the owner may be momentarily {@code null} even if there are + * threads trying to acquire the lock but have not yet done so. + * This method is designed to facilitate construction of + * subclasses that provide more extensive lock monitoring + * facilities. + * + * @return the owner, or {@code null} if not owned + */ + protected Thread getOwner() { + return sync.getOwner(); + } + + /** + * Queries the number of read locks held for this lock. This + * method is designed for use in monitoring system state, not for + * synchronization control. + * @return the number of read locks held. + */ + public int getReadLockCount() { + return sync.getReadLockCount(); + } + + /** + * Queries if the write lock is held by any thread. This method is + * designed for use in monitoring system state, not for + * synchronization control. + * + * @return {@code true} if any thread holds the write lock and + * {@code false} otherwise + */ + public boolean isWriteLocked() { + return sync.isWriteLocked(); + } + + /** + * Queries if the write lock is held by the current thread. + * + * @return {@code true} if the current thread holds the write lock and + * {@code false} otherwise + */ + public boolean isWriteLockedByCurrentThread() { + return sync.isHeldExclusively(); + } + + /** + * Queries the number of reentrant write holds on this lock by the + * current thread. A writer thread has a hold on a lock for + * each lock action that is not matched by an unlock action. + * + * @return the number of holds on the write lock by the current thread, + * or zero if the write lock is not held by the current thread + */ + public int getWriteHoldCount() { + return sync.getWriteHoldCount(); + } + + /** + * Queries the number of reentrant read holds on this lock by the + * current thread. A reader thread has a hold on a lock for + * each lock action that is not matched by an unlock action. + * + * @return the number of holds on the read lock by the current thread, + * or zero if the read lock is not held by the current thread + * @since 1.6 + */ + public int getReadHoldCount() { + return sync.getReadHoldCount(); + } + + /** + * Returns a collection containing threads that may be waiting to + * acquire the write lock. Because the actual set of threads may + * change dynamically while constructing this result, the returned + * collection is only a best-effort estimate. The elements of the + * returned collection are in no particular order. This method is + * designed to facilitate construction of subclasses that provide + * more extensive lock monitoring facilities. + * + * @return the collection of threads + */ + protected Collection<Thread> getQueuedWriterThreads() { + return sync.getExclusiveQueuedThreads(); + } + + /** + * Returns a collection containing threads that may be waiting to + * acquire the read lock. Because the actual set of threads may + * change dynamically while constructing this result, the returned + * collection is only a best-effort estimate. The elements of the + * returned collection are in no particular order. This method is + * designed to facilitate construction of subclasses that provide + * more extensive lock monitoring facilities. + * + * @return the collection of threads + */ + protected Collection<Thread> getQueuedReaderThreads() { + return sync.getSharedQueuedThreads(); + } + + /** + * Queries whether any threads are waiting to acquire the read or + * write lock. Note that because cancellations may occur at any + * time, a {@code true} return does not guarantee that any other + * thread will ever acquire a lock. This method is designed + * primarily for use in monitoring of the system state. + * + * @return {@code true} if there may be other threads waiting to + * acquire the lock + */ + public final boolean hasQueuedThreads() { + return sync.hasQueuedThreads(); + } + + /** + * Queries whether the given thread is waiting to acquire either + * the read or write lock. Note that because cancellations may + * occur at any time, a {@code true} return does not guarantee + * that this thread will ever acquire a lock. This method is + * designed primarily for use in monitoring of the system state. + * + * @param thread the thread + * @return {@code true} if the given thread is queued waiting for this lock + * @throws NullPointerException if the thread is null + */ + public final boolean hasQueuedThread(Thread thread) { + return sync.isQueued(thread); + } + + /** + * Returns an estimate of the number of threads waiting to acquire + * 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 + * synchronization control. + * + * @return the estimated number of threads waiting for this lock + */ + public final int getQueueLength() { + return sync.getQueueLength(); + } + + /** + * Returns a collection containing threads that may be waiting to + * acquire either the read or write lock. Because the actual set + * of threads may change dynamically while constructing this + * result, the returned collection is only a best-effort estimate. + * The elements of the returned collection are in no particular + * order. This method is designed to facilitate construction of + * subclasses that provide more extensive monitoring facilities. + * + * @return the collection of threads + */ + protected Collection<Thread> getQueuedThreads() { + return sync.getQueuedThreads(); + } + + /** + * Queries whether any threads are waiting on the given condition + * associated with the write lock. Note that because timeouts and + * interrupts may occur at any time, a {@code true} return does + * not guarantee that a future {@code signal} will awaken any + * threads. This method is designed primarily for use in + * monitoring of the system state. + * + * @param condition the condition + * @return {@code true} if there are any waiting threads + * @throws IllegalMonitorStateException if this lock is not held + * @throws IllegalArgumentException if the given condition is + * not associated with this lock + * @throws NullPointerException if the condition is null + */ + public boolean hasWaiters(Condition condition) { + if (condition == null) + throw new NullPointerException(); + if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) + throw new IllegalArgumentException("not owner"); + return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition); + } + + /** + * Returns an estimate of the number of threads waiting on the + * given condition associated with the write lock. 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. + * + * @param condition the condition + * @return the estimated number of waiting threads + * @throws IllegalMonitorStateException if this lock is not held + * @throws IllegalArgumentException if the given condition is + * not associated with this lock + * @throws NullPointerException if the condition is null + */ + public int getWaitQueueLength(Condition condition) { + if (condition == null) + throw new NullPointerException(); + if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) + throw new IllegalArgumentException("not owner"); + return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition); + } + + /** + * Returns a collection containing those threads that may be + * waiting on the given condition associated with the write lock. + * Because the actual set of threads may change dynamically while + * constructing this result, the returned collection is only a + * best-effort estimate. The elements of the returned collection + * are in no particular order. This method is designed to + * facilitate construction of subclasses that provide more + * extensive condition monitoring facilities. + * + * @param condition the condition + * @return the collection of threads + * @throws IllegalMonitorStateException if this lock is not held + * @throws IllegalArgumentException if the given condition is + * not associated with this lock + * @throws NullPointerException if the condition is null + */ + protected Collection<Thread> getWaitingThreads(Condition condition) { + if (condition == null) + throw new NullPointerException(); + if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) + throw new IllegalArgumentException("not owner"); + return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition); + } + + /** + * Returns a string identifying this lock, as well as its lock state. + * The state, in brackets, includes the String {@code "Write locks ="} + * followed by the number of reentrantly held write locks, and the + * String {@code "Read locks ="} followed by the number of held + * read locks. + * + * @return a string identifying this lock, as well as its lock state + */ + public String toString() { + int c = sync.getCount(); + int w = Sync.exclusiveCount(c); + int r = Sync.sharedCount(c); + + return super.toString() + + "[Write locks = " + w + ", Read locks = " + r + "]"; + } + +} |