mirror of
https://github.com/openjdk/jdk.git
synced 2026-04-18 02:40:41 +00:00
8011427: java.util.concurrent collection Spliterator implementations
Reviewed-by: martin
This commit is contained in:
parent
5a360a7579
commit
efb561f632
File diff suppressed because it is too large
Load Diff
@ -41,17 +41,18 @@ import java.util.*;
|
||||
* 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
|
||||
* <p>{@code BlockingDeque} 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
|
||||
* {@code null} or {@code false}, 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>
|
||||
* <caption>Summary of BlockingDeque methods</caption>
|
||||
* <tr>
|
||||
* <td ALIGN=CENTER COLSPAN = 5> <b>First Element (Head)</b></td>
|
||||
* </tr>
|
||||
@ -116,20 +117,21 @@ import java.util.*;
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* <p>Like any {@link BlockingQueue}, a <tt>BlockingDeque</tt> is thread safe,
|
||||
* <p>Like any {@link BlockingQueue}, a {@code BlockingDeque} 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>A {@code BlockingDeque} implementation may be used directly as a FIFO
|
||||
* {@code BlockingQueue}. The methods inherited from the
|
||||
* {@code BlockingQueue} interface are precisely equivalent to
|
||||
* {@code BlockingDeque} methods as indicated in the following table:
|
||||
*
|
||||
* <p>
|
||||
* <table BORDER CELLPADDING=3 CELLSPACING=1>
|
||||
* <caption>Comparison of BlockingQueue and BlockingDeque methods</caption>
|
||||
* <tr>
|
||||
* <td ALIGN=CENTER> <b><tt>BlockingQueue</tt> Method</b></td>
|
||||
* <td ALIGN=CENTER> <b>Equivalent <tt>BlockingDeque</tt> Method</b></td>
|
||||
* <td ALIGN=CENTER> <b>{@code BlockingQueue} Method</b></td>
|
||||
* <td ALIGN=CENTER> <b>Equivalent {@code BlockingDeque} Method</b></td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td ALIGN=CENTER COLSPAN = 2> <b>Insert</b></td>
|
||||
@ -208,7 +210,7 @@ public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> {
|
||||
/**
|
||||
* 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
|
||||
* throwing an {@code IllegalStateException} if no space is currently
|
||||
* available. When using a capacity-restricted deque, it is generally
|
||||
* preferable to use {@link #offerFirst(Object) offerFirst}.
|
||||
*
|
||||
@ -223,7 +225,7 @@ public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<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
|
||||
* throwing an {@code IllegalStateException} if no space is currently
|
||||
* available. When using a capacity-restricted deque, it is generally
|
||||
* preferable to use {@link #offerLast(Object) offerLast}.
|
||||
*
|
||||
@ -238,7 +240,7 @@ public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<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
|
||||
* returning {@code true} upon success and {@code false} 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
|
||||
@ -254,7 +256,7 @@ public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<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
|
||||
* returning {@code true} upon success and {@code false} 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
|
||||
@ -302,10 +304,10 @@ public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> {
|
||||
*
|
||||
* @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
|
||||
* {@code unit}
|
||||
* @param unit a {@code TimeUnit} determining how to interpret the
|
||||
* {@code timeout} parameter
|
||||
* @return {@code true} if successful, or {@code false} 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
|
||||
@ -324,10 +326,10 @@ public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> {
|
||||
*
|
||||
* @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
|
||||
* {@code unit}
|
||||
* @param unit a {@code TimeUnit} determining how to interpret the
|
||||
* {@code timeout} parameter
|
||||
* @return {@code true} if successful, or {@code false} 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
|
||||
@ -363,10 +365,10 @@ public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> {
|
||||
* 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
|
||||
* {@code unit}
|
||||
* @param unit a {@code TimeUnit} determining how to interpret the
|
||||
* {@code timeout} parameter
|
||||
* @return the head of this deque, or {@code null} if the specified
|
||||
* waiting time elapses before an element is available
|
||||
* @throws InterruptedException if interrupted while waiting
|
||||
*/
|
||||
@ -379,10 +381,10 @@ public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> {
|
||||
* 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
|
||||
* {@code unit}
|
||||
* @param unit a {@code TimeUnit} determining how to interpret the
|
||||
* {@code timeout} parameter
|
||||
* @return the tail of this deque, or {@code null} if the specified
|
||||
* waiting time elapses before an element is available
|
||||
* @throws InterruptedException if interrupted while waiting
|
||||
*/
|
||||
@ -392,13 +394,13 @@ public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> {
|
||||
/**
|
||||
* Removes the first occurrence of the specified element from this deque.
|
||||
* If the deque does not contain the element, it is unchanged.
|
||||
* More formally, removes the first element <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
|
||||
* More formally, removes the first element {@code e} such that
|
||||
* {@code o.equals(e)} (if such an element exists).
|
||||
* Returns {@code true} if this deque contained the specified element
|
||||
* (or equivalently, if this deque changed as a result of the call).
|
||||
*
|
||||
* @param o element to be removed from this deque, if present
|
||||
* @return <tt>true</tt> if an element was removed as a result of this call
|
||||
* @return {@code true} if an element was removed as a result of this call
|
||||
* @throws ClassCastException if the class of the specified element
|
||||
* is incompatible with this deque
|
||||
* (<a href="../Collection.html#optional-restrictions">optional</a>)
|
||||
@ -410,13 +412,13 @@ public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> {
|
||||
/**
|
||||
* Removes the last occurrence of the specified element from this deque.
|
||||
* If the deque does not contain the element, it is unchanged.
|
||||
* More formally, removes the last element <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
|
||||
* More formally, removes the last element {@code e} such that
|
||||
* {@code o.equals(e)} (if such an element exists).
|
||||
* Returns {@code true} if this deque contained the specified element
|
||||
* (or equivalently, if this deque changed as a result of the call).
|
||||
*
|
||||
* @param o element to be removed from this deque, if present
|
||||
* @return <tt>true</tt> if an element was removed as a result of this call
|
||||
* @return {@code true} if an element was removed as a result of this call
|
||||
* @throws ClassCastException if the class of the specified element
|
||||
* is incompatible with this deque
|
||||
* (<a href="../Collection.html#optional-restrictions">optional</a>)
|
||||
@ -431,8 +433,8 @@ public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<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 throwing an
|
||||
* <tt>IllegalStateException</tt> if no space is currently available.
|
||||
* {@code true} upon success and throwing an
|
||||
* {@code IllegalStateException} if no space is currently available.
|
||||
* When using a capacity-restricted deque, it is generally preferable to
|
||||
* use {@link #offer(Object) offer}.
|
||||
*
|
||||
@ -452,7 +454,7 @@ public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<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
|
||||
* {@code true} upon success and {@code false} 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.
|
||||
@ -494,8 +496,8 @@ public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> {
|
||||
* {@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>
|
||||
* @return {@code true} if the element was added to this deque, else
|
||||
* {@code false}
|
||||
* @throws InterruptedException {@inheritDoc}
|
||||
* @throws ClassCastException if the class of the specified element
|
||||
* prevents it from being added to this deque
|
||||
@ -522,11 +524,11 @@ public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> {
|
||||
/**
|
||||
* 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.
|
||||
* {@code null} 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
|
||||
* @return the head of this deque, or {@code null} if this deque is empty
|
||||
*/
|
||||
E poll();
|
||||
|
||||
@ -550,7 +552,7 @@ public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> {
|
||||
* <p>This method is equivalent to
|
||||
* {@link #pollFirst(long,TimeUnit) pollFirst}.
|
||||
*
|
||||
* @return the head of this deque, or <tt>null</tt> if the
|
||||
* @return the head of this deque, or {@code null} if the
|
||||
* specified waiting time elapses before an element is available
|
||||
* @throws InterruptedException if interrupted while waiting
|
||||
*/
|
||||
@ -573,27 +575,27 @@ public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> {
|
||||
/**
|
||||
* 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.
|
||||
* returns {@code null} 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
|
||||
* @return the head of this deque, or {@code null} 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
|
||||
* More formally, removes the first element {@code e} such that
|
||||
* {@code o.equals(e)} (if such an element exists).
|
||||
* Returns {@code true} if this deque contained the specified element
|
||||
* (or equivalently, if this deque changed as a result of the call).
|
||||
*
|
||||
* <p>This method is equivalent to
|
||||
* {@link #removeFirstOccurrence(Object) 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
|
||||
* @return {@code true} if this deque changed as a result of the call
|
||||
* @throws ClassCastException if the class of the specified element
|
||||
* is incompatible with this deque
|
||||
* (<a href="../Collection.html#optional-restrictions">optional</a>)
|
||||
@ -603,12 +605,12 @@ public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> {
|
||||
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>.
|
||||
* Returns {@code true} if this deque contains the specified element.
|
||||
* More formally, returns {@code true} if and only if this deque contains
|
||||
* at least one element {@code e} such that {@code o.equals(e)}.
|
||||
*
|
||||
* @param o object to be checked for containment in this deque
|
||||
* @return <tt>true</tt> if this deque contains the specified element
|
||||
* @return {@code true} if this deque contains the specified element
|
||||
* @throws ClassCastException if the class of the specified element
|
||||
* is incompatible with this deque
|
||||
* (<a href="../Collection.html#optional-restrictions">optional</a>)
|
||||
@ -635,9 +637,10 @@ public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> {
|
||||
// *** 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.
|
||||
* 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, throwing an
|
||||
* {@code IllegalStateException} if no space is currently available.
|
||||
*
|
||||
* <p>This method is equivalent to {@link #addFirst(Object) addFirst}.
|
||||
*
|
||||
|
||||
@ -44,17 +44,18 @@ import java.util.Queue;
|
||||
* 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
|
||||
* <p>{@code BlockingQueue} 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
|
||||
* {@code null} or {@code false}, 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>
|
||||
* <caption>Summary of BlockingQueue methods</caption>
|
||||
* <tr>
|
||||
* <td></td>
|
||||
* <td ALIGN=CENTER><em>Throws exception</em></td>
|
||||
@ -85,37 +86,37 @@ import java.util.Queue;
|
||||
* </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 {@code BlockingQueue} does not accept {@code null} elements.
|
||||
* Implementations throw {@code NullPointerException} on attempts
|
||||
* to {@code add}, {@code put} or {@code offer} a {@code null}. A
|
||||
* {@code null} is used as a sentinel value to indicate failure of
|
||||
* {@code poll} 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>A {@code BlockingQueue} may be capacity bounded. At any given
|
||||
* time it may have a {@code remainingCapacity} beyond which no
|
||||
* additional elements can be {@code put} without blocking.
|
||||
* A {@code BlockingQueue} without any intrinsic capacity constraints always
|
||||
* reports a remaining capacity of {@code Integer.MAX_VALUE}.
|
||||
*
|
||||
* <p> <tt>BlockingQueue</tt> implementations are designed to be used
|
||||
* <p>{@code BlockingQueue} 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
|
||||
* {@code remove(x)}. 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
|
||||
* <p>{@code BlockingQueue} 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>bulk</em> Collection operations {@code addAll},
|
||||
* {@code containsAll}, {@code retainAll} and {@code removeAll} 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>.
|
||||
* {@code addAll(c)} to fail (throwing an exception) after adding
|
||||
* only some of the elements in {@code c}.
|
||||
*
|
||||
* <p>A <tt>BlockingQueue</tt> does <em>not</em> intrinsically support
|
||||
* <p>A {@code BlockingQueue} 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
|
||||
@ -125,7 +126,7 @@ import java.util.Queue;
|
||||
*
|
||||
* <p>
|
||||
* Usage example, based on a typical producer-consumer scenario.
|
||||
* Note that a <tt>BlockingQueue</tt> can safely be used with multiple
|
||||
* Note that a {@code BlockingQueue} can safely be used with multiple
|
||||
* producers and multiple consumers.
|
||||
* <pre> {@code
|
||||
* class Producer implements Runnable {
|
||||
@ -181,13 +182,13 @@ 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.
|
||||
* {@code true} upon success and throwing an
|
||||
* {@code IllegalStateException} 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})
|
||||
* @return {@code true} (as specified by {@link Collection#add})
|
||||
* @throws IllegalStateException if the element cannot be added at this
|
||||
* time due to capacity restrictions
|
||||
* @throws ClassCastException if the class of the specified element
|
||||
@ -201,14 +202,14 @@ 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 <tt>false</tt> if no space is currently
|
||||
* {@code true} upon success and {@code false} 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>
|
||||
* @return {@code true} if the element was added to this queue, else
|
||||
* {@code false}
|
||||
* @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
|
||||
@ -237,10 +238,10 @@ public interface BlockingQueue<E> extends Queue<E> {
|
||||
*
|
||||
* @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
|
||||
* {@code unit}
|
||||
* @param unit a {@code TimeUnit} determining how to interpret the
|
||||
* {@code timeout} parameter
|
||||
* @return {@code true} if successful, or {@code false} 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
|
||||
@ -266,10 +267,10 @@ public interface BlockingQueue<E> extends Queue<E> {
|
||||
* 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
|
||||
* {@code unit}
|
||||
* @param unit a {@code TimeUnit} determining how to interpret the
|
||||
* {@code timeout} parameter
|
||||
* @return the head of this queue, or {@code null} if the
|
||||
* specified waiting time elapses before an element is available
|
||||
* @throws InterruptedException if interrupted while waiting
|
||||
*/
|
||||
@ -279,11 +280,11 @@ public interface BlockingQueue<E> extends Queue<E> {
|
||||
/**
|
||||
* 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
|
||||
* blocking, or {@code Integer.MAX_VALUE} 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>
|
||||
* an element will succeed by inspecting {@code remainingCapacity}
|
||||
* because it may be the case that another thread is about to
|
||||
* insert or remove an element.
|
||||
*
|
||||
@ -293,14 +294,14 @@ public interface BlockingQueue<E> extends Queue<E> {
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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 <tt>true</tt> if this queue contained the specified element
|
||||
* Returns {@code true} 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
|
||||
* @return {@code true} if this queue changed as a result of the call
|
||||
* @throws ClassCastException if the class of the specified element
|
||||
* is incompatible with this queue
|
||||
* (<a href="../Collection.html#optional-restrictions">optional</a>)
|
||||
@ -310,12 +311,12 @@ public interface BlockingQueue<E> extends Queue<E> {
|
||||
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>.
|
||||
* 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
|
||||
* @return {@code true} if this queue contains the specified element
|
||||
* @throws ClassCastException if the class of the specified element
|
||||
* is incompatible with this queue
|
||||
* (<a href="../Collection.html#optional-restrictions">optional</a>)
|
||||
@ -329,10 +330,10 @@ public interface BlockingQueue<E> extends Queue<E> {
|
||||
* 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,
|
||||
* collection {@code c} 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
|
||||
* {@code IllegalArgumentException}. Further, the behavior of
|
||||
* this operation is undefined if the specified collection is
|
||||
* modified while the operation is in progress.
|
||||
*
|
||||
@ -353,10 +354,10 @@ public interface BlockingQueue<E> extends Queue<E> {
|
||||
* 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,
|
||||
* collection {@code c} 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
|
||||
* {@code IllegalArgumentException}. Further, the behavior of
|
||||
* this operation is undefined if the specified collection is
|
||||
* modified while the operation is in progress.
|
||||
*
|
||||
|
||||
@ -42,6 +42,9 @@ import java.util.Deque;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Queue;
|
||||
import java.util.Spliterator;
|
||||
import java.util.Spliterators;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* An unbounded concurrent {@linkplain Deque deque} based on linked nodes.
|
||||
@ -816,7 +819,7 @@ public class ConcurrentLinkedDeque<E>
|
||||
* Creates an array list and fills it with elements of this list.
|
||||
* Used by toArray.
|
||||
*
|
||||
* @return the arrayList
|
||||
* @return the array list
|
||||
*/
|
||||
private ArrayList<E> toArrayList() {
|
||||
ArrayList<E> list = new ArrayList<E>();
|
||||
@ -1024,12 +1027,28 @@ public class ConcurrentLinkedDeque<E>
|
||||
}
|
||||
|
||||
public E poll() { return pollFirst(); }
|
||||
public E remove() { return removeFirst(); }
|
||||
public E peek() { return peekFirst(); }
|
||||
public E element() { return getFirst(); }
|
||||
public void push(E e) { addFirst(e); }
|
||||
|
||||
/**
|
||||
* @throws NoSuchElementException {@inheritDoc}
|
||||
*/
|
||||
public E remove() { return removeFirst(); }
|
||||
|
||||
/**
|
||||
* @throws NoSuchElementException {@inheritDoc}
|
||||
*/
|
||||
public E pop() { return removeFirst(); }
|
||||
|
||||
/**
|
||||
* @throws NoSuchElementException {@inheritDoc}
|
||||
*/
|
||||
public E element() { return getFirst(); }
|
||||
|
||||
/**
|
||||
* @throws NullPointerException {@inheritDoc}
|
||||
*/
|
||||
public void push(E e) { addFirst(e); }
|
||||
|
||||
/**
|
||||
* Removes the first element {@code e} such that
|
||||
* {@code o.equals(e)}, if such an element exists in this deque.
|
||||
@ -1385,6 +1404,99 @@ public class ConcurrentLinkedDeque<E>
|
||||
Node<E> nextNode(Node<E> p) { return pred(p); }
|
||||
}
|
||||
|
||||
/** A customized variant of Spliterators.IteratorSpliterator */
|
||||
static final class CLDSpliterator<E> implements Spliterator<E> {
|
||||
static final int MAX_BATCH = 1 << 25; // max batch array size;
|
||||
final ConcurrentLinkedDeque<E> queue;
|
||||
Node<E> current; // current node; null until initialized
|
||||
int batch; // batch size for splits
|
||||
boolean exhausted; // true when no more nodes
|
||||
CLDSpliterator(ConcurrentLinkedDeque<E> queue) {
|
||||
this.queue = queue;
|
||||
}
|
||||
|
||||
public Spliterator<E> trySplit() {
|
||||
Node<E> p;
|
||||
final ConcurrentLinkedDeque<E> q = this.queue;
|
||||
int b = batch;
|
||||
int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
|
||||
if (!exhausted &&
|
||||
((p = current) != null || (p = q.first()) != null)) {
|
||||
if (p.item == null && p == (p = p.next))
|
||||
current = p = q.first();
|
||||
if (p != null && p.next != null) {
|
||||
Object[] a = new Object[n];
|
||||
int i = 0;
|
||||
do {
|
||||
if ((a[i] = p.item) != null)
|
||||
++i;
|
||||
if (p == (p = p.next))
|
||||
p = q.first();
|
||||
} while (p != null && i < n);
|
||||
if ((current = p) == null)
|
||||
exhausted = true;
|
||||
if (i > 0) {
|
||||
batch = i;
|
||||
return Spliterators.spliterator
|
||||
(a, 0, i, Spliterator.ORDERED | Spliterator.NONNULL |
|
||||
Spliterator.CONCURRENT);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void forEachRemaining(Consumer<? super E> action) {
|
||||
Node<E> p;
|
||||
if (action == null) throw new NullPointerException();
|
||||
final ConcurrentLinkedDeque<E> q = this.queue;
|
||||
if (!exhausted &&
|
||||
((p = current) != null || (p = q.first()) != null)) {
|
||||
exhausted = true;
|
||||
do {
|
||||
E e = p.item;
|
||||
if (p == (p = p.next))
|
||||
p = q.first();
|
||||
if (e != null)
|
||||
action.accept(e);
|
||||
} while (p != null);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean tryAdvance(Consumer<? super E> action) {
|
||||
Node<E> p;
|
||||
if (action == null) throw new NullPointerException();
|
||||
final ConcurrentLinkedDeque<E> q = this.queue;
|
||||
if (!exhausted &&
|
||||
((p = current) != null || (p = q.first()) != null)) {
|
||||
E e;
|
||||
do {
|
||||
e = p.item;
|
||||
if (p == (p = p.next))
|
||||
p = q.first();
|
||||
} while (e == null && p != null);
|
||||
if ((current = p) == null)
|
||||
exhausted = true;
|
||||
if (e != null) {
|
||||
action.accept(e);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public long estimateSize() { return Long.MAX_VALUE; }
|
||||
|
||||
public int characteristics() {
|
||||
return Spliterator.ORDERED | Spliterator.NONNULL |
|
||||
Spliterator.CONCURRENT;
|
||||
}
|
||||
}
|
||||
|
||||
public Spliterator<E> spliterator() {
|
||||
return new CLDSpliterator<E>(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves this deque to a stream (that is, serializes it).
|
||||
*
|
||||
|
||||
@ -41,6 +41,9 @@ import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Queue;
|
||||
import java.util.Spliterator;
|
||||
import java.util.Spliterators;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* An unbounded thread-safe {@linkplain Queue queue} based on linked nodes.
|
||||
@ -56,7 +59,7 @@ import java.util.Queue;
|
||||
* Like most other concurrent collection implementations, this class
|
||||
* does not permit the use of {@code null} elements.
|
||||
*
|
||||
* <p>This implementation employs an efficient "wait-free"
|
||||
* <p>This implementation employs an efficient <em>non-blocking</em>
|
||||
* algorithm based on one described in <a
|
||||
* href="http://www.cs.rochester.edu/u/michael/PODC96.html"> Simple,
|
||||
* Fast, and Practical Non-Blocking and Blocking Concurrent Queue
|
||||
@ -295,7 +298,7 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to CAS head to p. If successful, repoint old head to itself
|
||||
* Tries to CAS head to p. If successful, repoint old head to itself
|
||||
* as sentinel for succ(), below.
|
||||
*/
|
||||
final void updateHead(Node<E> h, Node<E> p) {
|
||||
@ -792,6 +795,96 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
|
||||
tail = t;
|
||||
}
|
||||
|
||||
/** A customized variant of Spliterators.IteratorSpliterator */
|
||||
static final class CLQSpliterator<E> implements Spliterator<E> {
|
||||
static final int MAX_BATCH = 1 << 25; // max batch array size;
|
||||
final ConcurrentLinkedQueue<E> queue;
|
||||
Node<E> current; // current node; null until initialized
|
||||
int batch; // batch size for splits
|
||||
boolean exhausted; // true when no more nodes
|
||||
CLQSpliterator(ConcurrentLinkedQueue<E> queue) {
|
||||
this.queue = queue;
|
||||
}
|
||||
|
||||
public Spliterator<E> trySplit() {
|
||||
Node<E> p;
|
||||
final ConcurrentLinkedQueue<E> q = this.queue;
|
||||
int b = batch;
|
||||
int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
|
||||
if (!exhausted &&
|
||||
((p = current) != null || (p = q.first()) != null) &&
|
||||
p.next != null) {
|
||||
Object[] a = new Object[n];
|
||||
int i = 0;
|
||||
do {
|
||||
if ((a[i] = p.item) != null)
|
||||
++i;
|
||||
if (p == (p = p.next))
|
||||
p = q.first();
|
||||
} while (p != null && i < n);
|
||||
if ((current = p) == null)
|
||||
exhausted = true;
|
||||
if (i > 0) {
|
||||
batch = i;
|
||||
return Spliterators.spliterator
|
||||
(a, 0, i, Spliterator.ORDERED | Spliterator.NONNULL |
|
||||
Spliterator.CONCURRENT);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void forEachRemaining(Consumer<? super E> action) {
|
||||
Node<E> p;
|
||||
if (action == null) throw new NullPointerException();
|
||||
final ConcurrentLinkedQueue<E> q = this.queue;
|
||||
if (!exhausted &&
|
||||
((p = current) != null || (p = q.first()) != null)) {
|
||||
exhausted = true;
|
||||
do {
|
||||
E e = p.item;
|
||||
if (p == (p = p.next))
|
||||
p = q.first();
|
||||
if (e != null)
|
||||
action.accept(e);
|
||||
} while (p != null);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean tryAdvance(Consumer<? super E> action) {
|
||||
Node<E> p;
|
||||
if (action == null) throw new NullPointerException();
|
||||
final ConcurrentLinkedQueue<E> q = this.queue;
|
||||
if (!exhausted &&
|
||||
((p = current) != null || (p = q.first()) != null)) {
|
||||
E e;
|
||||
do {
|
||||
e = p.item;
|
||||
if (p == (p = p.next))
|
||||
p = q.first();
|
||||
} while (e == null && p != null);
|
||||
if ((current = p) == null)
|
||||
exhausted = true;
|
||||
if (e != null) {
|
||||
action.accept(e);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public long estimateSize() { return Long.MAX_VALUE; }
|
||||
|
||||
public int characteristics() {
|
||||
return Spliterator.ORDERED | Spliterator.NONNULL |
|
||||
Spliterator.CONCURRENT;
|
||||
}
|
||||
}
|
||||
|
||||
public Spliterator<E> spliterator() {
|
||||
return new CLQSpliterator<E>(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws NullPointerException if argument is null.
|
||||
*
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -34,7 +34,17 @@
|
||||
*/
|
||||
|
||||
package java.util.concurrent;
|
||||
import java.util.*;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.NavigableMap;
|
||||
import java.util.NavigableSet;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.Spliterator;
|
||||
|
||||
/**
|
||||
* A scalable concurrent {@link NavigableSet} implementation based on
|
||||
@ -44,33 +54,33 @@ import java.util.*;
|
||||
* 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>
|
||||
* cost for the {@code contains}, {@code add}, and {@code remove}
|
||||
* 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.
|
||||
* java.util.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>
|
||||
* <p>Beware that, unlike in most collections, the {@code size}
|
||||
* 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, and so may report
|
||||
* inaccurate results if this collection is modified during traversal.
|
||||
* Additionally, the bulk operations <tt>addAll</tt>,
|
||||
* <tt>removeAll</tt>, <tt>retainAll</tt>, <tt>containsAll</tt>,
|
||||
* <tt>equals</tt>, and <tt>toArray</tt> are <em>not</em> guaranteed
|
||||
* Additionally, the bulk operations {@code addAll},
|
||||
* {@code removeAll}, {@code retainAll}, {@code containsAll},
|
||||
* {@code equals}, and {@code toArray} 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
|
||||
* concurrently with an {@code addAll} 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
|
||||
* this class does not permit the use of {@code null} elements,
|
||||
* because {@code null} arguments and return values cannot be reliably
|
||||
* distinguished from the absence of elements.
|
||||
*
|
||||
* <p>This class is a member of the
|
||||
@ -90,7 +100,7 @@ public class ConcurrentSkipListSet<E>
|
||||
/**
|
||||
* 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()
|
||||
* safety, which entails some ugliness in clone().
|
||||
*/
|
||||
private final ConcurrentNavigableMap<E,Object> m;
|
||||
|
||||
@ -107,7 +117,7 @@ public class ConcurrentSkipListSet<E>
|
||||
* the specified comparator.
|
||||
*
|
||||
* @param comparator the comparator that will be used to order this set.
|
||||
* If <tt>null</tt>, the {@linkplain Comparable natural
|
||||
* If {@code null}, the {@linkplain Comparable natural
|
||||
* ordering} of the elements will be used.
|
||||
*/
|
||||
public ConcurrentSkipListSet(Comparator<? super E> comparator) {
|
||||
@ -120,7 +130,7 @@ public class ConcurrentSkipListSet<E>
|
||||
* {@linkplain Comparable natural ordering}.
|
||||
*
|
||||
* @param c The elements that will comprise the new set
|
||||
* @throws ClassCastException if the elements in <tt>c</tt> are
|
||||
* @throws ClassCastException if the elements in {@code c} are
|
||||
* not {@link Comparable}, or are not mutually comparable
|
||||
* @throws NullPointerException if the specified collection or any
|
||||
* of its elements are null
|
||||
@ -151,7 +161,7 @@ public class ConcurrentSkipListSet<E>
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a shallow copy of this <tt>ConcurrentSkipListSet</tt>
|
||||
* Returns a shallow copy of this {@code ConcurrentSkipListSet}
|
||||
* instance. (The elements themselves are not cloned.)
|
||||
*
|
||||
* @return a shallow copy of this set
|
||||
@ -172,8 +182,8 @@ public class ConcurrentSkipListSet<E>
|
||||
|
||||
/**
|
||||
* 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>.
|
||||
* contains more than {@code Integer.MAX_VALUE} elements, it
|
||||
* returns {@code Integer.MAX_VALUE}.
|
||||
*
|
||||
* <p>Beware that, unlike in most collections, this method is
|
||||
* <em>NOT</em> a constant-time operation. Because of the
|
||||
@ -191,20 +201,20 @@ public class ConcurrentSkipListSet<E>
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <tt>true</tt> if this set contains no elements.
|
||||
* @return <tt>true</tt> if this set contains no elements
|
||||
* Returns {@code true} if this set contains no elements.
|
||||
* @return {@code true} 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>.
|
||||
* Returns {@code true} if this set contains the specified element.
|
||||
* More formally, returns {@code true} if and only if this set
|
||||
* contains an element {@code e} such that {@code o.equals(e)}.
|
||||
*
|
||||
* @param o object to be checked for containment in this set
|
||||
* @return <tt>true</tt> if this set contains the specified element
|
||||
* @return {@code true} 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
|
||||
@ -215,15 +225,15 @@ public class ConcurrentSkipListSet<E>
|
||||
|
||||
/**
|
||||
* 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>.
|
||||
* More formally, adds the specified element {@code e} to this set if
|
||||
* the set contains no element {@code e2} such that {@code e.equals(e2)}.
|
||||
* If this set already contains the element, the call leaves the set
|
||||
* unchanged and returns <tt>false</tt>.
|
||||
* unchanged and returns {@code false}.
|
||||
*
|
||||
* @param e element to be added to this set
|
||||
* @return <tt>true</tt> if this set did not already contain the
|
||||
* @return {@code true} if this set did not already contain the
|
||||
* specified element
|
||||
* @throws ClassCastException if <tt>e</tt> cannot be compared
|
||||
* @throws ClassCastException if {@code e} cannot be compared
|
||||
* with the elements currently in this set
|
||||
* @throws NullPointerException if the specified element is null
|
||||
*/
|
||||
@ -233,15 +243,15 @@ public class ConcurrentSkipListSet<E>
|
||||
|
||||
/**
|
||||
* 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
|
||||
* More formally, removes an element {@code e} such that
|
||||
* {@code o.equals(e)}, if this set contains such an element.
|
||||
* Returns {@code true} if this set contained the element (or
|
||||
* equivalently, if this set changed as a result of the call).
|
||||
* (This set will not contain the element once the call returns.)
|
||||
*
|
||||
* @param o object to be removed from this set, if present
|
||||
* @return <tt>true</tt> if this set contained the specified element
|
||||
* @throws ClassCastException if <tt>o</tt> cannot be compared
|
||||
* @return {@code true} if this set contained the specified element
|
||||
* @throws ClassCastException if {@code o} cannot be compared
|
||||
* with the elements currently in this set
|
||||
* @throws NullPointerException if the specified element is null
|
||||
*/
|
||||
@ -279,7 +289,7 @@ public class ConcurrentSkipListSet<E>
|
||||
|
||||
/**
|
||||
* Compares the specified object with this set for equality. Returns
|
||||
* <tt>true</tt> if the specified object is also a set, the two sets
|
||||
* {@code true} 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
|
||||
@ -287,7 +297,7 @@ public class ConcurrentSkipListSet<E>
|
||||
* 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
|
||||
* @return {@code true} if the specified object is equal to this set
|
||||
*/
|
||||
public boolean equals(Object o) {
|
||||
// Override AbstractSet version to avoid calling size()
|
||||
@ -312,7 +322,7 @@ public class ConcurrentSkipListSet<E>
|
||||
* 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
|
||||
* @return {@code true} if this set changed as a result of the call
|
||||
* @throws ClassCastException if the types of one or more elements in this
|
||||
* set are incompatible with the specified collection
|
||||
* @throws NullPointerException if the specified collection or any
|
||||
@ -380,14 +390,14 @@ public class ConcurrentSkipListSet<E>
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws NoSuchElementException {@inheritDoc}
|
||||
* @throws java.util.NoSuchElementException {@inheritDoc}
|
||||
*/
|
||||
public E first() {
|
||||
return m.firstKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws NoSuchElementException {@inheritDoc}
|
||||
* @throws java.util.NoSuchElementException {@inheritDoc}
|
||||
*/
|
||||
public E last() {
|
||||
return m.lastKey();
|
||||
@ -460,7 +470,7 @@ public class ConcurrentSkipListSet<E>
|
||||
* 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>.
|
||||
* {@link Collections#reverseOrder(Comparator) Collections.reverseOrder}{@code (comparator())}.
|
||||
* The expression {@code s.descendingSet().descendingSet()} returns a
|
||||
* view of {@code s} essentially equivalent to {@code s}.
|
||||
*
|
||||
@ -470,6 +480,14 @@ public class ConcurrentSkipListSet<E>
|
||||
return new ConcurrentSkipListSet<E>(m.descendingMap());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Spliterator<E> spliterator() {
|
||||
if (m instanceof ConcurrentSkipListMap)
|
||||
return ((ConcurrentSkipListMap<E,?>)m).keySpliterator();
|
||||
else
|
||||
return (Spliterator<E>)((ConcurrentSkipListMap.SubMap<E,?>)m).keyIterator();
|
||||
}
|
||||
|
||||
// Support for resetting map in clone
|
||||
private void setMap(ConcurrentNavigableMap<E,Object> map) {
|
||||
UNSAFE.putObjectVolatile(this, mapOffset, map);
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -34,7 +33,19 @@
|
||||
*/
|
||||
|
||||
package java.util.concurrent;
|
||||
import java.util.*;
|
||||
import java.util.AbstractList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
import java.util.RandomAccess;
|
||||
import java.util.Spliterator;
|
||||
import java.util.Spliterators;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
@ -42,10 +53,10 @@ import java.util.function.UnaryOperator;
|
||||
|
||||
/**
|
||||
* A thread-safe variant of {@link java.util.ArrayList} in which all mutative
|
||||
* operations (<tt>add</tt>, <tt>set</tt>, and so on) are implemented by
|
||||
* operations ({@code add}, {@code set}, and so on) are implemented by
|
||||
* making a fresh copy of the underlying array.
|
||||
*
|
||||
* <p> This is ordinarily too costly, but may be <em>more</em> efficient
|
||||
* <p>This is ordinarily too costly, but may be <em>more</em> efficient
|
||||
* than alternatives when traversal operations vastly outnumber
|
||||
* mutations, and is useful when you cannot or don't want to
|
||||
* synchronize traversals, yet need to preclude interference among
|
||||
@ -53,14 +64,14 @@ import java.util.function.UnaryOperator;
|
||||
* reference to the state of the array at the point that the iterator
|
||||
* was created. This array never changes during the lifetime of the
|
||||
* iterator, so interference is impossible and the iterator is
|
||||
* guaranteed not to throw <tt>ConcurrentModificationException</tt>.
|
||||
* guaranteed not to throw {@code ConcurrentModificationException}.
|
||||
* The iterator will not reflect additions, removals, or changes to
|
||||
* the list since the iterator was created. Element-changing
|
||||
* operations on iterators themselves (<tt>remove</tt>, <tt>set</tt>, and
|
||||
* <tt>add</tt>) are not supported. These methods throw
|
||||
* <tt>UnsupportedOperationException</tt>.
|
||||
* operations on iterators themselves ({@code remove}, {@code set}, and
|
||||
* {@code add}) are not supported. These methods throw
|
||||
* {@code UnsupportedOperationException}.
|
||||
*
|
||||
* <p>All elements are permitted, including <tt>null</tt>.
|
||||
* <p>All elements are permitted, including {@code null}.
|
||||
*
|
||||
* <p>Memory consistency effects: As with other concurrent
|
||||
* collections, actions in a thread prior to placing an object into a
|
||||
@ -82,10 +93,10 @@ public class CopyOnWriteArrayList<E>
|
||||
private static final long serialVersionUID = 8673264195747942595L;
|
||||
|
||||
/** The lock protecting all mutators */
|
||||
transient final ReentrantLock lock = new ReentrantLock();
|
||||
final transient ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
/** The array, accessed only via getArray/setArray. */
|
||||
private volatile transient Object[] array;
|
||||
private transient volatile Object[] array;
|
||||
|
||||
/**
|
||||
* Gets the array. Non-private so as to also be accessible
|
||||
@ -118,10 +129,15 @@ public class CopyOnWriteArrayList<E>
|
||||
* @throws NullPointerException if the specified collection is null
|
||||
*/
|
||||
public CopyOnWriteArrayList(Collection<? extends E> c) {
|
||||
Object[] elements = c.toArray();
|
||||
// c.toArray might (incorrectly) not return Object[] (see 6260652)
|
||||
if (elements.getClass() != Object[].class)
|
||||
elements = Arrays.copyOf(elements, elements.length, Object[].class);
|
||||
Object[] elements;
|
||||
if (c.getClass() == CopyOnWriteArrayList.class)
|
||||
elements = ((CopyOnWriteArrayList<?>)c).getArray();
|
||||
else {
|
||||
elements = c.toArray();
|
||||
// c.toArray might (incorrectly) not return Object[] (see 6260652)
|
||||
if (elements.getClass() != Object[].class)
|
||||
elements = Arrays.copyOf(elements, elements.length, Object[].class);
|
||||
}
|
||||
setArray(elements);
|
||||
}
|
||||
|
||||
@ -146,9 +162,9 @@ public class CopyOnWriteArrayList<E>
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <tt>true</tt> if this list contains no elements.
|
||||
* Returns {@code true} if this list contains no elements.
|
||||
*
|
||||
* @return <tt>true</tt> if this list contains no elements
|
||||
* @return {@code true} if this list contains no elements
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return size() == 0;
|
||||
@ -158,7 +174,7 @@ public class CopyOnWriteArrayList<E>
|
||||
* Tests for equality, coping with nulls.
|
||||
*/
|
||||
private static boolean eq(Object o1, Object o2) {
|
||||
return (o1 == null ? o2 == null : o1.equals(o2));
|
||||
return (o1 == null) ? o2 == null : o1.equals(o2);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -205,13 +221,13 @@ public class CopyOnWriteArrayList<E>
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <tt>true</tt> if this list contains the specified element.
|
||||
* More formally, returns <tt>true</tt> if and only if this list contains
|
||||
* at least one element <tt>e</tt> such that
|
||||
* Returns {@code true} if this list contains the specified element.
|
||||
* More formally, returns {@code true} if and only if this list contains
|
||||
* at least one element {@code e} such that
|
||||
* <tt>(o==null ? e==null : o.equals(e))</tt>.
|
||||
*
|
||||
* @param o element whose presence in this list is to be tested
|
||||
* @return <tt>true</tt> if this list contains the specified element
|
||||
* @return {@code true} if this list contains the specified element
|
||||
*/
|
||||
public boolean contains(Object o) {
|
||||
Object[] elements = getArray();
|
||||
@ -228,17 +244,17 @@ public class CopyOnWriteArrayList<E>
|
||||
|
||||
/**
|
||||
* Returns the index of the first occurrence of the specified element in
|
||||
* this list, searching forwards from <tt>index</tt>, or returns -1 if
|
||||
* this list, searching forwards from {@code index}, or returns -1 if
|
||||
* the element is not found.
|
||||
* More formally, returns the lowest index <tt>i</tt> such that
|
||||
* More formally, returns the lowest index {@code i} such that
|
||||
* <tt>(i >= index && (e==null ? get(i)==null : e.equals(get(i))))</tt>,
|
||||
* or -1 if there is no such index.
|
||||
*
|
||||
* @param e element to search for
|
||||
* @param index index to start searching from
|
||||
* @return the index of the first occurrence of the element in
|
||||
* this list at position <tt>index</tt> or later in the list;
|
||||
* <tt>-1</tt> if the element is not found.
|
||||
* this list at position {@code index} or later in the list;
|
||||
* {@code -1} if the element is not found.
|
||||
* @throws IndexOutOfBoundsException if the specified index is negative
|
||||
*/
|
||||
public int indexOf(E e, int index) {
|
||||
@ -256,16 +272,16 @@ public class CopyOnWriteArrayList<E>
|
||||
|
||||
/**
|
||||
* Returns the index of the last occurrence of the specified element in
|
||||
* this list, searching backwards from <tt>index</tt>, or returns -1 if
|
||||
* this list, searching backwards from {@code index}, or returns -1 if
|
||||
* the element is not found.
|
||||
* More formally, returns the highest index <tt>i</tt> such that
|
||||
* More formally, returns the highest index {@code i} such that
|
||||
* <tt>(i <= index && (e==null ? get(i)==null : e.equals(get(i))))</tt>,
|
||||
* or -1 if there is no such index.
|
||||
*
|
||||
* @param e element to search for
|
||||
* @param index index to start searching backwards from
|
||||
* @return the index of the last occurrence of the element at position
|
||||
* less than or equal to <tt>index</tt> in this list;
|
||||
* less than or equal to {@code index} in this list;
|
||||
* -1 if the element is not found.
|
||||
* @throws IndexOutOfBoundsException if the specified index is greater
|
||||
* than or equal to the current size of this list
|
||||
@ -323,7 +339,7 @@ public class CopyOnWriteArrayList<E>
|
||||
* <p>If this list fits in the specified array with room to spare
|
||||
* (i.e., the array has more elements than this list), the element in
|
||||
* the array immediately following the end of the list is set to
|
||||
* <tt>null</tt>. (This is useful in determining the length of this
|
||||
* {@code null}. (This is useful in determining the length of this
|
||||
* list <i>only</i> if the caller knows that this list does not contain
|
||||
* any null elements.)
|
||||
*
|
||||
@ -332,14 +348,14 @@ public class CopyOnWriteArrayList<E>
|
||||
* 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 list known to contain only strings.
|
||||
* <p>Suppose {@code x} is a list known to contain only strings.
|
||||
* The following code can be used to dump the list into a newly
|
||||
* allocated array of <tt>String</tt>:
|
||||
* allocated array of {@code String}:
|
||||
*
|
||||
* <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
|
||||
*
|
||||
* Note that <tt>toArray(new Object[0])</tt> is identical in function to
|
||||
* <tt>toArray()</tt>.
|
||||
* Note that {@code toArray(new Object[0])} is identical in function to
|
||||
* {@code toArray()}.
|
||||
*
|
||||
* @param a the array into which the elements of the list are to
|
||||
* be stored, if it is big enough; otherwise, a new array of the
|
||||
@ -412,7 +428,7 @@ public class CopyOnWriteArrayList<E>
|
||||
* Appends the specified element to the end of this list.
|
||||
*
|
||||
* @param e element to be appended to this list
|
||||
* @return <tt>true</tt> (as specified by {@link Collection#add})
|
||||
* @return {@code true} (as specified by {@link Collection#add})
|
||||
*/
|
||||
public boolean add(E e) {
|
||||
final ReentrantLock lock = this.lock;
|
||||
@ -496,45 +512,54 @@ public class CopyOnWriteArrayList<E>
|
||||
* Removes the first occurrence of the specified element from this list,
|
||||
* if it is present. If this list does not contain the element, it is
|
||||
* unchanged. More formally, removes the element with the lowest index
|
||||
* <tt>i</tt> such that
|
||||
* {@code i} such that
|
||||
* <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>
|
||||
* (if such an element exists). Returns <tt>true</tt> if this list
|
||||
* (if such an element exists). Returns {@code true} if this list
|
||||
* contained the specified element (or equivalently, if this list
|
||||
* changed as a result of the call).
|
||||
*
|
||||
* @param o element to be removed from this list, if present
|
||||
* @return <tt>true</tt> if this list contained the specified element
|
||||
* @return {@code true} if this list contained the specified element
|
||||
*/
|
||||
public boolean remove(Object o) {
|
||||
Object[] snapshot = getArray();
|
||||
int index = indexOf(o, snapshot, 0, snapshot.length);
|
||||
return (index < 0) ? false : remove(o, snapshot, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* A version of remove(Object) using the strong hint that given
|
||||
* recent snapshot contains o at the given index.
|
||||
*/
|
||||
private boolean remove(Object o, Object[] snapshot, int index) {
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
Object[] elements = getArray();
|
||||
int len = elements.length;
|
||||
if (len != 0) {
|
||||
// Copy while searching for element to remove
|
||||
// This wins in the normal case of element being present
|
||||
int newlen = len - 1;
|
||||
Object[] newElements = new Object[newlen];
|
||||
|
||||
for (int i = 0; i < newlen; ++i) {
|
||||
if (eq(o, elements[i])) {
|
||||
// found one; copy remaining and exit
|
||||
for (int k = i + 1; k < len; ++k)
|
||||
newElements[k-1] = elements[k];
|
||||
setArray(newElements);
|
||||
return true;
|
||||
} else
|
||||
newElements[i] = elements[i];
|
||||
}
|
||||
|
||||
// special handling for last cell
|
||||
if (eq(o, elements[newlen])) {
|
||||
setArray(newElements);
|
||||
return true;
|
||||
Object[] current = getArray();
|
||||
int len = current.length;
|
||||
if (snapshot != current) findIndex: {
|
||||
int prefix = Math.min(index, len);
|
||||
for (int i = 0; i < prefix; i++) {
|
||||
if (current[i] != snapshot[i] && eq(o, current[i])) {
|
||||
index = i;
|
||||
break findIndex;
|
||||
}
|
||||
}
|
||||
if (index >= len)
|
||||
return false;
|
||||
if (current[index] == o)
|
||||
break findIndex;
|
||||
index = indexOf(o, current, index, len);
|
||||
if (index < 0)
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
Object[] newElements = new Object[len - 1];
|
||||
System.arraycopy(current, 0, newElements, 0, index);
|
||||
System.arraycopy(current, index + 1,
|
||||
newElements, index,
|
||||
len - index - 1);
|
||||
setArray(newElements);
|
||||
return true;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
@ -542,10 +567,10 @@ public class CopyOnWriteArrayList<E>
|
||||
|
||||
/**
|
||||
* Removes from this list all of the elements whose index is between
|
||||
* <tt>fromIndex</tt>, inclusive, and <tt>toIndex</tt>, exclusive.
|
||||
* {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
|
||||
* Shifts any succeeding elements to the left (reduces their index).
|
||||
* This call shortens the list by <tt>(toIndex - fromIndex)</tt> elements.
|
||||
* (If <tt>toIndex==fromIndex</tt>, this operation has no effect.)
|
||||
* This call shortens the list by {@code (toIndex - fromIndex)} elements.
|
||||
* (If {@code toIndex==fromIndex}, this operation has no effect.)
|
||||
*
|
||||
* @param fromIndex index of first element to be removed
|
||||
* @param toIndex index after last element to be removed
|
||||
@ -581,23 +606,34 @@ public class CopyOnWriteArrayList<E>
|
||||
* Appends the element, if not present.
|
||||
*
|
||||
* @param e element to be added to this list, if absent
|
||||
* @return <tt>true</tt> if the element was added
|
||||
* @return {@code true} if the element was added
|
||||
*/
|
||||
public boolean addIfAbsent(E e) {
|
||||
Object[] snapshot = getArray();
|
||||
return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false :
|
||||
addIfAbsent(e, snapshot);
|
||||
}
|
||||
|
||||
/**
|
||||
* A version of addIfAbsent using the strong hint that given
|
||||
* recent snapshot does not contain e.
|
||||
*/
|
||||
private boolean addIfAbsent(E e, Object[] snapshot) {
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
// Copy while checking if already present.
|
||||
// This wins in the most common case where it is not present
|
||||
Object[] elements = getArray();
|
||||
int len = elements.length;
|
||||
Object[] newElements = new Object[len + 1];
|
||||
for (int i = 0; i < len; ++i) {
|
||||
if (eq(e, elements[i]))
|
||||
return false; // exit, throwing away copy
|
||||
else
|
||||
newElements[i] = elements[i];
|
||||
Object[] current = getArray();
|
||||
int len = current.length;
|
||||
if (snapshot != current) {
|
||||
// Optimize for lost race to another addXXX operation
|
||||
int common = Math.min(snapshot.length, len);
|
||||
for (int i = 0; i < common; i++)
|
||||
if (current[i] != snapshot[i] && eq(e, current[i]))
|
||||
return false;
|
||||
if (indexOf(e, current, common, len) >= 0)
|
||||
return false;
|
||||
}
|
||||
Object[] newElements = Arrays.copyOf(current, len + 1);
|
||||
newElements[len] = e;
|
||||
setArray(newElements);
|
||||
return true;
|
||||
@ -607,11 +643,11 @@ public class CopyOnWriteArrayList<E>
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <tt>true</tt> if this list contains all of the elements of the
|
||||
* Returns {@code true} if this list contains all of the elements of the
|
||||
* specified collection.
|
||||
*
|
||||
* @param c collection to be checked for containment in this list
|
||||
* @return <tt>true</tt> if this list contains all of the elements of the
|
||||
* @return {@code true} if this list contains all of the elements of the
|
||||
* specified collection
|
||||
* @throws NullPointerException if the specified collection is null
|
||||
* @see #contains(Object)
|
||||
@ -632,7 +668,7 @@ public class CopyOnWriteArrayList<E>
|
||||
* in this class because of the need for an internal temporary array.
|
||||
*
|
||||
* @param c collection containing elements to be removed from this list
|
||||
* @return <tt>true</tt> if this list changed as a result of the call
|
||||
* @return {@code true} if this list changed as a result of the call
|
||||
* @throws ClassCastException if the class of an element of this list
|
||||
* is incompatible with the specified collection
|
||||
* (<a href="../Collection.html#optional-restrictions">optional</a>)
|
||||
@ -675,7 +711,7 @@ public class CopyOnWriteArrayList<E>
|
||||
* its elements that are not contained in the specified collection.
|
||||
*
|
||||
* @param c collection containing elements to be retained in this list
|
||||
* @return <tt>true</tt> if this list changed as a result of the call
|
||||
* @return {@code true} if this list changed as a result of the call
|
||||
* @throws ClassCastException if the class of an element of this list
|
||||
* is incompatible with the specified collection
|
||||
* (<a href="../Collection.html#optional-restrictions">optional</a>)
|
||||
@ -727,22 +763,22 @@ public class CopyOnWriteArrayList<E>
|
||||
Object[] cs = c.toArray();
|
||||
if (cs.length == 0)
|
||||
return 0;
|
||||
Object[] uniq = new Object[cs.length];
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
Object[] elements = getArray();
|
||||
int len = elements.length;
|
||||
int added = 0;
|
||||
for (int i = 0; i < cs.length; ++i) { // scan for duplicates
|
||||
// uniquify and compact elements in cs
|
||||
for (int i = 0; i < cs.length; ++i) {
|
||||
Object e = cs[i];
|
||||
if (indexOf(e, elements, 0, len) < 0 &&
|
||||
indexOf(e, uniq, 0, added) < 0)
|
||||
uniq[added++] = e;
|
||||
indexOf(e, cs, 0, added) < 0)
|
||||
cs[added++] = e;
|
||||
}
|
||||
if (added > 0) {
|
||||
Object[] newElements = Arrays.copyOf(elements, len + added);
|
||||
System.arraycopy(uniq, 0, newElements, len, added);
|
||||
System.arraycopy(cs, 0, newElements, len, added);
|
||||
setArray(newElements);
|
||||
}
|
||||
return added;
|
||||
@ -771,12 +807,13 @@ public class CopyOnWriteArrayList<E>
|
||||
* collection's iterator.
|
||||
*
|
||||
* @param c collection containing elements to be added to this list
|
||||
* @return <tt>true</tt> if this list changed as a result of the call
|
||||
* @return {@code true} if this list 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) {
|
||||
Object[] cs = c.toArray();
|
||||
Object[] cs = (c.getClass() == CopyOnWriteArrayList.class) ?
|
||||
((CopyOnWriteArrayList<?>)c).getArray() : c.toArray();
|
||||
if (cs.length == 0)
|
||||
return false;
|
||||
final ReentrantLock lock = this.lock;
|
||||
@ -784,9 +821,13 @@ public class CopyOnWriteArrayList<E>
|
||||
try {
|
||||
Object[] elements = getArray();
|
||||
int len = elements.length;
|
||||
Object[] newElements = Arrays.copyOf(elements, len + cs.length);
|
||||
System.arraycopy(cs, 0, newElements, len, cs.length);
|
||||
setArray(newElements);
|
||||
if (len == 0 && cs.getClass() == Object[].class)
|
||||
setArray(cs);
|
||||
else {
|
||||
Object[] newElements = Arrays.copyOf(elements, len + cs.length);
|
||||
System.arraycopy(cs, 0, newElements, len, cs.length);
|
||||
setArray(newElements);
|
||||
}
|
||||
return true;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
@ -804,7 +845,7 @@ public class CopyOnWriteArrayList<E>
|
||||
* @param index index at which to insert the first element
|
||||
* from the specified collection
|
||||
* @param c collection containing elements to be added to this list
|
||||
* @return <tt>true</tt> if this list changed as a result of the call
|
||||
* @return {@code true} if this list changed as a result of the call
|
||||
* @throws IndexOutOfBoundsException {@inheritDoc}
|
||||
* @throws NullPointerException if the specified collection is null
|
||||
* @see #add(int,Object)
|
||||
@ -840,6 +881,74 @@ public class CopyOnWriteArrayList<E>
|
||||
}
|
||||
}
|
||||
|
||||
public void forEach(Consumer<? super E> action) {
|
||||
if (action == null) throw new NullPointerException();
|
||||
Object[] elements = getArray();
|
||||
int len = elements.length;
|
||||
for (int i = 0; i < len; ++i) {
|
||||
@SuppressWarnings("unchecked") E e = (E) elements[i];
|
||||
action.accept(e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean removeIf(Predicate<? super E> filter) {
|
||||
if (filter == null) throw new NullPointerException();
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
Object[] elements = getArray();
|
||||
int len = elements.length;
|
||||
if (len != 0) {
|
||||
int newlen = 0;
|
||||
Object[] temp = new Object[len];
|
||||
for (int i = 0; i < len; ++i) {
|
||||
@SuppressWarnings("unchecked") E e = (E) elements[i];
|
||||
if (!filter.test(e))
|
||||
temp[newlen++] = e;
|
||||
}
|
||||
if (newlen != len) {
|
||||
setArray(Arrays.copyOf(temp, newlen));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void replaceAll(UnaryOperator<E> operator) {
|
||||
if (operator == null) throw new NullPointerException();
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
Object[] elements = getArray();
|
||||
int len = elements.length;
|
||||
Object[] newElements = Arrays.copyOf(elements, len);
|
||||
for (int i = 0; i < len; ++i) {
|
||||
@SuppressWarnings("unchecked") E e = (E) elements[i];
|
||||
newElements[i] = operator.apply(e);
|
||||
}
|
||||
setArray(newElements);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void sort(Comparator<? super E> c) {
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
Object[] elements = getArray();
|
||||
Object[] newElements = Arrays.copyOf(elements, elements.length);
|
||||
@SuppressWarnings("unchecked") E[] es = (E[])newElements;
|
||||
Arrays.sort(es, c);
|
||||
setArray(newElements);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves this list to a stream (that is, serializes it).
|
||||
*
|
||||
@ -886,8 +995,8 @@ public class CopyOnWriteArrayList<E>
|
||||
* Returns a string representation of this list. The string
|
||||
* representation consists of the string representations of the list's
|
||||
* elements in the order they are returned by its iterator, enclosed in
|
||||
* square brackets (<tt>"[]"</tt>). Adjacent elements are separated by
|
||||
* the characters <tt>", "</tt> (comma and space). Elements are
|
||||
* square brackets ({@code "[]"}). Adjacent elements are separated by
|
||||
* the characters {@code ", "} (comma and space). Elements are
|
||||
* converted to strings as by {@link String#valueOf(Object)}.
|
||||
*
|
||||
* @return a string representation of this list
|
||||
@ -953,7 +1062,7 @@ public class CopyOnWriteArrayList<E>
|
||||
* <p>The returned iterator provides a snapshot of the state of the list
|
||||
* 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.
|
||||
* {@code remove} method.
|
||||
*
|
||||
* @return an iterator over the elements in this list in proper sequence
|
||||
*/
|
||||
@ -967,7 +1076,7 @@ public class CopyOnWriteArrayList<E>
|
||||
* <p>The returned iterator provides a snapshot of the state of the list
|
||||
* when the iterator was constructed. No synchronization is needed while
|
||||
* traversing the iterator. The iterator does <em>NOT</em> support the
|
||||
* <tt>remove</tt>, <tt>set</tt> or <tt>add</tt> methods.
|
||||
* {@code remove}, {@code set} or {@code add} methods.
|
||||
*/
|
||||
public ListIterator<E> listIterator() {
|
||||
return new COWIterator<E>(getArray(), 0);
|
||||
@ -979,7 +1088,7 @@ public class CopyOnWriteArrayList<E>
|
||||
* <p>The returned iterator provides a snapshot of the state of the list
|
||||
* when the iterator was constructed. No synchronization is needed while
|
||||
* traversing the iterator. The iterator does <em>NOT</em> support the
|
||||
* <tt>remove</tt>, <tt>set</tt> or <tt>add</tt> methods.
|
||||
* {@code remove}, {@code set} or {@code add} methods.
|
||||
*
|
||||
* @throws IndexOutOfBoundsException {@inheritDoc}
|
||||
*/
|
||||
@ -992,7 +1101,12 @@ public class CopyOnWriteArrayList<E>
|
||||
return new COWIterator<E>(elements, index);
|
||||
}
|
||||
|
||||
private static class COWIterator<E> implements ListIterator<E> {
|
||||
public Spliterator<E> spliterator() {
|
||||
return Spliterators.spliterator
|
||||
(getArray(), Spliterator.IMMUTABLE | Spliterator.ORDERED);
|
||||
}
|
||||
|
||||
static final class COWIterator<E> implements ListIterator<E> {
|
||||
/** Snapshot of the array */
|
||||
private final Object[] snapshot;
|
||||
/** Index of element to be returned by subsequent call to next. */
|
||||
@ -1035,7 +1149,7 @@ public class CopyOnWriteArrayList<E>
|
||||
|
||||
/**
|
||||
* Not supported. Always throws UnsupportedOperationException.
|
||||
* @throws UnsupportedOperationException always; <tt>remove</tt>
|
||||
* @throws UnsupportedOperationException always; {@code remove}
|
||||
* is not supported by this iterator.
|
||||
*/
|
||||
public void remove() {
|
||||
@ -1044,7 +1158,7 @@ public class CopyOnWriteArrayList<E>
|
||||
|
||||
/**
|
||||
* Not supported. Always throws UnsupportedOperationException.
|
||||
* @throws UnsupportedOperationException always; <tt>set</tt>
|
||||
* @throws UnsupportedOperationException always; {@code set}
|
||||
* is not supported by this iterator.
|
||||
*/
|
||||
public void set(E e) {
|
||||
@ -1053,7 +1167,7 @@ public class CopyOnWriteArrayList<E>
|
||||
|
||||
/**
|
||||
* Not supported. Always throws UnsupportedOperationException.
|
||||
* @throws UnsupportedOperationException always; <tt>add</tt>
|
||||
* @throws UnsupportedOperationException always; {@code add}
|
||||
* is not supported by this iterator.
|
||||
*/
|
||||
public void add(E e) {
|
||||
@ -1061,12 +1175,13 @@ public class CopyOnWriteArrayList<E>
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void forEachRemaining(Consumer<? super E> action) {
|
||||
Objects.requireNonNull(action);
|
||||
final int size = snapshot.length;
|
||||
for (int i=cursor; i < size; i++) {
|
||||
action.accept((E) snapshot[i]);
|
||||
Object[] elements = snapshot;
|
||||
final int size = elements.length;
|
||||
for (int i = cursor; i < size; i++) {
|
||||
@SuppressWarnings("unchecked") E e = (E) elements[i];
|
||||
action.accept(e);
|
||||
}
|
||||
cursor = size;
|
||||
}
|
||||
@ -1074,7 +1189,7 @@ public class CopyOnWriteArrayList<E>
|
||||
|
||||
/**
|
||||
* Returns a view of the portion of this list between
|
||||
* <tt>fromIndex</tt>, inclusive, and <tt>toIndex</tt>, exclusive.
|
||||
* {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
|
||||
* The returned list is backed by this list, so changes in the
|
||||
* returned list are reflected in this list.
|
||||
*
|
||||
@ -1274,55 +1389,196 @@ public class CopyOnWriteArrayList<E>
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEach(Consumer<? super E> action) {
|
||||
@SuppressWarnings("unchecked")
|
||||
final E[] elements = (E[]) l.getArray();
|
||||
checkForComodification();
|
||||
l.forEach(action, elements, offset, offset + size);
|
||||
if (action == null) throw new NullPointerException();
|
||||
int lo = offset;
|
||||
int hi = offset + size;
|
||||
Object[] a = expectedArray;
|
||||
if (l.getArray() != a)
|
||||
throw new ConcurrentModificationException();
|
||||
if (lo < 0 || hi > a.length)
|
||||
throw new IndexOutOfBoundsException();
|
||||
for (int i = lo; i < hi; ++i) {
|
||||
@SuppressWarnings("unchecked") E e = (E) a[i];
|
||||
action.accept(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void replaceAll(UnaryOperator<E> operator) {
|
||||
if (operator == null) throw new NullPointerException();
|
||||
final ReentrantLock lock = l.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
int lo = offset;
|
||||
int hi = offset + size;
|
||||
Object[] elements = expectedArray;
|
||||
if (l.getArray() != elements)
|
||||
throw new ConcurrentModificationException();
|
||||
int len = elements.length;
|
||||
if (lo < 0 || hi > len)
|
||||
throw new IndexOutOfBoundsException();
|
||||
Object[] newElements = Arrays.copyOf(elements, len);
|
||||
for (int i = lo; i < hi; ++i) {
|
||||
@SuppressWarnings("unchecked") E e = (E) elements[i];
|
||||
newElements[i] = operator.apply(e);
|
||||
}
|
||||
l.setArray(expectedArray = newElements);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sort(Comparator<? super E> c) {
|
||||
final ReentrantLock lock = l.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
checkForComodification();
|
||||
l.sort(c, offset, offset + size);
|
||||
expectedArray = l.getArray();
|
||||
int lo = offset;
|
||||
int hi = offset + size;
|
||||
Object[] elements = expectedArray;
|
||||
if (l.getArray() != elements)
|
||||
throw new ConcurrentModificationException();
|
||||
int len = elements.length;
|
||||
if (lo < 0 || hi > len)
|
||||
throw new IndexOutOfBoundsException();
|
||||
Object[] newElements = Arrays.copyOf(elements, len);
|
||||
@SuppressWarnings("unchecked") E[] es = (E[])newElements;
|
||||
Arrays.sort(es, lo, hi, c);
|
||||
l.setArray(expectedArray = newElements);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
if (c == null) throw new NullPointerException();
|
||||
boolean removed = false;
|
||||
final ReentrantLock lock = l.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
int n = size;
|
||||
if (n > 0) {
|
||||
int lo = offset;
|
||||
int hi = offset + n;
|
||||
Object[] elements = expectedArray;
|
||||
if (l.getArray() != elements)
|
||||
throw new ConcurrentModificationException();
|
||||
int len = elements.length;
|
||||
if (lo < 0 || hi > len)
|
||||
throw new IndexOutOfBoundsException();
|
||||
int newSize = 0;
|
||||
Object[] temp = new Object[n];
|
||||
for (int i = lo; i < hi; ++i) {
|
||||
Object element = elements[i];
|
||||
if (!c.contains(element))
|
||||
temp[newSize++] = element;
|
||||
}
|
||||
if (newSize != n) {
|
||||
Object[] newElements = new Object[len - n + newSize];
|
||||
System.arraycopy(elements, 0, newElements, 0, lo);
|
||||
System.arraycopy(temp, 0, newElements, lo, newSize);
|
||||
System.arraycopy(elements, hi, newElements,
|
||||
lo + newSize, len - hi);
|
||||
size = newSize;
|
||||
removed = true;
|
||||
l.setArray(expectedArray = newElements);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
if (c == null) throw new NullPointerException();
|
||||
boolean removed = false;
|
||||
final ReentrantLock lock = l.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
int n = size;
|
||||
if (n > 0) {
|
||||
int lo = offset;
|
||||
int hi = offset + n;
|
||||
Object[] elements = expectedArray;
|
||||
if (l.getArray() != elements)
|
||||
throw new ConcurrentModificationException();
|
||||
int len = elements.length;
|
||||
if (lo < 0 || hi > len)
|
||||
throw new IndexOutOfBoundsException();
|
||||
int newSize = 0;
|
||||
Object[] temp = new Object[n];
|
||||
for (int i = lo; i < hi; ++i) {
|
||||
Object element = elements[i];
|
||||
if (c.contains(element))
|
||||
temp[newSize++] = element;
|
||||
}
|
||||
if (newSize != n) {
|
||||
Object[] newElements = new Object[len - n + newSize];
|
||||
System.arraycopy(elements, 0, newElements, 0, lo);
|
||||
System.arraycopy(temp, 0, newElements, lo, newSize);
|
||||
System.arraycopy(elements, hi, newElements,
|
||||
lo + newSize, len - hi);
|
||||
size = newSize;
|
||||
removed = true;
|
||||
l.setArray(expectedArray = newElements);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
public boolean removeIf(Predicate<? super E> filter) {
|
||||
Objects.requireNonNull(filter);
|
||||
if (filter == null) throw new NullPointerException();
|
||||
boolean removed = false;
|
||||
final ReentrantLock lock = l.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
checkForComodification();
|
||||
final int removeCount =
|
||||
l.removeIf(filter, offset, offset + size);
|
||||
expectedArray = l.getArray();
|
||||
size -= removeCount;
|
||||
return removeCount > 0;
|
||||
int n = size;
|
||||
if (n > 0) {
|
||||
int lo = offset;
|
||||
int hi = offset + n;
|
||||
Object[] elements = expectedArray;
|
||||
if (l.getArray() != elements)
|
||||
throw new ConcurrentModificationException();
|
||||
int len = elements.length;
|
||||
if (lo < 0 || hi > len)
|
||||
throw new IndexOutOfBoundsException();
|
||||
int newSize = 0;
|
||||
Object[] temp = new Object[n];
|
||||
for (int i = lo; i < hi; ++i) {
|
||||
@SuppressWarnings("unchecked") E e = (E) elements[i];
|
||||
if (!filter.test(e))
|
||||
temp[newSize++] = e;
|
||||
}
|
||||
if (newSize != n) {
|
||||
Object[] newElements = new Object[len - n + newSize];
|
||||
System.arraycopy(elements, 0, newElements, 0, lo);
|
||||
System.arraycopy(temp, 0, newElements, lo, newSize);
|
||||
System.arraycopy(elements, hi, newElements,
|
||||
lo + newSize, len - hi);
|
||||
size = newSize;
|
||||
removed = true;
|
||||
l.setArray(expectedArray = newElements);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replaceAll(UnaryOperator<E> operator) {
|
||||
final ReentrantLock lock = l.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
checkForComodification();
|
||||
l.replaceAll(operator, offset, offset + size);
|
||||
expectedArray = l.getArray();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
public Spliterator<E> spliterator() {
|
||||
int lo = offset;
|
||||
int hi = offset + size;
|
||||
Object[] a = expectedArray;
|
||||
if (l.getArray() != a)
|
||||
throw new ConcurrentModificationException();
|
||||
if (lo < 0 || hi > a.length)
|
||||
throw new IndexOutOfBoundsException();
|
||||
return Spliterators.spliterator
|
||||
(a, lo, hi, Spliterator.IMMUTABLE | Spliterator.ORDERED);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1380,11 +1636,12 @@ public class CopyOnWriteArrayList<E>
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void forEachRemaining(Consumer<? super E> action) {
|
||||
Objects.requireNonNull(action);
|
||||
while (nextIndex() < size) {
|
||||
action.accept(it.next());
|
||||
int s = size;
|
||||
ListIterator<E> i = it;
|
||||
while (nextIndex() < s) {
|
||||
action.accept(i.next());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1405,139 +1662,4 @@ public class CopyOnWriteArrayList<E>
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void forEach(Consumer<? super E> action) {
|
||||
forEach(action, (E[]) getArray(), 0, size());
|
||||
}
|
||||
|
||||
private void forEach(Consumer<? super E> action,
|
||||
final E[] elements,
|
||||
final int from, final int to) {
|
||||
Objects.requireNonNull(action);
|
||||
for (int i = from; i < to; i++) {
|
||||
action.accept(elements[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sort(Comparator<? super E> c) {
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
sort(c, 0, size());
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
// must be called with this.lock held
|
||||
@SuppressWarnings("unchecked")
|
||||
private void sort(Comparator<? super E> c, final int from, final int to) {
|
||||
final E[] elements = (E[]) getArray();
|
||||
final E[] newElements = Arrays.copyOf(elements, elements.length);
|
||||
// only elements [from, to) are sorted
|
||||
Arrays.sort(newElements, from, to, c);
|
||||
setArray(newElements);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeIf(Predicate<? super E> filter) {
|
||||
Objects.requireNonNull(filter);
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
return removeIf(filter, 0, size()) > 0;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
// must be called with this.lock held
|
||||
private int removeIf(Predicate<? super E> filter, final int from, final int to) {
|
||||
Objects.requireNonNull(filter);
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
final E[] elements = (E[]) getArray();
|
||||
|
||||
// figure out which elements are to be removed
|
||||
// any exception thrown from the filter predicate at this stage
|
||||
// will leave the collection unmodified
|
||||
int removeCount = 0;
|
||||
final int range = to - from;
|
||||
final BitSet removeSet = new BitSet(range);
|
||||
for (int i = 0; i < range; i++) {
|
||||
final E element = elements[from + i];
|
||||
if (filter.test(element)) {
|
||||
// removeSet is zero-based to keep its size small
|
||||
removeSet.set(i);
|
||||
removeCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// copy surviving elements into a new array
|
||||
if (removeCount > 0) {
|
||||
final int newSize = elements.length - removeCount;
|
||||
final int newRange = newSize - from;
|
||||
@SuppressWarnings("unchecked")
|
||||
final E[] newElements = (E[]) new Object[newSize];
|
||||
// copy elements before [from, to) unmodified
|
||||
for (int i = 0; i < from; i++) {
|
||||
newElements[i] = elements[i];
|
||||
}
|
||||
// elements [from, to) are subject to removal
|
||||
int j = 0;
|
||||
for (int i = 0; (i < range) && (j < newRange); i++) {
|
||||
i = removeSet.nextClearBit(i);
|
||||
if (i >= range) {
|
||||
break;
|
||||
}
|
||||
newElements[from + (j++)] = elements[from + i];
|
||||
}
|
||||
// copy any remaining elements beyond [from, to)
|
||||
j += from;
|
||||
for (int i = to; (i < elements.length) && (j < newSize); i++) {
|
||||
newElements[j++] = elements[i];
|
||||
}
|
||||
setArray(newElements);
|
||||
}
|
||||
|
||||
return removeCount;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replaceAll(UnaryOperator<E> operator) {
|
||||
Objects.requireNonNull(operator);
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
replaceAll(operator, 0, size());
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
// must be called with this.lock held
|
||||
@SuppressWarnings("unchecked")
|
||||
private void replaceAll(UnaryOperator<E> operator, final int from, final int to) {
|
||||
final E[] elements = (E[]) getArray();
|
||||
final E[] newElements = (E[]) new Object[elements.length];
|
||||
for (int i = 0; i < from; i++) {
|
||||
newElements[i] = elements[i];
|
||||
}
|
||||
// the operator is only applied to elements [from, to)
|
||||
for (int i = from; i < to; i++) {
|
||||
newElements[i] = operator.apply(elements[i]);
|
||||
}
|
||||
for (int i = to; i < elements.length; i++) {
|
||||
newElements[i] = elements[i];
|
||||
}
|
||||
setArray(newElements);
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,7 +34,14 @@
|
||||
*/
|
||||
|
||||
package java.util.concurrent;
|
||||
import java.util.*;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Spliterator;
|
||||
import java.util.Spliterators;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* A {@link java.util.Set} that uses an internal {@link CopyOnWriteArrayList}
|
||||
@ -45,17 +52,17 @@ import java.util.*;
|
||||
* 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.)
|
||||
* <li>Mutative operations ({@code add}, {@code set}, {@code remove}, etc.)
|
||||
* are expensive since they usually entail copying the entire underlying
|
||||
* array.
|
||||
* <li>Iterators do not support the mutative <tt>remove</tt> operation.
|
||||
* <li>Iterators do not support the mutative {@code remove} 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
|
||||
* <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.
|
||||
*
|
||||
@ -73,7 +80,7 @@ import java.util.*;
|
||||
* public void update() {
|
||||
* changeState();
|
||||
* for (Handler handler : handlers)
|
||||
* handler.handle();
|
||||
* handler.handle();
|
||||
* }
|
||||
* }}</pre>
|
||||
*
|
||||
@ -107,8 +114,15 @@ public class CopyOnWriteArraySet<E> extends AbstractSet<E>
|
||||
* @throws NullPointerException if the specified collection is null
|
||||
*/
|
||||
public CopyOnWriteArraySet(Collection<? extends E> c) {
|
||||
al = new CopyOnWriteArrayList<E>();
|
||||
al.addAllAbsent(c);
|
||||
if (c.getClass() == CopyOnWriteArraySet.class) {
|
||||
@SuppressWarnings("unchecked") CopyOnWriteArraySet<E> cc =
|
||||
(CopyOnWriteArraySet<E>)c;
|
||||
al = new CopyOnWriteArrayList<E>(cc.al);
|
||||
}
|
||||
else {
|
||||
al = new CopyOnWriteArrayList<E>();
|
||||
al.addAllAbsent(c);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -121,22 +135,22 @@ public class CopyOnWriteArraySet<E> extends AbstractSet<E>
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <tt>true</tt> if this set contains no elements.
|
||||
* Returns {@code true} if this set contains no elements.
|
||||
*
|
||||
* @return <tt>true</tt> if this set contains no elements
|
||||
* @return {@code true} 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
|
||||
* Returns {@code true} if this set contains the specified element.
|
||||
* More formally, returns {@code true} if and only if this set
|
||||
* contains an element {@code e} such that
|
||||
* <tt>(o==null ? e==null : o.equals(e))</tt>.
|
||||
*
|
||||
* @param o element whose presence in this set is to be tested
|
||||
* @return <tt>true</tt> if this set contains the specified element
|
||||
* @return {@code true} if this set contains the specified element
|
||||
*/
|
||||
public boolean contains(Object o) {
|
||||
return al.contains(o);
|
||||
@ -172,7 +186,7 @@ public class CopyOnWriteArraySet<E> extends AbstractSet<E>
|
||||
* <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
|
||||
* {@code null}. (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.)
|
||||
*
|
||||
@ -185,14 +199,14 @@ public class CopyOnWriteArraySet<E> extends AbstractSet<E>
|
||||
* 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.
|
||||
* <p>Suppose {@code x} 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>:
|
||||
* array of {@code String}:
|
||||
*
|
||||
* <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
|
||||
*
|
||||
* Note that <tt>toArray(new Object[0])</tt> is identical in function to
|
||||
* <tt>toArray()</tt>.
|
||||
* Note that {@code toArray(new Object[0])} is identical in function to
|
||||
* {@code toArray()}.
|
||||
*
|
||||
* @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
|
||||
@ -217,15 +231,15 @@ public class CopyOnWriteArraySet<E> extends AbstractSet<E>
|
||||
|
||||
/**
|
||||
* Removes the specified element from this set if it is present.
|
||||
* More formally, removes an element <tt>e</tt> such that
|
||||
* More formally, removes an element {@code e} such that
|
||||
* <tt>(o==null ? e==null : o.equals(e))</tt>,
|
||||
* if this set contains such an element. Returns <tt>true</tt> if
|
||||
* if this set contains such an element. Returns {@code true} if
|
||||
* this set contained the element (or equivalently, if this set
|
||||
* changed as a result of the call). (This set will not contain the
|
||||
* element once the call returns.)
|
||||
*
|
||||
* @param o object to be removed from this set, if present
|
||||
* @return <tt>true</tt> if this set contained the specified element
|
||||
* @return {@code true} if this set contained the specified element
|
||||
*/
|
||||
public boolean remove(Object o) {
|
||||
return al.remove(o);
|
||||
@ -233,14 +247,14 @@ public class CopyOnWriteArraySet<E> extends AbstractSet<E>
|
||||
|
||||
/**
|
||||
* Adds the specified element to this set if it is not already present.
|
||||
* More formally, adds the specified element <tt>e</tt> to this set if
|
||||
* the set contains no element <tt>e2</tt> such that
|
||||
* More formally, adds the specified element {@code e} to this set if
|
||||
* the set contains no element {@code e2} such that
|
||||
* <tt>(e==null ? e2==null : e.equals(e2))</tt>.
|
||||
* If this set already contains the element, the call leaves the set
|
||||
* unchanged and returns <tt>false</tt>.
|
||||
* unchanged and returns {@code false}.
|
||||
*
|
||||
* @param e element to be added to this set
|
||||
* @return <tt>true</tt> if this set did not already contain the specified
|
||||
* @return {@code true} if this set did not already contain the specified
|
||||
* element
|
||||
*/
|
||||
public boolean add(E e) {
|
||||
@ -248,12 +262,12 @@ public class CopyOnWriteArraySet<E> extends AbstractSet<E>
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <tt>true</tt> if this set contains all of the elements of the
|
||||
* Returns {@code true} 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.
|
||||
* method returns {@code true} 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
|
||||
* @return {@code true} if this set contains all of the elements of the
|
||||
* specified collection
|
||||
* @throws NullPointerException if the specified collection is null
|
||||
* @see #contains(Object)
|
||||
@ -265,13 +279,13 @@ public class CopyOnWriteArraySet<E> extends AbstractSet<E>
|
||||
/**
|
||||
* 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
|
||||
* set, the {@code addAll} 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
|
||||
* @return {@code true} if this set changed as a result of the call
|
||||
* @throws NullPointerException if the specified collection is null
|
||||
* @see #add(Object)
|
||||
*/
|
||||
@ -286,7 +300,7 @@ public class CopyOnWriteArraySet<E> extends AbstractSet<E>
|
||||
* <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
|
||||
* @return {@code true} if this set changed as a result of the call
|
||||
* @throws ClassCastException if the class of an element of this set
|
||||
* is incompatible with the specified collection (optional)
|
||||
* @throws NullPointerException if this set contains a null element and the
|
||||
@ -307,7 +321,7 @@ public class CopyOnWriteArraySet<E> extends AbstractSet<E>
|
||||
* 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
|
||||
* @return {@code true} if this set changed as a result of the call
|
||||
* @throws ClassCastException if the class of an element of this set
|
||||
* is incompatible with the specified collection (optional)
|
||||
* @throws NullPointerException if this set contains a null element and the
|
||||
@ -326,7 +340,7 @@ public class CopyOnWriteArraySet<E> extends AbstractSet<E>
|
||||
* <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.
|
||||
* {@code remove} method.
|
||||
*
|
||||
* @return an iterator over the elements in this set
|
||||
*/
|
||||
@ -338,7 +352,7 @@ public class CopyOnWriteArraySet<E> extends AbstractSet<E>
|
||||
* 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
|
||||
* returned by an {@linkplain Set#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
|
||||
@ -382,6 +396,19 @@ public class CopyOnWriteArraySet<E> extends AbstractSet<E>
|
||||
return k == len;
|
||||
}
|
||||
|
||||
public boolean removeIf(Predicate<? super E> filter) {
|
||||
return al.removeIf(filter);
|
||||
}
|
||||
|
||||
public void forEach(Consumer<? super E> action) {
|
||||
al.forEach(action);
|
||||
}
|
||||
|
||||
public Spliterator<E> spliterator() {
|
||||
return Spliterators.spliterator
|
||||
(al.getArray(), Spliterator.IMMUTABLE | Spliterator.DISTINCT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for equality, coping with nulls.
|
||||
*/
|
||||
|
||||
@ -33,28 +33,31 @@
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
|
||||
package java.util.concurrent;
|
||||
import java.util.concurrent.locks.*;
|
||||
import static java.util.concurrent.TimeUnit.NANOSECONDS;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* An unbounded {@linkplain BlockingQueue blocking queue} of
|
||||
* <tt>Delayed</tt> elements, in which an element can only be taken
|
||||
* {@code Delayed} 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
|
||||
* {@code Delayed} element whose delay expired furthest in the
|
||||
* past. If no delay has expired there is no head and {@code poll}
|
||||
* will return {@code null}. Expiration occurs when an element's
|
||||
* {@code getDelay(TimeUnit.NANOSECONDS)} 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
|
||||
* removed using {@code take} or {@code poll}, they are otherwise
|
||||
* treated as normal elements. For example, the {@code size} 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.
|
||||
* Iterator} interfaces. The Iterator provided in method {@link
|
||||
* #iterator()} is <em>not</em> guaranteed to traverse the elements of
|
||||
* the DelayQueue in any particular order.
|
||||
*
|
||||
* <p>This class is a member of the
|
||||
* <a href="{@docRoot}/../technotes/guides/collections/index.html">
|
||||
@ -64,11 +67,10 @@ import java.util.*;
|
||||
* @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 final transient ReentrantLock lock = new ReentrantLock();
|
||||
private final PriorityQueue<E> q = new PriorityQueue<E>();
|
||||
|
||||
/**
|
||||
@ -97,12 +99,12 @@ public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
|
||||
private final Condition available = lock.newCondition();
|
||||
|
||||
/**
|
||||
* Creates a new <tt>DelayQueue</tt> that is initially empty.
|
||||
* Creates a new {@code DelayQueue} that is initially empty.
|
||||
*/
|
||||
public DelayQueue() {}
|
||||
|
||||
/**
|
||||
* Creates a <tt>DelayQueue</tt> initially containing the elements of the
|
||||
* Creates a {@code DelayQueue} initially containing the elements of the
|
||||
* given collection of {@link Delayed} instances.
|
||||
*
|
||||
* @param c the collection of elements to initially contain
|
||||
@ -117,7 +119,7 @@ public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
|
||||
* Inserts the specified element into this delay queue.
|
||||
*
|
||||
* @param e the element to add
|
||||
* @return <tt>true</tt> (as specified by {@link Collection#add})
|
||||
* @return {@code true} (as specified by {@link Collection#add})
|
||||
* @throws NullPointerException if the specified element is null
|
||||
*/
|
||||
public boolean add(E e) {
|
||||
@ -128,7 +130,7 @@ public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
|
||||
* Inserts the specified element into this delay queue.
|
||||
*
|
||||
* @param e the element to add
|
||||
* @return <tt>true</tt>
|
||||
* @return {@code true}
|
||||
* @throws NullPointerException if the specified element is null
|
||||
*/
|
||||
public boolean offer(E e) {
|
||||
@ -164,7 +166,7 @@ public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
|
||||
* @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>
|
||||
* @return {@code true}
|
||||
* @throws NullPointerException {@inheritDoc}
|
||||
*/
|
||||
public boolean offer(E e, long timeout, TimeUnit unit) {
|
||||
@ -172,10 +174,10 @@ public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves and removes the head of this queue, or returns <tt>null</tt>
|
||||
* Retrieves and removes the head of this queue, or returns {@code null}
|
||||
* if this queue has no elements with an expired delay.
|
||||
*
|
||||
* @return the head of this queue, or <tt>null</tt> if this
|
||||
* @return the head of this queue, or {@code null} if this
|
||||
* queue has no elements with an expired delay
|
||||
*/
|
||||
public E poll() {
|
||||
@ -183,7 +185,7 @@ public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
|
||||
lock.lock();
|
||||
try {
|
||||
E first = q.peek();
|
||||
if (first == null || first.getDelay(TimeUnit.NANOSECONDS) > 0)
|
||||
if (first == null || first.getDelay(NANOSECONDS) > 0)
|
||||
return null;
|
||||
else
|
||||
return q.poll();
|
||||
@ -208,10 +210,11 @@ public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
|
||||
if (first == null)
|
||||
available.await();
|
||||
else {
|
||||
long delay = first.getDelay(TimeUnit.NANOSECONDS);
|
||||
long delay = first.getDelay(NANOSECONDS);
|
||||
if (delay <= 0)
|
||||
return q.poll();
|
||||
else if (leader != null)
|
||||
first = null; // don't retain ref while waiting
|
||||
if (leader != null)
|
||||
available.await();
|
||||
else {
|
||||
Thread thisThread = Thread.currentThread();
|
||||
@ -237,7 +240,7 @@ public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
|
||||
* 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
|
||||
* @return the head of this queue, or {@code null} if the
|
||||
* specified waiting time elapses before an element with
|
||||
* an expired delay becomes available
|
||||
* @throws InterruptedException {@inheritDoc}
|
||||
@ -255,11 +258,12 @@ public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
|
||||
else
|
||||
nanos = available.awaitNanos(nanos);
|
||||
} else {
|
||||
long delay = first.getDelay(TimeUnit.NANOSECONDS);
|
||||
long delay = first.getDelay(NANOSECONDS);
|
||||
if (delay <= 0)
|
||||
return q.poll();
|
||||
if (nanos <= 0)
|
||||
return null;
|
||||
first = null; // don't retain ref while waiting
|
||||
if (nanos < delay || leader != null)
|
||||
nanos = available.awaitNanos(nanos);
|
||||
else {
|
||||
@ -284,13 +288,13 @@ public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
|
||||
|
||||
/**
|
||||
* 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,
|
||||
* returns {@code null} if this queue is empty. Unlike
|
||||
* {@code poll}, 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.
|
||||
* @return the head of this queue, or {@code null} if this
|
||||
* queue is empty
|
||||
*/
|
||||
public E peek() {
|
||||
final ReentrantLock lock = this.lock;
|
||||
@ -312,6 +316,17 @@ public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns first element only if it is expired.
|
||||
* Used only by drainTo. Call only when holding lock.
|
||||
*/
|
||||
private E peekExpired() {
|
||||
// assert lock.isHeldByCurrentThread();
|
||||
E first = q.peek();
|
||||
return (first == null || first.getDelay(NANOSECONDS) > 0) ?
|
||||
null : first;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws UnsupportedOperationException {@inheritDoc}
|
||||
* @throws ClassCastException {@inheritDoc}
|
||||
@ -327,11 +342,9 @@ public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
|
||||
lock.lock();
|
||||
try {
|
||||
int n = 0;
|
||||
for (;;) {
|
||||
E first = q.peek();
|
||||
if (first == null || first.getDelay(TimeUnit.NANOSECONDS) > 0)
|
||||
break;
|
||||
c.add(q.poll());
|
||||
for (E e; (e = peekExpired()) != null;) {
|
||||
c.add(e); // In this order, in case add() throws.
|
||||
q.poll();
|
||||
++n;
|
||||
}
|
||||
return n;
|
||||
@ -357,11 +370,9 @@ public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
|
||||
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());
|
||||
for (E e; n < maxElements && (e = peekExpired()) != null;) {
|
||||
c.add(e); // In this order, in case add() throws.
|
||||
q.poll();
|
||||
++n;
|
||||
}
|
||||
return n;
|
||||
@ -387,10 +398,10 @@ public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns <tt>Integer.MAX_VALUE</tt> because
|
||||
* a <tt>DelayQueue</tt> is not capacity constrained.
|
||||
* Always returns {@code Integer.MAX_VALUE} because
|
||||
* a {@code DelayQueue} is not capacity constrained.
|
||||
*
|
||||
* @return <tt>Integer.MAX_VALUE</tt>
|
||||
* @return {@code Integer.MAX_VALUE}
|
||||
*/
|
||||
public int remainingCapacity() {
|
||||
return Integer.MAX_VALUE;
|
||||
@ -430,7 +441,7 @@ public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
|
||||
* <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>.
|
||||
* {@code null}.
|
||||
*
|
||||
* <p>Like the {@link #toArray()} method, this method acts as bridge between
|
||||
* array-based and collection-based APIs. Further, this method allows
|
||||
@ -438,13 +449,12 @@ public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
|
||||
* 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>:
|
||||
* allocated array of {@code Delayed}:
|
||||
*
|
||||
* <pre>
|
||||
* Delayed[] a = q.toArray(new Delayed[0]);</pre>
|
||||
* <pre> {@code Delayed[] a = q.toArray(new Delayed[0]);}</pre>
|
||||
*
|
||||
* Note that <tt>toArray(new Object[0])</tt> is identical in function to
|
||||
* <tt>toArray()</tt>.
|
||||
* Note that {@code toArray(new Object[0])} is identical in function to
|
||||
* {@code toArray()}.
|
||||
*
|
||||
* @param a the array into which the elements of the queue are to
|
||||
* be stored, if it is big enough; otherwise, a new array of the
|
||||
@ -479,6 +489,24 @@ public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Identity-based version for use in Itr.remove
|
||||
*/
|
||||
void removeEQ(Object o) {
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
for (Iterator<E> it = q.iterator(); it.hasNext(); ) {
|
||||
if (o == it.next()) {
|
||||
it.remove();
|
||||
break;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator over all the elements (both expired and
|
||||
* unexpired) in this queue. The iterator does not return the
|
||||
@ -502,7 +530,7 @@ public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
|
||||
*/
|
||||
private class Itr implements Iterator<E> {
|
||||
final Object[] array; // Array of all elements
|
||||
int cursor; // index of next element to return;
|
||||
int cursor; // index of next element to return
|
||||
int lastRet; // index of last element, or -1 if no such
|
||||
|
||||
Itr(Object[] array) {
|
||||
@ -525,21 +553,8 @@ public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
|
||||
public void remove() {
|
||||
if (lastRet < 0)
|
||||
throw new IllegalStateException();
|
||||
Object x = array[lastRet];
|
||||
removeEQ(array[lastRet]);
|
||||
lastRet = -1;
|
||||
// Traverse underlying queue to find == element,
|
||||
// not just a .equals element.
|
||||
lock.lock();
|
||||
try {
|
||||
for (Iterator<E> it = q.iterator(); it.hasNext(); ) {
|
||||
if (it.next() == x) {
|
||||
it.remove();
|
||||
return;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -40,8 +40,8 @@ package java.util.concurrent;
|
||||
* 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.
|
||||
* {@code compareTo} method that provides an ordering consistent with
|
||||
* its {@code getDelay} method.
|
||||
*
|
||||
* @since 1.5
|
||||
* @author Doug Lea
|
||||
|
||||
@ -41,12 +41,15 @@ import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.Spliterator;
|
||||
import java.util.Spliterators;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* An optionally-bounded {@linkplain BlockingDeque blocking deque} based on
|
||||
* linked nodes.
|
||||
*
|
||||
* <p> The optional capacity bound constructor argument serves as a
|
||||
* <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
|
||||
@ -315,8 +318,8 @@ public class LinkedBlockingDeque<E>
|
||||
// BlockingDeque methods
|
||||
|
||||
/**
|
||||
* @throws IllegalStateException {@inheritDoc}
|
||||
* @throws NullPointerException {@inheritDoc}
|
||||
* @throws IllegalStateException if this deque is full
|
||||
* @throws NullPointerException {@inheritDoc}
|
||||
*/
|
||||
public void addFirst(E e) {
|
||||
if (!offerFirst(e))
|
||||
@ -324,7 +327,7 @@ public class LinkedBlockingDeque<E>
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IllegalStateException {@inheritDoc}
|
||||
* @throws IllegalStateException if this deque is full
|
||||
* @throws NullPointerException {@inheritDoc}
|
||||
*/
|
||||
public void addLast(E e) {
|
||||
@ -623,8 +626,7 @@ public class LinkedBlockingDeque<E>
|
||||
*
|
||||
* <p>This method is equivalent to {@link #addLast}.
|
||||
*
|
||||
* @throws IllegalStateException if the element cannot be added at this
|
||||
* time due to capacity restrictions
|
||||
* @throws IllegalStateException if this deque is full
|
||||
* @throws NullPointerException if the specified element is null
|
||||
*/
|
||||
public boolean add(E e) {
|
||||
@ -761,8 +763,8 @@ public class LinkedBlockingDeque<E>
|
||||
// Stack methods
|
||||
|
||||
/**
|
||||
* @throws IllegalStateException {@inheritDoc}
|
||||
* @throws NullPointerException {@inheritDoc}
|
||||
* @throws IllegalStateException if this deque is full
|
||||
* @throws NullPointerException {@inheritDoc}
|
||||
*/
|
||||
public void push(E e) {
|
||||
addFirst(e);
|
||||
@ -852,7 +854,7 @@ public class LinkedBlockingDeque<E>
|
||||
// * @throws ClassCastException {@inheritDoc}
|
||||
// * @throws NullPointerException {@inheritDoc}
|
||||
// * @throws IllegalArgumentException {@inheritDoc}
|
||||
// * @throws IllegalStateException {@inheritDoc}
|
||||
// * @throws IllegalStateException if this deque is full
|
||||
// * @see #add(Object)
|
||||
// */
|
||||
// public boolean addAll(Collection<? extends E> c) {
|
||||
@ -1151,6 +1153,127 @@ public class LinkedBlockingDeque<E>
|
||||
Node<E> nextNode(Node<E> n) { return n.prev; }
|
||||
}
|
||||
|
||||
/** A customized variant of Spliterators.IteratorSpliterator */
|
||||
static final class LBDSpliterator<E> implements Spliterator<E> {
|
||||
static final int MAX_BATCH = 1 << 25; // max batch array size;
|
||||
final LinkedBlockingDeque<E> queue;
|
||||
Node<E> current; // current node; null until initialized
|
||||
int batch; // batch size for splits
|
||||
boolean exhausted; // true when no more nodes
|
||||
long est; // size estimate
|
||||
LBDSpliterator(LinkedBlockingDeque<E> queue) {
|
||||
this.queue = queue;
|
||||
this.est = queue.size();
|
||||
}
|
||||
|
||||
public long estimateSize() { return est; }
|
||||
|
||||
public Spliterator<E> trySplit() {
|
||||
Node<E> h;
|
||||
final LinkedBlockingDeque<E> q = this.queue;
|
||||
int b = batch;
|
||||
int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
|
||||
if (!exhausted &&
|
||||
((h = current) != null || (h = q.first) != null) &&
|
||||
h.next != null) {
|
||||
Object[] a = new Object[n];
|
||||
final ReentrantLock lock = q.lock;
|
||||
int i = 0;
|
||||
Node<E> p = current;
|
||||
lock.lock();
|
||||
try {
|
||||
if (p != null || (p = q.first) != null) {
|
||||
do {
|
||||
if ((a[i] = p.item) != null)
|
||||
++i;
|
||||
} while ((p = p.next) != null && i < n);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
if ((current = p) == null) {
|
||||
est = 0L;
|
||||
exhausted = true;
|
||||
}
|
||||
else if ((est -= i) < 0L)
|
||||
est = 0L;
|
||||
if (i > 0) {
|
||||
batch = i;
|
||||
return Spliterators.spliterator
|
||||
(a, 0, i, Spliterator.ORDERED | Spliterator.NONNULL |
|
||||
Spliterator.CONCURRENT);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void forEachRemaining(Consumer<? super E> action) {
|
||||
if (action == null) throw new NullPointerException();
|
||||
final LinkedBlockingDeque<E> q = this.queue;
|
||||
final ReentrantLock lock = q.lock;
|
||||
if (!exhausted) {
|
||||
exhausted = true;
|
||||
Node<E> p = current;
|
||||
do {
|
||||
E e = null;
|
||||
lock.lock();
|
||||
try {
|
||||
if (p == null)
|
||||
p = q.first;
|
||||
while (p != null) {
|
||||
e = p.item;
|
||||
p = p.next;
|
||||
if (e != null)
|
||||
break;
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
if (e != null)
|
||||
action.accept(e);
|
||||
} while (p != null);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean tryAdvance(Consumer<? super E> action) {
|
||||
if (action == null) throw new NullPointerException();
|
||||
final LinkedBlockingDeque<E> q = this.queue;
|
||||
final ReentrantLock lock = q.lock;
|
||||
if (!exhausted) {
|
||||
E e = null;
|
||||
lock.lock();
|
||||
try {
|
||||
if (current == null)
|
||||
current = q.first;
|
||||
while (current != null) {
|
||||
e = current.item;
|
||||
current = current.next;
|
||||
if (e != null)
|
||||
break;
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
if (current == null)
|
||||
exhausted = true;
|
||||
if (e != null) {
|
||||
action.accept(e);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int characteristics() {
|
||||
return Spliterator.ORDERED | Spliterator.NONNULL |
|
||||
Spliterator.CONCURRENT;
|
||||
}
|
||||
}
|
||||
|
||||
public Spliterator<E> spliterator() {
|
||||
return new LBDSpliterator<E>(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves this deque to a stream (that is, serializes it).
|
||||
*
|
||||
|
||||
@ -42,6 +42,9 @@ import java.util.AbstractQueue;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Spliterator;
|
||||
import java.util.Spliterators;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* An optionally-bounded {@linkplain BlockingQueue blocking queue} based on
|
||||
@ -56,7 +59,7 @@ import java.util.NoSuchElementException;
|
||||
* 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
|
||||
* <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
|
||||
@ -216,7 +219,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock to prevent both puts and takes.
|
||||
* Locks to prevent both puts and takes.
|
||||
*/
|
||||
void fullyLock() {
|
||||
putLock.lock();
|
||||
@ -224,7 +227,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlock to allow both puts and takes.
|
||||
* Unlocks to allow both puts and takes.
|
||||
*/
|
||||
void fullyUnlock() {
|
||||
takeLock.unlock();
|
||||
@ -362,7 +365,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
|
||||
* necessary up to the specified wait time for space to become available.
|
||||
*
|
||||
* @return {@code true} if successful, or {@code false} if
|
||||
* the specified waiting time elapses before space is available.
|
||||
* the specified waiting time elapses before space is available
|
||||
* @throws InterruptedException {@inheritDoc}
|
||||
* @throws NullPointerException {@inheritDoc}
|
||||
*/
|
||||
@ -782,6 +785,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
|
||||
* 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;
|
||||
@ -855,6 +859,124 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
|
||||
}
|
||||
}
|
||||
|
||||
/** A customized variant of Spliterators.IteratorSpliterator */
|
||||
static final class LBQSpliterator<E> implements Spliterator<E> {
|
||||
static final int MAX_BATCH = 1 << 25; // max batch array size;
|
||||
final LinkedBlockingQueue<E> queue;
|
||||
Node<E> current; // current node; null until initialized
|
||||
int batch; // batch size for splits
|
||||
boolean exhausted; // true when no more nodes
|
||||
long est; // size estimate
|
||||
LBQSpliterator(LinkedBlockingQueue<E> queue) {
|
||||
this.queue = queue;
|
||||
this.est = queue.size();
|
||||
}
|
||||
|
||||
public long estimateSize() { return est; }
|
||||
|
||||
public Spliterator<E> trySplit() {
|
||||
Node<E> h;
|
||||
final LinkedBlockingQueue<E> q = this.queue;
|
||||
int b = batch;
|
||||
int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
|
||||
if (!exhausted &&
|
||||
((h = current) != null || (h = q.head.next) != null) &&
|
||||
h.next != null) {
|
||||
Object[] a = new Object[n];
|
||||
int i = 0;
|
||||
Node<E> p = current;
|
||||
q.fullyLock();
|
||||
try {
|
||||
if (p != null || (p = q.head.next) != null) {
|
||||
do {
|
||||
if ((a[i] = p.item) != null)
|
||||
++i;
|
||||
} while ((p = p.next) != null && i < n);
|
||||
}
|
||||
} finally {
|
||||
q.fullyUnlock();
|
||||
}
|
||||
if ((current = p) == null) {
|
||||
est = 0L;
|
||||
exhausted = true;
|
||||
}
|
||||
else if ((est -= i) < 0L)
|
||||
est = 0L;
|
||||
if (i > 0) {
|
||||
batch = i;
|
||||
return Spliterators.spliterator
|
||||
(a, 0, i, Spliterator.ORDERED | Spliterator.NONNULL |
|
||||
Spliterator.CONCURRENT);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void forEachRemaining(Consumer<? super E> action) {
|
||||
if (action == null) throw new NullPointerException();
|
||||
final LinkedBlockingQueue<E> q = this.queue;
|
||||
if (!exhausted) {
|
||||
exhausted = true;
|
||||
Node<E> p = current;
|
||||
do {
|
||||
E e = null;
|
||||
q.fullyLock();
|
||||
try {
|
||||
if (p == null)
|
||||
p = q.head.next;
|
||||
while (p != null) {
|
||||
e = p.item;
|
||||
p = p.next;
|
||||
if (e != null)
|
||||
break;
|
||||
}
|
||||
} finally {
|
||||
q.fullyUnlock();
|
||||
}
|
||||
if (e != null)
|
||||
action.accept(e);
|
||||
} while (p != null);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean tryAdvance(Consumer<? super E> action) {
|
||||
if (action == null) throw new NullPointerException();
|
||||
final LinkedBlockingQueue<E> q = this.queue;
|
||||
if (!exhausted) {
|
||||
E e = null;
|
||||
q.fullyLock();
|
||||
try {
|
||||
if (current == null)
|
||||
current = q.head.next;
|
||||
while (current != null) {
|
||||
e = current.item;
|
||||
current = current.next;
|
||||
if (e != null)
|
||||
break;
|
||||
}
|
||||
} finally {
|
||||
q.fullyUnlock();
|
||||
}
|
||||
if (current == null)
|
||||
exhausted = true;
|
||||
if (e != null) {
|
||||
action.accept(e);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int characteristics() {
|
||||
return Spliterator.ORDERED | Spliterator.NONNULL |
|
||||
Spliterator.CONCURRENT;
|
||||
}
|
||||
}
|
||||
|
||||
public Spliterator<E> spliterator() {
|
||||
return new LBQSpliterator<E>(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves this queue to a stream (that is, serializes it).
|
||||
*
|
||||
|
||||
@ -40,8 +40,10 @@ import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
import java.util.Spliterator;
|
||||
import java.util.Spliterators;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* An unbounded {@link TransferQueue} based on linked nodes.
|
||||
@ -776,6 +778,24 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Version of firstOfMode used by Spliterator
|
||||
*/
|
||||
final Node firstDataNode() {
|
||||
for (Node p = head; p != null;) {
|
||||
Object item = p.item;
|
||||
if (p.isData) {
|
||||
if (item != null && item != p)
|
||||
return p;
|
||||
}
|
||||
else if (item == null)
|
||||
break;
|
||||
if (p == (p = p.next))
|
||||
p = head;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the item in the first unmatched node with isData; or
|
||||
* null if none. Used by peek.
|
||||
@ -910,6 +930,98 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
}
|
||||
}
|
||||
|
||||
/** A customized variant of Spliterators.IteratorSpliterator */
|
||||
static final class LTQSpliterator<E> implements Spliterator<E> {
|
||||
static final int MAX_BATCH = 1 << 25; // max batch array size;
|
||||
final LinkedTransferQueue<E> queue;
|
||||
Node current; // current node; null until initialized
|
||||
int batch; // batch size for splits
|
||||
boolean exhausted; // true when no more nodes
|
||||
LTQSpliterator(LinkedTransferQueue<E> queue) {
|
||||
this.queue = queue;
|
||||
}
|
||||
|
||||
public Spliterator<E> trySplit() {
|
||||
Node p;
|
||||
final LinkedTransferQueue<E> q = this.queue;
|
||||
int b = batch;
|
||||
int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
|
||||
if (!exhausted &&
|
||||
((p = current) != null || (p = q.firstDataNode()) != null) &&
|
||||
p.next != null) {
|
||||
Object[] a = new Object[n];
|
||||
int i = 0;
|
||||
do {
|
||||
if ((a[i] = p.item) != null)
|
||||
++i;
|
||||
if (p == (p = p.next))
|
||||
p = q.firstDataNode();
|
||||
} while (p != null && i < n);
|
||||
if ((current = p) == null)
|
||||
exhausted = true;
|
||||
if (i > 0) {
|
||||
batch = i;
|
||||
return Spliterators.spliterator
|
||||
(a, 0, i, Spliterator.ORDERED | Spliterator.NONNULL |
|
||||
Spliterator.CONCURRENT);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void forEachRemaining(Consumer<? super E> action) {
|
||||
Node p;
|
||||
if (action == null) throw new NullPointerException();
|
||||
final LinkedTransferQueue<E> q = this.queue;
|
||||
if (!exhausted &&
|
||||
((p = current) != null || (p = q.firstDataNode()) != null)) {
|
||||
exhausted = true;
|
||||
do {
|
||||
Object e = p.item;
|
||||
if (p == (p = p.next))
|
||||
p = q.firstDataNode();
|
||||
if (e != null)
|
||||
action.accept((E)e);
|
||||
} while (p != null);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public boolean tryAdvance(Consumer<? super E> action) {
|
||||
Node p;
|
||||
if (action == null) throw new NullPointerException();
|
||||
final LinkedTransferQueue<E> q = this.queue;
|
||||
if (!exhausted &&
|
||||
((p = current) != null || (p = q.firstDataNode()) != null)) {
|
||||
Object e;
|
||||
do {
|
||||
e = p.item;
|
||||
if (p == (p = p.next))
|
||||
p = q.firstDataNode();
|
||||
} while (e == null && p != null);
|
||||
if ((current = p) == null)
|
||||
exhausted = true;
|
||||
if (e != null) {
|
||||
action.accept((E)e);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public long estimateSize() { return Long.MAX_VALUE; }
|
||||
|
||||
public int characteristics() {
|
||||
return Spliterator.ORDERED | Spliterator.NONNULL |
|
||||
Spliterator.CONCURRENT;
|
||||
}
|
||||
}
|
||||
|
||||
public Spliterator<E> spliterator() {
|
||||
return new LTQSpliterator<E>(this);
|
||||
}
|
||||
|
||||
/* -------------- Removal methods -------------- */
|
||||
|
||||
/**
|
||||
|
||||
@ -37,7 +37,17 @@ package java.util.concurrent;
|
||||
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.*;
|
||||
import java.util.AbstractQueue;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.PriorityQueue;
|
||||
import java.util.Queue;
|
||||
import java.util.SortedSet;
|
||||
import java.util.Spliterator;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* An unbounded {@linkplain BlockingQueue blocking queue} that uses
|
||||
@ -342,7 +352,6 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
|
||||
* @param k the position to fill
|
||||
* @param x the item to insert
|
||||
* @param array the heap array
|
||||
* @param n heap size
|
||||
*/
|
||||
private static <T> void siftUpComparable(int k, T x, Object[] array) {
|
||||
Comparable<? super T> key = (Comparable<? super T>) x;
|
||||
@ -936,6 +945,70 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
|
||||
}
|
||||
}
|
||||
|
||||
// Similar to Collections.ArraySnapshotSpliterator but avoids
|
||||
// commitment to toArray until needed
|
||||
static final class PBQSpliterator<E> implements Spliterator<E> {
|
||||
final PriorityBlockingQueue<E> queue;
|
||||
Object[] array;
|
||||
int index;
|
||||
int fence;
|
||||
|
||||
PBQSpliterator(PriorityBlockingQueue<E> queue, Object[] array,
|
||||
int index, int fence) {
|
||||
this.queue = queue;
|
||||
this.array = array;
|
||||
this.index = index;
|
||||
this.fence = fence;
|
||||
}
|
||||
|
||||
final int getFence() {
|
||||
int hi;
|
||||
if ((hi = fence) < 0)
|
||||
hi = fence = (array = queue.toArray()).length;
|
||||
return hi;
|
||||
}
|
||||
|
||||
public Spliterator<E> trySplit() {
|
||||
int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
|
||||
return (lo >= mid) ? null :
|
||||
new PBQSpliterator<E>(queue, array, lo, index = mid);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void forEachRemaining(Consumer<? super E> action) {
|
||||
Object[] a; int i, hi; // hoist accesses and checks from loop
|
||||
if (action == null)
|
||||
throw new NullPointerException();
|
||||
if ((a = array) == null)
|
||||
fence = (a = queue.toArray()).length;
|
||||
if ((hi = fence) <= a.length &&
|
||||
(i = index) >= 0 && i < (index = hi)) {
|
||||
do { action.accept((E)a[i]); } while (++i < hi);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean tryAdvance(Consumer<? super E> action) {
|
||||
if (action == null)
|
||||
throw new NullPointerException();
|
||||
if (getFence() > index && index >= 0) {
|
||||
@SuppressWarnings("unchecked") E e = (E) array[index++];
|
||||
action.accept(e);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public long estimateSize() { return (long)(getFence() - index); }
|
||||
|
||||
public int characteristics() {
|
||||
return Spliterator.NONNULL | Spliterator.SIZED | Spliterator.SUBSIZED;
|
||||
}
|
||||
}
|
||||
|
||||
public Spliterator<E> spliterator() {
|
||||
return new PBQSpliterator<E>(this, null, 0, -1);
|
||||
}
|
||||
|
||||
// Unsafe mechanics
|
||||
private static final sun.misc.Unsafe UNSAFE;
|
||||
private static final long allocationSpinLockOffset;
|
||||
|
||||
@ -44,17 +44,17 @@ import java.util.*;
|
||||
* 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
|
||||
* {@code peek} 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.
|
||||
* {@code poll()} will return {@code null}. For purposes of other
|
||||
* {@code Collection} methods (for example {@code contains}), a
|
||||
* {@code SynchronousQueue} acts as an empty collection. This queue
|
||||
* does not permit {@code null} elements.
|
||||
*
|
||||
* <p>Synchronous queues are similar to rendezvous channels used in
|
||||
* CSP and Ada. They are well suited for handoff designs, in which an
|
||||
@ -62,10 +62,10 @@ import java.util.*;
|
||||
* in another thread in order to hand it some information, event, or
|
||||
* task.
|
||||
*
|
||||
* <p> This class supports an optional fairness policy for ordering
|
||||
* <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.
|
||||
* to {@code true} 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
|
||||
@ -599,7 +599,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
/**
|
||||
* Reference to a cancelled node that might not yet have been
|
||||
* unlinked from queue because it was the last inserted node
|
||||
* when it cancelled.
|
||||
* when it was cancelled.
|
||||
*/
|
||||
transient volatile QNode cleanMe;
|
||||
|
||||
@ -847,14 +847,14 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
private transient volatile Transferer<E> transferer;
|
||||
|
||||
/**
|
||||
* Creates a <tt>SynchronousQueue</tt> with nonfair access policy.
|
||||
* Creates a {@code SynchronousQueue} with nonfair access policy.
|
||||
*/
|
||||
public SynchronousQueue() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a <tt>SynchronousQueue</tt> with the specified fairness policy.
|
||||
* Creates a {@code SynchronousQueue} with the specified fairness policy.
|
||||
*
|
||||
* @param fair if true, waiting threads contend in FIFO order for
|
||||
* access; otherwise the order is unspecified.
|
||||
@ -882,8 +882,8 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
* 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.
|
||||
* @return {@code true} if successful, or {@code false} if the
|
||||
* specified waiting time elapses before a consumer appears
|
||||
* @throws InterruptedException {@inheritDoc}
|
||||
* @throws NullPointerException {@inheritDoc}
|
||||
*/
|
||||
@ -902,8 +902,8 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
* 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>
|
||||
* @return {@code true} if the element was added to this queue, else
|
||||
* {@code false}
|
||||
* @throws NullPointerException if the specified element is null
|
||||
*/
|
||||
public boolean offer(E e) {
|
||||
@ -931,8 +931,8 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
* 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.
|
||||
* @return the head of this queue, or {@code null} if the
|
||||
* specified waiting time elapses before an element is present
|
||||
* @throws InterruptedException {@inheritDoc}
|
||||
*/
|
||||
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
|
||||
@ -946,18 +946,18 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
* 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.
|
||||
* @return the head of this queue, or {@code null} if no
|
||||
* element is available
|
||||
*/
|
||||
public E poll() {
|
||||
return transferer.transfer(null, true, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns <tt>true</tt>.
|
||||
* A <tt>SynchronousQueue</tt> has no internal capacity.
|
||||
* Always returns {@code true}.
|
||||
* A {@code SynchronousQueue} has no internal capacity.
|
||||
*
|
||||
* @return <tt>true</tt>
|
||||
* @return {@code true}
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return true;
|
||||
@ -965,9 +965,9 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
|
||||
/**
|
||||
* Always returns zero.
|
||||
* A <tt>SynchronousQueue</tt> has no internal capacity.
|
||||
* A {@code SynchronousQueue} has no internal capacity.
|
||||
*
|
||||
* @return zero.
|
||||
* @return zero
|
||||
*/
|
||||
public int size() {
|
||||
return 0;
|
||||
@ -975,9 +975,9 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
|
||||
/**
|
||||
* Always returns zero.
|
||||
* A <tt>SynchronousQueue</tt> has no internal capacity.
|
||||
* A {@code SynchronousQueue} has no internal capacity.
|
||||
*
|
||||
* @return zero.
|
||||
* @return zero
|
||||
*/
|
||||
public int remainingCapacity() {
|
||||
return 0;
|
||||
@ -985,80 +985,80 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
|
||||
/**
|
||||
* Does nothing.
|
||||
* A <tt>SynchronousQueue</tt> has no internal capacity.
|
||||
* A {@code SynchronousQueue} has no internal capacity.
|
||||
*/
|
||||
public void clear() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns <tt>false</tt>.
|
||||
* A <tt>SynchronousQueue</tt> has no internal capacity.
|
||||
* Always returns {@code false}.
|
||||
* A {@code SynchronousQueue} has no internal capacity.
|
||||
*
|
||||
* @param o the element
|
||||
* @return <tt>false</tt>
|
||||
* @return {@code false}
|
||||
*/
|
||||
public boolean contains(Object o) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns <tt>false</tt>.
|
||||
* A <tt>SynchronousQueue</tt> has no internal capacity.
|
||||
* Always returns {@code false}.
|
||||
* A {@code SynchronousQueue} has no internal capacity.
|
||||
*
|
||||
* @param o the element to remove
|
||||
* @return <tt>false</tt>
|
||||
* @return {@code false}
|
||||
*/
|
||||
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.
|
||||
* Returns {@code false} unless the given collection is empty.
|
||||
* A {@code SynchronousQueue} has no internal capacity.
|
||||
*
|
||||
* @param c the collection
|
||||
* @return <tt>false</tt> unless given collection is empty
|
||||
* @return {@code false} 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.
|
||||
* Always returns {@code false}.
|
||||
* A {@code SynchronousQueue} has no internal capacity.
|
||||
*
|
||||
* @param c the collection
|
||||
* @return <tt>false</tt>
|
||||
* @return {@code false}
|
||||
*/
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns <tt>false</tt>.
|
||||
* A <tt>SynchronousQueue</tt> has no internal capacity.
|
||||
* Always returns {@code false}.
|
||||
* A {@code SynchronousQueue} has no internal capacity.
|
||||
*
|
||||
* @param c the collection
|
||||
* @return <tt>false</tt>
|
||||
* @return {@code false}
|
||||
*/
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns <tt>null</tt>.
|
||||
* A <tt>SynchronousQueue</tt> does not return elements
|
||||
* Always returns {@code null}.
|
||||
* A {@code SynchronousQueue} does not return elements
|
||||
* unless actively waited on.
|
||||
*
|
||||
* @return <tt>null</tt>
|
||||
* @return {@code null}
|
||||
*/
|
||||
public E peek() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an empty iterator in which <tt>hasNext</tt> always returns
|
||||
* <tt>false</tt>.
|
||||
* Returns an empty iterator in which {@code hasNext} always returns
|
||||
* {@code false}.
|
||||
*
|
||||
* @return an empty iterator
|
||||
*/
|
||||
@ -1077,6 +1077,10 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
public void remove() { throw new IllegalStateException(); }
|
||||
}
|
||||
|
||||
public Spliterator<E> spliterator() {
|
||||
return Spliterators.emptySpliterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a zero-length array.
|
||||
* @return a zero-length array
|
||||
@ -1086,7 +1090,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the zeroeth element of the specified array to <tt>null</tt>
|
||||
* Sets the zeroeth element of the specified array to {@code null}
|
||||
* (if the array has non-zero length) and returns it.
|
||||
*
|
||||
* @param a the array
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user