diff options
author | Jesse Wilson <jessewilson@google.com> | 2010-04-09 16:48:34 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2010-04-09 16:48:34 -0700 |
commit | cabe39b8ed4f98a711f864267a47a5f58b7d0b10 (patch) | |
tree | 6a54ad1628a08678a47e91784c3bcd7c5dde2e4e | |
parent | fc032185188db3fb8fbdb924c4c75f954643e60c (diff) | |
parent | 6232a5efed0ea103e35aec73206e5e03a8b82e0c (diff) | |
download | libcore-cabe39b8ed4f98a711f864267a47a5f58b7d0b10.zip libcore-cabe39b8ed4f98a711f864267a47a5f58b7d0b10.tar.gz libcore-cabe39b8ed4f98a711f864267a47a5f58b7d0b10.tar.bz2 |
Merge "Latest java.util.concurrent from the JSR 166 project." into dalvik-dev
106 files changed, 30243 insertions, 10419 deletions
diff --git a/concurrent/src/main/java/java/util/concurrent/AbstractExecutorService.java b/concurrent/src/main/java/java/util/concurrent/AbstractExecutorService.java index f7ed15c..a7c8fe5 100644 --- a/concurrent/src/main/java/java/util/concurrent/AbstractExecutorService.java +++ b/concurrent/src/main/java/java/util/concurrent/AbstractExecutorService.java @@ -10,26 +10,74 @@ import java.util.*; /** * Provides default implementations of {@link ExecutorService} * execution methods. This class implements the <tt>submit</tt>, - * <tt>invokeAny</tt> and <tt>invokeAll</tt> methods using the default - * {@link FutureTask} class provided in this package. For example, + * <tt>invokeAny</tt> and <tt>invokeAll</tt> methods using a + * {@link RunnableFuture} returned by <tt>newTaskFor</tt>, which defaults + * to the {@link FutureTask} class provided in this package. For example, * the implementation of <tt>submit(Runnable)</tt> creates an - * associated <tt>FutureTask</tt> that is executed and - * returned. Subclasses overriding these methods to use different - * {@link Future} implementations should do so consistently for each - * of these methods. + * associated <tt>RunnableFuture</tt> that is executed and + * returned. Subclasses may override the <tt>newTaskFor</tt> methods + * to return <tt>RunnableFuture</tt> implementations other than + * <tt>FutureTask</tt>. * + * <p> <b>Extension example</b>. Here is a sketch of a class + * that customizes {@link ThreadPoolExecutor} to use + * a <tt>CustomTask</tt> class instead of the default <tt>FutureTask</tt>: + * <pre> + * public class CustomThreadPoolExecutor extends ThreadPoolExecutor { + * + * static class CustomTask<V> implements RunnableFuture<V> {...} + * + * protected <V> RunnableFuture<V> newTaskFor(Callable<V> c) { + * return new CustomTask<V>(c); + * } + * protected <V> RunnableFuture<V> newTaskFor(Runnable r, V v) { + * return new CustomTask<V>(r, v); + * } + * // ... add constructors, etc. + * } + * </pre> * @since 1.5 * @author Doug Lea */ public abstract class AbstractExecutorService implements ExecutorService { /** + * Returns a <tt>RunnableFuture</tt> for the given runnable and default + * value. + * + * @param runnable the runnable task being wrapped + * @param value the default value for the returned future + * @return a <tt>RunnableFuture</tt> which when run will run the + * underlying runnable and which, as a <tt>Future</tt>, will yield + * the given value as its result and provide for cancellation of + * the underlying task. + * @since 1.6 + */ + protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) { + return new FutureTask<T>(runnable, value); + } + + /** + * Returns a <tt>RunnableFuture</tt> for the given callable task. + * + * @param callable the callable task being wrapped + * @return a <tt>RunnableFuture</tt> which when run will call the + * underlying callable and which, as a <tt>Future</tt>, will yield + * the callable's result as its result and provide for + * cancellation of the underlying task. + * @since 1.6 + */ + protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) { + return new FutureTask<T>(callable); + } + + /** * @throws RejectedExecutionException {@inheritDoc} * @throws NullPointerException {@inheritDoc} */ public Future<?> submit(Runnable task) { if (task == null) throw new NullPointerException(); - FutureTask<Object> ftask = new FutureTask<Object>(task, null); + RunnableFuture<Object> ftask = newTaskFor(task, null); execute(ftask); return ftask; } @@ -40,7 +88,7 @@ public abstract class AbstractExecutorService implements ExecutorService { */ public <T> Future<T> submit(Runnable task, T result) { if (task == null) throw new NullPointerException(); - FutureTask<T> ftask = new FutureTask<T>(task, result); + RunnableFuture<T> ftask = newTaskFor(task, result); execute(ftask); return ftask; } @@ -51,7 +99,7 @@ public abstract class AbstractExecutorService implements ExecutorService { */ public <T> Future<T> submit(Callable<T> task) { if (task == null) throw new NullPointerException(); - FutureTask<T> ftask = new FutureTask<T>(task); + RunnableFuture<T> ftask = newTaskFor(task); execute(ftask); return ftask; } @@ -59,7 +107,7 @@ public abstract class AbstractExecutorService implements ExecutorService { /** * the main mechanics of invokeAny. */ - private <T> T doInvokeAny(Collection<Callable<T>> tasks, + private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks, boolean timed, long nanos) throws InterruptedException, ExecutionException, TimeoutException { if (tasks == null) @@ -82,7 +130,7 @@ public abstract class AbstractExecutorService implements ExecutorService { // result, we can throw the last exception we got. ExecutionException ee = null; long lastTime = (timed)? System.nanoTime() : 0; - Iterator<Callable<T>> it = tasks.iterator(); + Iterator<? extends Callable<T>> it = tasks.iterator(); // Start one task for sure; the rest incrementally futures.add(ecs.submit(it.next())); @@ -134,7 +182,7 @@ public abstract class AbstractExecutorService implements ExecutorService { } } - public <T> T invokeAny(Collection<Callable<T>> tasks) + public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException { try { return doInvokeAny(tasks, false, 0); @@ -144,13 +192,13 @@ public abstract class AbstractExecutorService implements ExecutorService { } } - public <T> T invokeAny(Collection<Callable<T>> tasks, + public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { return doInvokeAny(tasks, true, unit.toNanos(timeout)); } - public <T> List<Future<T>> invokeAll(Collection<Callable<T>> tasks) + public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException { if (tasks == null) throw new NullPointerException(); @@ -158,7 +206,7 @@ public abstract class AbstractExecutorService implements ExecutorService { boolean done = false; try { for (Callable<T> t : tasks) { - FutureTask<T> f = new FutureTask<T>(t); + RunnableFuture<T> f = newTaskFor(t); futures.add(f); execute(f); } @@ -180,7 +228,7 @@ public abstract class AbstractExecutorService implements ExecutorService { } } - public <T> List<Future<T>> invokeAll(Collection<Callable<T>> tasks, + public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException { if (tasks == null || unit == null) @@ -190,7 +238,7 @@ public abstract class AbstractExecutorService implements ExecutorService { boolean done = false; try { for (Callable<T> t : tasks) - futures.add(new FutureTask<T>(t)); + futures.add(newTaskFor(t)); long lastTime = System.nanoTime(); diff --git a/concurrent/src/main/java/java/util/concurrent/ArrayBlockingQueue.java b/concurrent/src/main/java/java/util/concurrent/ArrayBlockingQueue.java index 0082f07..1c6f613 100644 --- a/concurrent/src/main/java/java/util/concurrent/ArrayBlockingQueue.java +++ b/concurrent/src/main/java/java/util/concurrent/ArrayBlockingQueue.java @@ -189,8 +189,8 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E> if (capacity < c.size()) throw new IllegalArgumentException(); - for (Iterator<? extends E> it = c.iterator(); it.hasNext();) - add(it.next()); + for (E e : c) + add(e); } /** diff --git a/concurrent/src/main/java/java/util/concurrent/BlockingDeque.java b/concurrent/src/main/java/java/util/concurrent/BlockingDeque.java new file mode 100644 index 0000000..d77a965 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/BlockingDeque.java @@ -0,0 +1,613 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.*; + +/** + * A {@link Deque} that additionally supports blocking operations that wait + * for the deque to become non-empty when retrieving an element, and wait for + * space to become available in the deque when storing an element. + * + * <p><tt>BlockingDeque</tt> methods come in four forms, with different ways + * of handling operations that cannot be satisfied immediately, but may be + * satisfied at some point in the future: + * one throws an exception, the second returns a special value (either + * <tt>null</tt> or <tt>false</tt>, depending on the operation), the third + * blocks the current thread indefinitely until the operation can succeed, + * and the fourth blocks for only a given maximum time limit before giving + * up. These methods are summarized in the following table: + * + * <p> + * <table BORDER CELLPADDING=3 CELLSPACING=1> + * <tr> + * <td ALIGN=CENTER COLSPAN = 5> <b>First Element (Head)</b></td> + * </tr> + * <tr> + * <td></td> + * <td ALIGN=CENTER><em>Throws exception</em></td> + * <td ALIGN=CENTER><em>Special value</em></td> + * <td ALIGN=CENTER><em>Blocks</em></td> + * <td ALIGN=CENTER><em>Times out</em></td> + * </tr> + * <tr> + * <td><b>Insert</b></td> + * <td>{@link #addFirst addFirst(e)}</td> + * <td>{@link #offerFirst(Object) offerFirst(e)}</td> + * <td>{@link #putFirst putFirst(e)}</td> + * <td>{@link #offerFirst(Object, long, TimeUnit) offerFirst(e, time, unit)}</td> + * </tr> + * <tr> + * <td><b>Remove</b></td> + * <td>{@link #removeFirst removeFirst()}</td> + * <td>{@link #pollFirst pollFirst()}</td> + * <td>{@link #takeFirst takeFirst()}</td> + * <td>{@link #pollFirst(long, TimeUnit) pollFirst(time, unit)}</td> + * </tr> + * <tr> + * <td><b>Examine</b></td> + * <td>{@link #getFirst getFirst()}</td> + * <td>{@link #peekFirst peekFirst()}</td> + * <td><em>not applicable</em></td> + * <td><em>not applicable</em></td> + * </tr> + * <tr> + * <td ALIGN=CENTER COLSPAN = 5> <b>Last Element (Tail)</b></td> + * </tr> + * <tr> + * <td></td> + * <td ALIGN=CENTER><em>Throws exception</em></td> + * <td ALIGN=CENTER><em>Special value</em></td> + * <td ALIGN=CENTER><em>Blocks</em></td> + * <td ALIGN=CENTER><em>Times out</em></td> + * </tr> + * <tr> + * <td><b>Insert</b></td> + * <td>{@link #addLast addLast(e)}</td> + * <td>{@link #offerLast(Object) offerLast(e)}</td> + * <td>{@link #putLast putLast(e)}</td> + * <td>{@link #offerLast(Object, long, TimeUnit) offerLast(e, time, unit)}</td> + * </tr> + * <tr> + * <td><b>Remove</b></td> + * <td>{@link #removeLast() removeLast()}</td> + * <td>{@link #pollLast() pollLast()}</td> + * <td>{@link #takeLast takeLast()}</td> + * <td>{@link #pollLast(long, TimeUnit) pollLast(time, unit)}</td> + * </tr> + * <tr> + * <td><b>Examine</b></td> + * <td>{@link #getLast getLast()}</td> + * <td>{@link #peekLast peekLast()}</td> + * <td><em>not applicable</em></td> + * <td><em>not applicable</em></td> + * </tr> + * </table> + * + * <p>Like any {@link BlockingQueue}, a <tt>BlockingDeque</tt> is thread safe, + * does not permit null elements, and may (or may not) be + * capacity-constrained. + * + * <p>A <tt>BlockingDeque</tt> implementation may be used directly as a FIFO + * <tt>BlockingQueue</tt>. The methods inherited from the + * <tt>BlockingQueue</tt> interface are precisely equivalent to + * <tt>BlockingDeque</tt> methods as indicated in the following table: + * + * <p> + * <table BORDER CELLPADDING=3 CELLSPACING=1> + * <tr> + * <td ALIGN=CENTER> <b><tt>BlockingQueue</tt> Method</b></td> + * <td ALIGN=CENTER> <b>Equivalent <tt>BlockingDeque</tt> Method</b></td> + * </tr> + * <tr> + * <td ALIGN=CENTER COLSPAN = 2> <b>Insert</b></td> + * </tr> + * <tr> + * <td>{@link #add(Object) add(e)}</td> + * <td>{@link #addLast(Object) addLast(e)}</td> + * </tr> + * <tr> + * <td>{@link #offer(Object) offer(e)}</td> + * <td>{@link #offerLast(Object) offerLast(e)}</td> + * </tr> + * <tr> + * <td>{@link #put(Object) put(e)}</td> + * <td>{@link #putLast(Object) putLast(e)}</td> + * </tr> + * <tr> + * <td>{@link #offer(Object, long, TimeUnit) offer(e, time, unit)}</td> + * <td>{@link #offerLast(Object, long, TimeUnit) offerLast(e, time, unit)}</td> + * </tr> + * <tr> + * <td ALIGN=CENTER COLSPAN = 2> <b>Remove</b></td> + * </tr> + * <tr> + * <td>{@link #remove() remove()}</td> + * <td>{@link #removeFirst() removeFirst()}</td> + * </tr> + * <tr> + * <td>{@link #poll() poll()}</td> + * <td>{@link #pollFirst() pollFirst()}</td> + * </tr> + * <tr> + * <td>{@link #take() take()}</td> + * <td>{@link #takeFirst() takeFirst()}</td> + * </tr> + * <tr> + * <td>{@link #poll(long, TimeUnit) poll(time, unit)}</td> + * <td>{@link #pollFirst(long, TimeUnit) pollFirst(time, unit)}</td> + * </tr> + * <tr> + * <td ALIGN=CENTER COLSPAN = 2> <b>Examine</b></td> + * </tr> + * <tr> + * <td>{@link #element() element()}</td> + * <td>{@link #getFirst() getFirst()}</td> + * </tr> + * <tr> + * <td>{@link #peek() peek()}</td> + * <td>{@link #peekFirst() peekFirst()}</td> + * </tr> + * </table> + * + * <p>Memory consistency effects: As with other concurrent + * collections, actions in a thread prior to placing an object into a + * {@code BlockingDeque} + * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a> + * actions subsequent to the access or removal of that element from + * the {@code BlockingDeque} in another thread. + * + * <p>This interface is a member of the + * <a href="{@docRoot}/../technotes/guides/collections/index.html"> + * Java Collections Framework</a>. + * + * @since 1.6 + * @author Doug Lea + * @param <E> the type of elements held in this collection + */ +public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> { + /* + * We have "diamond" multiple interface inheritance here, and that + * introduces ambiguities. Methods might end up with different + * specs depending on the branch chosen by javadoc. Thus a lot of + * methods specs here are copied from superinterfaces. + */ + + /** + * Inserts the specified element at the front of this deque if it is + * possible to do so immediately without violating capacity restrictions, + * throwing an <tt>IllegalStateException</tt> if no space is currently + * available. When using a capacity-restricted deque, it is generally + * preferable to use {@link #offerFirst(Object) offerFirst}. + * + * @param e the element to add + * @throws IllegalStateException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException {@inheritDoc} + */ + void addFirst(E e); + + /** + * Inserts the specified element at the end of this deque if it is + * possible to do so immediately without violating capacity restrictions, + * throwing an <tt>IllegalStateException</tt> if no space is currently + * available. When using a capacity-restricted deque, it is generally + * preferable to use {@link #offerLast(Object) offerLast}. + * + * @param e the element to add + * @throws IllegalStateException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException {@inheritDoc} + */ + void addLast(E e); + + /** + * Inserts the specified element at the front of this deque if it is + * possible to do so immediately without violating capacity restrictions, + * returning <tt>true</tt> upon success and <tt>false</tt> if no space is + * currently available. + * When using a capacity-restricted deque, this method is generally + * preferable to the {@link #addFirst(Object) addFirst} method, which can + * fail to insert an element only by throwing an exception. + * + * @param e the element to add + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException {@inheritDoc} + */ + boolean offerFirst(E e); + + /** + * Inserts the specified element at the end of this deque if it is + * possible to do so immediately without violating capacity restrictions, + * returning <tt>true</tt> upon success and <tt>false</tt> if no space is + * currently available. + * When using a capacity-restricted deque, this method is generally + * preferable to the {@link #addLast(Object) addLast} method, which can + * fail to insert an element only by throwing an exception. + * + * @param e the element to add + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException {@inheritDoc} + */ + boolean offerLast(E e); + + /** + * Inserts the specified element at the front of this deque, + * waiting if necessary for space to become available. + * + * @param e the element to add + * @throws InterruptedException if interrupted while waiting + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this deque + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this deque + */ + void putFirst(E e) throws InterruptedException; + + /** + * Inserts the specified element at the end of this deque, + * waiting if necessary for space to become available. + * + * @param e the element to add + * @throws InterruptedException if interrupted while waiting + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this deque + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this deque + */ + void putLast(E e) throws InterruptedException; + + /** + * Inserts the specified element at the front of this deque, + * waiting up to the specified wait time if necessary for space to + * become available. + * + * @param e the element to add + * @param timeout how long to wait before giving up, in units of + * <tt>unit</tt> + * @param unit a <tt>TimeUnit</tt> determining how to interpret the + * <tt>timeout</tt> parameter + * @return <tt>true</tt> if successful, or <tt>false</tt> if + * the specified waiting time elapses before space is available + * @throws InterruptedException if interrupted while waiting + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this deque + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this deque + */ + boolean offerFirst(E e, long timeout, TimeUnit unit) + throws InterruptedException; + + /** + * Inserts the specified element at the end of this deque, + * waiting up to the specified wait time if necessary for space to + * become available. + * + * @param e the element to add + * @param timeout how long to wait before giving up, in units of + * <tt>unit</tt> + * @param unit a <tt>TimeUnit</tt> determining how to interpret the + * <tt>timeout</tt> parameter + * @return <tt>true</tt> if successful, or <tt>false</tt> if + * the specified waiting time elapses before space is available + * @throws InterruptedException if interrupted while waiting + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this deque + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this deque + */ + boolean offerLast(E e, long timeout, TimeUnit unit) + throws InterruptedException; + + /** + * Retrieves and removes the first element of this deque, waiting + * if necessary until an element becomes available. + * + * @return the head of this deque + * @throws InterruptedException if interrupted while waiting + */ + E takeFirst() throws InterruptedException; + + /** + * Retrieves and removes the last element of this deque, waiting + * if necessary until an element becomes available. + * + * @return the tail of this deque + * @throws InterruptedException if interrupted while waiting + */ + E takeLast() throws InterruptedException; + + /** + * Retrieves and removes the first element of this deque, waiting + * up to the specified wait time if necessary for an element to + * become available. + * + * @param timeout how long to wait before giving up, in units of + * <tt>unit</tt> + * @param unit a <tt>TimeUnit</tt> determining how to interpret the + * <tt>timeout</tt> parameter + * @return the head of this deque, or <tt>null</tt> if the specified + * waiting time elapses before an element is available + * @throws InterruptedException if interrupted while waiting + */ + E pollFirst(long timeout, TimeUnit unit) + throws InterruptedException; + + /** + * Retrieves and removes the last element of this deque, waiting + * up to the specified wait time if necessary for an element to + * become available. + * + * @param timeout how long to wait before giving up, in units of + * <tt>unit</tt> + * @param unit a <tt>TimeUnit</tt> determining how to interpret the + * <tt>timeout</tt> parameter + * @return the tail of this deque, or <tt>null</tt> if the specified + * waiting time elapses before an element is available + * @throws InterruptedException if interrupted while waiting + */ + E pollLast(long timeout, TimeUnit unit) + throws InterruptedException; + + /** + * Removes the first occurrence of the specified element from this deque. + * If the deque does not contain the element, it is unchanged. + * More formally, removes the first element <tt>e</tt> such that + * <tt>o.equals(e)</tt> (if such an element exists). + * Returns <tt>true</tt> if this deque contained the specified element + * (or equivalently, if this deque changed as a result of the call). + * + * @param o element to be removed from this deque, if present + * @return <tt>true</tt> if an element was removed as a result of this call + * @throws ClassCastException if the class of the specified element + * is incompatible with this deque (optional) + * @throws NullPointerException if the specified element is null (optional) + */ + boolean removeFirstOccurrence(Object o); + + /** + * Removes the last occurrence of the specified element from this deque. + * If the deque does not contain the element, it is unchanged. + * More formally, removes the last element <tt>e</tt> such that + * <tt>o.equals(e)</tt> (if such an element exists). + * Returns <tt>true</tt> if this deque contained the specified element + * (or equivalently, if this deque changed as a result of the call). + * + * @param o element to be removed from this deque, if present + * @return <tt>true</tt> if an element was removed as a result of this call + * @throws ClassCastException if the class of the specified element + * is incompatible with this deque (optional) + * @throws NullPointerException if the specified element is null (optional) + */ + boolean removeLastOccurrence(Object o); + + // *** BlockingQueue methods *** + + /** + * Inserts the specified element into the queue represented by this deque + * (in other words, at the tail of this deque) if it is possible to do so + * immediately without violating capacity restrictions, returning + * <tt>true</tt> upon success and throwing an + * <tt>IllegalStateException</tt> if no space is currently available. + * When using a capacity-restricted deque, it is generally preferable to + * use {@link #offer(Object) offer}. + * + * <p>This method is equivalent to {@link #addLast(Object) addLast}. + * + * @param e the element to add + * @throws IllegalStateException {@inheritDoc} + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this deque + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this deque + */ + boolean add(E e); + + /** + * Inserts the specified element into the queue represented by this deque + * (in other words, at the tail of this deque) if it is possible to do so + * immediately without violating capacity restrictions, returning + * <tt>true</tt> upon success and <tt>false</tt> if no space is currently + * available. When using a capacity-restricted deque, this method is + * generally preferable to the {@link #add} method, which can fail to + * insert an element only by throwing an exception. + * + * <p>This method is equivalent to {@link #offerLast(Object) offerLast}. + * + * @param e the element to add + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this deque + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this deque + */ + boolean offer(E e); + + /** + * Inserts the specified element into the queue represented by this deque + * (in other words, at the tail of this deque), waiting if necessary for + * space to become available. + * + * <p>This method is equivalent to {@link #putLast(Object) putLast}. + * + * @param e the element to add + * @throws InterruptedException {@inheritDoc} + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this deque + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this deque + */ + void put(E e) throws InterruptedException; + + /** + * Inserts the specified element into the queue represented by this deque + * (in other words, at the tail of this deque), waiting up to the + * specified wait time if necessary for space to become available. + * + * <p>This method is equivalent to + * {@link #offerLast(Object,long,TimeUnit) offerLast}. + * + * @param e the element to add + * @return <tt>true</tt> if the element was added to this deque, else + * <tt>false</tt> + * @throws InterruptedException {@inheritDoc} + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this deque + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this deque + */ + boolean offer(E e, long timeout, TimeUnit unit) + throws InterruptedException; + + /** + * Retrieves and removes the head of the queue represented by this deque + * (in other words, the first element of this deque). + * This method differs from {@link #poll poll} only in that it + * throws an exception if this deque is empty. + * + * <p>This method is equivalent to {@link #removeFirst() removeFirst}. + * + * @return the head of the queue represented by this deque + * @throws NoSuchElementException if this deque is empty + */ + E remove(); + + /** + * Retrieves and removes the head of the queue represented by this deque + * (in other words, the first element of this deque), or returns + * <tt>null</tt> if this deque is empty. + * + * <p>This method is equivalent to {@link #pollFirst()}. + * + * @return the head of this deque, or <tt>null</tt> if this deque is empty + */ + E poll(); + + /** + * Retrieves and removes the head of the queue represented by this deque + * (in other words, the first element of this deque), waiting if + * necessary until an element becomes available. + * + * <p>This method is equivalent to {@link #takeFirst() takeFirst}. + * + * @return the head of this deque + * @throws InterruptedException if interrupted while waiting + */ + E take() throws InterruptedException; + + /** + * Retrieves and removes the head of the queue represented by this deque + * (in other words, the first element of this deque), waiting up to the + * specified wait time if necessary for an element to become available. + * + * <p>This method is equivalent to + * {@link #pollFirst(long,TimeUnit) pollFirst}. + * + * @return the head of this deque, or <tt>null</tt> if the + * specified waiting time elapses before an element is available + * @throws InterruptedException if interrupted while waiting + */ + E poll(long timeout, TimeUnit unit) + throws InterruptedException; + + /** + * Retrieves, but does not remove, the head of the queue represented by + * this deque (in other words, the first element of this deque). + * This method differs from {@link #peek peek} only in that it throws an + * exception if this deque is empty. + * + * <p>This method is equivalent to {@link #getFirst() getFirst}. + * + * @return the head of this deque + * @throws NoSuchElementException if this deque is empty + */ + E element(); + + /** + * Retrieves, but does not remove, the head of the queue represented by + * this deque (in other words, the first element of this deque), or + * returns <tt>null</tt> if this deque is empty. + * + * <p>This method is equivalent to {@link #peekFirst() peekFirst}. + * + * @return the head of this deque, or <tt>null</tt> if this deque is empty + */ + E peek(); + + /** + * Removes the first occurrence of the specified element from this deque. + * If the deque does not contain the element, it is unchanged. + * More formally, removes the first element <tt>e</tt> such that + * <tt>o.equals(e)</tt> (if such an element exists). + * Returns <tt>true</tt> if this deque contained the specified element + * (or equivalently, if this deque changed as a result of the call). + * + * <p>This method is equivalent to + * {@link #removeFirstOccurrence(Object) removeFirstOccurrence}. + * + * @param o element to be removed from this deque, if present + * @return <tt>true</tt> if this deque changed as a result of the call + * @throws ClassCastException if the class of the specified element + * is incompatible with this deque (optional) + * @throws NullPointerException if the specified element is null (optional) + */ + boolean remove(Object o); + + /** + * Returns <tt>true</tt> if this deque contains the specified element. + * More formally, returns <tt>true</tt> if and only if this deque contains + * at least one element <tt>e</tt> such that <tt>o.equals(e)</tt>. + * + * @param o object to be checked for containment in this deque + * @return <tt>true</tt> if this deque contains the specified element + * @throws ClassCastException if the class of the specified element + * is incompatible with this deque (optional) + * @throws NullPointerException if the specified element is null (optional) + */ + public boolean contains(Object o); + + /** + * Returns the number of elements in this deque. + * + * @return the number of elements in this deque + */ + public int size(); + + /** + * Returns an iterator over the elements in this deque in proper sequence. + * The elements will be returned in order from first (head) to last (tail). + * + * @return an iterator over the elements in this deque in proper sequence + */ + Iterator<E> iterator(); + + // *** Stack methods *** + + /** + * Pushes an element onto the stack represented by this deque. In other + * words, inserts the element at the front of this deque unless it would + * violate capacity restrictions. + * + * <p>This method is equivalent to {@link #addFirst(Object) addFirst}. + * + * @throws IllegalStateException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException {@inheritDoc} + */ + void push(E e); +} diff --git a/concurrent/src/main/java/java/util/concurrent/BlockingQueue.java b/concurrent/src/main/java/java/util/concurrent/BlockingQueue.java index d01c097..85945b9 100644 --- a/concurrent/src/main/java/java/util/concurrent/BlockingQueue.java +++ b/concurrent/src/main/java/java/util/concurrent/BlockingQueue.java @@ -42,7 +42,7 @@ import java.util.Queue; * <td>{@link #add add(e)}</td> * <td>{@link #offer offer(e)}</td> * <td>{@link #put put(e)}</td> - * <td>{@link #offer offer(e, time, unit)}</td> + * <td>{@link #offer(Object, long, TimeUnit) offer(e, time, unit)}</td> * </tr> * <tr> * <td><b>Remove</b></td> @@ -156,7 +156,7 @@ public interface BlockingQueue<E> extends Queue<E> { * <tt>true</tt> upon success and throwing an * <tt>IllegalStateException</tt> if no space is currently available. * When using a capacity-restricted queue, it is generally preferable to - * use {@link #offer offer}. + * use {@link #offer(Object) offer}. * * @param e the element to add * @return <tt>true</tt> (as specified by {@link Collection#add}) diff --git a/concurrent/src/main/java/java/util/concurrent/ConcurrentHashMap.java b/concurrent/src/main/java/java/util/concurrent/ConcurrentHashMap.java index cb5fb3f..1c157b4 100644 --- a/concurrent/src/main/java/java/util/concurrent/ConcurrentHashMap.java +++ b/concurrent/src/main/java/java/util/concurrent/ConcurrentHashMap.java @@ -613,6 +613,24 @@ public class ConcurrentHashMap<K, V> extends AbstractMap<K, V> } /** + * Creates a new, empty map with the specified initial capacity + * and load factor and with the default concurrencyLevel (16). + * + * @param initialCapacity The implementation performs internal + * sizing to accommodate this many elements. + * @param loadFactor the load factor threshold, used to control resizing. + * Resizing may be performed when the average number of elements per + * bin exceeds this threshold. + * @throws IllegalArgumentException if the initial capacity of + * elements is negative or the load factor is nonpositive + * + * @since 1.6 + */ + public ConcurrentHashMap(int initialCapacity, float loadFactor) { + this(initialCapacity, loadFactor, DEFAULT_CONCURRENCY_LEVEL); + } + + /** * Creates a new, empty map with the specified initial capacity, * and with default load factor (0.75) and concurrencyLevel (16). * @@ -1112,7 +1130,7 @@ public class ConcurrentHashMap<K, V> extends AbstractMap<K, V> * setValue changes to the underlying map. */ final class WriteThroughEntry - extends SimpleEntry<K,V> + extends AbstractMap.SimpleEntry<K,V> { WriteThroughEntry(K k, V v) { super(k,v); @@ -1212,60 +1230,7 @@ public class ConcurrentHashMap<K, V> extends AbstractMap<K, V> } } - /** - * This duplicates java.util.AbstractMap.SimpleEntry until this class - * is made accessible. - */ - static class SimpleEntry<K,V> implements Entry<K,V> { - K key; - V value; - - public SimpleEntry(K key, V value) { - this.key = key; - this.value = value; - } - - public SimpleEntry(Entry<K,V> e) { - this.key = e.getKey(); - this.value = e.getValue(); - } - - public K getKey() { - return key; - } - - public V getValue() { - return value; - } - - public V setValue(V value) { - V oldValue = this.value; - this.value = value; - return oldValue; - } - - public boolean equals(Object o) { - if (!(o instanceof Map.Entry)) - return false; - Map.Entry e = (Map.Entry)o; - return eq(key, e.getKey()) && eq(value, e.getValue()); - } - - public int hashCode() { - return ((key == null) ? 0 : key.hashCode()) ^ - ((value == null) ? 0 : value.hashCode()); - } - - public String toString() { - return key + "=" + value; - } - - static boolean eq(Object o1, Object o2) { - return (o1 == null ? o2 == null : o1.equals(o2)); - } - } - - /* ---------------- Serialization Support -------------- */ + /* ---------------- Serialization Support -------------- */ /** * Save the state of the <tt>ConcurrentHashMap</tt> instance to a diff --git a/concurrent/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java b/concurrent/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java new file mode 100644 index 0000000..ee3534e --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java @@ -0,0 +1,1246 @@ +/* + * Written by Doug Lea and Martin Buchholz with assistance from members of + * JCP JSR-166 Expert Group and released to the public domain, as explained + * at http://creativecommons.org/licenses/publicdomain + */ + +package java.util.concurrent; + +import java.util.AbstractCollection; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Deque; +import java.util.Iterator; +import java.util.ConcurrentModificationException; +import java.util.NoSuchElementException; +import java.util.concurrent.atomic.AtomicReference; + +/** + * A concurrent linked-list implementation of a {@link Deque} + * (double-ended queue). Concurrent insertion, removal, and access + * operations execute safely across multiple threads. Iterators are + * <i>weakly consistent</i>, returning elements reflecting the state + * of the deque 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. + * + * <p>This class and its iterators implement all of the + * <em>optional</em> methods of the {@link Collection} and {@link + * Iterator} interfaces. Like most other concurrent collection + * implementations, this class does not permit the use of + * {@code null} elements. because some null arguments and return + * values cannot be reliably distinguished from the absence of + * elements. Arbitrarily, the {@link Collection#remove} method is + * mapped to {@code removeFirstOccurrence}, and {@link + * Collection#add} is mapped to {@code addLast}. + * + * <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 deques, determining the current number + * of elements requires a traversal of the elements. + * + * <p>This class is {@code Serializable}, but relies on default + * serialization mechanisms. Usually, it is a better idea for any + * serializable class using a {@code ConcurrentLinkedDeque} to instead + * serialize a snapshot of the elements obtained by method + * {@code toArray}. + * + * @author Doug Lea + * @author Martin Buchholz + * @param <E> the type of elements held in this collection + */ + +public class ConcurrentLinkedDeque<E> + extends AbstractCollection<E> + implements Deque<E>, java.io.Serializable { + + /* + * This is an implementation of a concurrent lock-free deque + * supporting interior removes but not interior insertions, as + * required to fully support the Deque interface. + * + * We extend the techniques developed for + * ConcurrentLinkedQueue and LinkedTransferQueue + * (see the internal docs for those classes). + * + * At any time, there is precisely one "first" active node with a + * null prev pointer. Similarly there is one "last" active node + * with a null next pointer. New nodes are simply enqueued by + * null-CASing. + * + * A node p is considered "active" if it either contains an + * element, or is an end node and neither next nor prev pointers + * are self-links: + * + * p.item != null || + * (p.prev == null && p.next != p) || + * (p.next == null && p.prev != p) + * + * The head and tail pointers are only approximations to the start + * and end of the deque. The first node can always be found by + * following prev pointers from head; likewise for tail. However, + * head and tail may be pointing at deleted nodes that have been + * unlinked and so may not be reachable from any live node. + * + * There are 3 levels of node deletion: + * - logical deletion atomically removes the element + * - "unlinking" makes a deleted node unreachable from active + * nodes, and thus eventually reclaimable by GC + * - "gc-unlinking" further does the reverse of making active + * nodes unreachable from deleted nodes, making it easier for + * the GC to reclaim future deleted nodes + * + * TODO: find a better name for "gc-unlinked" + * + * Logical deletion of a node simply involves CASing its element + * to null. Physical deletion is merely an optimization (albeit a + * critical one), and can be performed at our convenience. At any + * time, the set of non-logically-deleted nodes maintained by prev + * and next links are identical, that is the live elements found + * via next links from the first node is equal to the elements + * found via prev links from the last node. However, this is not + * true for nodes that have already been logically deleted - such + * nodes may only be reachable in one direction. + * + * When a node is dequeued at either end, e.g. via poll(), we + * would like to break any references from the node to live nodes, + * to stop old garbage from causing retention of new garbage with + * a generational or conservative GC. We develop further the + * self-linking trick that was very effective in other concurrent + * collection classes. The idea is to replace prev and next + * pointers to active nodes with special values that are + * interpreted to mean off-the-list-at-one-end. These are + * approximations, but good enough to preserve the properties we + * want in our traversals, e.g. we guarantee that a traversal will + * never hit the same element twice, but we don't guarantee + * whether a traversal that runs out of elements will be able to + * see more elements later after more elements are added at that + * end. Doing gc-unlinking safely is particularly tricky, since + * any node can be in use indefinitely (for example by an + * iterator). We must make sure that the nodes pointed at by + * head/tail do not get gc-unlinked, since head/tail are needed to + * get "back on track" by other nodes that are gc-unlinked. + * gc-unlinking accounts for much of the implementation complexity. + * + * Since neither unlinking nor gc-unlinking are necessary for + * correctness, there are many implementation choices regarding + * frequency (eagerness) of these operations. Since volatile + * reads are likely to be much cheaper than CASes, saving CASes by + * unlinking multiple adjacent nodes at a time may be a win. + * gc-unlinking can be performed rarely and still be effective, + * since it is most important that long chains of deleted nodes + * are occasionally broken. + * + * The actual representation we use is that p.next == p means to + * goto the first node, and p.next == null && p.prev == p means + * that the iteration is at an end and that p is a (final static) + * dummy node, NEXT_TERMINATOR, and not the last active node. + * Finishing the iteration when encountering such a TERMINATOR is + * good enough for read-only traversals. When the last active + * node is desired, for example when enqueueing, goto tail and + * continue traversal. + * + * The implementation is completely directionally symmetrical, + * except that most public methods that iterate through the list + * follow next pointers ("forward" direction). + * + * There is one desirable property we would like to have, but + * don't: it is possible, when an addFirst(A) is racing with + * pollFirst() removing B, for an iterating observer to see A B C + * and subsequently see A C, even though no interior removes are + * ever performed. I believe this wart can only be removed at + * significant runtime cost. + * + * Empirically, microbenchmarks suggest that this class adds about + * 40% overhead relative to ConcurrentLinkedQueue, which feels as + * good as we can hope for. + */ + + /** + * A node from which the first node on list (that is, the unique + * node with node.prev == null) can be reached in O(1) time. + * Invariants: + * - the first node is always O(1) reachable from head via prev links + * - all live nodes are reachable from the first node via succ() + * - head != null + * - (tmp = head).next != tmp || tmp != head + * Non-invariants: + * - head.item may or may not be null + * - head may not be reachable from the first or last node, or from tail + */ + private transient volatile Node<E> head = new Node<E>(null); + + private final static Node<Object> PREV_TERMINATOR, NEXT_TERMINATOR; + + static { + PREV_TERMINATOR = new Node<Object>(null); + PREV_TERMINATOR.next = PREV_TERMINATOR; + NEXT_TERMINATOR = new Node<Object>(null); + NEXT_TERMINATOR.prev = NEXT_TERMINATOR; + } + + @SuppressWarnings("unchecked") + Node<E> prevTerminator() { + return (Node<E>) PREV_TERMINATOR; + } + + @SuppressWarnings("unchecked") + Node<E> nextTerminator() { + return (Node<E>) NEXT_TERMINATOR; + } + + /** + * A node from which the last node on list (that is, the unique + * node with node.next == null) can be reached in O(1) time. + * Invariants: + * - the last node is always O(1) reachable from tail via next links + * - all live nodes are reachable from the last node via pred() + * - tail != null + * Non-invariants: + * - tail.item may or may not be null + * - tail may not be reachable from the first or last node, or from head + */ + private transient volatile Node<E> tail = head; + + static final class Node<E> { + volatile Node<E> prev; + volatile E item; + volatile Node<E> next; + + Node(E item) { + // Piggyback on imminent casNext() or casPrev() + lazySetItem(item); + } + + boolean casItem(E cmp, E val) { + return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val); + } + + void lazySetItem(E val) { + UNSAFE.putOrderedObject(this, itemOffset, val); + } + + void lazySetNext(Node<E> val) { + UNSAFE.putOrderedObject(this, nextOffset, val); + } + + boolean casNext(Node<E> cmp, Node<E> val) { + return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val); + } + + void lazySetPrev(Node<E> val) { + UNSAFE.putOrderedObject(this, prevOffset, val); + } + + boolean casPrev(Node<E> cmp, Node<E> val) { + return UNSAFE.compareAndSwapObject(this, prevOffset, cmp, val); + } + + // Unsafe mechanics + + private static final sun.misc.Unsafe UNSAFE = + sun.misc.Unsafe.getUnsafe(); + private static final long prevOffset = + objectFieldOffset(UNSAFE, "prev", Node.class); + private static final long itemOffset = + objectFieldOffset(UNSAFE, "item", Node.class); + private static final long nextOffset = + objectFieldOffset(UNSAFE, "next", Node.class); + } + + /** + * Links e as first element. + */ + private void linkFirst(E e) { + checkNotNull(e); + final Node<E> newNode = new Node<E>(e); + + retry: + for (;;) { + for (Node<E> h = head, p = h;;) { + Node<E> q = p.prev; + if (q == null) { + if (p.next == p) + continue retry; + newNode.lazySetNext(p); // CAS piggyback + if (p.casPrev(null, newNode)) { + if (p != h) // hop two nodes at a time + casHead(h, newNode); + return; + } else { + p = p.prev; // lost CAS race to another thread + } + } + else if (p == q) + continue retry; + else + p = q; + } + } + } + + /** + * Links e as last element. + */ + private void linkLast(E e) { + checkNotNull(e); + final Node<E> newNode = new Node<E>(e); + + retry: + for (;;) { + for (Node<E> t = tail, p = t;;) { + Node<E> q = p.next; + if (q == null) { + if (p.prev == p) + continue retry; + newNode.lazySetPrev(p); // CAS piggyback + if (p.casNext(null, newNode)) { + if (p != t) // hop two nodes at a time + casTail(t, newNode); + return; + } else { + p = p.next; // lost CAS race to another thread + } + } + else if (p == q) + continue retry; + else + p = q; + } + } + } + + // TODO: Is there a better cheap way of performing some cleanup + // operation "occasionally"? + static class Count { + int count = 0; + } + private final static ThreadLocal<Count> tlc = + new ThreadLocal<Count>() { + protected Count initialValue() { return new Count(); } + }; + private static boolean shouldGCUnlinkOccasionally() { + return (tlc.get().count++ & 0x3) == 0; + } + + private final static int HOPS = 2; + + /** + * Unlinks non-null node x. + */ + void unlink(Node<E> x) { + assert x != null; + assert x.item == null; + assert x != PREV_TERMINATOR; + assert x != NEXT_TERMINATOR; + + final Node<E> prev = x.prev; + final Node<E> next = x.next; + if (prev == null) { + unlinkFirst(x, next); + } else if (next == null) { + unlinkLast(x, prev); + } else { + // Unlink interior node. + // + // This is the common case, since a series of polls at the + // same end will be "interior" removes, except perhaps for + // the first one, since end nodes cannot be physically removed. + // + // At any time, all active nodes are mutually reachable by + // following a sequence of either next or prev pointers. + // + // Our strategy is to find the unique active predecessor + // and successor of x. Try to fix up their links so that + // they point to each other, leaving x unreachable from + // active nodes. If successful, and if x has no live + // predecessor/successor, we additionally try to leave + // active nodes unreachable from x, by rechecking that + // the status of predecessor and successor are unchanged + // and ensuring that x is not reachable from tail/head, + // before setting x's prev/next links to their logical + // approximate replacements, self/TERMINATOR. + Node<E> activePred, activeSucc; + boolean isFirst, isLast; + int hops = 1; + + // Find active predecessor + for (Node<E> p = prev;; ++hops) { + if (p.item != null) { + activePred = p; + isFirst = false; + break; + } + Node<E> q = p.prev; + if (q == null) { + if (p == p.next) + return; + activePred = p; + isFirst = true; + break; + } + else if (p == q) + return; + else + p = q; + } + + // Find active successor + for (Node<E> p = next;; ++hops) { + if (p.item != null) { + activeSucc = p; + isLast = false; + break; + } + Node<E> q = p.next; + if (q == null) { + if (p == p.prev) + return; + activeSucc = p; + isLast = true; + break; + } + else if (p == q) + return; + else + p = q; + } + + // TODO: better HOP heuristics + if (hops < HOPS + // always squeeze out interior deleted nodes + && (isFirst | isLast)) + return; + + // Squeeze out deleted nodes between activePred and + // activeSucc, including x. + skipDeletedSuccessors(activePred); + skipDeletedPredecessors(activeSucc); + + // Try to gc-unlink, if possible + if ((isFirst | isLast) && + //shouldGCUnlinkOccasionally() && + + // Recheck expected state of predecessor and successor + (activePred.next == activeSucc) && + (activeSucc.prev == activePred) && + (isFirst ? activePred.prev == null : activePred.item != null) && + (isLast ? activeSucc.next == null : activeSucc.item != null)) { + + // Ensure x is not reachable from head or tail + updateHead(); + updateTail(); + x.lazySetPrev(isFirst ? prevTerminator() : x); + x.lazySetNext(isLast ? nextTerminator() : x); + } + } + } + + /** + * Unlinks non-null first node. + */ + private void unlinkFirst(Node<E> first, Node<E> next) { + assert first != null && next != null && first.item == null; + Node<E> o = null, p = next; + for (int hops = 0;; ++hops) { + Node<E> q; + if (p.item != null || (q = p.next) == null) { + if (hops >= HOPS) { + if (p == p.prev) + return; + if (first.casNext(next, p)) { + skipDeletedPredecessors(p); + if (//shouldGCUnlinkOccasionally() && + first.prev == null && + (p.next == null || p.item != null) && + p.prev == first) { + + updateHead(); + updateTail(); + o.lazySetNext(o); + o.lazySetPrev(prevTerminator()); + } + } + } + return; + } + else if (p == q) + return; + else { + o = p; + p = q; + } + } + } + + /** + * Unlinks non-null last node. + */ + private void unlinkLast(Node<E> last, Node<E> prev) { + assert last != null && prev != null && last.item == null; + Node<E> o = null, p = prev; + for (int hops = 0;; ++hops) { + Node<E> q; + if (p.item != null || (q = p.prev) == null) { + if (hops >= HOPS) { + if (p == p.next) + return; + if (last.casPrev(prev, p)) { + skipDeletedSuccessors(p); + if (//shouldGCUnlinkOccasionally() && + last.next == null && + (p.prev == null || p.item != null) && + p.next == last) { + + updateHead(); + updateTail(); + o.lazySetPrev(o); + o.lazySetNext(nextTerminator()); + } + } + } + return; + } + else if (p == q) + return; + else { + o = p; + p = q; + } + } + } + + private final void updateHead() { + first(); + } + + private final void updateTail() { + last(); + } + + private void skipDeletedPredecessors(Node<E> x) { + whileActive: + do { + Node<E> prev = x.prev; + assert prev != null; + assert x != NEXT_TERMINATOR; + assert x != PREV_TERMINATOR; + Node<E> p = prev; + findActive: + for (;;) { + if (p.item != null) + break findActive; + Node<E> q = p.prev; + if (q == null) { + if (p.next == p) + continue whileActive; + break findActive; + } + else if (p == q) + continue whileActive; + else + p = q; + } + + // found active CAS target + if (prev == p || x.casPrev(prev, p)) + return; + + } while (x.item != null || x.next == null); + } + + private void skipDeletedSuccessors(Node<E> x) { + whileActive: + do { + Node<E> next = x.next; + assert next != null; + assert x != NEXT_TERMINATOR; + assert x != PREV_TERMINATOR; + Node<E> p = next; + findActive: + for (;;) { + if (p.item != null) + break findActive; + Node<E> q = p.next; + if (q == null) { + if (p.prev == p) + continue whileActive; + break findActive; + } + else if (p == q) + continue whileActive; + else + p = q; + } + + // found active CAS target + if (next == p || x.casNext(next, p)) + return; + + } while (x.item != null || x.prev == null); + } + + /** + * Returns the successor of p, or the first node if p.next has been + * linked to self, which will only be true if traversing with a + * stale pointer that is now off the list. + */ + final Node<E> succ(Node<E> p) { + // TODO: should we skip deleted nodes here? + Node<E> q = p.next; + return (p == q) ? first() : q; + } + + /** + * Returns the predecessor of p, or the last node if p.prev has been + * linked to self, which will only be true if traversing with a + * stale pointer that is now off the list. + */ + final Node<E> pred(Node<E> p) { + Node<E> q = p.prev; + return (p == q) ? last() : q; + } + + /** + * Returns the first node, the unique node which has a null prev link. + * The returned node may or may not be logically deleted. + * Guarantees that head is set to the returned node. + */ + Node<E> first() { + retry: + for (;;) { + for (Node<E> h = head, p = h;;) { + Node<E> q = p.prev; + if (q == null) { + if (p == h + // It is possible that p is PREV_TERMINATOR, + // but if so, the CAS will fail. + || casHead(h, p)) + return p; + else + continue retry; + } else if (p == q) { + continue retry; + } else { + p = q; + } + } + } + } + + /** + * Returns the last node, the unique node which has a null next link. + * The returned node may or may not be logically deleted. + * Guarantees that tail is set to the returned node. + */ + Node<E> last() { + retry: + for (;;) { + for (Node<E> t = tail, p = t;;) { + Node<E> q = p.next; + if (q == null) { + if (p == t + // It is possible that p is NEXT_TERMINATOR, + // but if so, the CAS will fail. + || casTail(t, p)) + return p; + else + continue retry; + } else if (p == q) { + continue retry; + } else { + p = q; + } + } + } + } + + // Minor convenience utilities + + /** + * Throws NullPointerException if argument is null. + * + * @param v the element + */ + private static void checkNotNull(Object v) { + if (v == null) + throw new NullPointerException(); + } + + /** + * Returns element unless it is null, in which case throws + * NoSuchElementException. + * + * @param v the element + * @return the element + */ + private E screenNullResult(E v) { + if (v == null) + throw new NoSuchElementException(); + return v; + } + + /** + * Creates an array list and fills it with elements of this list. + * Used by toArray. + * + * @return the arrayList + */ + private ArrayList<E> toArrayList() { + ArrayList<E> c = new ArrayList<E>(); + for (Node<E> p = first(); p != null; p = succ(p)) { + E item = p.item; + if (item != null) + c.add(item); + } + return c; + } + + // Fields and constructors + + private static final long serialVersionUID = 876323262645176354L; + + /** + * Constructs an empty deque. + */ + public ConcurrentLinkedDeque() {} + + /** + * Constructs a deque initially containing the elements of + * the given collection, added in traversal order of the + * collection's iterator. + * + * @param c the collection of elements to initially contain + * @throws NullPointerException if the specified collection or any + * of its elements are null + */ + public ConcurrentLinkedDeque(Collection<? extends E> c) { + this(); + addAll(c); + } + + /** + * Inserts the specified element at the front of this deque. + * + * @throws NullPointerException {@inheritDoc} + */ + public void addFirst(E e) { + linkFirst(e); + } + + /** + * Inserts the specified element at the end of this deque. + * This is identical in function to the {@code add} method. + * + * @throws NullPointerException {@inheritDoc} + */ + public void addLast(E e) { + linkLast(e); + } + + /** + * Inserts the specified element at the front of this deque. + * + * @return {@code true} always + * @throws NullPointerException {@inheritDoc} + */ + public boolean offerFirst(E e) { + linkFirst(e); + return true; + } + + /** + * Inserts the specified element at the end of this deque. + * + * <p>This method is equivalent to {@link #add}. + * + * @return {@code true} always + * @throws NullPointerException {@inheritDoc} + */ + public boolean offerLast(E e) { + linkLast(e); + return true; + } + + public E peekFirst() { + for (Node<E> p = first(); p != null; p = succ(p)) { + E item = p.item; + if (item != null) + return item; + } + return null; + } + + public E peekLast() { + for (Node<E> p = last(); p != null; p = pred(p)) { + E item = p.item; + if (item != null) + return item; + } + return null; + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E getFirst() { + return screenNullResult(peekFirst()); + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E getLast() { + return screenNullResult(peekLast()); + } + + public E pollFirst() { + for (Node<E> p = first(); p != null; p = succ(p)) { + E item = p.item; + if (item != null && p.casItem(item, null)) { + unlink(p); + return item; + } + } + return null; + } + + public E pollLast() { + for (Node<E> p = last(); p != null; p = pred(p)) { + E item = p.item; + if (item != null && p.casItem(item, null)) { + unlink(p); + return item; + } + } + return null; + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E removeFirst() { + return screenNullResult(pollFirst()); + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E removeLast() { + return screenNullResult(pollLast()); + } + + // *** Queue and stack methods *** + + /** + * Inserts the specified element at the tail of this deque. + * + * @return {@code true} (as specified by {@link Queue#offer}) + * @throws NullPointerException if the specified element is null + */ + public boolean offer(E e) { + return offerLast(e); + } + + /** + * Inserts the specified element at the tail of this deque. + * + * @return {@code true} (as specified by {@link Collection#add}) + * @throws NullPointerException if the specified element is null + */ + public boolean add(E e) { + return offerLast(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); } + public E pop() { return removeFirst(); } + + /** + * Removes the first element {@code e} such that + * {@code o.equals(e)}, if such an element exists in this deque. + * If the deque does not contain the element, it is unchanged. + * + * @param o element to be removed from this deque, if present + * @return {@code true} if the deque contained the specified element + * @throws NullPointerException if the specified element is {@code null} + */ + public boolean removeFirstOccurrence(Object o) { + checkNotNull(o); + for (Node<E> p = first(); p != null; p = succ(p)) { + E item = p.item; + if (item != null && o.equals(item) && p.casItem(item, null)) { + unlink(p); + return true; + } + } + return false; + } + + /** + * Removes the last element {@code e} such that + * {@code o.equals(e)}, if such an element exists in this deque. + * If the deque does not contain the element, it is unchanged. + * + * @param o element to be removed from this deque, if present + * @return {@code true} if the deque contained the specified element + * @throws NullPointerException if the specified element is {@code null} + */ + public boolean removeLastOccurrence(Object o) { + checkNotNull(o); + for (Node<E> p = last(); p != null; p = pred(p)) { + E item = p.item; + if (item != null && o.equals(item) && p.casItem(item, null)) { + unlink(p); + return true; + } + } + return false; + } + + /** + * Returns {@code true} if this deque contains at least one + * element {@code e} such that {@code o.equals(e)}. + * + * @param o element whose presence in this deque is to be tested + * @return {@code true} if this deque contains the specified element + */ + public boolean contains(Object o) { + if (o == null) return false; + for (Node<E> p = first(); p != null; p = succ(p)) { + E item = p.item; + if (item != null && o.equals(item)) + return true; + } + return false; + } + + /** + * Returns {@code true} if this collection contains no elements. + * + * @return {@code true} if this collection contains no elements + */ + public boolean isEmpty() { + return peekFirst() == null; + } + + /** + * Returns the number of elements in this deque. If this deque + * 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 + * asynchronous nature of these deques, determining the current + * number of elements requires traversing them all to count them. + * Additionally, it is possible for the size to change during + * execution of this method, in which case the returned result + * will be inaccurate. Thus, this method is typically not very + * useful in concurrent applications. + * + * @return the number of elements in this deque + */ + public int size() { + long count = 0; + for (Node<E> p = first(); p != null; p = succ(p)) + if (p.item != null) + ++count; + return (count >= Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) count; + } + + /** + * Removes the first element {@code e} such that + * {@code o.equals(e)}, if such an element exists in this deque. + * If the deque does not contain the element, it is unchanged. + * + * @param o element to be removed from this deque, if present + * @return {@code true} if the deque contained the specified element + * @throws NullPointerException if the specified element is {@code null} + */ + public boolean remove(Object o) { + return removeFirstOccurrence(o); + } + + /** + * Appends all of the elements in the specified collection to the end of + * this deque, in the order that they are returned by the specified + * collection's iterator. The behavior of this operation is undefined if + * the specified collection is modified while the operation is in + * progress. (This implies that the behavior of this call is undefined if + * the specified Collection is this deque, and this deque is nonempty.) + * + * @param c the elements to be inserted into this deque + * @return {@code true} if this deque changed as a result of the call + * @throws NullPointerException if {@code c} or any element within it + * is {@code null} + */ + public boolean addAll(Collection<? extends E> c) { + Iterator<? extends E> it = c.iterator(); + if (!it.hasNext()) + return false; + do { + addLast(it.next()); + } while (it.hasNext()); + return true; + } + + /** + * Removes all of the elements from this deque. + */ + public void clear() { + while (pollFirst() != null) + ; + } + + /** + * Returns an array containing all of the elements in this deque, in + * proper sequence (from first to last element). + * + * <p>The returned array will be "safe" in that no references to it are + * maintained by this deque. (In other words, this method must allocate + * a new array). The caller is thus free to modify the returned array. + * + * <p>This method acts as bridge between array-based and collection-based + * APIs. + * + * @return an array containing all of the elements in this deque + */ + public Object[] toArray() { + return toArrayList().toArray(); + } + + /** + * Returns an array containing all of the elements in this deque, + * in proper sequence (from first to last element); the runtime + * type of the returned array is that of the specified array. If + * the deque fits in the specified array, it is returned therein. + * Otherwise, a new array is allocated with the runtime type of + * the specified array and the size of this deque. + * + * <p>If this deque fits in the specified array with room to spare + * (i.e., the array has more elements than this deque), the element in + * the array immediately following the end of the deque is set to + * {@code null}. + * + * <p>Like the {@link #toArray()} method, this method acts as bridge between + * array-based and collection-based APIs. Further, this method allows + * precise control over the runtime type of the output array, and may, + * under certain circumstances, be used to save allocation costs. + * + * <p>Suppose {@code x} is a deque known to contain only strings. + * The following code can be used to dump the deque into a newly + * allocated array of {@code String}: + * + * <pre> + * String[] y = x.toArray(new String[0]);</pre> + * + * Note that {@code toArray(new Object[0])} is identical in function to + * {@code toArray()}. + * + * @param a the array into which the elements of the deque are to + * be stored, if it is big enough; otherwise, a new array of the + * same runtime type is allocated for this purpose + * @return an array containing all of the elements in this deque + * @throws ArrayStoreException if the runtime type of the specified array + * is not a supertype of the runtime type of every element in + * this deque + * @throws NullPointerException if the specified array is null + */ + public <T> T[] toArray(T[] a) { + return toArrayList().toArray(a); + } + + /** + * Returns an iterator over the elements in this deque in proper sequence. + * The elements will be returned in order from first (head) to last (tail). + * + * <p>The returned {@code Iterator} is a "weakly consistent" iterator that + * will never throw {@link java.util.ConcurrentModificationException + * ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + * + * @return an iterator over the elements in this deque in proper sequence + */ + public Iterator<E> iterator() { + return new Itr(); + } + + /** + * Returns an iterator over the elements in this deque in reverse + * sequential order. The elements will be returned in order from + * last (tail) to first (head). + * + * <p>The returned {@code Iterator} is a "weakly consistent" iterator that + * will never throw {@link java.util.ConcurrentModificationException + * ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + */ + public Iterator<E> descendingIterator() { + return new DescendingItr(); + } + + private abstract class AbstractItr implements Iterator<E> { + /** + * Next node to return item for. + */ + private Node<E> nextNode; + + /** + * nextItem holds on to item fields because once we claim + * that an element exists in hasNext(), we must return it in + * the following next() call even if it was in the process of + * being removed when hasNext() was called. + */ + private E nextItem; + + /** + * Node returned by most recent call to next. Needed by remove. + * Reset to null if this element is deleted by a call to remove. + */ + private Node<E> lastRet; + + abstract Node<E> startNode(); + abstract Node<E> nextNode(Node<E> p); + + AbstractItr() { + advance(); + } + + /** + * Sets nextNode and nextItem to next valid node, or to null + * if no such. + */ + private void advance() { + lastRet = nextNode; + + Node<E> p = (nextNode == null) ? startNode() : nextNode(nextNode); + for (;; p = nextNode(p)) { + if (p == null) { + // p might be active end or TERMINATOR node; both are OK + nextNode = null; + nextItem = null; + break; + } + E item = p.item; + if (item != null) { + nextNode = p; + nextItem = item; + break; + } + } + } + + public boolean hasNext() { + return nextItem != null; + } + + public E next() { + E item = nextItem; + if (item == null) throw new NoSuchElementException(); + advance(); + return item; + } + + public void remove() { + Node<E> l = lastRet; + if (l == null) throw new IllegalStateException(); + l.item = null; + unlink(l); + lastRet = null; + } + } + + /** Forward iterator */ + private class Itr extends AbstractItr { + Node<E> startNode() { return first(); } + Node<E> nextNode(Node<E> p) { return succ(p); } + } + + /** Descending iterator */ + private class DescendingItr extends AbstractItr { + Node<E> startNode() { return last(); } + Node<E> nextNode(Node<E> p) { return pred(p); } + } + + /** + * Save the state to a stream (that is, serialize it). + * + * @serialData All of the elements (each an {@code E}) in + * the proper order, followed by a null + * @param s the stream + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + + // Write out any hidden stuff + s.defaultWriteObject(); + + // Write out all elements in the proper order. + for (Node<E> p = first(); p != null; p = succ(p)) { + Object item = p.item; + if (item != null) + s.writeObject(item); + } + + // Use trailing null as sentinel + s.writeObject(null); + } + + /** + * Reconstitute the Queue instance from a stream (that is, + * deserialize it). + * @param s the stream + */ + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + // Read in capacity, and any hidden stuff + s.defaultReadObject(); + tail = head = new Node<E>(null); + // Read in all elements and place in queue + for (;;) { + @SuppressWarnings("unchecked") + E item = (E)s.readObject(); + if (item == null) + break; + else + offer(item); + } + } + + // Unsafe mechanics + + private static final sun.misc.Unsafe UNSAFE = + sun.misc.Unsafe.getUnsafe(); + private static final long headOffset = + objectFieldOffset(UNSAFE, "head", ConcurrentLinkedDeque.class); + private static final long tailOffset = + objectFieldOffset(UNSAFE, "tail", ConcurrentLinkedDeque.class); + + private boolean casHead(Node<E> cmp, Node<E> val) { + return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val); + } + + private boolean casTail(Node<E> cmp, Node<E> val) { + return UNSAFE.compareAndSwapObject(this, tailOffset, cmp, val); + } + + static long objectFieldOffset(sun.misc.Unsafe UNSAFE, + String field, Class<?> klazz) { + try { + return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field)); + } catch (NoSuchFieldException e) { + // Convert Exception to corresponding Error + NoSuchFieldError error = new NoSuchFieldError(field); + error.initCause(e); + throw error; + } + } +} diff --git a/concurrent/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java b/concurrent/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java index 2253823..2d222c1 100644 --- a/concurrent/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java +++ b/concurrent/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java @@ -5,9 +5,13 @@ */ package java.util.concurrent; -import java.util.*; -import java.util.concurrent.atomic.*; +import java.util.AbstractQueue; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Queue; // BEGIN android-note // removed link to collections framework docs @@ -126,34 +130,34 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E> * CAS, so they never regress, although again this is merely an * optimization. */ + private static class Node<E> { private volatile E item; private volatile Node<E> next; - private static final - AtomicReferenceFieldUpdater<Node, Node> - nextUpdater = - AtomicReferenceFieldUpdater.newUpdater - (Node.class, Node.class, "next"); - private static final - AtomicReferenceFieldUpdater<Node, Object> - itemUpdater = - AtomicReferenceFieldUpdater.newUpdater - (Node.class, Object.class, "item"); - - - Node(E item) { setItem(item); } + Node(E item) { + // Piggyback on imminent casNext() + lazySetItem(item); + } E getItem() { return item; } boolean casItem(E cmp, E val) { - return itemUpdater.compareAndSet(this, cmp, val); + return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val); } void setItem(E val) { - itemUpdater.set(this, val); + item = val; + } + + void lazySetItem(E val) { + UNSAFE.putOrderedObject(this, itemOffset, val); + } + + void lazySetNext(Node<E> val) { + UNSAFE.putOrderedObject(this, nextOffset, val); } Node<E> getNext() { @@ -161,42 +165,45 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E> } boolean casNext(Node<E> cmp, Node<E> val) { - return nextUpdater.compareAndSet(this, cmp, val); + return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val); } - void setNext(Node<E> val) { - nextUpdater.set(this, val); - } + // Unsafe mechanics + private static final sun.misc.Unsafe UNSAFE = + sun.misc.Unsafe.getUnsafe(); + private static final long nextOffset = + objectFieldOffset(UNSAFE, "next", Node.class); + private static final long itemOffset = + objectFieldOffset(UNSAFE, "item", Node.class); } - private static final - AtomicReferenceFieldUpdater<ConcurrentLinkedQueue, Node> - tailUpdater = - AtomicReferenceFieldUpdater.newUpdater - (ConcurrentLinkedQueue.class, Node.class, "tail"); - private static final - AtomicReferenceFieldUpdater<ConcurrentLinkedQueue, Node> - headUpdater = - AtomicReferenceFieldUpdater.newUpdater - (ConcurrentLinkedQueue.class, Node.class, "head"); - - private boolean casTail(Node<E> cmp, Node<E> val) { - return tailUpdater.compareAndSet(this, cmp, val); - } - - private boolean casHead(Node<E> cmp, Node<E> val) { - return headUpdater.compareAndSet(this, cmp, val); - } - - - /** - * Pointer to first node, initialized to a dummy node. + * A node from which the first live (non-deleted) node (if any) + * can be reached in O(1) time. + * Invariants: + * - all live nodes are reachable from head via succ() + * - head != null + * - (tmp = head).next != tmp || tmp != head + * Non-invariants: + * - head.item may or may not be null. + * - it is permitted for tail to lag behind head, that is, for tail + * to not be reachable from head! */ private transient volatile Node<E> head = new Node<E>(null); - /** Pointer to last node on list */ + /** + * A node from which the last node on list (that is, the unique + * node with node.next == null) can be reached in O(1) time. + * Invariants: + * - the last node is always reachable from tail via succ() + * - tail != null + * Non-invariants: + * - tail.item may or may not be null. + * - it is permitted for tail to lag behind head, that is, for tail + * to not be reachable from head! + * - tail.next may or may not be self-pointing to tail. + */ private transient volatile Node<E> tail = head; @@ -214,8 +221,8 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E> * of its elements are null */ public ConcurrentLinkedQueue(Collection<? extends E> c) { - for (Iterator<? extends E> it = c.iterator(); it.hasNext();) - add(it.next()); + for (E e : c) + add(e); } // Have to override just to update the javadoc @@ -231,7 +238,7 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E> } /** - * We don't bother to update head or tail pointers if less than + * We don't bother to update head or tail pointers if fewer than * HOPS links from "true" location. We assume that volatile * writes are significantly more expensive than volatile reads. */ @@ -243,7 +250,7 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E> */ final void updateHead(Node<E> h, Node<E> p) { if (h != p && casHead(h, p)) - h.setNext(h); + h.lazySetNext(h); } /** @@ -328,10 +335,12 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E> } /** - * Returns the first actual (non-header) node on list. This is yet - * another variant of poll/peek; here returning out the first - * node, not element (so we cannot collapse with peek() without - * introducing race.) + * Returns the first live (non-deleted) node on list, or null if none. + * This is yet another variant of poll/peek; here returning the + * first node, not element. We could make peek() a wrapper around + * first(), but that would cost an extra volatile read of item, + * and the need to add a retry loop to deal with the possibility + * of losing a race to a concurrent poll(). */ Node<E> first() { Node<E> h = head; @@ -422,7 +431,9 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E> Node<E> pred = null; for (Node<E> p = first(); p != null; p = succ(p)) { E item = p.getItem(); - if (item != null && o.equals(item) && p.casItem(item, null)) { + if (item != null && + o.equals(item) && + p.casItem(item, null)) { Node<E> next = succ(p); if (pred != null && next != null) pred.casNext(p, next); @@ -522,7 +533,8 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E> /** * Returns an iterator over the elements in this queue in proper sequence. * The returned iterator is a "weakly consistent" iterator that - * will never throw {@link ConcurrentModificationException}, + * will never throw {@link java.util.ConcurrentModificationException + * ConcurrentModificationException}, * and guarantees to traverse elements as they existed upon * construction of the iterator, and may (but is not guaranteed to) * reflect any modifications subsequent to construction. @@ -658,4 +670,35 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E> } } + // Unsafe mechanics + + private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe(); + private static final long headOffset = + objectFieldOffset(UNSAFE, "head", ConcurrentLinkedQueue.class); + private static final long tailOffset = + objectFieldOffset(UNSAFE, "tail", ConcurrentLinkedQueue.class); + + private boolean casTail(Node<E> cmp, Node<E> val) { + return UNSAFE.compareAndSwapObject(this, tailOffset, cmp, val); + } + + private boolean casHead(Node<E> cmp, Node<E> val) { + return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val); + } + + private void lazySetHead(Node<E> val) { + UNSAFE.putOrderedObject(this, headOffset, val); + } + + static long objectFieldOffset(sun.misc.Unsafe UNSAFE, + String field, Class<?> klazz) { + try { + return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field)); + } catch (NoSuchFieldException e) { + // Convert Exception to corresponding Error + NoSuchFieldError error = new NoSuchFieldError(field); + error.initCause(e); + throw error; + } + } } diff --git a/concurrent/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java b/concurrent/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java new file mode 100644 index 0000000..7d86afb --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java @@ -0,0 +1,148 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.*; + +/** + * A {@link ConcurrentMap} supporting {@link NavigableMap} operations, + * and recursively so for its navigable sub-maps. + * + * <p>This interface is a member of the + * <a href="{@docRoot}/../technotes/guides/collections/index.html"> + * Java Collections Framework</a>. + * + * @author Doug Lea + * @param <K> the type of keys maintained by this map + * @param <V> the type of mapped values + * @since 1.6 + */ +public interface ConcurrentNavigableMap<K,V> + extends ConcurrentMap<K,V>, NavigableMap<K,V> +{ + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + ConcurrentNavigableMap<K,V> subMap(K fromKey, boolean fromInclusive, + K toKey, boolean toInclusive); + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + ConcurrentNavigableMap<K,V> headMap(K toKey, boolean inclusive); + + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + ConcurrentNavigableMap<K,V> tailMap(K fromKey, boolean inclusive); + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + ConcurrentNavigableMap<K,V> subMap(K fromKey, K toKey); + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + ConcurrentNavigableMap<K,V> headMap(K toKey); + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + ConcurrentNavigableMap<K,V> tailMap(K fromKey); + + /** + * Returns a reverse order view of the mappings contained in this map. + * The descending map is backed by this map, so changes to the map are + * reflected in the descending map, and vice-versa. + * + * <p>The returned map has an ordering equivalent to + * <tt>{@link Collections#reverseOrder(Comparator) Collections.reverseOrder}(comparator())</tt>. + * The expression {@code m.descendingMap().descendingMap()} returns a + * view of {@code m} essentially equivalent to {@code m}. + * + * @return a reverse order view of this map + */ + ConcurrentNavigableMap<K,V> descendingMap(); + + /** + * Returns a {@link NavigableSet} view of the keys contained in this map. + * The set's iterator returns the keys in ascending order. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. The set supports element + * removal, which removes the corresponding mapping from the map, + * via the {@code Iterator.remove}, {@code Set.remove}, + * {@code removeAll}, {@code retainAll}, and {@code clear} + * operations. It does not support the {@code add} or {@code addAll} + * operations. + * + * <p>The view's {@code iterator} is a "weakly consistent" iterator + * that will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + * + * @return a navigable set view of the keys in this map + */ + public NavigableSet<K> navigableKeySet(); + + /** + * Returns a {@link NavigableSet} view of the keys contained in this map. + * The set's iterator returns the keys in ascending order. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. The set supports element + * removal, which removes the corresponding mapping from the map, + * via the {@code Iterator.remove}, {@code Set.remove}, + * {@code removeAll}, {@code retainAll}, and {@code clear} + * operations. It does not support the {@code add} or {@code addAll} + * operations. + * + * <p>The view's {@code iterator} is a "weakly consistent" iterator + * that will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + * + * <p>This method is equivalent to method {@code navigableKeySet}. + * + * @return a navigable set view of the keys in this map + */ + NavigableSet<K> keySet(); + + /** + * Returns a reverse order {@link NavigableSet} view of the keys contained in this map. + * The set's iterator returns the keys in descending order. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. The set supports element + * removal, which removes the corresponding mapping from the map, + * via the {@code Iterator.remove}, {@code Set.remove}, + * {@code removeAll}, {@code retainAll}, and {@code clear} + * operations. It does not support the {@code add} or {@code addAll} + * operations. + * + * <p>The view's {@code iterator} is a "weakly consistent" iterator + * that will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + * + * @return a reverse order navigable set view of the keys in this map + */ + public NavigableSet<K> descendingKeySet(); +} diff --git a/concurrent/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java b/concurrent/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java new file mode 100644 index 0000000..d73d163 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java @@ -0,0 +1,3115 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.*; +import java.util.concurrent.atomic.*; + +/** + * A scalable concurrent {@link ConcurrentNavigableMap} implementation. + * The map is sorted according to the {@linkplain Comparable natural + * ordering} of its keys, or by a {@link Comparator} provided at map + * creation time, depending on which constructor is used. + * + * <p>This class implements a concurrent variant of <a + * href="http://www.cs.umd.edu/~pugh/">SkipLists</a> providing + * expected average <i>log(n)</i> time cost for the + * <tt>containsKey</tt>, <tt>get</tt>, <tt>put</tt> and + * <tt>remove</tt> operations and their variants. Insertion, removal, + * update, and access operations safely execute concurrently by + * multiple threads. Iterators are <i>weakly consistent</i>, returning + * elements reflecting the state of the map at some point at or since + * the creation of the iterator. They do <em>not</em> throw {@link + * ConcurrentModificationException}, and may proceed concurrently with + * other operations. Ascending key ordered views and their iterators + * are faster than descending ones. + * + * <p>All <tt>Map.Entry</tt> pairs returned by methods in this class + * and its views represent snapshots of mappings at the time they were + * produced. They do <em>not</em> support the <tt>Entry.setValue</tt> + * method. (Note however that it is possible to change mappings in the + * associated map using <tt>put</tt>, <tt>putIfAbsent</tt>, or + * <tt>replace</tt>, depending on exactly which effect you need.) + * + * <p>Beware that, unlike in most collections, the <tt>size</tt> + * method is <em>not</em> a constant-time operation. Because of the + * asynchronous nature of these maps, determining the current number + * of elements requires a traversal of the elements. Additionally, + * the bulk operations <tt>putAll</tt>, <tt>equals</tt>, and + * <tt>clear</tt> are <em>not</em> guaranteed to be performed + * atomically. For example, an iterator operating concurrently with a + * <tt>putAll</tt> operation might view only some of the added + * elements. + * + * <p>This class and its views and iterators implement all of the + * <em>optional</em> methods of the {@link Map} and {@link Iterator} + * interfaces. Like most other concurrent collections, this class does + * <em>not</em> permit the use of <tt>null</tt> keys or values because some + * null return values cannot be reliably distinguished from the absence of + * elements. + * + * <p>This class is a member of the + * <a href="{@docRoot}/../technotes/guides/collections/index.html"> + * Java Collections Framework</a>. + * + * @author Doug Lea + * @param <K> the type of keys maintained by this map + * @param <V> the type of mapped values + * @since 1.6 + */ +public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V> + implements ConcurrentNavigableMap<K,V>, + Cloneable, + java.io.Serializable { + /* + * This class implements a tree-like two-dimensionally linked skip + * list in which the index levels are represented in separate + * nodes from the base nodes holding data. There are two reasons + * for taking this approach instead of the usual array-based + * structure: 1) Array based implementations seem to encounter + * more complexity and overhead 2) We can use cheaper algorithms + * for the heavily-traversed index lists than can be used for the + * base lists. Here's a picture of some of the basics for a + * possible list with 2 levels of index: + * + * Head nodes Index nodes + * +-+ right +-+ +-+ + * |2|---------------->| |--------------------->| |->null + * +-+ +-+ +-+ + * | down | | + * v v v + * +-+ +-+ +-+ +-+ +-+ +-+ + * |1|----------->| |->| |------>| |----------->| |------>| |->null + * +-+ +-+ +-+ +-+ +-+ +-+ + * v | | | | | + * Nodes next v v v v v + * +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ + * | |->|A|->|B|->|C|->|D|->|E|->|F|->|G|->|H|->|I|->|J|->|K|->null + * +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ + * + * The base lists use a variant of the HM linked ordered set + * algorithm. See Tim Harris, "A pragmatic implementation of + * non-blocking linked lists" + * http://www.cl.cam.ac.uk/~tlh20/publications.html and Maged + * Michael "High Performance Dynamic Lock-Free Hash Tables and + * List-Based Sets" + * http://www.research.ibm.com/people/m/michael/pubs.htm. The + * basic idea in these lists is to mark the "next" pointers of + * deleted nodes when deleting to avoid conflicts with concurrent + * insertions, and when traversing to keep track of triples + * (predecessor, node, successor) in order to detect when and how + * to unlink these deleted nodes. + * + * Rather than using mark-bits to mark list deletions (which can + * be slow and space-intensive using AtomicMarkedReference), nodes + * use direct CAS'able next pointers. On deletion, instead of + * marking a pointer, they splice in another node that can be + * thought of as standing for a marked pointer (indicating this by + * using otherwise impossible field values). Using plain nodes + * acts roughly like "boxed" implementations of marked pointers, + * but uses new nodes only when nodes are deleted, not for every + * link. This requires less space and supports faster + * traversal. Even if marked references were better supported by + * JVMs, traversal using this technique might still be faster + * because any search need only read ahead one more node than + * otherwise required (to check for trailing marker) rather than + * unmasking mark bits or whatever on each read. + * + * This approach maintains the essential property needed in the HM + * algorithm of changing the next-pointer of a deleted node so + * that any other CAS of it will fail, but implements the idea by + * changing the pointer to point to a different node, not by + * marking it. While it would be possible to further squeeze + * space by defining marker nodes not to have key/value fields, it + * isn't worth the extra type-testing overhead. The deletion + * markers are rarely encountered during traversal and are + * normally quickly garbage collected. (Note that this technique + * would not work well in systems without garbage collection.) + * + * In addition to using deletion markers, the lists also use + * nullness of value fields to indicate deletion, in a style + * similar to typical lazy-deletion schemes. If a node's value is + * null, then it is considered logically deleted and ignored even + * though it is still reachable. This maintains proper control of + * concurrent replace vs delete operations -- an attempted replace + * must fail if a delete beat it by nulling field, and a delete + * must return the last non-null value held in the field. (Note: + * Null, rather than some special marker, is used for value fields + * here because it just so happens to mesh with the Map API + * requirement that method get returns null if there is no + * mapping, which allows nodes to remain concurrently readable + * even when deleted. Using any other marker value here would be + * messy at best.) + * + * Here's the sequence of events for a deletion of node n with + * predecessor b and successor f, initially: + * + * +------+ +------+ +------+ + * ... | b |------>| n |----->| f | ... + * +------+ +------+ +------+ + * + * 1. CAS n's value field from non-null to null. + * From this point on, no public operations encountering + * the node consider this mapping to exist. However, other + * ongoing insertions and deletions might still modify + * n's next pointer. + * + * 2. CAS n's next pointer to point to a new marker node. + * From this point on, no other nodes can be appended to n. + * which avoids deletion errors in CAS-based linked lists. + * + * +------+ +------+ +------+ +------+ + * ... | b |------>| n |----->|marker|------>| f | ... + * +------+ +------+ +------+ +------+ + * + * 3. CAS b's next pointer over both n and its marker. + * From this point on, no new traversals will encounter n, + * and it can eventually be GCed. + * +------+ +------+ + * ... | b |----------------------------------->| f | ... + * +------+ +------+ + * + * A failure at step 1 leads to simple retry due to a lost race + * with another operation. Steps 2-3 can fail because some other + * thread noticed during a traversal a node with null value and + * helped out by marking and/or unlinking. This helping-out + * ensures that no thread can become stuck waiting for progress of + * the deleting thread. The use of marker nodes slightly + * complicates helping-out code because traversals must track + * consistent reads of up to four nodes (b, n, marker, f), not + * just (b, n, f), although the next field of a marker is + * immutable, and once a next field is CAS'ed to point to a + * marker, it never again changes, so this requires less care. + * + * Skip lists add indexing to this scheme, so that the base-level + * traversals start close to the locations being found, inserted + * or deleted -- usually base level traversals only traverse a few + * nodes. This doesn't change the basic algorithm except for the + * need to make sure base traversals start at predecessors (here, + * b) that are not (structurally) deleted, otherwise retrying + * after processing the deletion. + * + * Index levels are maintained as lists with volatile next fields, + * using CAS to link and unlink. Races are allowed in index-list + * operations that can (rarely) fail to link in a new index node + * or delete one. (We can't do this of course for data nodes.) + * However, even when this happens, the index lists remain sorted, + * so correctly serve as indices. This can impact performance, + * but since skip lists are probabilistic anyway, the net result + * is that under contention, the effective "p" value may be lower + * than its nominal value. And race windows are kept small enough + * that in practice these failures are rare, even under a lot of + * contention. + * + * The fact that retries (for both base and index lists) are + * relatively cheap due to indexing allows some minor + * simplifications of retry logic. Traversal restarts are + * performed after most "helping-out" CASes. This isn't always + * strictly necessary, but the implicit backoffs tend to help + * reduce other downstream failed CAS's enough to outweigh restart + * cost. This worsens the worst case, but seems to improve even + * highly contended cases. + * + * Unlike most skip-list implementations, index insertion and + * deletion here require a separate traversal pass occuring after + * the base-level action, to add or remove index nodes. This adds + * to single-threaded overhead, but improves contended + * multithreaded performance by narrowing interference windows, + * and allows deletion to ensure that all index nodes will be made + * unreachable upon return from a public remove operation, thus + * avoiding unwanted garbage retention. This is more important + * here than in some other data structures because we cannot null + * out node fields referencing user keys since they might still be + * read by other ongoing traversals. + * + * Indexing uses skip list parameters that maintain good search + * performance while using sparser-than-usual indices: The + * hardwired parameters k=1, p=0.5 (see method randomLevel) mean + * that about one-quarter of the nodes have indices. Of those that + * do, half have one level, a quarter have two, and so on (see + * Pugh's Skip List Cookbook, sec 3.4). The expected total space + * requirement for a map is slightly less than for the current + * implementation of java.util.TreeMap. + * + * Changing the level of the index (i.e, the height of the + * tree-like structure) also uses CAS. The head index has initial + * level/height of one. Creation of an index with height greater + * than the current level adds a level to the head index by + * CAS'ing on a new top-most head. To maintain good performance + * after a lot of removals, deletion methods heuristically try to + * reduce the height if the topmost levels appear to be empty. + * This may encounter races in which it possible (but rare) to + * reduce and "lose" a level just as it is about to contain an + * index (that will then never be encountered). This does no + * structural harm, and in practice appears to be a better option + * than allowing unrestrained growth of levels. + * + * The code for all this is more verbose than you'd like. Most + * operations entail locating an element (or position to insert an + * element). The code to do this can't be nicely factored out + * because subsequent uses require a snapshot of predecessor + * and/or successor and/or value fields which can't be returned + * all at once, at least not without creating yet another object + * to hold them -- creating such little objects is an especially + * bad idea for basic internal search operations because it adds + * to GC overhead. (This is one of the few times I've wished Java + * had macros.) Instead, some traversal code is interleaved within + * insertion and removal operations. The control logic to handle + * all the retry conditions is sometimes twisty. Most search is + * broken into 2 parts. findPredecessor() searches index nodes + * only, returning a base-level predecessor of the key. findNode() + * finishes out the base-level search. Even with this factoring, + * there is a fair amount of near-duplication of code to handle + * variants. + * + * For explanation of algorithms sharing at least a couple of + * features with this one, see Mikhail Fomitchev's thesis + * (http://www.cs.yorku.ca/~mikhail/), Keir Fraser's thesis + * (http://www.cl.cam.ac.uk/users/kaf24/), and Hakan Sundell's + * thesis (http://www.cs.chalmers.se/~phs/). + * + * Given the use of tree-like index nodes, you might wonder why + * this doesn't use some kind of search tree instead, which would + * support somewhat faster search operations. The reason is that + * there are no known efficient lock-free insertion and deletion + * algorithms for search trees. The immutability of the "down" + * links of index nodes (as opposed to mutable "left" fields in + * true trees) makes this tractable using only CAS operations. + * + * Notation guide for local variables + * Node: b, n, f for predecessor, node, successor + * Index: q, r, d for index node, right, down. + * t for another index node + * Head: h + * Levels: j + * Keys: k, key + * Values: v, value + * Comparisons: c + */ + + private static final long serialVersionUID = -8627078645895051609L; + + /** + * Generates the initial random seed for the cheaper per-instance + * random number generators used in randomLevel. + */ + private static final Random seedGenerator = new Random(); + + /** + * Special value used to identify base-level header + */ + private static final Object BASE_HEADER = new Object(); + + /** + * The topmost head index of the skiplist. + */ + private transient volatile HeadIndex<K,V> head; + + /** + * The comparator used to maintain order in this map, or null + * if using natural ordering. + * @serial + */ + private final Comparator<? super K> comparator; + + /** + * Seed for simple random number generator. Not volatile since it + * doesn't matter too much if different threads don't see updates. + */ + private transient int randomSeed; + + /** Lazily initialized key set */ + private transient KeySet keySet; + /** Lazily initialized entry set */ + private transient EntrySet entrySet; + /** Lazily initialized values collection */ + private transient Values values; + /** Lazily initialized descending key set */ + private transient ConcurrentNavigableMap<K,V> descendingMap; + + /** + * Initializes or resets state. Needed by constructors, clone, + * clear, readObject. and ConcurrentSkipListSet.clone. + * (Note that comparator must be separately initialized.) + */ + final void initialize() { + keySet = null; + entrySet = null; + values = null; + descendingMap = null; + randomSeed = seedGenerator.nextInt() | 0x0100; // ensure nonzero + head = new HeadIndex<K,V>(new Node<K,V>(null, BASE_HEADER, null), + null, null, 1); + } + + /** Updater for casHead */ + private static final + AtomicReferenceFieldUpdater<ConcurrentSkipListMap, HeadIndex> + headUpdater = AtomicReferenceFieldUpdater.newUpdater + (ConcurrentSkipListMap.class, HeadIndex.class, "head"); + + /** + * compareAndSet head node + */ + private boolean casHead(HeadIndex<K,V> cmp, HeadIndex<K,V> val) { + return headUpdater.compareAndSet(this, cmp, val); + } + + /* ---------------- Nodes -------------- */ + + /** + * Nodes hold keys and values, and are singly linked in sorted + * order, possibly with some intervening marker nodes. The list is + * headed by a dummy node accessible as head.node. The value field + * is declared only as Object because it takes special non-V + * values for marker and header nodes. + */ + static final class Node<K,V> { + final K key; + volatile Object value; + volatile Node<K,V> next; + + /** + * Creates a new regular node. + */ + Node(K key, Object value, Node<K,V> next) { + this.key = key; + this.value = value; + this.next = next; + } + + /** + * Creates a new marker node. A marker is distinguished by + * having its value field point to itself. Marker nodes also + * have null keys, a fact that is exploited in a few places, + * but this doesn't distinguish markers from the base-level + * header node (head.node), which also has a null key. + */ + Node(Node<K,V> next) { + this.key = null; + this.value = this; + this.next = next; + } + + /** Updater for casNext */ + static final AtomicReferenceFieldUpdater<Node, Node> + nextUpdater = AtomicReferenceFieldUpdater.newUpdater + (Node.class, Node.class, "next"); + + /** Updater for casValue */ + static final AtomicReferenceFieldUpdater<Node, Object> + valueUpdater = AtomicReferenceFieldUpdater.newUpdater + (Node.class, Object.class, "value"); + + /** + * compareAndSet value field + */ + boolean casValue(Object cmp, Object val) { + return valueUpdater.compareAndSet(this, cmp, val); + } + + /** + * compareAndSet next field + */ + boolean casNext(Node<K,V> cmp, Node<K,V> val) { + return nextUpdater.compareAndSet(this, cmp, val); + } + + /** + * Returns true if this node is a marker. This method isn't + * actually called in any current code checking for markers + * because callers will have already read value field and need + * to use that read (not another done here) and so directly + * test if value points to node. + * @param n a possibly null reference to a node + * @return true if this node is a marker node + */ + boolean isMarker() { + return value == this; + } + + /** + * Returns true if this node is the header of base-level list. + * @return true if this node is header node + */ + boolean isBaseHeader() { + return value == BASE_HEADER; + } + + /** + * Tries to append a deletion marker to this node. + * @param f the assumed current successor of this node + * @return true if successful + */ + boolean appendMarker(Node<K,V> f) { + return casNext(f, new Node<K,V>(f)); + } + + /** + * Helps out a deletion by appending marker or unlinking from + * predecessor. This is called during traversals when value + * field seen to be null. + * @param b predecessor + * @param f successor + */ + void helpDelete(Node<K,V> b, Node<K,V> f) { + /* + * Rechecking links and then doing only one of the + * help-out stages per call tends to minimize CAS + * interference among helping threads. + */ + if (f == next && this == b.next) { + if (f == null || f.value != f) // not already marked + appendMarker(f); + else + b.casNext(this, f.next); + } + } + + /** + * Returns value if this node contains a valid key-value pair, + * else null. + * @return this node's value if it isn't a marker or header or + * is deleted, else null. + */ + V getValidValue() { + Object v = value; + if (v == this || v == BASE_HEADER) + return null; + return (V)v; + } + + /** + * Creates and returns a new SimpleImmutableEntry holding current + * mapping if this node holds a valid value, else null. + * @return new entry or null + */ + AbstractMap.SimpleImmutableEntry<K,V> createSnapshot() { + V v = getValidValue(); + if (v == null) + return null; + return new AbstractMap.SimpleImmutableEntry<K,V>(key, v); + } + } + + /* ---------------- Indexing -------------- */ + + /** + * Index nodes represent the levels of the skip list. Note that + * even though both Nodes and Indexes have forward-pointing + * fields, they have different types and are handled in different + * ways, that can't nicely be captured by placing field in a + * shared abstract class. + */ + static class Index<K,V> { + final Node<K,V> node; + final Index<K,V> down; + volatile Index<K,V> right; + + /** + * Creates index node with given values. + */ + Index(Node<K,V> node, Index<K,V> down, Index<K,V> right) { + this.node = node; + this.down = down; + this.right = right; + } + + /** Updater for casRight */ + static final AtomicReferenceFieldUpdater<Index, Index> + rightUpdater = AtomicReferenceFieldUpdater.newUpdater + (Index.class, Index.class, "right"); + + /** + * compareAndSet right field + */ + final boolean casRight(Index<K,V> cmp, Index<K,V> val) { + return rightUpdater.compareAndSet(this, cmp, val); + } + + /** + * Returns true if the node this indexes has been deleted. + * @return true if indexed node is known to be deleted + */ + final boolean indexesDeletedNode() { + return node.value == null; + } + + /** + * Tries to CAS newSucc as successor. To minimize races with + * unlink that may lose this index node, if the node being + * indexed is known to be deleted, it doesn't try to link in. + * @param succ the expected current successor + * @param newSucc the new successor + * @return true if successful + */ + final boolean link(Index<K,V> succ, Index<K,V> newSucc) { + Node<K,V> n = node; + newSucc.right = succ; + return n.value != null && casRight(succ, newSucc); + } + + /** + * Tries to CAS right field to skip over apparent successor + * succ. Fails (forcing a retraversal by caller) if this node + * is known to be deleted. + * @param succ the expected current successor + * @return true if successful + */ + final boolean unlink(Index<K,V> succ) { + return !indexesDeletedNode() && casRight(succ, succ.right); + } + } + + /* ---------------- Head nodes -------------- */ + + /** + * Nodes heading each level keep track of their level. + */ + static final class HeadIndex<K,V> extends Index<K,V> { + final int level; + HeadIndex(Node<K,V> node, Index<K,V> down, Index<K,V> right, int level) { + super(node, down, right); + this.level = level; + } + } + + /* ---------------- Comparison utilities -------------- */ + + /** + * Represents a key with a comparator as a Comparable. + * + * Because most sorted collections seem to use natural ordering on + * Comparables (Strings, Integers, etc), most internal methods are + * geared to use them. This is generally faster than checking + * per-comparison whether to use comparator or comparable because + * it doesn't require a (Comparable) cast for each comparison. + * (Optimizers can only sometimes remove such redundant checks + * themselves.) When Comparators are used, + * ComparableUsingComparators are created so that they act in the + * same way as natural orderings. This penalizes use of + * Comparators vs Comparables, which seems like the right + * tradeoff. + */ + static final class ComparableUsingComparator<K> implements Comparable<K> { + final K actualKey; + final Comparator<? super K> cmp; + ComparableUsingComparator(K key, Comparator<? super K> cmp) { + this.actualKey = key; + this.cmp = cmp; + } + public int compareTo(K k2) { + return cmp.compare(actualKey, k2); + } + } + + /** + * If using comparator, return a ComparableUsingComparator, else + * cast key as Comparable, which may cause ClassCastException, + * which is propagated back to caller. + */ + private Comparable<? super K> comparable(Object key) throws ClassCastException { + if (key == null) + throw new NullPointerException(); + if (comparator != null) + return new ComparableUsingComparator<K>((K)key, comparator); + else + return (Comparable<? super K>)key; + } + + /** + * Compares using comparator or natural ordering. Used when the + * ComparableUsingComparator approach doesn't apply. + */ + int compare(K k1, K k2) throws ClassCastException { + Comparator<? super K> cmp = comparator; + if (cmp != null) + return cmp.compare(k1, k2); + else + return ((Comparable<? super K>)k1).compareTo(k2); + } + + /** + * Returns true if given key greater than or equal to least and + * strictly less than fence, bypassing either test if least or + * fence are null. Needed mainly in submap operations. + */ + boolean inHalfOpenRange(K key, K least, K fence) { + if (key == null) + throw new NullPointerException(); + return ((least == null || compare(key, least) >= 0) && + (fence == null || compare(key, fence) < 0)); + } + + /** + * Returns true if given key greater than or equal to least and less + * or equal to fence. Needed mainly in submap operations. + */ + boolean inOpenRange(K key, K least, K fence) { + if (key == null) + throw new NullPointerException(); + return ((least == null || compare(key, least) >= 0) && + (fence == null || compare(key, fence) <= 0)); + } + + /* ---------------- Traversal -------------- */ + + /** + * Returns a base-level node with key strictly less than given key, + * or the base-level header if there is no such node. Also + * unlinks indexes to deleted nodes found along the way. Callers + * rely on this side-effect of clearing indices to deleted nodes. + * @param key the key + * @return a predecessor of key + */ + private Node<K,V> findPredecessor(Comparable<? super K> key) { + if (key == null) + throw new NullPointerException(); // don't postpone errors + for (;;) { + Index<K,V> q = head; + Index<K,V> r = q.right; + for (;;) { + if (r != null) { + Node<K,V> n = r.node; + K k = n.key; + if (n.value == null) { + if (!q.unlink(r)) + break; // restart + r = q.right; // reread r + continue; + } + if (key.compareTo(k) > 0) { + q = r; + r = r.right; + continue; + } + } + Index<K,V> d = q.down; + if (d != null) { + q = d; + r = d.right; + } else + return q.node; + } + } + } + + /** + * Returns node holding key or null if no such, clearing out any + * deleted nodes seen along the way. Repeatedly traverses at + * base-level looking for key starting at predecessor returned + * from findPredecessor, processing base-level deletions as + * encountered. Some callers rely on this side-effect of clearing + * deleted nodes. + * + * Restarts occur, at traversal step centered on node n, if: + * + * (1) After reading n's next field, n is no longer assumed + * predecessor b's current successor, which means that + * we don't have a consistent 3-node snapshot and so cannot + * unlink any subsequent deleted nodes encountered. + * + * (2) n's value field is null, indicating n is deleted, in + * which case we help out an ongoing structural deletion + * before retrying. Even though there are cases where such + * unlinking doesn't require restart, they aren't sorted out + * here because doing so would not usually outweigh cost of + * restarting. + * + * (3) n is a marker or n's predecessor's value field is null, + * indicating (among other possibilities) that + * findPredecessor returned a deleted node. We can't unlink + * the node because we don't know its predecessor, so rely + * on another call to findPredecessor to notice and return + * some earlier predecessor, which it will do. This check is + * only strictly needed at beginning of loop, (and the + * b.value check isn't strictly needed at all) but is done + * each iteration to help avoid contention with other + * threads by callers that will fail to be able to change + * links, and so will retry anyway. + * + * The traversal loops in doPut, doRemove, and findNear all + * include the same three kinds of checks. And specialized + * versions appear in findFirst, and findLast and their + * variants. They can't easily share code because each uses the + * reads of fields held in locals occurring in the orders they + * were performed. + * + * @param key the key + * @return node holding key, or null if no such + */ + private Node<K,V> findNode(Comparable<? super K> key) { + for (;;) { + Node<K,V> b = findPredecessor(key); + Node<K,V> n = b.next; + for (;;) { + if (n == null) + return null; + Node<K,V> f = n.next; + if (n != b.next) // inconsistent read + break; + Object v = n.value; + if (v == null) { // n is deleted + n.helpDelete(b, f); + break; + } + if (v == n || b.value == null) // b is deleted + break; + int c = key.compareTo(n.key); + if (c == 0) + return n; + if (c < 0) + return null; + b = n; + n = f; + } + } + } + + /** + * Specialized variant of findNode to perform Map.get. Does a weak + * traversal, not bothering to fix any deleted index nodes, + * returning early if it happens to see key in index, and passing + * over any deleted base nodes, falling back to getUsingFindNode + * only if it would otherwise return value from an ongoing + * deletion. Also uses "bound" to eliminate need for some + * comparisons (see Pugh Cookbook). Also folds uses of null checks + * and node-skipping because markers have null keys. + * @param okey the key + * @return the value, or null if absent + */ + private V doGet(Object okey) { + Comparable<? super K> key = comparable(okey); + Node<K,V> bound = null; + Index<K,V> q = head; + Index<K,V> r = q.right; + Node<K,V> n; + K k; + int c; + for (;;) { + Index<K,V> d; + // Traverse rights + if (r != null && (n = r.node) != bound && (k = n.key) != null) { + if ((c = key.compareTo(k)) > 0) { + q = r; + r = r.right; + continue; + } else if (c == 0) { + Object v = n.value; + return (v != null)? (V)v : getUsingFindNode(key); + } else + bound = n; + } + + // Traverse down + if ((d = q.down) != null) { + q = d; + r = d.right; + } else + break; + } + + // Traverse nexts + for (n = q.node.next; n != null; n = n.next) { + if ((k = n.key) != null) { + if ((c = key.compareTo(k)) == 0) { + Object v = n.value; + return (v != null)? (V)v : getUsingFindNode(key); + } else if (c < 0) + break; + } + } + return null; + } + + /** + * Performs map.get via findNode. Used as a backup if doGet + * encounters an in-progress deletion. + * @param key the key + * @return the value, or null if absent + */ + private V getUsingFindNode(Comparable<? super K> key) { + /* + * Loop needed here and elsewhere in case value field goes + * null just as it is about to be returned, in which case we + * lost a race with a deletion, so must retry. + */ + for (;;) { + Node<K,V> n = findNode(key); + if (n == null) + return null; + Object v = n.value; + if (v != null) + return (V)v; + } + } + + /* ---------------- Insertion -------------- */ + + /** + * Main insertion method. Adds element if not present, or + * replaces value if present and onlyIfAbsent is false. + * @param kkey the key + * @param value the value that must be associated with key + * @param onlyIfAbsent if should not insert if already present + * @return the old value, or null if newly inserted + */ + private V doPut(K kkey, V value, boolean onlyIfAbsent) { + Comparable<? super K> key = comparable(kkey); + for (;;) { + Node<K,V> b = findPredecessor(key); + Node<K,V> n = b.next; + for (;;) { + if (n != null) { + Node<K,V> f = n.next; + if (n != b.next) // inconsistent read + break; + Object v = n.value; + if (v == null) { // n is deleted + n.helpDelete(b, f); + break; + } + if (v == n || b.value == null) // b is deleted + break; + int c = key.compareTo(n.key); + if (c > 0) { + b = n; + n = f; + continue; + } + if (c == 0) { + if (onlyIfAbsent || n.casValue(v, value)) + return (V)v; + else + break; // restart if lost race to replace value + } + // else c < 0; fall through + } + + Node<K,V> z = new Node<K,V>(kkey, value, n); + if (!b.casNext(n, z)) + break; // restart if lost race to append to b + int level = randomLevel(); + if (level > 0) + insertIndex(z, level); + return null; + } + } + } + + /** + * Returns a random level for inserting a new node. + * Hardwired to k=1, p=0.5, max 31 (see above and + * Pugh's "Skip List Cookbook", sec 3.4). + * + * This uses the simplest of the generators described in George + * Marsaglia's "Xorshift RNGs" paper. This is not a high-quality + * generator but is acceptable here. + */ + private int randomLevel() { + int x = randomSeed; + x ^= x << 13; + x ^= x >>> 17; + randomSeed = x ^= x << 5; + if ((x & 0x8001) != 0) // test highest and lowest bits + return 0; + int level = 1; + while (((x >>>= 1) & 1) != 0) ++level; + return level; + } + + /** + * Creates and adds index nodes for the given node. + * @param z the node + * @param level the level of the index + */ + private void insertIndex(Node<K,V> z, int level) { + HeadIndex<K,V> h = head; + int max = h.level; + + if (level <= max) { + Index<K,V> idx = null; + for (int i = 1; i <= level; ++i) + idx = new Index<K,V>(z, idx, null); + addIndex(idx, h, level); + + } else { // Add a new level + /* + * To reduce interference by other threads checking for + * empty levels in tryReduceLevel, new levels are added + * with initialized right pointers. Which in turn requires + * keeping levels in an array to access them while + * creating new head index nodes from the opposite + * direction. + */ + level = max + 1; + Index<K,V>[] idxs = (Index<K,V>[])new Index[level+1]; + Index<K,V> idx = null; + for (int i = 1; i <= level; ++i) + idxs[i] = idx = new Index<K,V>(z, idx, null); + + HeadIndex<K,V> oldh; + int k; + for (;;) { + oldh = head; + int oldLevel = oldh.level; + if (level <= oldLevel) { // lost race to add level + k = level; + break; + } + HeadIndex<K,V> newh = oldh; + Node<K,V> oldbase = oldh.node; + for (int j = oldLevel+1; j <= level; ++j) + newh = new HeadIndex<K,V>(oldbase, newh, idxs[j], j); + if (casHead(oldh, newh)) { + k = oldLevel; + break; + } + } + addIndex(idxs[k], oldh, k); + } + } + + /** + * Adds given index nodes from given level down to 1. + * @param idx the topmost index node being inserted + * @param h the value of head to use to insert. This must be + * snapshotted by callers to provide correct insertion level + * @param indexLevel the level of the index + */ + private void addIndex(Index<K,V> idx, HeadIndex<K,V> h, int indexLevel) { + // Track next level to insert in case of retries + int insertionLevel = indexLevel; + Comparable<? super K> key = comparable(idx.node.key); + if (key == null) throw new NullPointerException(); + + // Similar to findPredecessor, but adding index nodes along + // path to key. + for (;;) { + int j = h.level; + Index<K,V> q = h; + Index<K,V> r = q.right; + Index<K,V> t = idx; + for (;;) { + if (r != null) { + Node<K,V> n = r.node; + // compare before deletion check avoids needing recheck + int c = key.compareTo(n.key); + if (n.value == null) { + if (!q.unlink(r)) + break; + r = q.right; + continue; + } + if (c > 0) { + q = r; + r = r.right; + continue; + } + } + + if (j == insertionLevel) { + // Don't insert index if node already deleted + if (t.indexesDeletedNode()) { + findNode(key); // cleans up + return; + } + if (!q.link(r, t)) + break; // restart + if (--insertionLevel == 0) { + // need final deletion check before return + if (t.indexesDeletedNode()) + findNode(key); + return; + } + } + + if (--j >= insertionLevel && j < indexLevel) + t = t.down; + q = q.down; + r = q.right; + } + } + } + + /* ---------------- Deletion -------------- */ + + /** + * Main deletion method. Locates node, nulls value, appends a + * deletion marker, unlinks predecessor, removes associated index + * nodes, and possibly reduces head index level. + * + * Index nodes are cleared out simply by calling findPredecessor. + * which unlinks indexes to deleted nodes found along path to key, + * which will include the indexes to this node. This is done + * unconditionally. We can't check beforehand whether there are + * index nodes because it might be the case that some or all + * indexes hadn't been inserted yet for this node during initial + * search for it, and we'd like to ensure lack of garbage + * retention, so must call to be sure. + * + * @param okey the key + * @param value if non-null, the value that must be + * associated with key + * @return the node, or null if not found + */ + final V doRemove(Object okey, Object value) { + Comparable<? super K> key = comparable(okey); + for (;;) { + Node<K,V> b = findPredecessor(key); + Node<K,V> n = b.next; + for (;;) { + if (n == null) + return null; + Node<K,V> f = n.next; + if (n != b.next) // inconsistent read + break; + Object v = n.value; + if (v == null) { // n is deleted + n.helpDelete(b, f); + break; + } + if (v == n || b.value == null) // b is deleted + break; + int c = key.compareTo(n.key); + if (c < 0) + return null; + if (c > 0) { + b = n; + n = f; + continue; + } + if (value != null && !value.equals(v)) + return null; + if (!n.casValue(v, null)) + break; + if (!n.appendMarker(f) || !b.casNext(n, f)) + findNode(key); // Retry via findNode + else { + findPredecessor(key); // Clean index + if (head.right == null) + tryReduceLevel(); + } + return (V)v; + } + } + } + + /** + * Possibly reduce head level if it has no nodes. This method can + * (rarely) make mistakes, in which case levels can disappear even + * though they are about to contain index nodes. This impacts + * performance, not correctness. To minimize mistakes as well as + * to reduce hysteresis, the level is reduced by one only if the + * topmost three levels look empty. Also, if the removed level + * looks non-empty after CAS, we try to change it back quick + * before anyone notices our mistake! (This trick works pretty + * well because this method will practically never make mistakes + * unless current thread stalls immediately before first CAS, in + * which case it is very unlikely to stall again immediately + * afterwards, so will recover.) + * + * We put up with all this rather than just let levels grow + * because otherwise, even a small map that has undergone a large + * number of insertions and removals will have a lot of levels, + * slowing down access more than would an occasional unwanted + * reduction. + */ + private void tryReduceLevel() { + HeadIndex<K,V> h = head; + HeadIndex<K,V> d; + HeadIndex<K,V> e; + if (h.level > 3 && + (d = (HeadIndex<K,V>)h.down) != null && + (e = (HeadIndex<K,V>)d.down) != null && + e.right == null && + d.right == null && + h.right == null && + casHead(h, d) && // try to set + h.right != null) // recheck + casHead(d, h); // try to backout + } + + /* ---------------- Finding and removing first element -------------- */ + + /** + * Specialized variant of findNode to get first valid node. + * @return first node or null if empty + */ + Node<K,V> findFirst() { + for (;;) { + Node<K,V> b = head.node; + Node<K,V> n = b.next; + if (n == null) + return null; + if (n.value != null) + return n; + n.helpDelete(b, n.next); + } + } + + /** + * Removes first entry; returns its snapshot. + * @return null if empty, else snapshot of first entry + */ + Map.Entry<K,V> doRemoveFirstEntry() { + for (;;) { + Node<K,V> b = head.node; + Node<K,V> n = b.next; + if (n == null) + return null; + Node<K,V> f = n.next; + if (n != b.next) + continue; + Object v = n.value; + if (v == null) { + n.helpDelete(b, f); + continue; + } + if (!n.casValue(v, null)) + continue; + if (!n.appendMarker(f) || !b.casNext(n, f)) + findFirst(); // retry + clearIndexToFirst(); + return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, (V)v); + } + } + + /** + * Clears out index nodes associated with deleted first entry. + */ + private void clearIndexToFirst() { + for (;;) { + Index<K,V> q = head; + for (;;) { + Index<K,V> r = q.right; + if (r != null && r.indexesDeletedNode() && !q.unlink(r)) + break; + if ((q = q.down) == null) { + if (head.right == null) + tryReduceLevel(); + return; + } + } + } + } + + + /* ---------------- Finding and removing last element -------------- */ + + /** + * Specialized version of find to get last valid node. + * @return last node or null if empty + */ + Node<K,V> findLast() { + /* + * findPredecessor can't be used to traverse index level + * because this doesn't use comparisons. So traversals of + * both levels are folded together. + */ + Index<K,V> q = head; + for (;;) { + Index<K,V> d, r; + if ((r = q.right) != null) { + if (r.indexesDeletedNode()) { + q.unlink(r); + q = head; // restart + } + else + q = r; + } else if ((d = q.down) != null) { + q = d; + } else { + Node<K,V> b = q.node; + Node<K,V> n = b.next; + for (;;) { + if (n == null) + return (b.isBaseHeader())? null : b; + Node<K,V> f = n.next; // inconsistent read + if (n != b.next) + break; + Object v = n.value; + if (v == null) { // n is deleted + n.helpDelete(b, f); + break; + } + if (v == n || b.value == null) // b is deleted + break; + b = n; + n = f; + } + q = head; // restart + } + } + } + + /** + * Specialized variant of findPredecessor to get predecessor of last + * valid node. Needed when removing the last entry. It is possible + * that all successors of returned node will have been deleted upon + * return, in which case this method can be retried. + * @return likely predecessor of last node + */ + private Node<K,V> findPredecessorOfLast() { + for (;;) { + Index<K,V> q = head; + for (;;) { + Index<K,V> d, r; + if ((r = q.right) != null) { + if (r.indexesDeletedNode()) { + q.unlink(r); + break; // must restart + } + // proceed as far across as possible without overshooting + if (r.node.next != null) { + q = r; + continue; + } + } + if ((d = q.down) != null) + q = d; + else + return q.node; + } + } + } + + /** + * Removes last entry; returns its snapshot. + * Specialized variant of doRemove. + * @return null if empty, else snapshot of last entry + */ + Map.Entry<K,V> doRemoveLastEntry() { + for (;;) { + Node<K,V> b = findPredecessorOfLast(); + Node<K,V> n = b.next; + if (n == null) { + if (b.isBaseHeader()) // empty + return null; + else + continue; // all b's successors are deleted; retry + } + for (;;) { + Node<K,V> f = n.next; + if (n != b.next) // inconsistent read + break; + Object v = n.value; + if (v == null) { // n is deleted + n.helpDelete(b, f); + break; + } + if (v == n || b.value == null) // b is deleted + break; + if (f != null) { + b = n; + n = f; + continue; + } + if (!n.casValue(v, null)) + break; + K key = n.key; + Comparable<? super K> ck = comparable(key); + if (!n.appendMarker(f) || !b.casNext(n, f)) + findNode(ck); // Retry via findNode + else { + findPredecessor(ck); // Clean index + if (head.right == null) + tryReduceLevel(); + } + return new AbstractMap.SimpleImmutableEntry<K,V>(key, (V)v); + } + } + } + + /* ---------------- Relational operations -------------- */ + + // Control values OR'ed as arguments to findNear + + private static final int EQ = 1; + private static final int LT = 2; + private static final int GT = 0; // Actually checked as !LT + + /** + * Utility for ceiling, floor, lower, higher methods. + * @param kkey the key + * @param rel the relation -- OR'ed combination of EQ, LT, GT + * @return nearest node fitting relation, or null if no such + */ + Node<K,V> findNear(K kkey, int rel) { + Comparable<? super K> key = comparable(kkey); + for (;;) { + Node<K,V> b = findPredecessor(key); + Node<K,V> n = b.next; + for (;;) { + if (n == null) + return ((rel & LT) == 0 || b.isBaseHeader())? null : b; + Node<K,V> f = n.next; + if (n != b.next) // inconsistent read + break; + Object v = n.value; + if (v == null) { // n is deleted + n.helpDelete(b, f); + break; + } + if (v == n || b.value == null) // b is deleted + break; + int c = key.compareTo(n.key); + if ((c == 0 && (rel & EQ) != 0) || + (c < 0 && (rel & LT) == 0)) + return n; + if ( c <= 0 && (rel & LT) != 0) + return (b.isBaseHeader())? null : b; + b = n; + n = f; + } + } + } + + /** + * Returns SimpleImmutableEntry for results of findNear. + * @param key the key + * @param rel the relation -- OR'ed combination of EQ, LT, GT + * @return Entry fitting relation, or null if no such + */ + AbstractMap.SimpleImmutableEntry<K,V> getNear(K key, int rel) { + for (;;) { + Node<K,V> n = findNear(key, rel); + if (n == null) + return null; + AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot(); + if (e != null) + return e; + } + } + + + /* ---------------- Constructors -------------- */ + + /** + * Constructs a new, empty map, sorted according to the + * {@linkplain Comparable natural ordering} of the keys. + */ + public ConcurrentSkipListMap() { + this.comparator = null; + initialize(); + } + + /** + * Constructs a new, empty map, sorted according to the specified + * comparator. + * + * @param comparator the comparator that will be used to order this map. + * If <tt>null</tt>, the {@linkplain Comparable natural + * ordering} of the keys will be used. + */ + public ConcurrentSkipListMap(Comparator<? super K> comparator) { + this.comparator = comparator; + initialize(); + } + + /** + * Constructs a new map containing the same mappings as the given map, + * sorted according to the {@linkplain Comparable natural ordering} of + * the keys. + * + * @param m the map whose mappings are to be placed in this map + * @throws ClassCastException if the keys in <tt>m</tt> are not + * {@link Comparable}, or are not mutually comparable + * @throws NullPointerException if the specified map or any of its keys + * or values are null + */ + public ConcurrentSkipListMap(Map<? extends K, ? extends V> m) { + this.comparator = null; + initialize(); + putAll(m); + } + + /** + * Constructs a new map containing the same mappings and using the + * same ordering as the specified sorted map. + * + * @param m the sorted map whose mappings are to be placed in this + * map, and whose comparator is to be used to sort this map + * @throws NullPointerException if the specified sorted map or any of + * its keys or values are null + */ + public ConcurrentSkipListMap(SortedMap<K, ? extends V> m) { + this.comparator = m.comparator(); + initialize(); + buildFromSorted(m); + } + + /** + * Returns a shallow copy of this <tt>ConcurrentSkipListMap</tt> + * instance. (The keys and values themselves are not cloned.) + * + * @return a shallow copy of this map + */ + public ConcurrentSkipListMap<K,V> clone() { + ConcurrentSkipListMap<K,V> clone = null; + try { + clone = (ConcurrentSkipListMap<K,V>) super.clone(); + } catch (CloneNotSupportedException e) { + throw new InternalError(); + } + + clone.initialize(); + clone.buildFromSorted(this); + return clone; + } + + /** + * Streamlined bulk insertion to initialize from elements of + * given sorted map. Call only from constructor or clone + * method. + */ + private void buildFromSorted(SortedMap<K, ? extends V> map) { + if (map == null) + throw new NullPointerException(); + + HeadIndex<K,V> h = head; + Node<K,V> basepred = h.node; + + // Track the current rightmost node at each level. Uses an + // ArrayList to avoid committing to initial or maximum level. + ArrayList<Index<K,V>> preds = new ArrayList<Index<K,V>>(); + + // initialize + for (int i = 0; i <= h.level; ++i) + preds.add(null); + Index<K,V> q = h; + for (int i = h.level; i > 0; --i) { + preds.set(i, q); + q = q.down; + } + + Iterator<? extends Map.Entry<? extends K, ? extends V>> it = + map.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry<? extends K, ? extends V> e = it.next(); + int j = randomLevel(); + if (j > h.level) j = h.level + 1; + K k = e.getKey(); + V v = e.getValue(); + if (k == null || v == null) + throw new NullPointerException(); + Node<K,V> z = new Node<K,V>(k, v, null); + basepred.next = z; + basepred = z; + if (j > 0) { + Index<K,V> idx = null; + for (int i = 1; i <= j; ++i) { + idx = new Index<K,V>(z, idx, null); + if (i > h.level) + h = new HeadIndex<K,V>(h.node, h, idx, i); + + if (i < preds.size()) { + preds.get(i).right = idx; + preds.set(i, idx); + } else + preds.add(idx); + } + } + } + head = h; + } + + /* ---------------- Serialization -------------- */ + + /** + * Save the state of this map to a stream. + * + * @serialData The key (Object) and value (Object) for each + * key-value mapping represented by the map, followed by + * <tt>null</tt>. The key-value mappings are emitted in key-order + * (as determined by the Comparator, or by the keys' natural + * ordering if no Comparator). + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + // Write out the Comparator and any hidden stuff + s.defaultWriteObject(); + + // Write out keys and values (alternating) + for (Node<K,V> n = findFirst(); n != null; n = n.next) { + V v = n.getValidValue(); + if (v != null) { + s.writeObject(n.key); + s.writeObject(v); + } + } + s.writeObject(null); + } + + /** + * Reconstitute the map from a stream. + */ + private void readObject(final java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + // Read in the Comparator and any hidden stuff + s.defaultReadObject(); + // Reset transients + initialize(); + + /* + * This is nearly identical to buildFromSorted, but is + * distinct because readObject calls can't be nicely adapted + * as the kind of iterator needed by buildFromSorted. (They + * can be, but doing so requires type cheats and/or creation + * of adaptor classes.) It is simpler to just adapt the code. + */ + + HeadIndex<K,V> h = head; + Node<K,V> basepred = h.node; + ArrayList<Index<K,V>> preds = new ArrayList<Index<K,V>>(); + for (int i = 0; i <= h.level; ++i) + preds.add(null); + Index<K,V> q = h; + for (int i = h.level; i > 0; --i) { + preds.set(i, q); + q = q.down; + } + + for (;;) { + Object k = s.readObject(); + if (k == null) + break; + Object v = s.readObject(); + if (v == null) + throw new NullPointerException(); + K key = (K) k; + V val = (V) v; + int j = randomLevel(); + if (j > h.level) j = h.level + 1; + Node<K,V> z = new Node<K,V>(key, val, null); + basepred.next = z; + basepred = z; + if (j > 0) { + Index<K,V> idx = null; + for (int i = 1; i <= j; ++i) { + idx = new Index<K,V>(z, idx, null); + if (i > h.level) + h = new HeadIndex<K,V>(h.node, h, idx, i); + + if (i < preds.size()) { + preds.get(i).right = idx; + preds.set(i, idx); + } else + preds.add(idx); + } + } + } + head = h; + } + + /* ------ Map API methods ------ */ + + /** + * Returns <tt>true</tt> if this map contains a mapping for the specified + * key. + * + * @param key key whose presence in this map is to be tested + * @return <tt>true</tt> if this map contains a mapping for the specified key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + */ + public boolean containsKey(Object key) { + return doGet(key) != null; + } + + /** + * Returns the value to which the specified key is mapped, + * or {@code null} if this map contains no mapping for the key. + * + * <p>More formally, if this map contains a mapping from a key + * {@code k} to a value {@code v} such that {@code key} compares + * equal to {@code k} according to the map's ordering, then this + * method returns {@code v}; otherwise it returns {@code null}. + * (There can be at most one such mapping.) + * + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + */ + public V get(Object key) { + return doGet(key); + } + + /** + * Associates the specified value with the specified key in this map. + * If the map previously contained a mapping for the key, the old + * value is replaced. + * + * @param key key with which the specified value is to be associated + * @param value value to be associated with the specified key + * @return the previous value associated with the specified key, or + * <tt>null</tt> if there was no mapping for the key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key or value is null + */ + public V put(K key, V value) { + if (value == null) + throw new NullPointerException(); + return doPut(key, value, false); + } + + /** + * Removes the mapping for the specified key from this map if present. + * + * @param key key for which mapping should be removed + * @return the previous value associated with the specified key, or + * <tt>null</tt> if there was no mapping for the key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + */ + public V remove(Object key) { + return doRemove(key, null); + } + + /** + * Returns <tt>true</tt> if this map maps one or more keys to the + * specified value. This operation requires time linear in the + * map size. + * + * @param value value whose presence in this map is to be tested + * @return <tt>true</tt> if a mapping to <tt>value</tt> exists; + * <tt>false</tt> otherwise + * @throws NullPointerException if the specified value is null + */ + public boolean containsValue(Object value) { + if (value == null) + throw new NullPointerException(); + for (Node<K,V> n = findFirst(); n != null; n = n.next) { + V v = n.getValidValue(); + if (v != null && value.equals(v)) + return true; + } + return false; + } + + /** + * Returns the number of key-value mappings in this map. If this map + * contains more than <tt>Integer.MAX_VALUE</tt> elements, it + * returns <tt>Integer.MAX_VALUE</tt>. + * + * <p>Beware that, unlike in most collections, this method is + * <em>NOT</em> a constant-time operation. Because of the + * asynchronous nature of these maps, determining the current + * number of elements requires traversing them all to count them. + * Additionally, it is possible for the size to change during + * execution of this method, in which case the returned result + * will be inaccurate. Thus, this method is typically not very + * useful in concurrent applications. + * + * @return the number of elements in this map + */ + public int size() { + long count = 0; + for (Node<K,V> n = findFirst(); n != null; n = n.next) { + if (n.getValidValue() != null) + ++count; + } + return (count >= Integer.MAX_VALUE)? Integer.MAX_VALUE : (int)count; + } + + /** + * Returns <tt>true</tt> if this map contains no key-value mappings. + * @return <tt>true</tt> if this map contains no key-value mappings + */ + public boolean isEmpty() { + return findFirst() == null; + } + + /** + * Removes all of the mappings from this map. + */ + public void clear() { + initialize(); + } + + /* ---------------- View methods -------------- */ + + /* + * Note: Lazy initialization works for views because view classes + * are stateless/immutable so it doesn't matter wrt correctness if + * more than one is created (which will only rarely happen). Even + * so, the following idiom conservatively ensures that the method + * returns the one it created if it does so, not one created by + * another racing thread. + */ + + /** + * Returns a {@link NavigableSet} view of the keys contained in this map. + * The set's iterator returns the keys in ascending order. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. The set supports element + * removal, which removes the corresponding mapping from the map, + * via the {@code Iterator.remove}, {@code Set.remove}, + * {@code removeAll}, {@code retainAll}, and {@code clear} + * operations. It does not support the {@code add} or {@code addAll} + * operations. + * + * <p>The view's {@code iterator} is a "weakly consistent" iterator + * that will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + * + * <p>This method is equivalent to method {@code navigableKeySet}. + * + * @return a navigable set view of the keys in this map + */ + public NavigableSet<K> keySet() { + KeySet ks = keySet; + return (ks != null) ? ks : (keySet = new KeySet(this)); + } + + public NavigableSet<K> navigableKeySet() { + KeySet ks = keySet; + return (ks != null) ? ks : (keySet = new KeySet(this)); + } + + /** + * Returns a {@link Collection} view of the values contained in this map. + * The collection's iterator returns the values in ascending order + * of the corresponding keys. + * The collection is backed by the map, so changes to the map are + * reflected in the collection, and vice-versa. The collection + * supports element removal, which removes the corresponding + * mapping from the map, via the <tt>Iterator.remove</tt>, + * <tt>Collection.remove</tt>, <tt>removeAll</tt>, + * <tt>retainAll</tt> and <tt>clear</tt> operations. It does not + * support the <tt>add</tt> or <tt>addAll</tt> operations. + * + * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator + * that will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + */ + public Collection<V> values() { + Values vs = values; + return (vs != null) ? vs : (values = new Values(this)); + } + + /** + * Returns a {@link Set} view of the mappings contained in this map. + * The set's iterator returns the entries in ascending key order. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. The set supports element + * removal, which removes the corresponding mapping from the map, + * via the <tt>Iterator.remove</tt>, <tt>Set.remove</tt>, + * <tt>removeAll</tt>, <tt>retainAll</tt> and <tt>clear</tt> + * operations. It does not support the <tt>add</tt> or + * <tt>addAll</tt> operations. + * + * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator + * that will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + * + * <p>The <tt>Map.Entry</tt> elements returned by + * <tt>iterator.next()</tt> do <em>not</em> support the + * <tt>setValue</tt> operation. + * + * @return a set view of the mappings contained in this map, + * sorted in ascending key order + */ + public Set<Map.Entry<K,V>> entrySet() { + EntrySet es = entrySet; + return (es != null) ? es : (entrySet = new EntrySet(this)); + } + + public ConcurrentNavigableMap<K,V> descendingMap() { + ConcurrentNavigableMap<K,V> dm = descendingMap; + return (dm != null) ? dm : (descendingMap = new SubMap<K,V> + (this, null, false, null, false, true)); + } + + public NavigableSet<K> descendingKeySet() { + return descendingMap().navigableKeySet(); + } + + /* ---------------- AbstractMap Overrides -------------- */ + + /** + * Compares the specified object with this map for equality. + * Returns <tt>true</tt> if the given object is also a map and the + * two maps represent the same mappings. More formally, two maps + * <tt>m1</tt> and <tt>m2</tt> represent the same mappings if + * <tt>m1.entrySet().equals(m2.entrySet())</tt>. This + * operation may return misleading results if either map is + * concurrently modified during execution of this method. + * + * @param o object to be compared for equality with this map + * @return <tt>true</tt> if the specified object is equal to this map + */ + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof Map)) + return false; + Map<?,?> m = (Map<?,?>) o; + try { + for (Map.Entry<K,V> e : this.entrySet()) + if (! e.getValue().equals(m.get(e.getKey()))) + return false; + for (Map.Entry<?,?> e : m.entrySet()) { + Object k = e.getKey(); + Object v = e.getValue(); + if (k == null || v == null || !v.equals(get(k))) + return false; + } + return true; + } catch (ClassCastException unused) { + return false; + } catch (NullPointerException unused) { + return false; + } + } + + /* ------ ConcurrentMap API methods ------ */ + + /** + * {@inheritDoc} + * + * @return the previous value associated with the specified key, + * or <tt>null</tt> if there was no mapping for the key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key or value is null + */ + public V putIfAbsent(K key, V value) { + if (value == null) + throw new NullPointerException(); + return doPut(key, value, true); + } + + /** + * {@inheritDoc} + * + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + */ + public boolean remove(Object key, Object value) { + if (key == null) + throw new NullPointerException(); + if (value == null) + return false; + return doRemove(key, value) != null; + } + + /** + * {@inheritDoc} + * + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if any of the arguments are null + */ + public boolean replace(K key, V oldValue, V newValue) { + if (oldValue == null || newValue == null) + throw new NullPointerException(); + Comparable<? super K> k = comparable(key); + for (;;) { + Node<K,V> n = findNode(k); + if (n == null) + return false; + Object v = n.value; + if (v != null) { + if (!oldValue.equals(v)) + return false; + if (n.casValue(v, newValue)) + return true; + } + } + } + + /** + * {@inheritDoc} + * + * @return the previous value associated with the specified key, + * or <tt>null</tt> if there was no mapping for the key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key or value is null + */ + public V replace(K key, V value) { + if (value == null) + throw new NullPointerException(); + Comparable<? super K> k = comparable(key); + for (;;) { + Node<K,V> n = findNode(k); + if (n == null) + return null; + Object v = n.value; + if (v != null && n.casValue(v, value)) + return (V)v; + } + } + + /* ------ SortedMap API methods ------ */ + + public Comparator<? super K> comparator() { + return comparator; + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public K firstKey() { + Node<K,V> n = findFirst(); + if (n == null) + throw new NoSuchElementException(); + return n.key; + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public K lastKey() { + Node<K,V> n = findLast(); + if (n == null) + throw new NoSuchElementException(); + return n.key; + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromKey} or {@code toKey} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public ConcurrentNavigableMap<K,V> subMap(K fromKey, + boolean fromInclusive, + K toKey, + boolean toInclusive) { + if (fromKey == null || toKey == null) + throw new NullPointerException(); + return new SubMap<K,V> + (this, fromKey, fromInclusive, toKey, toInclusive, false); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code toKey} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public ConcurrentNavigableMap<K,V> headMap(K toKey, + boolean inclusive) { + if (toKey == null) + throw new NullPointerException(); + return new SubMap<K,V> + (this, null, false, toKey, inclusive, false); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromKey} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public ConcurrentNavigableMap<K,V> tailMap(K fromKey, + boolean inclusive) { + if (fromKey == null) + throw new NullPointerException(); + return new SubMap<K,V> + (this, fromKey, inclusive, null, false, false); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromKey} or {@code toKey} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public ConcurrentNavigableMap<K,V> subMap(K fromKey, K toKey) { + return subMap(fromKey, true, toKey, false); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code toKey} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public ConcurrentNavigableMap<K,V> headMap(K toKey) { + return headMap(toKey, false); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromKey} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public ConcurrentNavigableMap<K,V> tailMap(K fromKey) { + return tailMap(fromKey, true); + } + + /* ---------------- Relational operations -------------- */ + + /** + * Returns a key-value mapping associated with the greatest key + * strictly less than the given key, or <tt>null</tt> if there is + * no such key. The returned entry does <em>not</em> support the + * <tt>Entry.setValue</tt> method. + * + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + */ + public Map.Entry<K,V> lowerEntry(K key) { + return getNear(key, LT); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + */ + public K lowerKey(K key) { + Node<K,V> n = findNear(key, LT); + return (n == null)? null : n.key; + } + + /** + * Returns a key-value mapping associated with the greatest key + * less than or equal to the given key, or <tt>null</tt> if there + * is no such key. The returned entry does <em>not</em> support + * the <tt>Entry.setValue</tt> method. + * + * @param key the key + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + */ + public Map.Entry<K,V> floorEntry(K key) { + return getNear(key, LT|EQ); + } + + /** + * @param key the key + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + */ + public K floorKey(K key) { + Node<K,V> n = findNear(key, LT|EQ); + return (n == null)? null : n.key; + } + + /** + * Returns a key-value mapping associated with the least key + * greater than or equal to the given key, or <tt>null</tt> if + * there is no such entry. The returned entry does <em>not</em> + * support the <tt>Entry.setValue</tt> method. + * + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + */ + public Map.Entry<K,V> ceilingEntry(K key) { + return getNear(key, GT|EQ); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + */ + public K ceilingKey(K key) { + Node<K,V> n = findNear(key, GT|EQ); + return (n == null)? null : n.key; + } + + /** + * Returns a key-value mapping associated with the least key + * strictly greater than the given key, or <tt>null</tt> if there + * is no such key. The returned entry does <em>not</em> support + * the <tt>Entry.setValue</tt> method. + * + * @param key the key + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + */ + public Map.Entry<K,V> higherEntry(K key) { + return getNear(key, GT); + } + + /** + * @param key the key + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + */ + public K higherKey(K key) { + Node<K,V> n = findNear(key, GT); + return (n == null)? null : n.key; + } + + /** + * Returns a key-value mapping associated with the least + * key in this map, or <tt>null</tt> if the map is empty. + * The returned entry does <em>not</em> support + * the <tt>Entry.setValue</tt> method. + */ + public Map.Entry<K,V> firstEntry() { + for (;;) { + Node<K,V> n = findFirst(); + if (n == null) + return null; + AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot(); + if (e != null) + return e; + } + } + + /** + * Returns a key-value mapping associated with the greatest + * key in this map, or <tt>null</tt> if the map is empty. + * The returned entry does <em>not</em> support + * the <tt>Entry.setValue</tt> method. + */ + public Map.Entry<K,V> lastEntry() { + for (;;) { + Node<K,V> n = findLast(); + if (n == null) + return null; + AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot(); + if (e != null) + return e; + } + } + + /** + * Removes and returns a key-value mapping associated with + * the least key in this map, or <tt>null</tt> if the map is empty. + * The returned entry does <em>not</em> support + * the <tt>Entry.setValue</tt> method. + */ + public Map.Entry<K,V> pollFirstEntry() { + return doRemoveFirstEntry(); + } + + /** + * Removes and returns a key-value mapping associated with + * the greatest key in this map, or <tt>null</tt> if the map is empty. + * The returned entry does <em>not</em> support + * the <tt>Entry.setValue</tt> method. + */ + public Map.Entry<K,V> pollLastEntry() { + return doRemoveLastEntry(); + } + + + /* ---------------- Iterators -------------- */ + + /** + * Base of iterator classes: + */ + abstract class Iter<T> implements Iterator<T> { + /** the last node returned by next() */ + Node<K,V> lastReturned; + /** the next node to return from next(); */ + Node<K,V> next; + /** Cache of next value field to maintain weak consistency */ + V nextValue; + + /** Initializes ascending iterator for entire range. */ + Iter() { + for (;;) { + next = findFirst(); + if (next == null) + break; + Object x = next.value; + if (x != null && x != next) { + nextValue = (V) x; + break; + } + } + } + + public final boolean hasNext() { + return next != null; + } + + /** Advances next to higher entry. */ + final void advance() { + if (next == null) + throw new NoSuchElementException(); + lastReturned = next; + for (;;) { + next = next.next; + if (next == null) + break; + Object x = next.value; + if (x != null && x != next) { + nextValue = (V) x; + break; + } + } + } + + public void remove() { + Node<K,V> l = lastReturned; + if (l == null) + throw new IllegalStateException(); + // It would not be worth all of the overhead to directly + // unlink from here. Using remove is fast enough. + ConcurrentSkipListMap.this.remove(l.key); + lastReturned = null; + } + + } + + final class ValueIterator extends Iter<V> { + public V next() { + V v = nextValue; + advance(); + return v; + } + } + + final class KeyIterator extends Iter<K> { + public K next() { + Node<K,V> n = next; + advance(); + return n.key; + } + } + + final class EntryIterator extends Iter<Map.Entry<K,V>> { + public Map.Entry<K,V> next() { + Node<K,V> n = next; + V v = nextValue; + advance(); + return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v); + } + } + + // Factory methods for iterators needed by ConcurrentSkipListSet etc + + Iterator<K> keyIterator() { + return new KeyIterator(); + } + + Iterator<V> valueIterator() { + return new ValueIterator(); + } + + Iterator<Map.Entry<K,V>> entryIterator() { + return new EntryIterator(); + } + + /* ---------------- View Classes -------------- */ + + /* + * View classes are static, delegating to a ConcurrentNavigableMap + * to allow use by SubMaps, which outweighs the ugliness of + * needing type-tests for Iterator methods. + */ + + static final <E> List<E> toList(Collection<E> c) { + // Using size() here would be a pessimization. + List<E> list = new ArrayList<E>(); + for (E e : c) + list.add(e); + return list; + } + + static final class KeySet<E> extends AbstractSet<E> implements NavigableSet<E> { + private final ConcurrentNavigableMap<E,Object> m; + KeySet(ConcurrentNavigableMap<E,Object> map) { m = map; } + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean contains(Object o) { return m.containsKey(o); } + public boolean remove(Object o) { return m.remove(o) != null; } + public void clear() { m.clear(); } + public E lower(E e) { return m.lowerKey(e); } + public E floor(E e) { return m.floorKey(e); } + public E ceiling(E e) { return m.ceilingKey(e); } + public E higher(E e) { return m.higherKey(e); } + public Comparator<? super E> comparator() { return m.comparator(); } + public E first() { return m.firstKey(); } + public E last() { return m.lastKey(); } + public E pollFirst() { + Map.Entry<E,Object> e = m.pollFirstEntry(); + return e == null? null : e.getKey(); + } + public E pollLast() { + Map.Entry<E,Object> e = m.pollLastEntry(); + return e == null? null : e.getKey(); + } + public Iterator<E> iterator() { + if (m instanceof ConcurrentSkipListMap) + return ((ConcurrentSkipListMap<E,Object>)m).keyIterator(); + else + return ((ConcurrentSkipListMap.SubMap<E,Object>)m).keyIterator(); + } + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof Set)) + return false; + Collection<?> c = (Collection<?>) o; + try { + return containsAll(c) && c.containsAll(this); + } catch (ClassCastException unused) { + return false; + } catch (NullPointerException unused) { + return false; + } + } + public Object[] toArray() { return toList(this).toArray(); } + public <T> T[] toArray(T[] a) { return toList(this).toArray(a); } + public Iterator<E> descendingIterator() { + return descendingSet().iterator(); + } + public NavigableSet<E> subSet(E fromElement, + boolean fromInclusive, + E toElement, + boolean toInclusive) { + return new KeySet<E>(m.subMap(fromElement, fromInclusive, + toElement, toInclusive)); + } + public NavigableSet<E> headSet(E toElement, boolean inclusive) { + return new KeySet<E>(m.headMap(toElement, inclusive)); + } + public NavigableSet<E> tailSet(E fromElement, boolean inclusive) { + return new KeySet<E>(m.tailMap(fromElement, inclusive)); + } + public NavigableSet<E> subSet(E fromElement, E toElement) { + return subSet(fromElement, true, toElement, false); + } + public NavigableSet<E> headSet(E toElement) { + return headSet(toElement, false); + } + public NavigableSet<E> tailSet(E fromElement) { + return tailSet(fromElement, true); + } + public NavigableSet<E> descendingSet() { + return new KeySet(m.descendingMap()); + } + } + + static final class Values<E> extends AbstractCollection<E> { + private final ConcurrentNavigableMap<Object, E> m; + Values(ConcurrentNavigableMap<Object, E> map) { + m = map; + } + public Iterator<E> iterator() { + if (m instanceof ConcurrentSkipListMap) + return ((ConcurrentSkipListMap<Object,E>)m).valueIterator(); + else + return ((SubMap<Object,E>)m).valueIterator(); + } + public boolean isEmpty() { + return m.isEmpty(); + } + public int size() { + return m.size(); + } + public boolean contains(Object o) { + return m.containsValue(o); + } + public void clear() { + m.clear(); + } + public Object[] toArray() { return toList(this).toArray(); } + public <T> T[] toArray(T[] a) { return toList(this).toArray(a); } + } + + static final class EntrySet<K1,V1> extends AbstractSet<Map.Entry<K1,V1>> { + private final ConcurrentNavigableMap<K1, V1> m; + EntrySet(ConcurrentNavigableMap<K1, V1> map) { + m = map; + } + + public Iterator<Map.Entry<K1,V1>> iterator() { + if (m instanceof ConcurrentSkipListMap) + return ((ConcurrentSkipListMap<K1,V1>)m).entryIterator(); + else + return ((SubMap<K1,V1>)m).entryIterator(); + } + + public boolean contains(Object o) { + if (!(o instanceof Map.Entry)) + return false; + Map.Entry<K1,V1> e = (Map.Entry<K1,V1>)o; + V1 v = m.get(e.getKey()); + return v != null && v.equals(e.getValue()); + } + public boolean remove(Object o) { + if (!(o instanceof Map.Entry)) + return false; + Map.Entry<K1,V1> e = (Map.Entry<K1,V1>)o; + return m.remove(e.getKey(), + e.getValue()); + } + public boolean isEmpty() { + return m.isEmpty(); + } + public int size() { + return m.size(); + } + public void clear() { + m.clear(); + } + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof Set)) + return false; + Collection<?> c = (Collection<?>) o; + try { + return containsAll(c) && c.containsAll(this); + } catch (ClassCastException unused) { + return false; + } catch (NullPointerException unused) { + return false; + } + } + public Object[] toArray() { return toList(this).toArray(); } + public <T> T[] toArray(T[] a) { return toList(this).toArray(a); } + } + + /** + * Submaps returned by {@link ConcurrentSkipListMap} submap operations + * represent a subrange of mappings of their underlying + * maps. Instances of this class support all methods of their + * underlying maps, differing in that mappings outside their range are + * ignored, and attempts to add mappings outside their ranges result + * in {@link IllegalArgumentException}. Instances of this class are + * constructed only using the <tt>subMap</tt>, <tt>headMap</tt>, and + * <tt>tailMap</tt> methods of their underlying maps. + * + * @serial include + */ + static final class SubMap<K,V> extends AbstractMap<K,V> + implements ConcurrentNavigableMap<K,V>, Cloneable, + java.io.Serializable { + private static final long serialVersionUID = -7647078645895051609L; + + /** Underlying map */ + private final ConcurrentSkipListMap<K,V> m; + /** lower bound key, or null if from start */ + private final K lo; + /** upper bound key, or null if to end */ + private final K hi; + /** inclusion flag for lo */ + private final boolean loInclusive; + /** inclusion flag for hi */ + private final boolean hiInclusive; + /** direction */ + private final boolean isDescending; + + // Lazily initialized view holders + private transient KeySet<K> keySetView; + private transient Set<Map.Entry<K,V>> entrySetView; + private transient Collection<V> valuesView; + + /** + * Creates a new submap, initializing all fields + */ + SubMap(ConcurrentSkipListMap<K,V> map, + K fromKey, boolean fromInclusive, + K toKey, boolean toInclusive, + boolean isDescending) { + if (fromKey != null && toKey != null && + map.compare(fromKey, toKey) > 0) + throw new IllegalArgumentException("inconsistent range"); + this.m = map; + this.lo = fromKey; + this.hi = toKey; + this.loInclusive = fromInclusive; + this.hiInclusive = toInclusive; + this.isDescending = isDescending; + } + + /* ---------------- Utilities -------------- */ + + private boolean tooLow(K key) { + if (lo != null) { + int c = m.compare(key, lo); + if (c < 0 || (c == 0 && !loInclusive)) + return true; + } + return false; + } + + private boolean tooHigh(K key) { + if (hi != null) { + int c = m.compare(key, hi); + if (c > 0 || (c == 0 && !hiInclusive)) + return true; + } + return false; + } + + private boolean inBounds(K key) { + return !tooLow(key) && !tooHigh(key); + } + + private void checkKeyBounds(K key) throws IllegalArgumentException { + if (key == null) + throw new NullPointerException(); + if (!inBounds(key)) + throw new IllegalArgumentException("key out of range"); + } + + /** + * Returns true if node key is less than upper bound of range + */ + private boolean isBeforeEnd(ConcurrentSkipListMap.Node<K,V> n) { + if (n == null) + return false; + if (hi == null) + return true; + K k = n.key; + if (k == null) // pass by markers and headers + return true; + int c = m.compare(k, hi); + if (c > 0 || (c == 0 && !hiInclusive)) + return false; + return true; + } + + /** + * Returns lowest node. This node might not be in range, so + * most usages need to check bounds + */ + private ConcurrentSkipListMap.Node<K,V> loNode() { + if (lo == null) + return m.findFirst(); + else if (loInclusive) + return m.findNear(lo, m.GT|m.EQ); + else + return m.findNear(lo, m.GT); + } + + /** + * Returns highest node. This node might not be in range, so + * most usages need to check bounds + */ + private ConcurrentSkipListMap.Node<K,V> hiNode() { + if (hi == null) + return m.findLast(); + else if (hiInclusive) + return m.findNear(hi, m.LT|m.EQ); + else + return m.findNear(hi, m.LT); + } + + /** + * Returns lowest absolute key (ignoring directonality) + */ + private K lowestKey() { + ConcurrentSkipListMap.Node<K,V> n = loNode(); + if (isBeforeEnd(n)) + return n.key; + else + throw new NoSuchElementException(); + } + + /** + * Returns highest absolute key (ignoring directonality) + */ + private K highestKey() { + ConcurrentSkipListMap.Node<K,V> n = hiNode(); + if (n != null) { + K last = n.key; + if (inBounds(last)) + return last; + } + throw new NoSuchElementException(); + } + + private Map.Entry<K,V> lowestEntry() { + for (;;) { + ConcurrentSkipListMap.Node<K,V> n = loNode(); + if (!isBeforeEnd(n)) + return null; + Map.Entry<K,V> e = n.createSnapshot(); + if (e != null) + return e; + } + } + + private Map.Entry<K,V> highestEntry() { + for (;;) { + ConcurrentSkipListMap.Node<K,V> n = hiNode(); + if (n == null || !inBounds(n.key)) + return null; + Map.Entry<K,V> e = n.createSnapshot(); + if (e != null) + return e; + } + } + + private Map.Entry<K,V> removeLowest() { + for (;;) { + Node<K,V> n = loNode(); + if (n == null) + return null; + K k = n.key; + if (!inBounds(k)) + return null; + V v = m.doRemove(k, null); + if (v != null) + return new AbstractMap.SimpleImmutableEntry<K,V>(k, v); + } + } + + private Map.Entry<K,V> removeHighest() { + for (;;) { + Node<K,V> n = hiNode(); + if (n == null) + return null; + K k = n.key; + if (!inBounds(k)) + return null; + V v = m.doRemove(k, null); + if (v != null) + return new AbstractMap.SimpleImmutableEntry<K,V>(k, v); + } + } + + /** + * Submap version of ConcurrentSkipListMap.getNearEntry + */ + private Map.Entry<K,V> getNearEntry(K key, int rel) { + if (isDescending) { // adjust relation for direction + if ((rel & m.LT) == 0) + rel |= m.LT; + else + rel &= ~m.LT; + } + if (tooLow(key)) + return ((rel & m.LT) != 0)? null : lowestEntry(); + if (tooHigh(key)) + return ((rel & m.LT) != 0)? highestEntry() : null; + for (;;) { + Node<K,V> n = m.findNear(key, rel); + if (n == null || !inBounds(n.key)) + return null; + K k = n.key; + V v = n.getValidValue(); + if (v != null) + return new AbstractMap.SimpleImmutableEntry<K,V>(k, v); + } + } + + // Almost the same as getNearEntry, except for keys + private K getNearKey(K key, int rel) { + if (isDescending) { // adjust relation for direction + if ((rel & m.LT) == 0) + rel |= m.LT; + else + rel &= ~m.LT; + } + if (tooLow(key)) { + if ((rel & m.LT) == 0) { + ConcurrentSkipListMap.Node<K,V> n = loNode(); + if (isBeforeEnd(n)) + return n.key; + } + return null; + } + if (tooHigh(key)) { + if ((rel & m.LT) != 0) { + ConcurrentSkipListMap.Node<K,V> n = hiNode(); + if (n != null) { + K last = n.key; + if (inBounds(last)) + return last; + } + } + return null; + } + for (;;) { + Node<K,V> n = m.findNear(key, rel); + if (n == null || !inBounds(n.key)) + return null; + K k = n.key; + V v = n.getValidValue(); + if (v != null) + return k; + } + } + + /* ---------------- Map API methods -------------- */ + + public boolean containsKey(Object key) { + if (key == null) throw new NullPointerException(); + K k = (K)key; + return inBounds(k) && m.containsKey(k); + } + + public V get(Object key) { + if (key == null) throw new NullPointerException(); + K k = (K)key; + return ((!inBounds(k)) ? null : m.get(k)); + } + + public V put(K key, V value) { + checkKeyBounds(key); + return m.put(key, value); + } + + public V remove(Object key) { + K k = (K)key; + return (!inBounds(k))? null : m.remove(k); + } + + public int size() { + long count = 0; + for (ConcurrentSkipListMap.Node<K,V> n = loNode(); + isBeforeEnd(n); + n = n.next) { + if (n.getValidValue() != null) + ++count; + } + return count >= Integer.MAX_VALUE? Integer.MAX_VALUE : (int)count; + } + + public boolean isEmpty() { + return !isBeforeEnd(loNode()); + } + + public boolean containsValue(Object value) { + if (value == null) + throw new NullPointerException(); + for (ConcurrentSkipListMap.Node<K,V> n = loNode(); + isBeforeEnd(n); + n = n.next) { + V v = n.getValidValue(); + if (v != null && value.equals(v)) + return true; + } + return false; + } + + public void clear() { + for (ConcurrentSkipListMap.Node<K,V> n = loNode(); + isBeforeEnd(n); + n = n.next) { + if (n.getValidValue() != null) + m.remove(n.key); + } + } + + /* ---------------- ConcurrentMap API methods -------------- */ + + public V putIfAbsent(K key, V value) { + checkKeyBounds(key); + return m.putIfAbsent(key, value); + } + + public boolean remove(Object key, Object value) { + K k = (K)key; + return inBounds(k) && m.remove(k, value); + } + + public boolean replace(K key, V oldValue, V newValue) { + checkKeyBounds(key); + return m.replace(key, oldValue, newValue); + } + + public V replace(K key, V value) { + checkKeyBounds(key); + return m.replace(key, value); + } + + /* ---------------- SortedMap API methods -------------- */ + + public Comparator<? super K> comparator() { + Comparator<? super K> cmp = m.comparator(); + if (isDescending) + return Collections.reverseOrder(cmp); + else + return cmp; + } + + /** + * Utility to create submaps, where given bounds override + * unbounded(null) ones and/or are checked against bounded ones. + */ + private SubMap<K,V> newSubMap(K fromKey, + boolean fromInclusive, + K toKey, + boolean toInclusive) { + if (isDescending) { // flip senses + K tk = fromKey; + fromKey = toKey; + toKey = tk; + boolean ti = fromInclusive; + fromInclusive = toInclusive; + toInclusive = ti; + } + if (lo != null) { + if (fromKey == null) { + fromKey = lo; + fromInclusive = loInclusive; + } + else { + int c = m.compare(fromKey, lo); + if (c < 0 || (c == 0 && !loInclusive && fromInclusive)) + throw new IllegalArgumentException("key out of range"); + } + } + if (hi != null) { + if (toKey == null) { + toKey = hi; + toInclusive = hiInclusive; + } + else { + int c = m.compare(toKey, hi); + if (c > 0 || (c == 0 && !hiInclusive && toInclusive)) + throw new IllegalArgumentException("key out of range"); + } + } + return new SubMap<K,V>(m, fromKey, fromInclusive, + toKey, toInclusive, isDescending); + } + + public SubMap<K,V> subMap(K fromKey, + boolean fromInclusive, + K toKey, + boolean toInclusive) { + if (fromKey == null || toKey == null) + throw new NullPointerException(); + return newSubMap(fromKey, fromInclusive, toKey, toInclusive); + } + + public SubMap<K,V> headMap(K toKey, + boolean inclusive) { + if (toKey == null) + throw new NullPointerException(); + return newSubMap(null, false, toKey, inclusive); + } + + public SubMap<K,V> tailMap(K fromKey, + boolean inclusive) { + if (fromKey == null) + throw new NullPointerException(); + return newSubMap(fromKey, inclusive, null, false); + } + + public SubMap<K,V> subMap(K fromKey, K toKey) { + return subMap(fromKey, true, toKey, false); + } + + public SubMap<K,V> headMap(K toKey) { + return headMap(toKey, false); + } + + public SubMap<K,V> tailMap(K fromKey) { + return tailMap(fromKey, true); + } + + public SubMap<K,V> descendingMap() { + return new SubMap<K,V>(m, lo, loInclusive, + hi, hiInclusive, !isDescending); + } + + /* ---------------- Relational methods -------------- */ + + public Map.Entry<K,V> ceilingEntry(K key) { + return getNearEntry(key, (m.GT|m.EQ)); + } + + public K ceilingKey(K key) { + return getNearKey(key, (m.GT|m.EQ)); + } + + public Map.Entry<K,V> lowerEntry(K key) { + return getNearEntry(key, (m.LT)); + } + + public K lowerKey(K key) { + return getNearKey(key, (m.LT)); + } + + public Map.Entry<K,V> floorEntry(K key) { + return getNearEntry(key, (m.LT|m.EQ)); + } + + public K floorKey(K key) { + return getNearKey(key, (m.LT|m.EQ)); + } + + public Map.Entry<K,V> higherEntry(K key) { + return getNearEntry(key, (m.GT)); + } + + public K higherKey(K key) { + return getNearKey(key, (m.GT)); + } + + public K firstKey() { + return isDescending? highestKey() : lowestKey(); + } + + public K lastKey() { + return isDescending? lowestKey() : highestKey(); + } + + public Map.Entry<K,V> firstEntry() { + return isDescending? highestEntry() : lowestEntry(); + } + + public Map.Entry<K,V> lastEntry() { + return isDescending? lowestEntry() : highestEntry(); + } + + public Map.Entry<K,V> pollFirstEntry() { + return isDescending? removeHighest() : removeLowest(); + } + + public Map.Entry<K,V> pollLastEntry() { + return isDescending? removeLowest() : removeHighest(); + } + + /* ---------------- Submap Views -------------- */ + + public NavigableSet<K> keySet() { + KeySet<K> ks = keySetView; + return (ks != null) ? ks : (keySetView = new KeySet(this)); + } + + public NavigableSet<K> navigableKeySet() { + KeySet<K> ks = keySetView; + return (ks != null) ? ks : (keySetView = new KeySet(this)); + } + + public Collection<V> values() { + Collection<V> vs = valuesView; + return (vs != null) ? vs : (valuesView = new Values(this)); + } + + public Set<Map.Entry<K,V>> entrySet() { + Set<Map.Entry<K,V>> es = entrySetView; + return (es != null) ? es : (entrySetView = new EntrySet(this)); + } + + public NavigableSet<K> descendingKeySet() { + return descendingMap().navigableKeySet(); + } + + Iterator<K> keyIterator() { + return new SubMapKeyIterator(); + } + + Iterator<V> valueIterator() { + return new SubMapValueIterator(); + } + + Iterator<Map.Entry<K,V>> entryIterator() { + return new SubMapEntryIterator(); + } + + /** + * Variant of main Iter class to traverse through submaps. + */ + abstract class SubMapIter<T> implements Iterator<T> { + /** the last node returned by next() */ + Node<K,V> lastReturned; + /** the next node to return from next(); */ + Node<K,V> next; + /** Cache of next value field to maintain weak consistency */ + V nextValue; + + SubMapIter() { + for (;;) { + next = isDescending ? hiNode() : loNode(); + if (next == null) + break; + Object x = next.value; + if (x != null && x != next) { + if (! inBounds(next.key)) + next = null; + else + nextValue = (V) x; + break; + } + } + } + + public final boolean hasNext() { + return next != null; + } + + final void advance() { + if (next == null) + throw new NoSuchElementException(); + lastReturned = next; + if (isDescending) + descend(); + else + ascend(); + } + + private void ascend() { + for (;;) { + next = next.next; + if (next == null) + break; + Object x = next.value; + if (x != null && x != next) { + if (tooHigh(next.key)) + next = null; + else + nextValue = (V) x; + break; + } + } + } + + private void descend() { + for (;;) { + next = m.findNear(lastReturned.key, LT); + if (next == null) + break; + Object x = next.value; + if (x != null && x != next) { + if (tooLow(next.key)) + next = null; + else + nextValue = (V) x; + break; + } + } + } + + public void remove() { + Node<K,V> l = lastReturned; + if (l == null) + throw new IllegalStateException(); + m.remove(l.key); + lastReturned = null; + } + + } + + final class SubMapValueIterator extends SubMapIter<V> { + public V next() { + V v = nextValue; + advance(); + return v; + } + } + + final class SubMapKeyIterator extends SubMapIter<K> { + public K next() { + Node<K,V> n = next; + advance(); + return n.key; + } + } + + final class SubMapEntryIterator extends SubMapIter<Map.Entry<K,V>> { + public Map.Entry<K,V> next() { + Node<K,V> n = next; + V v = nextValue; + advance(); + return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v); + } + } + } +} diff --git a/concurrent/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java b/concurrent/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java new file mode 100644 index 0000000..7fd1c76 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java @@ -0,0 +1,456 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package java.util.concurrent; +import java.util.*; +import sun.misc.Unsafe; + +/** + * A scalable concurrent {@link NavigableSet} implementation based on + * a {@link ConcurrentSkipListMap}. The elements of the set are kept + * sorted according to their {@linkplain Comparable natural ordering}, + * or by a {@link Comparator} provided at set creation time, depending + * on which constructor is used. + * + * <p>This implementation provides expected average <i>log(n)</i> time + * cost for the <tt>contains</tt>, <tt>add</tt>, and <tt>remove</tt> + * operations and their variants. Insertion, removal, and access + * operations safely execute concurrently by multiple threads. + * Iterators are <i>weakly consistent</i>, returning elements + * reflecting the state of the set at some point at or since the + * creation of the iterator. They do <em>not</em> throw {@link + * ConcurrentModificationException}, and may proceed concurrently with + * other operations. Ascending ordered views and their iterators are + * faster than descending ones. + * + * <p>Beware that, unlike in most collections, the <tt>size</tt> + * method is <em>not</em> a constant-time operation. Because of the + * asynchronous nature of these sets, determining the current number + * of elements requires a traversal of the elements. Additionally, the + * bulk operations <tt>addAll</tt>, <tt>removeAll</tt>, + * <tt>retainAll</tt>, and <tt>containsAll</tt> are <em>not</em> + * guaranteed to be performed atomically. For example, an iterator + * operating concurrently with an <tt>addAll</tt> operation might view + * only some of the added elements. + * + * <p>This class and its iterators implement all of the + * <em>optional</em> methods of the {@link Set} and {@link Iterator} + * interfaces. Like most other concurrent collection implementations, + * this class does not permit the use of <tt>null</tt> elements, + * because <tt>null</tt> arguments and return values cannot be reliably + * distinguished from the absence of elements. + * + * <p>This class is a member of the + * <a href="{@docRoot}/../technotes/guides/collections/index.html"> + * Java Collections Framework</a>. + * + * @author Doug Lea + * @param <E> the type of elements maintained by this set + * @since 1.6 + */ +public class ConcurrentSkipListSet<E> + extends AbstractSet<E> + implements NavigableSet<E>, Cloneable, java.io.Serializable { + + private static final long serialVersionUID = -2479143111061671589L; + + /** + * The underlying map. Uses Boolean.TRUE as value for each + * element. This field is declared final for the sake of thread + * safety, which entails some ugliness in clone() + */ + private final ConcurrentNavigableMap<E,Object> m; + + /** + * Constructs a new, empty set that orders its elements according to + * their {@linkplain Comparable natural ordering}. + */ + public ConcurrentSkipListSet() { + m = new ConcurrentSkipListMap<E,Object>(); + } + + /** + * Constructs a new, empty set that orders its elements according to + * the specified comparator. + * + * @param comparator the comparator that will be used to order this set. + * If <tt>null</tt>, the {@linkplain Comparable natural + * ordering} of the elements will be used. + */ + public ConcurrentSkipListSet(Comparator<? super E> comparator) { + m = new ConcurrentSkipListMap<E,Object>(comparator); + } + + /** + * Constructs a new set containing the elements in the specified + * collection, that orders its elements according to their + * {@linkplain Comparable natural ordering}. + * + * @param c The elements that will comprise the new set + * @throws ClassCastException if the elements in <tt>c</tt> are + * not {@link Comparable}, or are not mutually comparable + * @throws NullPointerException if the specified collection or any + * of its elements are null + */ + public ConcurrentSkipListSet(Collection<? extends E> c) { + m = new ConcurrentSkipListMap<E,Object>(); + addAll(c); + } + + /** + * Constructs a new set containing the same elements and using the + * same ordering as the specified sorted set. + * + * @param s sorted set whose elements will comprise the new set + * @throws NullPointerException if the specified sorted set or any + * of its elements are null + */ + public ConcurrentSkipListSet(SortedSet<E> s) { + m = new ConcurrentSkipListMap<E,Object>(s.comparator()); + addAll(s); + } + + /** + * For use by submaps + */ + ConcurrentSkipListSet(ConcurrentNavigableMap<E,Object> m) { + this.m = m; + } + + /** + * Returns a shallow copy of this <tt>ConcurrentSkipListSet</tt> + * instance. (The elements themselves are not cloned.) + * + * @return a shallow copy of this set + */ + public ConcurrentSkipListSet<E> clone() { + ConcurrentSkipListSet<E> clone = null; + try { + clone = (ConcurrentSkipListSet<E>) super.clone(); + clone.setMap(new ConcurrentSkipListMap(m)); + } catch (CloneNotSupportedException e) { + throw new InternalError(); + } + + return clone; + } + + /* ---------------- Set operations -------------- */ + + /** + * Returns the number of elements in this set. If this set + * contains more than <tt>Integer.MAX_VALUE</tt> elements, it + * returns <tt>Integer.MAX_VALUE</tt>. + * + * <p>Beware that, unlike in most collections, this method is + * <em>NOT</em> a constant-time operation. Because of the + * asynchronous nature of these sets, determining the current + * number of elements requires traversing them all to count them. + * Additionally, it is possible for the size to change during + * execution of this method, in which case the returned result + * will be inaccurate. Thus, this method is typically not very + * useful in concurrent applications. + * + * @return the number of elements in this set + */ + public int size() { + return m.size(); + } + + /** + * Returns <tt>true</tt> if this set contains no elements. + * @return <tt>true</tt> if this set contains no elements + */ + public boolean isEmpty() { + return m.isEmpty(); + } + + /** + * Returns <tt>true</tt> if this set contains the specified element. + * More formally, returns <tt>true</tt> if and only if this set + * contains an element <tt>e</tt> such that <tt>o.equals(e)</tt>. + * + * @param o object to be checked for containment in this set + * @return <tt>true</tt> if this set contains the specified element + * @throws ClassCastException if the specified element cannot be + * compared with the elements currently in this set + * @throws NullPointerException if the specified element is null + */ + public boolean contains(Object o) { + return m.containsKey(o); + } + + /** + * Adds the specified element to this set if it is not already present. + * More formally, adds the specified element <tt>e</tt> to this set if + * the set contains no element <tt>e2</tt> such that <tt>e.equals(e2)</tt>. + * If this set already contains the element, the call leaves the set + * unchanged and returns <tt>false</tt>. + * + * @param e element to be added to this set + * @return <tt>true</tt> if this set did not already contain the + * specified element + * @throws ClassCastException if <tt>e</tt> cannot be compared + * with the elements currently in this set + * @throws NullPointerException if the specified element is null + */ + public boolean add(E e) { + return m.putIfAbsent(e, Boolean.TRUE) == null; + } + + /** + * Removes the specified element from this set if it is present. + * More formally, removes an element <tt>e</tt> such that + * <tt>o.equals(e)</tt>, if this set contains such an element. + * Returns <tt>true</tt> if this set contained the element (or + * equivalently, if this set changed as a result of the call). + * (This set will not contain the element once the call returns.) + * + * @param o object to be removed from this set, if present + * @return <tt>true</tt> if this set contained the specified element + * @throws ClassCastException if <tt>o</tt> cannot be compared + * with the elements currently in this set + * @throws NullPointerException if the specified element is null + */ + public boolean remove(Object o) { + return m.remove(o, Boolean.TRUE); + } + + /** + * Removes all of the elements from this set. + */ + public void clear() { + m.clear(); + } + + /** + * Returns an iterator over the elements in this set in ascending order. + * + * @return an iterator over the elements in this set in ascending order + */ + public Iterator<E> iterator() { + return m.navigableKeySet().iterator(); + } + + /** + * Returns an iterator over the elements in this set in descending order. + * + * @return an iterator over the elements in this set in descending order + */ + public Iterator<E> descendingIterator() { + return m.descendingKeySet().iterator(); + } + + + /* ---------------- AbstractSet Overrides -------------- */ + + /** + * Compares the specified object with this set for equality. Returns + * <tt>true</tt> if the specified object is also a set, the two sets + * have the same size, and every member of the specified set is + * contained in this set (or equivalently, every member of this set is + * contained in the specified set). This definition ensures that the + * equals method works properly across different implementations of the + * set interface. + * + * @param o the object to be compared for equality with this set + * @return <tt>true</tt> if the specified object is equal to this set + */ + public boolean equals(Object o) { + // Override AbstractSet version to avoid calling size() + if (o == this) + return true; + if (!(o instanceof Set)) + return false; + Collection<?> c = (Collection<?>) o; + try { + return containsAll(c) && c.containsAll(this); + } catch (ClassCastException unused) { + return false; + } catch (NullPointerException unused) { + return false; + } + } + + /** + * Removes from this set all of its elements that are contained in + * the specified collection. If the specified collection is also + * a set, this operation effectively modifies this set so that its + * value is the <i>asymmetric set difference</i> of the two sets. + * + * @param c collection containing elements to be removed from this set + * @return <tt>true</tt> if this set changed as a result of the call + * @throws ClassCastException if the types of one or more elements in this + * set are incompatible with the specified collection + * @throws NullPointerException if the specified collection or any + * of its elements are null + */ + public boolean removeAll(Collection<?> c) { + // Override AbstractSet version to avoid unnecessary call to size() + boolean modified = false; + for (Iterator<?> i = c.iterator(); i.hasNext(); ) + if (remove(i.next())) + modified = true; + return modified; + } + + /* ---------------- Relational operations -------------- */ + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + */ + public E lower(E e) { + return m.lowerKey(e); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + */ + public E floor(E e) { + return m.floorKey(e); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + */ + public E ceiling(E e) { + return m.ceilingKey(e); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + */ + public E higher(E e) { + return m.higherKey(e); + } + + public E pollFirst() { + Map.Entry<E,Object> e = m.pollFirstEntry(); + return e == null? null : e.getKey(); + } + + public E pollLast() { + Map.Entry<E,Object> e = m.pollLastEntry(); + return e == null? null : e.getKey(); + } + + + /* ---------------- SortedSet operations -------------- */ + + + public Comparator<? super E> comparator() { + return m.comparator(); + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E first() { + return m.firstKey(); + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E last() { + return m.lastKey(); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromElement} or + * {@code toElement} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public NavigableSet<E> subSet(E fromElement, + boolean fromInclusive, + E toElement, + boolean toInclusive) { + return new ConcurrentSkipListSet<E> + (m.subMap(fromElement, fromInclusive, + toElement, toInclusive)); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code toElement} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public NavigableSet<E> headSet(E toElement, boolean inclusive) { + return new ConcurrentSkipListSet<E>(m.headMap(toElement, inclusive)); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromElement} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public NavigableSet<E> tailSet(E fromElement, boolean inclusive) { + return new ConcurrentSkipListSet<E>(m.tailMap(fromElement, inclusive)); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromElement} or + * {@code toElement} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public NavigableSet<E> subSet(E fromElement, E toElement) { + return subSet(fromElement, true, toElement, false); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code toElement} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public NavigableSet<E> headSet(E toElement) { + return headSet(toElement, false); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromElement} is null + * @throws IllegalArgumentException {@inheritDoc} + */ + public NavigableSet<E> tailSet(E fromElement) { + return tailSet(fromElement, true); + } + + /** + * Returns a reverse order view of the elements contained in this set. + * The descending set is backed by this set, so changes to the set are + * reflected in the descending set, and vice-versa. + * + * <p>The returned set has an ordering equivalent to + * <tt>{@link Collections#reverseOrder(Comparator) Collections.reverseOrder}(comparator())</tt>. + * The expression {@code s.descendingSet().descendingSet()} returns a + * view of {@code s} essentially equivalent to {@code s}. + * + * @return a reverse order view of this set + */ + public NavigableSet<E> descendingSet() { + return new ConcurrentSkipListSet(m.descendingMap()); + } + + // Support for resetting map in clone + private static final Unsafe unsafe = Unsafe.getUnsafe(); + private static final long mapOffset; + static { + try { + mapOffset = unsafe.objectFieldOffset + (ConcurrentSkipListSet.class.getDeclaredField("m")); + } catch (Exception ex) { throw new Error(ex); } + } + private void setMap(ConcurrentNavigableMap<E,Object> map) { + unsafe.putObjectVolatile(this, mapOffset, map); + } + +} diff --git a/concurrent/src/main/java/java/util/concurrent/CopyOnWriteArrayList.java b/concurrent/src/main/java/java/util/concurrent/CopyOnWriteArrayList.java index f0c8ac6..237c5df 100644 --- a/concurrent/src/main/java/java/util/concurrent/CopyOnWriteArrayList.java +++ b/concurrent/src/main/java/java/util/concurrent/CopyOnWriteArrayList.java @@ -17,8 +17,6 @@ package java.util.concurrent; import java.util.*; import java.util.concurrent.locks.*; -import java.lang.reflect.Array; - import sun.misc.Unsafe; // BEGIN android-note @@ -102,7 +100,7 @@ public class CopyOnWriteArrayList<E> Object[] elements = c.toArray(); // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elements.getClass() != Object[].class) - elements = Java6Arrays.copyOf(elements, elements.length, Object[].class); + elements = Arrays.copyOf(elements, elements.length, Object[].class); setArray(elements); } @@ -114,7 +112,7 @@ public class CopyOnWriteArrayList<E> * @throws NullPointerException if the specified array is null */ public CopyOnWriteArrayList(E[] toCopyIn) { - setArray(Java6Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class)); + setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class)); } /** @@ -288,7 +286,7 @@ public class CopyOnWriteArrayList<E> */ public Object[] toArray() { Object[] elements = getArray(); - return Java6Arrays.copyOf(elements, elements.length); + return Arrays.copyOf(elements, elements.length); } /** @@ -335,7 +333,7 @@ public class CopyOnWriteArrayList<E> Object[] elements = getArray(); int len = elements.length; if (a.length < len) - return (T[]) Java6Arrays.copyOf(elements, len, a.getClass()); + return (T[]) Arrays.copyOf(elements, len, a.getClass()); else { System.arraycopy(elements, 0, a, 0, len); if (a.length > len) @@ -375,7 +373,7 @@ public class CopyOnWriteArrayList<E> if (oldValue != element) { int len = elements.length; - Object[] newElements = Java6Arrays.copyOf(elements, len); + Object[] newElements = Arrays.copyOf(elements, len); newElements[index] = element; setArray(newElements); } else { @@ -400,7 +398,7 @@ public class CopyOnWriteArrayList<E> try { Object[] elements = getArray(); int len = elements.length; - Object[] newElements = Java6Arrays.copyOf(elements, len + 1); + Object[] newElements = Arrays.copyOf(elements, len + 1); newElements[len] = e; setArray(newElements); return true; @@ -428,7 +426,7 @@ public class CopyOnWriteArrayList<E> Object[] newElements; int numMoved = len - index; if (numMoved == 0) - newElements = Java6Arrays.copyOf(elements, len + 1); + newElements = Arrays.copyOf(elements, len + 1); else { newElements = new Object[len + 1]; System.arraycopy(elements, 0, newElements, 0, index); @@ -458,7 +456,7 @@ public class CopyOnWriteArrayList<E> E oldValue = get(elements, index); int numMoved = len - index - 1; if (numMoved == 0) - setArray(Java6Arrays.copyOf(elements, len - 1)); + setArray(Arrays.copyOf(elements, len - 1)); else { Object[] newElements = new Object[len - 1]; System.arraycopy(elements, 0, newElements, 0, index); @@ -544,7 +542,7 @@ public class CopyOnWriteArrayList<E> int newlen = len - (toIndex - fromIndex); int numMoved = len - toIndex; if (numMoved == 0) - setArray(Java6Arrays.copyOf(elements, newlen)); + setArray(Arrays.copyOf(elements, newlen)); else { Object[] newElements = new Object[newlen]; System.arraycopy(elements, 0, newElements, 0, fromIndex); @@ -636,7 +634,7 @@ public class CopyOnWriteArrayList<E> temp[newlen++] = element; } if (newlen != len) { - setArray(Java6Arrays.copyOf(temp, newlen)); + setArray(Arrays.copyOf(temp, newlen)); return true; } } @@ -676,7 +674,7 @@ public class CopyOnWriteArrayList<E> temp[newlen++] = element; } if (newlen != len) { - setArray(Java6Arrays.copyOf(temp, newlen)); + setArray(Arrays.copyOf(temp, newlen)); return true; } } @@ -715,7 +713,7 @@ public class CopyOnWriteArrayList<E> uniq[added++] = e; } if (added > 0) { - Object[] newElements = Java6Arrays.copyOf(elements, len + added); + Object[] newElements = Arrays.copyOf(elements, len + added); System.arraycopy(uniq, 0, newElements, len, added); setArray(newElements); } @@ -758,7 +756,7 @@ public class CopyOnWriteArrayList<E> try { Object[] elements = getArray(); int len = elements.length; - Object[] newElements = Java6Arrays.copyOf(elements, len + cs.length); + Object[] newElements = Arrays.copyOf(elements, len + cs.length); System.arraycopy(cs, 0, newElements, len, cs.length); setArray(newElements); return true; @@ -798,7 +796,7 @@ public class CopyOnWriteArrayList<E> int numMoved = len - index; Object[] newElements; if (numMoved == 0) - newElements = Java6Arrays.copyOf(elements, len + cs.length); + newElements = Arrays.copyOf(elements, len + cs.length); else { newElements = new Object[len + cs.length]; System.arraycopy(elements, 0, newElements, 0, index); @@ -1314,4 +1312,5 @@ public class CopyOnWriteArrayList<E> private void resetLock() { unsafe.putObjectVolatile(this, lockOffset, new ReentrantLock()); } + } diff --git a/concurrent/src/main/java/java/util/concurrent/Delayed.java b/concurrent/src/main/java/java/util/concurrent/Delayed.java index af41300..b1ff4ee 100644 --- a/concurrent/src/main/java/java/util/concurrent/Delayed.java +++ b/concurrent/src/main/java/java/util/concurrent/Delayed.java @@ -4,19 +4,10 @@ * http://creativecommons.org/licenses/publicdomain */ -/* - * Modified in Apache Harmony to comply with Java 5 signature - * specification. - */ - package java.util.concurrent; import java.util.*; -// BEGIN android-note -// Added generic type Delayed to Comparable to be closer to the RI. -// END android-note - /** * A mix-in style interface for marking objects that should be * acted upon after a given delay. diff --git a/concurrent/src/main/java/java/util/concurrent/Exchanger.java b/concurrent/src/main/java/java/util/concurrent/Exchanger.java index f67659c..bb2193c 100644 --- a/concurrent/src/main/java/java/util/concurrent/Exchanger.java +++ b/concurrent/src/main/java/java/util/concurrent/Exchanger.java @@ -471,7 +471,7 @@ public class Exchanger<V> { else if (w.isInterrupted()) // Abort on interrupt tryCancel(node, slot); else // Block - LockSupport.park(); + LockSupport.park(node); } } @@ -506,7 +506,7 @@ public class Exchanger<V> { else if (w.isInterrupted()) tryCancel(node, slot); else - LockSupport.parkNanos(nanos); + LockSupport.parkNanos(node, nanos); } else if (tryCancel(node, slot) && !w.isInterrupted()) return scanOnTimeout(node); diff --git a/concurrent/src/main/java/java/util/concurrent/ExecutorCompletionService.java b/concurrent/src/main/java/java/util/concurrent/ExecutorCompletionService.java index 02606f9..bf4a584 100644 --- a/concurrent/src/main/java/java/util/concurrent/ExecutorCompletionService.java +++ b/concurrent/src/main/java/java/util/concurrent/ExecutorCompletionService.java @@ -84,7 +84,7 @@ public class ExecutorCompletionService<V> implements CompletionService<V> { * FutureTask extension to enqueue upon completion */ private class QueueingFuture extends FutureTask<Void> { - QueueingFuture(FutureTask<V> task) { + QueueingFuture(RunnableFuture<V> task) { super(task, null); this.task = task; } @@ -92,12 +92,18 @@ public class ExecutorCompletionService<V> implements CompletionService<V> { private final Future<V> task; } - private FutureTask<V> newTaskFor(Callable<V> task) { - return new FutureTask<V>(task); + private RunnableFuture<V> newTaskFor(Callable<V> task) { + if (aes == null) + return new FutureTask<V>(task); + else + return aes.newTaskFor(task); } - private FutureTask<V> newTaskFor(Runnable task, V result) { - return new FutureTask<V>(task, result); + private RunnableFuture<V> newTaskFor(Runnable task, V result) { + if (aes == null) + return new FutureTask<V>(task, result); + else + return aes.newTaskFor(task, result); } /** @@ -142,14 +148,14 @@ public class ExecutorCompletionService<V> implements CompletionService<V> { public Future<V> submit(Callable<V> task) { if (task == null) throw new NullPointerException(); - FutureTask<V> f = newTaskFor(task); + RunnableFuture<V> f = newTaskFor(task); executor.execute(new QueueingFuture(f)); return f; } public Future<V> submit(Runnable task, V result) { if (task == null) throw new NullPointerException(); - FutureTask<V> f = newTaskFor(task, result); + RunnableFuture<V> f = newTaskFor(task, result); executor.execute(new QueueingFuture(f)); return f; } diff --git a/concurrent/src/main/java/java/util/concurrent/ExecutorService.java b/concurrent/src/main/java/java/util/concurrent/ExecutorService.java index 757f7cb..ddd77bf 100644 --- a/concurrent/src/main/java/java/util/concurrent/ExecutorService.java +++ b/concurrent/src/main/java/java/util/concurrent/ExecutorService.java @@ -258,7 +258,7 @@ public interface ExecutorService extends Executor { * scheduled for execution */ - <T> List<Future<T>> invokeAll(Collection<Callable<T>> tasks) + <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException; /** @@ -288,7 +288,7 @@ public interface ExecutorService extends Executor { * @throws RejectedExecutionException if any task cannot be scheduled * for execution */ - <T> List<Future<T>> invokeAll(Collection<Callable<T>> tasks, + <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException; @@ -303,14 +303,14 @@ public interface ExecutorService extends Executor { * @param tasks the collection of tasks * @return the result returned by one of the tasks * @throws InterruptedException if interrupted while waiting - * @throws NullPointerException if tasks or any of its elements - * are <tt>null</tt> + * @throws NullPointerException if tasks or any element task + * subject to execution is <tt>null</tt> * @throws IllegalArgumentException if tasks is empty * @throws ExecutionException if no task successfully completes * @throws RejectedExecutionException if tasks cannot be scheduled * for execution */ - <T> T invokeAny(Collection<Callable<T>> tasks) + <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException; /** @@ -327,15 +327,15 @@ public interface ExecutorService extends Executor { * @param unit the time unit of the timeout argument * @return the result returned by one of the tasks. * @throws InterruptedException if interrupted while waiting - * @throws NullPointerException if tasks, any of its elements, or - * unit are <tt>null</tt> + * @throws NullPointerException if tasks, or unit, or any element + * task subject to execution is <tt>null</tt> * @throws TimeoutException if the given timeout elapses before * any task successfully completes * @throws ExecutionException if no task successfully completes * @throws RejectedExecutionException if tasks cannot be scheduled * for execution */ - <T> T invokeAny(Collection<Callable<T>> tasks, + <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; } diff --git a/concurrent/src/main/java/java/util/concurrent/Executors.java b/concurrent/src/main/java/java/util/concurrent/Executors.java index a57abe5..96f6c15 100644 --- a/concurrent/src/main/java/java/util/concurrent/Executors.java +++ b/concurrent/src/main/java/java/util/concurrent/Executors.java @@ -13,6 +13,7 @@ import java.security.PrivilegedAction; import java.security.PrivilegedExceptionAction; import java.security.PrivilegedActionException; import java.security.AccessControlException; +// import sun.security.util.SecurityConstants; // android-removed /** * Factory and utility methods for {@link Executor}, {@link @@ -359,7 +360,7 @@ public class Executors { * @return a callable object * @throws NullPointerException if action null */ - public static Callable<Object> callable(final PrivilegedAction action) { + public static Callable<Object> callable(final PrivilegedAction<?> action) { if (action == null) throw new NullPointerException(); return new Callable<Object>() { @@ -374,7 +375,7 @@ public class Executors { * @return a callable object * @throws NullPointerException if action null */ - public static Callable<Object> callable(final PrivilegedExceptionAction action) { + public static Callable<Object> callable(final PrivilegedExceptionAction<?> action) { if (action == null) throw new NullPointerException(); return new Callable<Object>() { @@ -484,7 +485,7 @@ public class Executors { // Calls to getContextClassLoader from this class // never trigger a security check, but we check // whether our callers have this permission anyways. - sm.checkPermission(new RuntimePermission("getContextClassLoader")); + sm.checkPermission(new RuntimePermission("getContextClassLoader")); // android-changed // Whether setContextClassLoader turns out to be necessary // or not, we fail fast if permission is not available. @@ -565,7 +566,7 @@ public class Executors { // Calls to getContextClassLoader from this class // never trigger a security check, but we check // whether our callers have this permission anyways. - sm.checkPermission(new RuntimePermission("getContextClassLoader")); + sm.checkPermission(new RuntimePermission("getContextClassLoader")); // android-changed // Fail fast sm.checkPermission(new RuntimePermission("setContextClassLoader")); @@ -614,20 +615,20 @@ public class Executors { public <T> Future<T> submit(Runnable task, T result) { return e.submit(task, result); } - public <T> List<Future<T>> invokeAll(Collection<Callable<T>> tasks) + public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException { return e.invokeAll(tasks); } - public <T> List<Future<T>> invokeAll(Collection<Callable<T>> tasks, + public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException { return e.invokeAll(tasks, timeout, unit); } - public <T> T invokeAny(Collection<Callable<T>> tasks) + public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException { return e.invokeAny(tasks); } - public <T> T invokeAny(Collection<Callable<T>> tasks, + public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { return e.invokeAny(tasks, timeout, unit); diff --git a/concurrent/src/main/java/java/util/concurrent/FutureTask.java b/concurrent/src/main/java/java/util/concurrent/FutureTask.java index 8aa9dd1..6bd13f9 100644 --- a/concurrent/src/main/java/java/util/concurrent/FutureTask.java +++ b/concurrent/src/main/java/java/util/concurrent/FutureTask.java @@ -30,7 +30,7 @@ import java.util.concurrent.locks.*; * @author Doug Lea * @param <V> The result type returned by this FutureTask's <tt>get</tt> method */ -public class FutureTask<V> implements Future<V>, Runnable { +public class FutureTask<V> implements RunnableFuture<V> { /** Synchronization control for FutureTask */ private final Sync sync; diff --git a/concurrent/src/main/java/java/util/concurrent/Java6Arrays.java b/concurrent/src/main/java/java/util/concurrent/Java6Arrays.java deleted file mode 100644 index 6b728be..0000000 --- a/concurrent/src/main/java/java/util/concurrent/Java6Arrays.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package java.util.concurrent; - -import java.lang.reflect.Array; - -/** - * Arrays.copyOf and Arrays.copyOfRange backported from Java 6. - */ -class Java6Arrays { - - static <T> T[] copyOf(T[] original, int newLength) { - if (null == original) { - throw new NullPointerException(); - } - if (0 <= newLength) { - return copyOfRange(original, 0, newLength); - } - throw new NegativeArraySizeException(); - } - - static <T, U> T[] copyOf(U[] original, int newLength, - Class<? extends T[]> newType) { - if (0 <= newLength) { - return copyOfRange(original, 0, newLength, newType); - } - throw new NegativeArraySizeException(); - } - - @SuppressWarnings("unchecked") - static <T> T[] copyOfRange(T[] original, int start, int end) { - if (original.length >= start && 0 <= start) { - if (start <= end) { - int length = end - start; - int copyLength = Math.min(length, original.length - start); - T[] copy = (T[]) Array.newInstance(original.getClass().getComponentType(), length); - System.arraycopy(original, start, copy, 0, copyLength); - return copy; - } - throw new IllegalArgumentException(); - } - throw new ArrayIndexOutOfBoundsException(); - } - - @SuppressWarnings("unchecked") - static <T, U> T[] copyOfRange(U[] original, int start, int end, - Class<? extends T[]> newType) { - if (start <= end) { - if (original.length >= start && 0 <= start) { - int length = end - start; - int copyLength = Math.min(length, original.length - start); - T[] copy = (T[]) Array.newInstance(newType.getComponentType(), - length); - System.arraycopy(original, start, copy, 0, copyLength); - return copy; - } - throw new ArrayIndexOutOfBoundsException(); - } - throw new IllegalArgumentException(); - } - -} diff --git a/concurrent/src/main/java/java/util/concurrent/LinkedBlockingDeque.java b/concurrent/src/main/java/java/util/concurrent/LinkedBlockingDeque.java new file mode 100644 index 0000000..196ea76 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/LinkedBlockingDeque.java @@ -0,0 +1,1137 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package java.util.concurrent; + +import java.util.AbstractQueue; +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; + +/** + * An optionally-bounded {@linkplain BlockingDeque blocking deque} based on + * linked nodes. + * + * <p> The optional capacity bound constructor argument serves as a + * way to prevent excessive expansion. The capacity, if unspecified, + * is equal to {@link Integer#MAX_VALUE}. Linked nodes are + * dynamically created upon each insertion unless this would bring the + * deque above capacity. + * + * <p>Most operations run in constant time (ignoring time spent + * blocking). Exceptions include {@link #remove(Object) remove}, + * {@link #removeFirstOccurrence removeFirstOccurrence}, {@link + * #removeLastOccurrence removeLastOccurrence}, {@link #contains + * contains}, {@link #iterator iterator.remove()}, and the bulk + * operations, all of which run in linear time. + * + * <p>This class and its iterator implement all of the + * <em>optional</em> methods of the {@link Collection} and {@link + * Iterator} interfaces. + * + * <p>This class is a member of the + * <a href="{@docRoot}/../technotes/guides/collections/index.html"> + * Java Collections Framework</a>. + * + * @since 1.6 + * @author Doug Lea + * @param <E> the type of elements held in this collection + */ +public class LinkedBlockingDeque<E> + extends AbstractQueue<E> + implements BlockingDeque<E>, java.io.Serializable { + + /* + * Implemented as a simple doubly-linked list protected by a + * single lock and using conditions to manage blocking. + * + * To implement weakly consistent iterators, it appears we need to + * keep all Nodes GC-reachable from a predecessor dequeued Node. + * That would cause two problems: + * - allow a rogue Iterator to cause unbounded memory retention + * - cause cross-generational linking of old Nodes to new Nodes if + * a Node was tenured while live, which generational GCs have a + * hard time dealing with, causing repeated major collections. + * However, only non-deleted Nodes need to be reachable from + * dequeued Nodes, and reachability does not necessarily have to + * be of the kind understood by the GC. We use the trick of + * linking a Node that has just been dequeued to itself. Such a + * self-link implicitly means to jump to "first" (for next links) + * or "last" (for prev links). + */ + + /* + * We have "diamond" multiple interface/abstract class inheritance + * here, and that introduces ambiguities. Often we want the + * BlockingDeque javadoc combined with the AbstractQueue + * implementation, so a lot of method specs are duplicated here. + */ + + private static final long serialVersionUID = -387911632671998426L; + + /** Doubly-linked list node class */ + static final class Node<E> { + /** + * The item, or null if this node has been removed. + */ + E item; + + /** + * One of: + * - the real predecessor Node + * - this Node, meaning the predecessor is tail + * - null, meaning there is no predecessor + */ + Node<E> prev; + + /** + * One of: + * - the real successor Node + * - this Node, meaning the successor is head + * - null, meaning there is no successor + */ + Node<E> next; + + Node(E x, Node<E> p, Node<E> n) { + item = x; + prev = p; + next = n; + } + } + + /** + * Pointer to first node. + * Invariant: (first == null && last == null) || + * (first.prev == null && first.item != null) + */ + transient Node<E> first; + + /** + * Pointer to last node. + * Invariant: (first == null && last == null) || + * (last.next == null && last.item != null) + */ + transient Node<E> last; + + /** Number of items in the deque */ + private transient int count; + + /** Maximum number of items in the deque */ + private final int capacity; + + /** Main lock guarding all access */ + final ReentrantLock lock = new ReentrantLock(); + + /** Condition for waiting takes */ + private final Condition notEmpty = lock.newCondition(); + + /** Condition for waiting puts */ + private final Condition notFull = lock.newCondition(); + + /** + * Creates a {@code LinkedBlockingDeque} with a capacity of + * {@link Integer#MAX_VALUE}. + */ + public LinkedBlockingDeque() { + this(Integer.MAX_VALUE); + } + + /** + * Creates a {@code LinkedBlockingDeque} with the given (fixed) capacity. + * + * @param capacity the capacity of this deque + * @throws IllegalArgumentException if {@code capacity} is less than 1 + */ + public LinkedBlockingDeque(int capacity) { + if (capacity <= 0) throw new IllegalArgumentException(); + this.capacity = capacity; + } + + /** + * Creates a {@code LinkedBlockingDeque} with a capacity of + * {@link Integer#MAX_VALUE}, initially containing the elements of + * the given collection, added in traversal order of the + * collection's iterator. + * + * @param c the collection of elements to initially contain + * @throws NullPointerException if the specified collection or any + * of its elements are null + */ + public LinkedBlockingDeque(Collection<? extends E> c) { + this(Integer.MAX_VALUE); + final ReentrantLock lock = this.lock; + lock.lock(); // Never contended, but necessary for visibility + try { + for (E e : c) { + if (e == null) + throw new NullPointerException(); + if (!linkLast(e)) + throw new IllegalStateException("Deque full"); + } + } finally { + lock.unlock(); + } + } + + + // Basic linking and unlinking operations, called only while holding lock + + /** + * Links e as first element, or returns false if full. + */ + private boolean linkFirst(E e) { + // assert lock.isHeldByCurrentThread(); + if (count >= capacity) + return false; + Node<E> f = first; + Node<E> x = new Node<E>(e, null, f); + first = x; + if (last == null) + last = x; + else + f.prev = x; + ++count; + notEmpty.signal(); + return true; + } + + /** + * Links e as last element, or returns false if full. + */ + private boolean linkLast(E e) { + // assert lock.isHeldByCurrentThread(); + if (count >= capacity) + return false; + Node<E> l = last; + Node<E> x = new Node<E>(e, l, null); + last = x; + if (first == null) + first = x; + else + l.next = x; + ++count; + notEmpty.signal(); + return true; + } + + /** + * Removes and returns first element, or null if empty. + */ + private E unlinkFirst() { + // assert lock.isHeldByCurrentThread(); + Node<E> f = first; + if (f == null) + return null; + Node<E> n = f.next; + E item = f.item; + f.item = null; + f.next = f; // help GC + first = n; + if (n == null) + last = null; + else + n.prev = null; + --count; + notFull.signal(); + return item; + } + + /** + * Removes and returns last element, or null if empty. + */ + private E unlinkLast() { + // assert lock.isHeldByCurrentThread(); + Node<E> l = last; + if (l == null) + return null; + Node<E> p = l.prev; + E item = l.item; + l.item = null; + l.prev = l; // help GC + last = p; + if (p == null) + first = null; + else + p.next = null; + --count; + notFull.signal(); + return item; + } + + /** + * Unlinks x. + */ + void unlink(Node<E> x) { + // assert lock.isHeldByCurrentThread(); + Node<E> p = x.prev; + Node<E> n = x.next; + if (p == null) { + unlinkFirst(); + } else if (n == null) { + unlinkLast(); + } else { + p.next = n; + n.prev = p; + x.item = null; + // Don't mess with x's links. They may still be in use by + // an iterator. + --count; + notFull.signal(); + } + } + + // BlockingDeque methods + + /** + * @throws IllegalStateException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public void addFirst(E e) { + if (!offerFirst(e)) + throw new IllegalStateException("Deque full"); + } + + /** + * @throws IllegalStateException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public void addLast(E e) { + if (!offerLast(e)) + throw new IllegalStateException("Deque full"); + } + + /** + * @throws NullPointerException {@inheritDoc} + */ + public boolean offerFirst(E e) { + if (e == null) throw new NullPointerException(); + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return linkFirst(e); + } finally { + lock.unlock(); + } + } + + /** + * @throws NullPointerException {@inheritDoc} + */ + public boolean offerLast(E e) { + if (e == null) throw new NullPointerException(); + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return linkLast(e); + } finally { + lock.unlock(); + } + } + + /** + * @throws NullPointerException {@inheritDoc} + * @throws InterruptedException {@inheritDoc} + */ + public void putFirst(E e) throws InterruptedException { + if (e == null) throw new NullPointerException(); + final ReentrantLock lock = this.lock; + lock.lock(); + try { + while (!linkFirst(e)) + notFull.await(); + } finally { + lock.unlock(); + } + } + + /** + * @throws NullPointerException {@inheritDoc} + * @throws InterruptedException {@inheritDoc} + */ + public void putLast(E e) throws InterruptedException { + if (e == null) throw new NullPointerException(); + final ReentrantLock lock = this.lock; + lock.lock(); + try { + while (!linkLast(e)) + notFull.await(); + } finally { + lock.unlock(); + } + } + + /** + * @throws NullPointerException {@inheritDoc} + * @throws InterruptedException {@inheritDoc} + */ + public boolean offerFirst(E e, long timeout, TimeUnit unit) + throws InterruptedException { + if (e == null) throw new NullPointerException(); + long nanos = unit.toNanos(timeout); + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + while (!linkFirst(e)) { + if (nanos <= 0) + return false; + nanos = notFull.awaitNanos(nanos); + } + return true; + } finally { + lock.unlock(); + } + } + + /** + * @throws NullPointerException {@inheritDoc} + * @throws InterruptedException {@inheritDoc} + */ + public boolean offerLast(E e, long timeout, TimeUnit unit) + throws InterruptedException { + if (e == null) throw new NullPointerException(); + long nanos = unit.toNanos(timeout); + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + while (!linkLast(e)) { + if (nanos <= 0) + return false; + nanos = notFull.awaitNanos(nanos); + } + return true; + } finally { + lock.unlock(); + } + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E removeFirst() { + E x = pollFirst(); + if (x == null) throw new NoSuchElementException(); + return x; + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E removeLast() { + E x = pollLast(); + if (x == null) throw new NoSuchElementException(); + return x; + } + + public E pollFirst() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return unlinkFirst(); + } finally { + lock.unlock(); + } + } + + public E pollLast() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return unlinkLast(); + } finally { + lock.unlock(); + } + } + + public E takeFirst() throws InterruptedException { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + E x; + while ( (x = unlinkFirst()) == null) + notEmpty.await(); + return x; + } finally { + lock.unlock(); + } + } + + public E takeLast() throws InterruptedException { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + E x; + while ( (x = unlinkLast()) == null) + notEmpty.await(); + return x; + } finally { + lock.unlock(); + } + } + + public E pollFirst(long timeout, TimeUnit unit) + throws InterruptedException { + long nanos = unit.toNanos(timeout); + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + E x; + while ( (x = unlinkFirst()) == null) { + if (nanos <= 0) + return null; + nanos = notEmpty.awaitNanos(nanos); + } + return x; + } finally { + lock.unlock(); + } + } + + public E pollLast(long timeout, TimeUnit unit) + throws InterruptedException { + long nanos = unit.toNanos(timeout); + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + E x; + while ( (x = unlinkLast()) == null) { + if (nanos <= 0) + return null; + nanos = notEmpty.awaitNanos(nanos); + } + return x; + } finally { + lock.unlock(); + } + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E getFirst() { + E x = peekFirst(); + if (x == null) throw new NoSuchElementException(); + return x; + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E getLast() { + E x = peekLast(); + if (x == null) throw new NoSuchElementException(); + return x; + } + + public E peekFirst() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return (first == null) ? null : first.item; + } finally { + lock.unlock(); + } + } + + public E peekLast() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return (last == null) ? null : last.item; + } finally { + lock.unlock(); + } + } + + public boolean removeFirstOccurrence(Object o) { + if (o == null) return false; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + for (Node<E> p = first; p != null; p = p.next) { + if (o.equals(p.item)) { + unlink(p); + return true; + } + } + return false; + } finally { + lock.unlock(); + } + } + + public boolean removeLastOccurrence(Object o) { + if (o == null) return false; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + for (Node<E> p = last; p != null; p = p.prev) { + if (o.equals(p.item)) { + unlink(p); + return true; + } + } + return false; + } finally { + lock.unlock(); + } + } + + // BlockingQueue methods + + /** + * Inserts the specified element at the end of this deque unless it would + * violate capacity restrictions. When using a capacity-restricted deque, + * it is generally preferable to use method {@link #offer(Object) offer}. + * + * <p>This method is equivalent to {@link #addLast}. + * + * @throws IllegalStateException if the element cannot be added at this + * time due to capacity restrictions + * @throws NullPointerException if the specified element is null + */ + public boolean add(E e) { + addLast(e); + return true; + } + + /** + * @throws NullPointerException if the specified element is null + */ + public boolean offer(E e) { + return offerLast(e); + } + + /** + * @throws NullPointerException {@inheritDoc} + * @throws InterruptedException {@inheritDoc} + */ + public void put(E e) throws InterruptedException { + putLast(e); + } + + /** + * @throws NullPointerException {@inheritDoc} + * @throws InterruptedException {@inheritDoc} + */ + public boolean offer(E e, long timeout, TimeUnit unit) + throws InterruptedException { + return offerLast(e, timeout, unit); + } + + /** + * Retrieves and removes the head of the queue represented by this deque. + * This method differs from {@link #poll poll} only in that it throws an + * exception if this deque is empty. + * + * <p>This method is equivalent to {@link #removeFirst() removeFirst}. + * + * @return the head of the queue represented by this deque + * @throws NoSuchElementException if this deque is empty + */ + public E remove() { + return removeFirst(); + } + + public E poll() { + return pollFirst(); + } + + public E take() throws InterruptedException { + return takeFirst(); + } + + public E poll(long timeout, TimeUnit unit) throws InterruptedException { + return pollFirst(timeout, unit); + } + + /** + * Retrieves, but does not remove, the head of the queue represented by + * this deque. This method differs from {@link #peek peek} only in that + * it throws an exception if this deque is empty. + * + * <p>This method is equivalent to {@link #getFirst() getFirst}. + * + * @return the head of the queue represented by this deque + * @throws NoSuchElementException if this deque is empty + */ + public E element() { + return getFirst(); + } + + public E peek() { + return peekFirst(); + } + + /** + * Returns the number of additional elements that this deque can ideally + * (in the absence of memory or resource constraints) accept without + * blocking. This is always equal to the initial capacity of this deque + * less the current {@code size} of this deque. + * + * <p>Note that you <em>cannot</em> always tell if an attempt to insert + * 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. + */ + public int remainingCapacity() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return capacity - count; + } finally { + lock.unlock(); + } + } + + /** + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public int drainTo(Collection<? super E> c) { + return drainTo(c, Integer.MAX_VALUE); + } + + /** + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public int drainTo(Collection<? super E> c, int maxElements) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + final ReentrantLock lock = this.lock; + lock.lock(); + try { + int n = Math.min(maxElements, count); + for (int i = 0; i < n; i++) { + c.add(first.item); // In this order, in case add() throws. + unlinkFirst(); + } + return n; + } finally { + lock.unlock(); + } + } + + // Stack methods + + /** + * @throws IllegalStateException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public void push(E e) { + addFirst(e); + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E pop() { + return removeFirst(); + } + + // Collection methods + + /** + * Removes the first occurrence of the specified element from this deque. + * If the deque does not contain the element, it is unchanged. + * More formally, removes the first element {@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 {@code true} if this deque changed as a result of the call + */ + public boolean remove(Object o) { + return removeFirstOccurrence(o); + } + + /** + * Returns the number of elements in this deque. + * + * @return the number of elements in this deque + */ + public int size() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return count; + } finally { + lock.unlock(); + } + } + + /** + * 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 {@code true} if this deque contains the specified element + */ + public boolean contains(Object o) { + if (o == null) return false; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + for (Node<E> p = first; p != null; p = p.next) + if (o.equals(p.item)) + return true; + return false; + } finally { + lock.unlock(); + } + } + + /* + * TODO: Add support for more efficient bulk operations. + * + * We don't want to acquire the lock for every iteration, but we + * also want other threads a chance to interact with the + * collection, especially when count is close to capacity. + */ + +// /** +// * Adds all of the elements in the specified collection to this +// * queue. Attempts to addAll of a queue to itself result in +// * {@code IllegalArgumentException}. Further, 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 queue +// * @return {@code true} if this queue changed as a result of the call +// * @throws ClassCastException {@inheritDoc} +// * @throws NullPointerException {@inheritDoc} +// * @throws IllegalArgumentException {@inheritDoc} +// * @throws IllegalStateException {@inheritDoc} +// * @see #add(Object) +// */ +// public boolean addAll(Collection<? extends E> c) { +// if (c == null) +// throw new NullPointerException(); +// if (c == this) +// throw new IllegalArgumentException(); +// final ReentrantLock lock = this.lock; +// lock.lock(); +// try { +// boolean modified = false; +// for (E e : c) +// if (linkLast(e)) +// modified = true; +// return modified; +// } finally { +// lock.unlock(); +// } +// } + + /** + * Returns an array containing all of the elements in this deque, in + * proper sequence (from first to last element). + * + * <p>The returned array will be "safe" in that no references to it are + * maintained by this deque. (In other words, this method must allocate + * a new array). The caller is thus free to modify the returned array. + * + * <p>This method acts as bridge between array-based and collection-based + * APIs. + * + * @return an array containing all of the elements in this deque + */ + @SuppressWarnings("unchecked") + public Object[] toArray() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + Object[] a = new Object[count]; + int k = 0; + for (Node<E> p = first; p != null; p = p.next) + a[k++] = p.item; + return a; + } finally { + lock.unlock(); + } + } + + /** + * Returns an array containing all of the elements in this deque, in + * proper sequence; the runtime type of the returned array is that of + * the specified array. If the deque fits in the specified array, it + * is returned therein. Otherwise, a new array is allocated with the + * runtime type of the specified array and the size of this deque. + * + * <p>If this deque fits in the specified array with room to spare + * (i.e., the array has more elements than this deque), the element in + * the array immediately following the end of the deque is set to + * {@code null}. + * + * <p>Like the {@link #toArray()} method, this method acts as bridge between + * array-based and collection-based APIs. Further, this method allows + * precise control over the runtime type of the output array, and may, + * under certain circumstances, be used to save allocation costs. + * + * <p>Suppose {@code x} is a deque known to contain only strings. + * The following code can be used to dump the deque into a newly + * allocated array of {@code String}: + * + * <pre> + * String[] y = x.toArray(new String[0]);</pre> + * + * Note that {@code toArray(new Object[0])} is identical in function to + * {@code toArray()}. + * + * @param a the array into which the elements of the deque are to + * be stored, if it is big enough; otherwise, a new array of the + * same runtime type is allocated for this purpose + * @return an array containing all of the elements in this deque + * @throws ArrayStoreException if the runtime type of the specified array + * is not a supertype of the runtime type of every element in + * this deque + * @throws NullPointerException if the specified array is null + */ + @SuppressWarnings("unchecked") + public <T> T[] toArray(T[] a) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + if (a.length < count) + a = (T[])java.lang.reflect.Array.newInstance + (a.getClass().getComponentType(), count); + + int k = 0; + for (Node<E> p = first; p != null; p = p.next) + a[k++] = (T)p.item; + if (a.length > k) + a[k] = null; + return a; + } finally { + lock.unlock(); + } + } + + public String toString() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return super.toString(); + } finally { + lock.unlock(); + } + } + + /** + * Atomically removes all of the elements from this deque. + * The deque will be empty after this call returns. + */ + public void clear() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + for (Node<E> f = first; f != null; ) { + f.item = null; + Node<E> n = f.next; + f.prev = null; + f.next = null; + f = n; + } + first = last = null; + count = 0; + notFull.signalAll(); + } finally { + lock.unlock(); + } + } + + /** + * Returns an iterator over the elements in this deque in proper sequence. + * The elements will be returned in order from first (head) to last (tail). + * The returned {@code Iterator} is a "weakly consistent" iterator that + * will never throw {@link java.util.ConcurrentModificationException + * ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + * + * @return an iterator over the elements in this deque in proper sequence + */ + public Iterator<E> iterator() { + return new Itr(); + } + + /** + * Returns an iterator over the elements in this deque in reverse + * sequential order. The elements will be returned in order from + * last (tail) to first (head). + * The returned {@code Iterator} is a "weakly consistent" iterator that + * will never throw {@link java.util.ConcurrentModificationException + * ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + */ + public Iterator<E> descendingIterator() { + return new DescendingItr(); + } + + /** + * Base class for Iterators for LinkedBlockingDeque + */ + private abstract class AbstractItr implements Iterator<E> { + /** + * The next node to return in next() + */ + Node<E> next; + + /** + * nextItem holds on to item fields because once we claim that + * an element exists in hasNext(), we must return item read + * under lock (in advance()) even if it was in the process of + * being removed when hasNext() was called. + */ + E nextItem; + + /** + * Node returned by most recent call to next. Needed by remove. + * Reset to null if this element is deleted by a call to remove. + */ + private Node<E> lastRet; + + abstract Node<E> firstNode(); + abstract Node<E> nextNode(Node<E> n); + + AbstractItr() { + // set to initial position + final ReentrantLock lock = LinkedBlockingDeque.this.lock; + lock.lock(); + try { + next = firstNode(); + nextItem = (next == null) ? null : next.item; + } finally { + lock.unlock(); + } + } + + /** + * Advances next. + */ + void advance() { + final ReentrantLock lock = LinkedBlockingDeque.this.lock; + lock.lock(); + try { + // assert next != null; + Node<E> s = nextNode(next); + if (s == next) { + next = firstNode(); + } else { + // Skip over removed nodes. + // May be necessary if multiple interior Nodes are removed. + while (s != null && s.item == null) + s = nextNode(s); + next = s; + } + nextItem = (next == null) ? null : next.item; + } finally { + lock.unlock(); + } + } + + public boolean hasNext() { + return next != null; + } + + public E next() { + if (next == null) + throw new NoSuchElementException(); + lastRet = next; + E x = nextItem; + advance(); + return x; + } + + public void remove() { + Node<E> n = lastRet; + if (n == null) + throw new IllegalStateException(); + lastRet = null; + final ReentrantLock lock = LinkedBlockingDeque.this.lock; + lock.lock(); + try { + if (n.item != null) + unlink(n); + } finally { + lock.unlock(); + } + } + } + + /** Forward iterator */ + private class Itr extends AbstractItr { + Node<E> firstNode() { return first; } + Node<E> nextNode(Node<E> n) { return n.next; } + } + + /** Descending iterator */ + private class DescendingItr extends AbstractItr { + Node<E> firstNode() { return last; } + Node<E> nextNode(Node<E> n) { return n.prev; } + } + + /** + * Save the state of this deque to a stream (that is, serialize it). + * + * @serialData The capacity (int), followed by elements (each an + * {@code Object}) in the proper order, followed by a null + * @param s the stream + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + // Write out capacity and any hidden stuff + s.defaultWriteObject(); + // Write out all elements in the proper order. + for (Node<E> p = first; p != null; p = p.next) + s.writeObject(p.item); + // Use trailing null as sentinel + s.writeObject(null); + } finally { + lock.unlock(); + } + } + + /** + * Reconstitute this deque from a stream (that is, + * deserialize it). + * @param s the stream + */ + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + count = 0; + first = null; + last = null; + // Read in all elements and place in queue + for (;;) { + @SuppressWarnings("unchecked") + E item = (E)s.readObject(); + if (item == null) + break; + add(item); + } + } + +} diff --git a/concurrent/src/main/java/java/util/concurrent/LinkedBlockingQueue.java b/concurrent/src/main/java/java/util/concurrent/LinkedBlockingQueue.java index e06f7bd..1a8e412 100644 --- a/concurrent/src/main/java/java/util/concurrent/LinkedBlockingQueue.java +++ b/concurrent/src/main/java/java/util/concurrent/LinkedBlockingQueue.java @@ -5,14 +5,19 @@ */ package java.util.concurrent; -import java.util.concurrent.atomic.*; -import java.util.concurrent.locks.*; -import java.util.*; // BEGIN android-note // removed link to collections framework docs // END android-note +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; +import java.util.AbstractQueue; +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; + /** * An optionally-bounded {@linkplain BlockingQueue blocking queue} based on * linked nodes. @@ -57,15 +62,43 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E> * items have been entered since the signal. And symmetrically for * takes signalling puts. Operations such as remove(Object) and * iterators acquire both locks. + * + * Visibility between writers and readers is provided as follows: + * + * Whenever an element is enqueued, the putLock is acquired and + * count updated. A subsequent reader guarantees visibility to the + * enqueued Node by either acquiring the putLock (via fullyLock) + * or by acquiring the takeLock, and then reading n = count.get(); + * this gives visibility to the first n items. + * + * To implement weakly consistent iterators, it appears we need to + * keep all Nodes GC-reachable from a predecessor dequeued Node. + * That would cause two problems: + * - allow a rogue Iterator to cause unbounded memory retention + * - cause cross-generational linking of old Nodes to new Nodes if + * a Node was tenured while live, which generational GCs have a + * hard time dealing with, causing repeated major collections. + * However, only non-deleted Nodes need to be reachable from + * dequeued Nodes, and reachability does not necessarily have to + * be of the kind understood by the GC. We use the trick of + * linking a Node that has just been dequeued to itself. Such a + * self-link implicitly means to advance to head.next. */ /** * Linked list node class */ static class Node<E> { - /** The item, volatile to ensure barrier separating write and read */ - volatile E item; + E item; + + /** + * One of: + * - the real successor Node + * - this Node, meaning the successor is head.next + * - null, meaning there is no successor (this is the last node) + */ Node<E> next; + Node(E x) { item = x; } } @@ -75,10 +108,16 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E> /** Current number of elements */ private final AtomicInteger count = new AtomicInteger(0); - /** Head of linked list */ + /** + * Head of linked list. + * Invariant: head.item == null + */ private transient Node<E> head; - /** Tail of linked list */ + /** + * Tail of linked list. + * Invariant: last.next == null + */ private transient Node<E> last; /** Lock held by take, poll, etc */ @@ -122,20 +161,26 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E> /** * Creates a node and links it at end of queue. + * * @param x the item */ - private void insert(E x) { + private void enqueue(E x) { + // assert putLock.isHeldByCurrentThread(); + // assert last.next == null; last = last.next = new Node<E>(x); } /** - * Removes a node from head of queue, + * Removes a node from head of queue. + * * @return the node */ - private E extract() { + private E dequeue() { + // assert takeLock.isHeldByCurrentThread(); + // assert head.item == null; Node<E> h = head; Node<E> first = h.next; - h.next = null; // help GC + h.next = h; // help GC head = first; E x = first.item; first.item = null; @@ -145,7 +190,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E> /** * Lock to prevent both puts and takes. */ - private void fullyLock() { + void fullyLock() { putLock.lock(); takeLock.lock(); } @@ -153,14 +198,21 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E> /** * Unlock to allow both puts and takes. */ - private void fullyUnlock() { + void fullyUnlock() { takeLock.unlock(); putLock.unlock(); } +// /** +// * Tells whether both locks are held by current thread. +// */ +// boolean isFullyLocked() { +// return (putLock.isHeldByCurrentThread() && +// takeLock.isHeldByCurrentThread()); +// } /** - * Creates a <tt>LinkedBlockingQueue</tt> with a capacity of + * Creates a {@code LinkedBlockingQueue} with a capacity of * {@link Integer#MAX_VALUE}. */ public LinkedBlockingQueue() { @@ -168,10 +220,10 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E> } /** - * Creates a <tt>LinkedBlockingQueue</tt> with the given (fixed) capacity. + * Creates a {@code LinkedBlockingQueue} with the given (fixed) capacity. * * @param capacity the capacity of this queue - * @throws IllegalArgumentException if <tt>capacity</tt> is not greater + * @throws IllegalArgumentException if {@code capacity} is not greater * than zero */ public LinkedBlockingQueue(int capacity) { @@ -181,7 +233,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E> } /** - * Creates a <tt>LinkedBlockingQueue</tt> with a capacity of + * Creates a {@code LinkedBlockingQueue} with a capacity of * {@link Integer#MAX_VALUE}, initially containing the elements of the * given collection, * added in traversal order of the collection's iterator. @@ -192,8 +244,22 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E> */ public LinkedBlockingQueue(Collection<? extends E> c) { this(Integer.MAX_VALUE); - for (E e : c) - add(e); + final ReentrantLock putLock = this.putLock; + putLock.lock(); // Never contended, but necessary for visibility + try { + int n = 0; + for (E e : c) { + if (e == null) + throw new NullPointerException(); + if (n == capacity) + throw new IllegalStateException("Queue full"); + enqueue(e); + ++n; + } + count.set(n); + } finally { + putLock.unlock(); + } } @@ -214,10 +280,10 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E> * Returns the number of additional elements that this queue can ideally * (in the absence of memory or resource constraints) accept without * blocking. This is always equal to the initial capacity of this queue - * less the current <tt>size</tt> of this queue. + * less the current {@code size} of this queue. * * <p>Note that you <em>cannot</em> always tell if an attempt to insert - * an element will succeed by inspecting <tt>remainingCapacity</tt> + * 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. */ @@ -234,8 +300,8 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E> */ public void put(E e) throws InterruptedException { if (e == null) throw new NullPointerException(); - // Note: convention in all put/take/etc is to preset - // local var holding count negative to indicate failure unless set. + // Note: convention in all put/take/etc is to preset local var + // holding count negative to indicate failure unless set. int c = -1; final ReentrantLock putLock = this.putLock; final AtomicInteger count = this.count; @@ -246,18 +312,13 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E> * not protected by lock. This works because count can * only decrease at this point (all other puts are shut * out by lock), and we (or some other waiting put) are - * signalled if it ever changes from - * capacity. Similarly for all other uses of count in - * other wait guards. + * signalled if it ever changes from capacity. Similarly + * for all other uses of count in other wait guards. */ - try { - while (count.get() == capacity) - notFull.await(); - } catch (InterruptedException ie) { - notFull.signal(); // propagate to a non-interrupted thread - throw ie; + while (count.get() == capacity) { + notFull.await(); } - insert(e); + enqueue(e); c = count.getAndIncrement(); if (c + 1 < capacity) notFull.signal(); @@ -272,7 +333,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E> * Inserts the specified element at the tail of this queue, waiting if * necessary up to the specified wait time for space to become available. * - * @return <tt>true</tt> if successful, or <tt>false</tt> if + * @return {@code true} if successful, or {@code false} if * the specified waiting time elapses before space is available. * @throws InterruptedException {@inheritDoc} * @throws NullPointerException {@inheritDoc} @@ -287,23 +348,15 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E> final AtomicInteger count = this.count; putLock.lockInterruptibly(); try { - for (;;) { - if (count.get() < capacity) { - insert(e); - c = count.getAndIncrement(); - if (c + 1 < capacity) - notFull.signal(); - break; - } + while (count.get() == capacity) { if (nanos <= 0) return false; - try { - nanos = notFull.awaitNanos(nanos); - } catch (InterruptedException ie) { - notFull.signal(); // propagate to a non-interrupted thread - throw ie; - } + nanos = notFull.awaitNanos(nanos); } + enqueue(e); + c = count.getAndIncrement(); + if (c + 1 < capacity) + notFull.signal(); } finally { putLock.unlock(); } @@ -315,7 +368,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E> /** * Inserts the specified element at the tail of this queue if it is * possible to do so immediately without exceeding the queue's capacity, - * returning <tt>true</tt> upon success and <tt>false</tt> if this queue + * returning {@code true} upon success and {@code false} if this queue * is full. * When using a capacity-restricted queue, this method is generally * preferable to method {@link BlockingQueue#add add}, which can fail to @@ -333,7 +386,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E> putLock.lock(); try { if (count.get() < capacity) { - insert(e); + enqueue(e); c = count.getAndIncrement(); if (c + 1 < capacity) notFull.signal(); @@ -354,15 +407,10 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E> final ReentrantLock takeLock = this.takeLock; takeLock.lockInterruptibly(); try { - try { - while (count.get() == 0) - notEmpty.await(); - } catch (InterruptedException ie) { - notEmpty.signal(); // propagate to a non-interrupted thread - throw ie; + while (count.get() == 0) { + notEmpty.await(); } - - x = extract(); + x = dequeue(); c = count.getAndDecrement(); if (c > 1) notEmpty.signal(); @@ -382,23 +430,15 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E> final ReentrantLock takeLock = this.takeLock; takeLock.lockInterruptibly(); try { - for (;;) { - if (count.get() > 0) { - x = extract(); - c = count.getAndDecrement(); - if (c > 1) - notEmpty.signal(); - break; - } + while (count.get() == 0) { if (nanos <= 0) return null; - try { - nanos = notEmpty.awaitNanos(nanos); - } catch (InterruptedException ie) { - notEmpty.signal(); // propagate to a non-interrupted thread - throw ie; - } + nanos = notEmpty.awaitNanos(nanos); } + x = dequeue(); + c = count.getAndDecrement(); + if (c > 1) + notEmpty.signal(); } finally { takeLock.unlock(); } @@ -417,7 +457,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E> takeLock.lock(); try { if (count.get() > 0) { - x = extract(); + x = dequeue(); c = count.getAndDecrement(); if (c > 1) notEmpty.signal(); @@ -430,7 +470,6 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E> return x; } - public E peek() { if (count.get() == 0) return null; @@ -448,43 +487,47 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E> } /** + * Unlinks interior Node p with predecessor trail. + */ + void unlink(Node<E> p, Node<E> trail) { + // assert isFullyLocked(); + // p.next is not changed, to allow iterators that are + // traversing p to maintain their weak-consistency guarantee. + p.item = null; + trail.next = p.next; + if (last == p) + last = trail; + if (count.getAndDecrement() == capacity) + notFull.signal(); + } + + /** * 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 */ public boolean remove(Object o) { if (o == null) return false; - boolean removed = false; fullyLock(); try { - Node<E> trail = head; - Node<E> p = head.next; - while (p != null) { + for (Node<E> trail = head, p = trail.next; + p != null; + trail = p, p = p.next) { if (o.equals(p.item)) { - removed = true; - break; + unlink(p, trail); + return true; } - trail = p; - p = p.next; - } - if (removed) { - p.item = null; - trail.next = p.next; - if (last == p) - last = trail; - if (count.getAndDecrement() == capacity) - notFull.signalAll(); } + return false; } finally { fullyUnlock(); } - return removed; } /** @@ -524,22 +567,22 @@ public class LinkedBlockingQueue<E> 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 * precise control over the runtime type of the output array, and may, * under certain circumstances, be used to save allocation costs. * - * <p>Suppose <tt>x</tt> is a queue known to contain only strings. + * <p>Suppose {@code x} is a queue known to contain only strings. * The following code can be used to dump the queue into a newly - * allocated array of <tt>String</tt>: + * allocated array of {@code String}: * * <pre> * String[] y = x.toArray(new String[0]);</pre> * - * Note that <tt>toArray(new Object[0])</tt> is identical in function to - * <tt>toArray()</tt>. + * 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 @@ -550,6 +593,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E> * this queue * @throws NullPointerException if the specified array is null */ + @SuppressWarnings("unchecked") public <T> T[] toArray(T[] a) { fullyLock(); try { @@ -559,7 +603,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E> (a.getClass().getComponentType(), size); int k = 0; - for (Node p = head.next; p != null; p = p.next) + for (Node<E> p = head.next; p != null; p = p.next) a[k++] = (T)p.item; if (a.length > k) a[k] = null; @@ -585,11 +629,14 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E> public void clear() { fullyLock(); try { - head.next = null; - assert head.item == null; - last = head; + for (Node<E> p, h = head; (p = h.next) != null; h = p) { + h.next = h; + p.item = null; + } + head = last; + // assert head.item == null && head.next == null; if (count.getAndSet(0) == capacity) - notFull.signalAll(); + notFull.signal(); } finally { fullyUnlock(); } @@ -602,30 +649,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E> * @throws IllegalArgumentException {@inheritDoc} */ public int drainTo(Collection<? super E> c) { - if (c == null) - throw new NullPointerException(); - if (c == this) - throw new IllegalArgumentException(); - Node<E> first; - fullyLock(); - try { - first = head.next; - head.next = null; - assert head.item == null; - last = head; - if (count.getAndSet(0) == capacity) - notFull.signalAll(); - } finally { - fullyUnlock(); - } - // Transfer the elements outside of locks - int n = 0; - for (Node<E> p = first; p != null; p = p.next) { - c.add(p.item); - p.item = null; - ++n; - } - return n; + return drainTo(c, Integer.MAX_VALUE); } /** @@ -639,34 +663,44 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E> throw new NullPointerException(); if (c == this) throw new IllegalArgumentException(); - fullyLock(); + boolean signalNotFull = false; + final ReentrantLock takeLock = this.takeLock; + takeLock.lock(); try { - int n = 0; - Node<E> p = head.next; - while (p != null && n < maxElements) { - c.add(p.item); - p.item = null; - p = p.next; - ++n; - } - if (n != 0) { - head.next = p; - assert head.item == null; - if (p == null) - last = head; - if (count.getAndAdd(-n) == capacity) - notFull.signalAll(); + int n = Math.min(maxElements, count.get()); + // count.get provides visibility to first n Nodes + Node<E> h = head; + int i = 0; + try { + while (i < n) { + Node<E> p = h.next; + c.add(p.item); + p.item = null; + h.next = h; + h = p; + ++i; + } + return n; + } finally { + // Restore invariants even if c.add() threw + if (i > 0) { + // assert h.item == null; + head = h; + signalNotFull = (count.getAndAdd(-i) == capacity); + } } - return n; } finally { - fullyUnlock(); + takeLock.unlock(); + if (signalNotFull) + signalNotFull(); } } /** * Returns an iterator over the elements in this queue in proper sequence. - * The returned <tt>Iterator</tt> is a "weakly consistent" iterator that - * will never throw {@link ConcurrentModificationException}, + * The returned {@code Iterator} is a "weakly consistent" iterator that + * will never throw {@link java.util.ConcurrentModificationException + * ConcurrentModificationException}, * and guarantees to traverse elements as they existed upon * construction of the iterator, and may (but is not guaranteed to) * reflect any modifications subsequent to construction. @@ -679,7 +713,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E> private class Itr implements Iterator<E> { /* - * Basic weak-consistent iterator. At all times hold the next + * Basic weakly-consistent iterator. At all times hold the next * item to hand out so that if hasNext() reports true, we will * still have it to return even if lost race with a take etc. */ @@ -688,17 +722,13 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E> private E currentElement; Itr() { - final ReentrantLock putLock = LinkedBlockingQueue.this.putLock; - final ReentrantLock takeLock = LinkedBlockingQueue.this.takeLock; - putLock.lock(); - takeLock.lock(); + fullyLock(); try { current = head.next; if (current != null) currentElement = current.item; } finally { - takeLock.unlock(); - putLock.unlock(); + fullyUnlock(); } } @@ -706,54 +736,56 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E> return current != null; } + /** + * Returns the next live successor of p, or null if no such. + * + * Unlike other traversal methods, iterators need to handle both: + * - dequeued nodes (p.next == p) + * - (possibly multiple) interior removed nodes (p.item == null) + */ + private Node<E> nextNode(Node<E> p) { + for (;;) { + Node<E> s = p.next; + if (s == p) + return head.next; + if (s == null || s.item != null) + return s; + p = s; + } + } + public E next() { - final ReentrantLock putLock = LinkedBlockingQueue.this.putLock; - final ReentrantLock takeLock = LinkedBlockingQueue.this.takeLock; - putLock.lock(); - takeLock.lock(); + fullyLock(); try { if (current == null) throw new NoSuchElementException(); E x = currentElement; lastRet = current; - current = current.next; - if (current != null) - currentElement = current.item; + current = nextNode(current); + currentElement = (current == null) ? null : current.item; return x; } finally { - takeLock.unlock(); - putLock.unlock(); + fullyUnlock(); } } public void remove() { if (lastRet == null) throw new IllegalStateException(); - final ReentrantLock putLock = LinkedBlockingQueue.this.putLock; - final ReentrantLock takeLock = LinkedBlockingQueue.this.takeLock; - putLock.lock(); - takeLock.lock(); + fullyLock(); try { Node<E> node = lastRet; lastRet = null; - Node<E> trail = head; - Node<E> p = head.next; - while (p != null && p != node) { - trail = p; - p = p.next; - } - if (p == node) { - p.item = null; - trail.next = p.next; - if (last == p) - last = trail; - int c = count.getAndDecrement(); - if (c == capacity) - notFull.signalAll(); + for (Node<E> trail = head, p = trail.next; + p != null; + trail = p, p = p.next) { + if (p == node) { + unlink(p, trail); + break; + } } } finally { - takeLock.unlock(); - putLock.unlock(); + fullyUnlock(); } } } @@ -762,7 +794,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E> * Save the state to a stream (that is, serialize it). * * @serialData The capacity is emitted (int), followed by all of - * its elements (each an <tt>Object</tt>) in the proper order, + * its elements (each an {@code Object}) in the proper order, * followed by a null * @param s the stream */ @@ -788,6 +820,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E> /** * Reconstitute this queue instance from a stream (that is, * deserialize it). + * * @param s the stream */ private void readObject(java.io.ObjectInputStream s) @@ -800,6 +833,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E> // Read in all elements and place in queue for (;;) { + @SuppressWarnings("unchecked") E item = (E)s.readObject(); if (item == null) break; diff --git a/concurrent/src/main/java/java/util/concurrent/PriorityBlockingQueue.java b/concurrent/src/main/java/java/util/concurrent/PriorityBlockingQueue.java index 7a33dc7..35d7b89 100644 --- a/concurrent/src/main/java/java/util/concurrent/PriorityBlockingQueue.java +++ b/concurrent/src/main/java/java/util/concurrent/PriorityBlockingQueue.java @@ -146,7 +146,6 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E> return offer(e); } - // BEGIN android-changed /** * Inserts the specified element into this priority queue. * diff --git a/concurrent/src/main/java/java/util/concurrent/RunnableFuture.java b/concurrent/src/main/java/java/util/concurrent/RunnableFuture.java new file mode 100644 index 0000000..d74211d --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/RunnableFuture.java @@ -0,0 +1,25 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package java.util.concurrent; + +/** + * A {@link Future} that is {@link Runnable}. Successful execution of + * the <tt>run</tt> method causes completion of the <tt>Future</tt> + * and allows access to its results. + * @see FutureTask + * @see Executor + * @since 1.6 + * @author Doug Lea + * @param <V> The result type returned by this Future's <tt>get</tt> method + */ +public interface RunnableFuture<V> extends Runnable, Future<V> { + /** + * Sets this Future to the result of its computation + * unless it has been cancelled. + */ + void run(); +} diff --git a/concurrent/src/main/java/java/util/concurrent/RunnableScheduledFuture.java b/concurrent/src/main/java/java/util/concurrent/RunnableScheduledFuture.java new file mode 100644 index 0000000..0e8cc32 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/RunnableScheduledFuture.java @@ -0,0 +1,29 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package java.util.concurrent; + +/** + * A {@link ScheduledFuture} that is {@link Runnable}. Successful + * execution of the <tt>run</tt> method causes completion of the + * <tt>Future</tt> and allows access to its results. + * @see FutureTask + * @see Executor + * @since 1.6 + * @author Doug Lea + * @param <V> The result type returned by this Future's <tt>get</tt> method + */ +public interface RunnableScheduledFuture<V> extends RunnableFuture<V>, ScheduledFuture<V> { + + /** + * Returns true if this is a periodic task. A periodic task may + * re-run according to some schedule. A non-periodic task can be + * run only once. + * + * @return true if this task is periodic + */ + boolean isPeriodic(); +} diff --git a/concurrent/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java b/concurrent/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java index 83ffb99..7e69936 100644 --- a/concurrent/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java +++ b/concurrent/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java @@ -4,10 +4,6 @@ * http://creativecommons.org/licenses/publicdomain */ -/* - * Modified in Apache Harmony. - */ - package java.util.concurrent; import java.util.concurrent.atomic.*; import java.util.concurrent.locks.*; @@ -27,6 +23,15 @@ import java.util.*; * execution time are enabled in first-in-first-out (FIFO) order of * submission. * + * <p>When a submitted task is cancelled before it is run, execution + * is suppressed. By default, such a cancelled task is not + * automatically removed from the work queue until its delay + * elapses. While this enables further inspection and monitoring, it + * may also cause unbounded retention of cancelled tasks. To avoid + * this, set {@link #setRemoveOnCancelPolicy} to {@code true}, which + * causes tasks to be immediately removed from the work queue at + * time of cancellation. + * * <p>Successive executions of a task scheduled via * <code>scheduleAtFixedRate</code> or * <code>scheduleWithFixedDelay</code> do not overlap. While different @@ -37,9 +42,47 @@ import java.util.*; * * <p>While this class inherits from {@link ThreadPoolExecutor}, a few * of the inherited tuning methods are not useful for it. In - * particular, because it acts as a fixed-sized pool using {@code - * corePoolSize} threads and an unbounded queue, adjustments to {@code - * maximumPoolSize} have no useful effect. + * particular, because it acts as a fixed-sized pool using + * {@code corePoolSize} threads and an unbounded queue, adjustments + * to {@code maximumPoolSize} have no useful effect. Additionally, it + * is almost never a good idea to set {@code corePoolSize} to zero or + * use {@code allowCoreThreadTimeOut} because this may leave the pool + * without threads to handle tasks once they become eligible to run. + * + * <p><b>Extension notes:</b> This class overrides the + * {@link ThreadPoolExecutor#execute execute} and + * {@link AbstractExecutorService#submit(Runnable) submit} + * methods to generate internal {@link ScheduledFuture} objects to + * control per-task delays and scheduling. To preserve + * functionality, any further overrides of these methods in + * subclasses must invoke superclass versions, which effectively + * disables additional task customization. However, this class + * provides alternative protected extension method + * {@code decorateTask} (one version each for {@code Runnable} and + * {@code Callable}) that can be used to customize the concrete task + * types used to execute commands entered via {@code execute}, + * {@code submit}, {@code schedule}, {@code scheduleAtFixedRate}, + * and {@code scheduleWithFixedDelay}. By default, a + * {@code ScheduledThreadPoolExecutor} uses a task type extending + * {@link FutureTask}. However, this may be modified or replaced using + * subclasses of the form: + * + * <pre> {@code + * public class CustomScheduledExecutor extends ScheduledThreadPoolExecutor { + * + * static class CustomTask<V> implements RunnableScheduledFuture<V> { ... } + * + * protected <V> RunnableScheduledFuture<V> decorateTask( + * Runnable r, RunnableScheduledFuture<V> task) { + * return new CustomTask<V>(r, task); + * } + * + * protected <V> RunnableScheduledFuture<V> decorateTask( + * Callable<V> c, RunnableScheduledFuture<V> task) { + * return new CustomTask<V>(c, task); + * } + * // ... add constructors, etc. + * }}</pre> * * @since 1.5 * @author Doug Lea @@ -96,23 +139,15 @@ public class ScheduledThreadPoolExecutor */ private static final AtomicLong sequencer = new AtomicLong(0); - - /** - * Value of System.nanoTime upon static initialization. This is - * used as an offset by now() to avoid wraparound of time values - * that would make them appear negative. - */ - static final long initialNanoTime = System.nanoTime(); - /** * Returns current nanosecond time. */ - static long now() { - return System.nanoTime() - initialNanoTime; + final long now() { + return System.nanoTime(); } private class ScheduledFutureTask<V> - extends FutureTask<V> implements ScheduledFuture<V> { + extends FutureTask<V> implements RunnableScheduledFuture<V> { /** Sequence number to break ties FIFO */ private final long sequenceNumber; @@ -129,7 +164,7 @@ public class ScheduledThreadPoolExecutor private final long period; /** The actual task to be re-enqueued by reExecutePeriodic */ - ScheduledFutureTask<V> outerTask = this; + RunnableScheduledFuture<V> outerTask = this; /** * Index into delay queue, to support faster cancellation. @@ -167,8 +202,7 @@ public class ScheduledThreadPoolExecutor } public long getDelay(TimeUnit unit) { - long d = time - now(); - return d<=0? 0 : unit.convert(d, TimeUnit.NANOSECONDS); + return unit.convert(time - now(), TimeUnit.NANOSECONDS); } public int compareTo(Delayed other) { @@ -208,7 +242,7 @@ public class ScheduledThreadPoolExecutor if (p > 0) time += p; else - time = now() - p; + time = triggerTime(-p); } public boolean cancel(boolean mayInterruptIfRunning) { @@ -257,7 +291,7 @@ public class ScheduledThreadPoolExecutor * * @param task the task */ - private void delayedExecute(ScheduledFutureTask<?> task) { + private void delayedExecute(RunnableScheduledFuture<?> task) { if (isShutdown()) reject(task); else { @@ -277,7 +311,7 @@ public class ScheduledThreadPoolExecutor * * @param task the task */ - void reExecutePeriodic(ScheduledFutureTask<?> task) { + void reExecutePeriodic(RunnableScheduledFuture<?> task) { if (canRunInCurrentRunState(true)) { super.getQueue().add(task); if (!canRunInCurrentRunState(true) && remove(task)) @@ -302,9 +336,9 @@ public class ScheduledThreadPoolExecutor else { // Traverse snapshot to avoid iterator exceptions for (Object e : q.toArray()) { - if (e instanceof ScheduledFutureTask) { - ScheduledFutureTask<?> t = - (ScheduledFutureTask<?>)e; + if (e instanceof RunnableScheduledFuture) { + RunnableScheduledFuture<?> t = + (RunnableScheduledFuture<?>)e; if ((t.isPeriodic() ? !keepPeriodic : !keepDelayed) || t.isCancelled()) { // also remove if already cancelled if (q.remove(t)) @@ -317,11 +351,43 @@ public class ScheduledThreadPoolExecutor } /** + * Modifies or replaces the task used to execute a runnable. + * This method can be used to override the concrete + * class used for managing internal tasks. + * The default implementation simply returns the given task. + * + * @param runnable the submitted Runnable + * @param task the task created to execute the runnable + * @return a task that can execute the runnable + * @since 1.6 + */ + protected <V> RunnableScheduledFuture<V> decorateTask( + Runnable runnable, RunnableScheduledFuture<V> task) { + return task; + } + + /** + * Modifies or replaces the task used to execute a callable. + * This method can be used to override the concrete + * class used for managing internal tasks. + * The default implementation simply returns the given task. + * + * @param callable the submitted Callable + * @param task the task created to execute the callable + * @return a task that can execute the callable + * @since 1.6 + */ + protected <V> RunnableScheduledFuture<V> decorateTask( + Callable<V> callable, RunnableScheduledFuture<V> task) { + return task; + } + + /** * Creates a new {@code ScheduledThreadPoolExecutor} with the * given core pool size. * * @param corePoolSize the number of threads to keep in the pool, even - * if they are idle + * if they are idle, unless {@code allowCoreThreadTimeOut} is set * @throws IllegalArgumentException if {@code corePoolSize < 0} */ public ScheduledThreadPoolExecutor(int corePoolSize) { @@ -334,7 +400,7 @@ public class ScheduledThreadPoolExecutor * given initial parameters. * * @param corePoolSize the number of threads to keep in the pool, even - * if they are idle + * if they are idle, unless {@code allowCoreThreadTimeOut} is set * @param threadFactory the factory to use when the executor * creates a new thread * @throws IllegalArgumentException if {@code corePoolSize < 0} @@ -351,7 +417,7 @@ public class ScheduledThreadPoolExecutor * initial parameters. * * @param corePoolSize the number of threads to keep in the pool, even - * if they are idle + * if they are idle, unless {@code allowCoreThreadTimeOut} is set * @param handler the handler to use when execution is blocked * because the thread bounds and queue capacities are reached * @throws IllegalArgumentException if {@code corePoolSize < 0} @@ -368,7 +434,7 @@ public class ScheduledThreadPoolExecutor * initial parameters. * * @param corePoolSize the number of threads to keep in the pool, even - * if they are idle + * if they are idle, unless {@code allowCoreThreadTimeOut} is set * @param threadFactory the factory to use when the executor * creates a new thread * @param handler the handler to use when execution is blocked @@ -385,17 +451,35 @@ public class ScheduledThreadPoolExecutor } /** - * Returns the trigger time of a delayed action + * Returns the trigger time of a delayed action. */ - private static long nextTriggerTime(long delay, TimeUnit unit) { - long triggerTime; - long now = now(); - if (delay <= 0) - return now; // avoid negative trigger times - else if ((triggerTime = now + unit.toNanos(delay)) < 0) - return Long.MAX_VALUE; // avoid numerical overflow - else - return triggerTime; + private long triggerTime(long delay, TimeUnit unit) { + return triggerTime(unit.toNanos((delay < 0) ? 0 : delay)); + } + + /** + * Returns the trigger time of a delayed action. + */ + long triggerTime(long delay) { + return now() + + ((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay)); + } + + /** + * Constrains the values of all delays in the queue to be within + * Long.MAX_VALUE of each other, to avoid overflow in compareTo. + * This may occur if a task is eligible to be dequeued, but has + * not yet been, while some other task is added with a delay of + * Long.MAX_VALUE. + */ + private long overflowFree(long delay) { + Delayed head = (Delayed) super.getQueue().peek(); + if (head != null) { + long headDelay = head.getDelay(TimeUnit.NANOSECONDS); + if (headDelay < 0 && (delay - headDelay < 0)) + delay = Long.MAX_VALUE + headDelay; + } + return delay; } /** @@ -407,9 +491,9 @@ public class ScheduledThreadPoolExecutor TimeUnit unit) { if (command == null || unit == null) throw new NullPointerException(); - long triggerTime = nextTriggerTime(delay, unit); - ScheduledFutureTask<?> t - = new ScheduledFutureTask<Void>(command, null, triggerTime); + RunnableScheduledFuture<?> t = decorateTask(command, + new ScheduledFutureTask<Void>(command, null, + triggerTime(delay, unit))); delayedExecute(t); return t; } @@ -423,9 +507,9 @@ public class ScheduledThreadPoolExecutor TimeUnit unit) { if (callable == null || unit == null) throw new NullPointerException(); - long triggerTime = nextTriggerTime(delay, unit); - ScheduledFutureTask<V> t - = new ScheduledFutureTask<V>(callable, triggerTime); + RunnableScheduledFuture<V> t = decorateTask(callable, + new ScheduledFutureTask<V>(callable, + triggerTime(delay, unit))); delayedExecute(t); return t; } @@ -443,16 +527,15 @@ public class ScheduledThreadPoolExecutor throw new NullPointerException(); if (period <= 0) throw new IllegalArgumentException(); - if (initialDelay < 0) initialDelay = 0; - long triggerTime = nextTriggerTime(initialDelay, unit); ScheduledFutureTask<Void> sft = new ScheduledFutureTask<Void>(command, null, - triggerTime, + triggerTime(initialDelay, unit), unit.toNanos(period)); - sft.outerTask = sft; - delayedExecute(sft); - return sft; + RunnableScheduledFuture<Void> t = decorateTask(command, sft); + sft.outerTask = t; + delayedExecute(t); + return t; } /** @@ -468,15 +551,15 @@ public class ScheduledThreadPoolExecutor throw new NullPointerException(); if (delay <= 0) throw new IllegalArgumentException(); - long triggerTime = nextTriggerTime(initialDelay, unit); ScheduledFutureTask<Void> sft = new ScheduledFutureTask<Void>(command, null, - triggerTime, + triggerTime(initialDelay, unit), unit.toNanos(-delay)); - sft.outerTask = sft; - delayedExecute(sft); - return sft; + RunnableScheduledFuture<Void> t = decorateTask(command, sft); + sft.outerTask = t; + delayedExecute(t); + return t; } /** @@ -595,6 +678,33 @@ public class ScheduledThreadPoolExecutor } /** + * Sets the policy on whether cancelled tasks should be immediately + * removed from the work queue at time of cancellation. This value is + * by default {@code false}. + * + * @param value if {@code true}, remove on cancellation, else don't + * @see #getRemoveOnCancelPolicy + * @since 1.7 + */ + /*public*/ void setRemoveOnCancelPolicy(boolean value) { // android-changed + removeOnCancel = value; + } + + /** + * Gets the policy on whether cancelled tasks should be immediately + * removed from the work queue at time of cancellation. This value is + * by default {@code false}. + * + * @return {@code true} if cancelled tasks are immediately removed + * from the queue + * @see #setRemoveOnCancelPolicy + * @since 1.7 + */ + /*public*/ boolean getRemoveOnCancelPolicy() { // android-changed + return removeOnCancel; + } + + /** * Initiates an orderly shutdown in which previously submitted * tasks are executed, but no new tasks will be accepted. * Invocation has no additional effect if already shut down. @@ -688,8 +798,8 @@ public class ScheduledThreadPoolExecutor */ private static final int INITIAL_CAPACITY = 16; - private ScheduledFutureTask[] queue = - new ScheduledFutureTask[INITIAL_CAPACITY]; + private RunnableScheduledFuture[] queue = + new RunnableScheduledFuture[INITIAL_CAPACITY]; private final ReentrantLock lock = new ReentrantLock(); private int size = 0; @@ -720,7 +830,7 @@ public class ScheduledThreadPoolExecutor /** * Set f's heapIndex if it is a ScheduledFutureTask. */ - private void setIndex(ScheduledFutureTask f, int idx) { + private void setIndex(RunnableScheduledFuture f, int idx) { if (f instanceof ScheduledFutureTask) ((ScheduledFutureTask)f).heapIndex = idx; } @@ -729,10 +839,10 @@ public class ScheduledThreadPoolExecutor * Sift element added at bottom up to its heap-ordered spot. * Call only when holding lock. */ - private void siftUp(int k, ScheduledFutureTask key) { + private void siftUp(int k, RunnableScheduledFuture key) { while (k > 0) { int parent = (k - 1) >>> 1; - ScheduledFutureTask e = queue[parent]; + RunnableScheduledFuture e = queue[parent]; if (key.compareTo(e) >= 0) break; queue[k] = e; @@ -747,11 +857,11 @@ public class ScheduledThreadPoolExecutor * Sift element added at top down to its heap-ordered spot. * Call only when holding lock. */ - private void siftDown(int k, ScheduledFutureTask key) { + private void siftDown(int k, RunnableScheduledFuture key) { int half = size >>> 1; while (k < half) { int child = (k << 1) + 1; - ScheduledFutureTask c = queue[child]; + RunnableScheduledFuture c = queue[child]; int right = child + 1; if (right < size && c.compareTo(queue[right]) > 0) c = queue[child = right]; @@ -773,7 +883,7 @@ public class ScheduledThreadPoolExecutor int newCapacity = oldCapacity + (oldCapacity >> 1); // grow 50% if (newCapacity < 0) // overflow newCapacity = Integer.MAX_VALUE; - queue = Java6Arrays.copyOf(queue, newCapacity); + queue = Arrays.copyOf(queue, newCapacity); } /** @@ -816,7 +926,7 @@ public class ScheduledThreadPoolExecutor setIndex(queue[i], -1); int s = --size; - ScheduledFutureTask replacement = queue[s]; + RunnableScheduledFuture replacement = queue[s]; queue[s] = null; if (s != i) { siftDown(i, replacement); @@ -847,7 +957,7 @@ public class ScheduledThreadPoolExecutor return Integer.MAX_VALUE; } - public ScheduledFutureTask peek() { + public RunnableScheduledFuture peek() { final ReentrantLock lock = this.lock; lock.lock(); try { @@ -860,7 +970,7 @@ public class ScheduledThreadPoolExecutor public boolean offer(Runnable x) { if (x == null) throw new NullPointerException(); - ScheduledFutureTask e = (ScheduledFutureTask)x; + RunnableScheduledFuture e = (RunnableScheduledFuture)x; final ReentrantLock lock = this.lock; lock.lock(); try { @@ -902,9 +1012,9 @@ public class ScheduledThreadPoolExecutor * holding lock. * @param f the task to remove and return */ - private ScheduledFutureTask finishPoll(ScheduledFutureTask f) { + private RunnableScheduledFuture finishPoll(RunnableScheduledFuture f) { int s = --size; - ScheduledFutureTask x = queue[s]; + RunnableScheduledFuture x = queue[s]; queue[s] = null; if (s != 0) siftDown(0, x); @@ -912,11 +1022,11 @@ public class ScheduledThreadPoolExecutor return f; } - public ScheduledFutureTask poll() { + public RunnableScheduledFuture poll() { final ReentrantLock lock = this.lock; lock.lock(); try { - ScheduledFutureTask first = queue[0]; + RunnableScheduledFuture first = queue[0]; if (first == null || first.getDelay(TimeUnit.NANOSECONDS) > 0) return null; else @@ -926,12 +1036,12 @@ public class ScheduledThreadPoolExecutor } } - public ScheduledFutureTask take() throws InterruptedException { + public RunnableScheduledFuture take() throws InterruptedException { final ReentrantLock lock = this.lock; lock.lockInterruptibly(); try { for (;;) { - ScheduledFutureTask first = queue[0]; + RunnableScheduledFuture first = queue[0]; if (first == null) available.await(); else { @@ -959,14 +1069,14 @@ public class ScheduledThreadPoolExecutor } } - public ScheduledFutureTask poll(long timeout, TimeUnit unit) + public RunnableScheduledFuture poll(long timeout, TimeUnit unit) throws InterruptedException { long nanos = unit.toNanos(timeout); final ReentrantLock lock = this.lock; lock.lockInterruptibly(); try { for (;;) { - ScheduledFutureTask first = queue[0]; + RunnableScheduledFuture first = queue[0]; if (first == null) { if (nanos <= 0) return null; @@ -1005,7 +1115,7 @@ public class ScheduledThreadPoolExecutor lock.lock(); try { for (int i = 0; i < size; i++) { - ScheduledFutureTask t = queue[i]; + RunnableScheduledFuture t = queue[i]; if (t != null) { queue[i] = null; setIndex(t, -1); @@ -1021,8 +1131,8 @@ public class ScheduledThreadPoolExecutor * Return and remove first element only if it is expired. * Used only by drainTo. Call only when holding lock. */ - private ScheduledFutureTask pollExpired() { - ScheduledFutureTask first = queue[0]; + private RunnableScheduledFuture pollExpired() { + RunnableScheduledFuture first = queue[0]; if (first == null || first.getDelay(TimeUnit.NANOSECONDS) > 0) return null; return finishPoll(first); @@ -1036,7 +1146,7 @@ public class ScheduledThreadPoolExecutor final ReentrantLock lock = this.lock; lock.lock(); try { - ScheduledFutureTask first; + RunnableScheduledFuture first; int n = 0; while ((first = pollExpired()) != null) { c.add(first); @@ -1058,7 +1168,7 @@ public class ScheduledThreadPoolExecutor final ReentrantLock lock = this.lock; lock.lock(); try { - ScheduledFutureTask first; + RunnableScheduledFuture first; int n = 0; while (n < maxElements && (first = pollExpired()) != null) { c.add(first); @@ -1074,7 +1184,7 @@ public class ScheduledThreadPoolExecutor final ReentrantLock lock = this.lock; lock.lock(); try { - return Java6Arrays.copyOf(queue, size, Object[].class); + return Arrays.copyOf(queue, size, Object[].class); } finally { lock.unlock(); } @@ -1086,7 +1196,7 @@ public class ScheduledThreadPoolExecutor lock.lock(); try { if (a.length < size) - return (T[]) Java6Arrays.copyOf(queue, size, a.getClass()); + return (T[]) Arrays.copyOf(queue, size, a.getClass()); System.arraycopy(queue, 0, a, 0, size); if (a.length > size) a[size] = null; @@ -1097,18 +1207,18 @@ public class ScheduledThreadPoolExecutor } public Iterator<Runnable> iterator() { - return new Itr(Java6Arrays.copyOf(queue, size)); + return new Itr(Arrays.copyOf(queue, size)); } /** * Snapshot iterator that works off copy of underlying q array. */ private class Itr implements Iterator<Runnable> { - final ScheduledFutureTask[] array; + final RunnableScheduledFuture[] array; int cursor = 0; // index of next element to return int lastRet = -1; // index of last element, or -1 if no such - Itr(ScheduledFutureTask[] array) { + Itr(RunnableScheduledFuture[] array) { this.array = array; } diff --git a/concurrent/src/main/java/java/util/concurrent/Semaphore.java b/concurrent/src/main/java/java/util/concurrent/Semaphore.java index 1052364..1f5c00e 100644 --- a/concurrent/src/main/java/java/util/concurrent/Semaphore.java +++ b/concurrent/src/main/java/java/util/concurrent/Semaphore.java @@ -212,10 +212,8 @@ public class Semaphore implements java.io.Serializable { } protected int tryAcquireShared(int acquires) { - Thread current = Thread.currentThread(); for (;;) { - Thread first = getFirstQueuedThread(); - if (first != null && first != current) + if (hasQueuedPredecessors()) return -1; int available = getState(); int remaining = available - acquires; diff --git a/concurrent/src/main/java/java/util/concurrent/SynchronousQueue.java b/concurrent/src/main/java/java/util/concurrent/SynchronousQueue.java index 0d297ff..5f9e8d7 100644 --- a/concurrent/src/main/java/java/util/concurrent/SynchronousQueue.java +++ b/concurrent/src/main/java/java/util/concurrent/SynchronousQueue.java @@ -419,9 +419,9 @@ public class SynchronousQueue<E> extends AbstractQueue<E> else if (s.waiter == null) s.waiter = w; // establish waiter so can park next iter else if (!timed) - LockSupport.park(); + LockSupport.park(this); else if (nanos > spinForTimeoutThreshold) - LockSupport.parkNanos(nanos); + LockSupport.parkNanos(this, nanos); } } @@ -711,9 +711,9 @@ public class SynchronousQueue<E> extends AbstractQueue<E> else if (s.waiter == null) s.waiter = w; else if (!timed) - LockSupport.park(); + LockSupport.park(this); else if (nanos > spinForTimeoutThreshold) - LockSupport.parkNanos(nanos); + LockSupport.parkNanos(this, nanos); } } @@ -991,19 +991,6 @@ public class SynchronousQueue<E> extends AbstractQueue<E> return null; } - - static class EmptyIterator<E> implements Iterator<E> { - public boolean hasNext() { - return false; - } - public E next() { - throw new NoSuchElementException(); - } - public void remove() { - throw new IllegalStateException(); - } - } - /** * Returns an empty iterator in which <tt>hasNext</tt> always returns * <tt>false</tt>. @@ -1011,7 +998,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E> * @return an empty iterator */ public Iterator<E> iterator() { - return new EmptyIterator<E>(); + return Collections.<E>emptySet().iterator(); // android-changed } /** diff --git a/concurrent/src/main/java/java/util/concurrent/ThreadPoolExecutor.java b/concurrent/src/main/java/java/util/concurrent/ThreadPoolExecutor.java index d0c934d..c362c99 100644 --- a/concurrent/src/main/java/java/util/concurrent/ThreadPoolExecutor.java +++ b/concurrent/src/main/java/java/util/concurrent/ThreadPoolExecutor.java @@ -92,9 +92,12 @@ import java.util.*; * threads will be constructed. This parameter can also be changed * dynamically using method {@link #setKeepAliveTime}. Using a value * of {@code Long.MAX_VALUE} {@link TimeUnit#NANOSECONDS} effectively - * disables idle threads from ever terminating prior to shut down. The - * keep-alive policy applies only when there are more than - * corePoolSizeThreads.</dd> + * disables idle threads from ever terminating prior to shut down. By + * default, the keep-alive policy applies only when there are more + * than corePoolSizeThreads. But method {@link + * #allowCoreThreadTimeOut(boolean)} can be used to apply this + * time-out policy to core threads as well, so long as the + * keepAliveTime value is non-zero. </dd> * * <dt>Queuing</dt> * @@ -228,7 +231,8 @@ import java.util.*; * you would like to ensure that unreferenced pools are reclaimed even * if users forget to call {@link #shutdown}, then you must arrange * that unused threads eventually die, by setting appropriate - * keep-alive times using a lower bound of zero core threads. </dd> + * keep-alive times, using a lower bound of zero core threads and/or + * setting {@link #allowCoreThreadTimeOut(boolean)}. </dd> * * </dl> * @@ -473,13 +477,22 @@ public class ThreadPoolExecutor extends AbstractExecutorService { /** * Timeout in nanoseconds for idle threads waiting for work. * Threads use this timeout when there are more than corePoolSize - * present. Otherwise they wait forever for new work. + * present or if allowCoreThreadTimeOut. Otherwise they wait + * forever for new work. */ private volatile long keepAliveTime; /** + * If false (default), core threads stay alive even when idle. + * If true, core threads use keepAliveTime to time out waiting + * for work. + */ + private volatile boolean allowCoreThreadTimeOut; + + /** * Core pool size is the minimum number of workers to keep alive - * (and not allow to time out etc). + * (and not allow to time out etc) unless allowCoreThreadTimeOut + * is set, in which case the minimum is zero. */ private volatile int corePoolSize; @@ -941,7 +954,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService { int c = ctl.get(); if (runStateLessThan(c, STOP)) { if (!completedAbruptly) { - int min = corePoolSize; + int min = allowCoreThreadTimeOut ? 0 : corePoolSize; if (min == 0 && ! workQueue.isEmpty()) min = 1; if (workerCountOf(c) >= min) @@ -961,7 +974,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService { * 3. The pool is shutdown and the queue is empty. * 4. This worker timed out waiting for a task, and timed-out * workers are subject to termination (that is, - * {@code workerCount > corePoolSize}) + * {@code allowCoreThreadTimeOut || workerCount > corePoolSize}) * both before and after the timed wait. * * @return task, or null if the worker must exit, in which case @@ -985,7 +998,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService { for (;;) { int wc = workerCountOf(c); - timed = wc > corePoolSize; + timed = allowCoreThreadTimeOut || wc > corePoolSize; if (wc <= maximumPoolSize && ! (timedOut && timed)) break; @@ -1096,7 +1109,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService { * methods instead of this general purpose constructor. * * @param corePoolSize the number of threads to keep in the pool, even - * if they are idle + * if they are idle, unless {@code allowCoreThreadTimeOut} is set * @param maximumPoolSize the maximum number of threads to allow in the * pool * @param keepAliveTime when the number of threads is greater than @@ -1127,7 +1140,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService { * parameters and default rejected execution handler. * * @param corePoolSize the number of threads to keep in the pool, even - * if they are idle + * if they are idle, unless {@code allowCoreThreadTimeOut} is set * @param maximumPoolSize the maximum number of threads to allow in the * pool * @param keepAliveTime when the number of threads is greater than @@ -1162,7 +1175,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService { * parameters and default thread factory. * * @param corePoolSize the number of threads to keep in the pool, even - * if they are idle + * if they are idle, unless {@code allowCoreThreadTimeOut} is set * @param maximumPoolSize the maximum number of threads to allow in the * pool * @param keepAliveTime when the number of threads is greater than @@ -1197,7 +1210,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService { * parameters. * * @param corePoolSize the number of threads to keep in the pool, even - * if they are idle + * if they are idle, unless {@code allowCoreThreadTimeOut} is set * @param maximumPoolSize the maximum number of threads to allow in the * pool * @param keepAliveTime when the number of threads is greater than @@ -1518,6 +1531,50 @@ public class ThreadPoolExecutor extends AbstractExecutorService { } /** + * Returns true if this pool allows core threads to time out and + * terminate if no tasks arrive within the keepAlive time, being + * replaced if needed when new tasks arrive. When true, the same + * keep-alive policy applying to non-core threads applies also to + * core threads. When false (the default), core threads are never + * terminated due to lack of incoming tasks. + * + * @return {@code true} if core threads are allowed to time out, + * else {@code false} + * + * @since 1.6 + */ + public boolean allowsCoreThreadTimeOut() { + return allowCoreThreadTimeOut; + } + + /** + * Sets the policy governing whether core threads may time out and + * terminate if no tasks arrive within the keep-alive time, being + * replaced if needed when new tasks arrive. When false, core + * threads are never terminated due to lack of incoming + * tasks. When true, the same keep-alive policy applying to + * non-core threads applies also to core threads. To avoid + * continual thread replacement, the keep-alive time must be + * greater than zero when setting {@code true}. This method + * should in general be called before the pool is actively used. + * + * @param value {@code true} if should time out, else {@code false} + * @throws IllegalArgumentException if value is {@code true} + * and the current keep-alive time is not greater than zero + * + * @since 1.6 + */ + public void allowCoreThreadTimeOut(boolean value) { + if (value && keepAliveTime <= 0) + throw new IllegalArgumentException("Core threads must have nonzero keep alive times"); + if (value != allowCoreThreadTimeOut) { + allowCoreThreadTimeOut = value; + if (value) + interruptIdleWorkers(); + } + } + + /** * Sets the maximum allowed number of threads. This overrides any * value set in the constructor. If the new value is smaller than * the current value, excess existing threads will be @@ -1564,6 +1621,8 @@ public class ThreadPoolExecutor extends AbstractExecutorService { public void setKeepAliveTime(long time, TimeUnit unit) { if (time < 0) throw new IllegalArgumentException(); + if (time == 0 && allowsCoreThreadTimeOut()) + throw new IllegalArgumentException("Core threads must have nonzero keep alive times"); long keepAliveTime = unit.toNanos(time); long delta = keepAliveTime - this.keepAliveTime; this.keepAliveTime = keepAliveTime; diff --git a/concurrent/src/main/java/java/util/concurrent/TimeUnit.java b/concurrent/src/main/java/java/util/concurrent/TimeUnit.java index 412d28a..ae78fda 100644 --- a/concurrent/src/main/java/java/util/concurrent/TimeUnit.java +++ b/concurrent/src/main/java/java/util/concurrent/TimeUnit.java @@ -40,7 +40,6 @@ package java.util.concurrent; * @author Doug Lea */ public enum TimeUnit { - /** TimeUnit which represents one nanosecond. */ NANOSECONDS { public long toNanos(long d) { return d; } public long toMicros(long d) { return d/(C1/C0); } @@ -52,7 +51,6 @@ public enum TimeUnit { public long convert(long d, TimeUnit u) { return u.toNanos(d); } int excessNanos(long d, long m) { return (int)(d - (m*C2)); } }, - /** TimeUnit which represents one microsecond. */ MICROSECONDS { public long toNanos(long d) { return x(d, C1/C0, MAX/(C1/C0)); } public long toMicros(long d) { return d; } @@ -64,7 +62,6 @@ public enum TimeUnit { public long convert(long d, TimeUnit u) { return u.toMicros(d); } int excessNanos(long d, long m) { return (int)((d*C1) - (m*C2)); } }, - /** TimeUnit which represents one millisecond. */ MILLISECONDS { public long toNanos(long d) { return x(d, C2/C0, MAX/(C2/C0)); } public long toMicros(long d) { return x(d, C2/C1, MAX/(C2/C1)); } @@ -76,7 +73,6 @@ public enum TimeUnit { public long convert(long d, TimeUnit u) { return u.toMillis(d); } int excessNanos(long d, long m) { return 0; } }, - /** TimeUnit which represents one second. */ SECONDS { public long toNanos(long d) { return x(d, C3/C0, MAX/(C3/C0)); } public long toMicros(long d) { return x(d, C3/C1, MAX/(C3/C1)); } @@ -87,6 +83,39 @@ public enum TimeUnit { public long toDays(long d) { return d/(C6/C3); } public long convert(long d, TimeUnit u) { return u.toSeconds(d); } int excessNanos(long d, long m) { return 0; } + }, + MINUTES { + public long toNanos(long d) { return x(d, C4/C0, MAX/(C4/C0)); } + public long toMicros(long d) { return x(d, C4/C1, MAX/(C4/C1)); } + public long toMillis(long d) { return x(d, C4/C2, MAX/(C4/C2)); } + public long toSeconds(long d) { return x(d, C4/C3, MAX/(C4/C3)); } + public long toMinutes(long d) { return d; } + public long toHours(long d) { return d/(C5/C4); } + public long toDays(long d) { return d/(C6/C4); } + public long convert(long d, TimeUnit u) { return u.toMinutes(d); } + int excessNanos(long d, long m) { return 0; } + }, + HOURS { + public long toNanos(long d) { return x(d, C5/C0, MAX/(C5/C0)); } + public long toMicros(long d) { return x(d, C5/C1, MAX/(C5/C1)); } + public long toMillis(long d) { return x(d, C5/C2, MAX/(C5/C2)); } + public long toSeconds(long d) { return x(d, C5/C3, MAX/(C5/C3)); } + public long toMinutes(long d) { return x(d, C5/C4, MAX/(C5/C4)); } + public long toHours(long d) { return d; } + public long toDays(long d) { return d/(C6/C5); } + public long convert(long d, TimeUnit u) { return u.toHours(d); } + int excessNanos(long d, long m) { return 0; } + }, + DAYS { + public long toNanos(long d) { return x(d, C6/C0, MAX/(C6/C0)); } + public long toMicros(long d) { return x(d, C6/C1, MAX/(C6/C1)); } + public long toMillis(long d) { return x(d, C6/C2, MAX/(C6/C2)); } + public long toSeconds(long d) { return x(d, C6/C3, MAX/(C6/C3)); } + public long toMinutes(long d) { return x(d, C6/C4, MAX/(C6/C4)); } + public long toHours(long d) { return x(d, C6/C5, MAX/(C6/C5)); } + public long toDays(long d) { return d; } + public long convert(long d, TimeUnit u) { return u.toDays(d); } + int excessNanos(long d, long m) { return 0; } }; // Handy constants for conversion methods @@ -193,8 +222,9 @@ public enum TimeUnit { * or <tt>Long.MIN_VALUE</tt> if conversion would negatively * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow. * @see #convert + * @since 1.6 */ - long toMinutes(long duration) { + public long toMinutes(long duration) { throw new AbstractMethodError(); } @@ -205,8 +235,9 @@ public enum TimeUnit { * or <tt>Long.MIN_VALUE</tt> if conversion would negatively * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow. * @see #convert + * @since 1.6 */ - long toHours(long duration) { + public long toHours(long duration) { throw new AbstractMethodError(); } @@ -215,8 +246,9 @@ public enum TimeUnit { * @param duration the duration * @return the converted duration * @see #convert + * @since 1.6 */ - long toDays(long duration) { + public long toDays(long duration) { throw new AbstractMethodError(); } diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java index ba60556..c774d21 100644 --- a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java +++ b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java @@ -21,10 +21,7 @@ import sun.misc.Unsafe; public class AtomicBoolean implements java.io.Serializable { private static final long serialVersionUID = 4654671469794556979L; // setup to use Unsafe.compareAndSwapInt for updates - // BEGIN android-changed - private static final Unsafe unsafe = UnsafeAccess.THE_ONE; - // END android-changed - + private static final Unsafe unsafe = UnsafeAccess.THE_ONE; // android-changed private static final long valueOffset; static { @@ -103,6 +100,17 @@ public class AtomicBoolean implements java.io.Serializable { } /** + * Eventually sets to the given value. + * + * @param newValue the new value + * @since 1.6 + */ + public final void lazySet(boolean newValue) { + int v = newValue ? 1 : 0; + unsafe.putOrderedInt(this, valueOffset, v); + } + + /** * Atomically sets to the given value and returns the previous value. * * @param newValue the new value diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicInteger.java b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicInteger.java index 1aa32f4..16dd568 100644 --- a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicInteger.java +++ b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicInteger.java @@ -24,9 +24,7 @@ public class AtomicInteger extends Number implements java.io.Serializable { private static final long serialVersionUID = 6214790243416807050L; // setup to use Unsafe.compareAndSwapInt for updates - // BEGIN android-changed - private static final Unsafe unsafe = UnsafeAccess.THE_ONE; - // END android-changed + private static final Unsafe unsafe = UnsafeAccess.THE_ONE; // android-changed private static final long valueOffset; static { @@ -72,6 +70,16 @@ public class AtomicInteger extends Number implements java.io.Serializable { } /** + * Eventually sets to the given value. + * + * @param newValue the new value + * @since 1.6 + */ + public final void lazySet(int newValue) { + unsafe.putOrderedInt(this, valueOffset, newValue); + } + + /** * Atomically sets to the given value and returns the old value. * * @param newValue the new value diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java index 312c76d..b6d6cc5 100644 --- a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java +++ b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java @@ -19,33 +19,30 @@ import java.util.*; public class AtomicIntegerArray implements java.io.Serializable { private static final long serialVersionUID = 2862133569453604235L; - // setup to use Unsafe.compareAndSwapInt for updates - // BEGIN android-changed - private static final Unsafe unsafe = UnsafeAccess.THE_ONE; - // END android-changed + private static final Unsafe unsafe = UnsafeAccess.THE_ONE; // android-changed private static final int base = unsafe.arrayBaseOffset(int[].class); private static final int scale = unsafe.arrayIndexScale(int[].class); private final int[] array; - private long rawIndex(int i) { + private long checkedByteOffset(int i) { if (i < 0 || i >= array.length) throw new IndexOutOfBoundsException("index " + i); - // BEGIN android-changed - // avoid memory corruption + + return byteOffset(i); + } + + private static long byteOffset(int i) { return base + (long) i * scale; - // END android-changed } /** - * Creates a new AtomicIntegerArray of given length. + * Creates a new AtomicIntegerArray of the given length, with all + * elements initially zero. * * @param length the length of the array */ public AtomicIntegerArray(int length) { array = new int[length]; - // must perform at least one volatile write to conform to JMM - if (length > 0) - unsafe.putIntVolatile(array, rawIndex(0), 0); } /** @@ -56,17 +53,8 @@ public class AtomicIntegerArray implements java.io.Serializable { * @throws NullPointerException if array is null */ public AtomicIntegerArray(int[] array) { - if (array == null) - throw new NullPointerException(); - int length = array.length; - this.array = new int[length]; - if (length > 0) { - int last = length-1; - for (int i = 0; i < last; ++i) - this.array[i] = array[i]; - // Do the last write as volatile - unsafe.putIntVolatile(this.array, rawIndex(last), array[last]); - } + // Visibility guaranteed by final field guarantees + this.array = array.clone(); } /** @@ -85,7 +73,11 @@ public class AtomicIntegerArray implements java.io.Serializable { * @return the current value */ public final int get(int i) { - return unsafe.getIntVolatile(array, rawIndex(i)); + return getRaw(checkedByteOffset(i)); + } + + private int getRaw(long offset) { + return unsafe.getIntVolatile(array, offset); } /** @@ -95,7 +87,18 @@ public class AtomicIntegerArray implements java.io.Serializable { * @param newValue the new value */ public final void set(int i, int newValue) { - unsafe.putIntVolatile(array, rawIndex(i), newValue); + unsafe.putIntVolatile(array, checkedByteOffset(i), newValue); + } + + /** + * Eventually sets the element at position {@code i} to the given value. + * + * @param i the index + * @param newValue the new value + * @since 1.6 + */ + public final void lazySet(int i, int newValue) { + unsafe.putOrderedInt(array, checkedByteOffset(i), newValue); } /** @@ -107,9 +110,10 @@ public class AtomicIntegerArray implements java.io.Serializable { * @return the previous value */ public final int getAndSet(int i, int newValue) { + long offset = checkedByteOffset(i); while (true) { - int current = get(i); - if (compareAndSet(i, current, newValue)) + int current = getRaw(offset); + if (compareAndSetRaw(offset, current, newValue)) return current; } } @@ -125,8 +129,11 @@ public class AtomicIntegerArray implements java.io.Serializable { * the actual value was not equal to the expected value. */ public final boolean compareAndSet(int i, int expect, int update) { - return unsafe.compareAndSwapInt(array, rawIndex(i), - expect, update); + return compareAndSetRaw(checkedByteOffset(i), expect, update); + } + + private boolean compareAndSetRaw(long offset, int expect, int update) { + return unsafe.compareAndSwapInt(array, offset, expect, update); } /** @@ -153,12 +160,7 @@ public class AtomicIntegerArray implements java.io.Serializable { * @return the previous value */ public final int getAndIncrement(int i) { - while (true) { - int current = get(i); - int next = current + 1; - if (compareAndSet(i, current, next)) - return current; - } + return getAndAdd(i, 1); } /** @@ -168,12 +170,7 @@ public class AtomicIntegerArray implements java.io.Serializable { * @return the previous value */ public final int getAndDecrement(int i) { - while (true) { - int current = get(i); - int next = current - 1; - if (compareAndSet(i, current, next)) - return current; - } + return getAndAdd(i, -1); } /** @@ -184,10 +181,10 @@ public class AtomicIntegerArray implements java.io.Serializable { * @return the previous value */ public final int getAndAdd(int i, int delta) { + long offset = checkedByteOffset(i); while (true) { - int current = get(i); - int next = current + delta; - if (compareAndSet(i, current, next)) + int current = getRaw(offset); + if (compareAndSetRaw(offset, current, current + delta)) return current; } } @@ -199,12 +196,7 @@ public class AtomicIntegerArray implements java.io.Serializable { * @return the updated value */ public final int incrementAndGet(int i) { - while (true) { - int current = get(i); - int next = current + 1; - if (compareAndSet(i, current, next)) - return next; - } + return addAndGet(i, 1); } /** @@ -214,12 +206,7 @@ public class AtomicIntegerArray implements java.io.Serializable { * @return the updated value */ public final int decrementAndGet(int i) { - while (true) { - int current = get(i); - int next = current - 1; - if (compareAndSet(i, current, next)) - return next; - } + return addAndGet(i, -1); } /** @@ -230,22 +217,32 @@ public class AtomicIntegerArray implements java.io.Serializable { * @return the updated value */ public final int addAndGet(int i, int delta) { + long offset = checkedByteOffset(i); while (true) { - int current = get(i); + int current = getRaw(offset); int next = current + delta; - if (compareAndSet(i, current, next)) + if (compareAndSetRaw(offset, current, next)) return next; } } /** * Returns the String representation of the current values of array. - * @return the String representation of the current values of array. + * @return the String representation of the current values of array */ public String toString() { - if (array.length > 0) // force volatile read - get(0); - return Arrays.toString(array); + int iMax = array.length - 1; + if (iMax == -1) + return "[]"; + + StringBuilder b = new StringBuilder(); + b.append('['); + for (int i = 0; ; i++) { + b.append(getRaw(byteOffset(i))); + if (i == iMax) + return b.append(']').toString(); + b.append(", "); + } } } diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java index f8d2c81..476bb0a 100644 --- a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java +++ b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java @@ -5,12 +5,10 @@ */ package java.util.concurrent.atomic; +import dalvik.system.VMStack; import sun.misc.Unsafe; import java.lang.reflect.*; -import org.apache.harmony.kernel.vm.VM; -import dalvik.system.VMStack; - /** * A reflection-based utility that enables atomic updates to * designated {@code volatile int} fields of designated classes. @@ -100,6 +98,17 @@ public abstract class AtomicIntegerFieldUpdater<T> { public abstract void set(T obj, int newValue); /** + * Eventually sets the field of the given object managed by this + * updater to the given updated value. + * + * @param obj An object whose field to set + * @param newValue the new value + * @since 1.6 + */ + public abstract void lazySet(T obj, int newValue); + + + /** * Gets the current value held in the field of the given object managed * by this updater. * @@ -226,9 +235,7 @@ public abstract class AtomicIntegerFieldUpdater<T> { * Standard hotspot implementation using intrinsics */ private static class AtomicIntegerFieldUpdaterImpl<T> extends AtomicIntegerFieldUpdater<T> { - // BEGIN android-changed - private static final Unsafe unsafe = UnsafeAccess.THE_ONE; - // END android-changed + private static final Unsafe unsafe = UnsafeAccess.THE_ONE; // android-changed private final long offset; private final Class<T> tclass; private final Class cclass; @@ -244,6 +251,7 @@ public abstract class AtomicIntegerFieldUpdater<T> { // END android-changed modifiers = field.getModifiers(); + // BEGIN android-added SecurityManager smgr = System.getSecurityManager(); if (smgr != null) { int type = Modifier.isPublic(modifiers) @@ -251,6 +259,13 @@ public abstract class AtomicIntegerFieldUpdater<T> { smgr.checkMemberAccess(tclass, type); smgr.checkPackageAccess(tclass.getPackage().getName()); } + // END android-added + // BEGIN android-removed + // modifiers = field.getModifiers(); + // sun.reflect.misc.ReflectUtil.ensureMemberAccess( + // caller, tclass, null, modifiers); + // sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); + // END android-removed } catch (Exception ex) { throw new RuntimeException(ex); } @@ -290,6 +305,11 @@ public abstract class AtomicIntegerFieldUpdater<T> { unsafe.putIntVolatile(obj, offset, newValue); } + public void lazySet(T obj, int newValue) { + if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); + unsafe.putOrderedInt(obj, offset, newValue); + } + public final int get(T obj) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); return unsafe.getIntVolatile(obj, offset); diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicLong.java b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicLong.java index 9b56002..e1f5dc7 100644 --- a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicLong.java +++ b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicLong.java @@ -24,9 +24,7 @@ public class AtomicLong extends Number implements java.io.Serializable { private static final long serialVersionUID = 1927816293512124184L; // setup to use Unsafe.compareAndSwapLong for updates - // BEGIN android-changed - private static final Unsafe unsafe = UnsafeAccess.THE_ONE; - // END android-changed + private static final Unsafe unsafe = UnsafeAccess.THE_ONE; // android-changed private static final long valueOffset; /** @@ -97,6 +95,16 @@ public class AtomicLong extends Number implements java.io.Serializable { } /** + * Eventually sets to the given value. + * + * @param newValue the new value + * @since 1.6 + */ + public final void lazySet(long newValue) { + unsafe.putOrderedLong(this, valueOffset, newValue); + } + + /** * Atomically sets to the given value and returns the old value. * * @param newValue the new value diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java index 187acbc..33e6914 100644 --- a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java +++ b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java @@ -18,33 +18,30 @@ import java.util.*; public class AtomicLongArray implements java.io.Serializable { private static final long serialVersionUID = -2308431214976778248L; - // setup to use Unsafe.compareAndSwapInt for updates - // BEGIN android-changed - private static final Unsafe unsafe = UnsafeAccess.THE_ONE; - // END android-changed + private static final Unsafe unsafe = UnsafeAccess.THE_ONE; // android-changed private static final int base = unsafe.arrayBaseOffset(long[].class); private static final int scale = unsafe.arrayIndexScale(long[].class); private final long[] array; - private long rawIndex(int i) { + private long checkedByteOffset(int i) { if (i < 0 || i >= array.length) throw new IndexOutOfBoundsException("index " + i); - // BEGIN android-changed - // avoid memory corruption + + return byteOffset(i); + } + + private static long byteOffset(int i) { return base + (long) i * scale; - // END android-changed } /** - * Creates a new AtomicLongArray of given length. + * Creates a new AtomicLongArray of the given length, with all + * elements initially zero. * * @param length the length of the array */ public AtomicLongArray(int length) { array = new long[length]; - // must perform at least one volatile write to conform to JMM - if (length > 0) - unsafe.putLongVolatile(array, rawIndex(0), 0); } /** @@ -55,17 +52,8 @@ public class AtomicLongArray implements java.io.Serializable { * @throws NullPointerException if array is null */ public AtomicLongArray(long[] array) { - if (array == null) - throw new NullPointerException(); - int length = array.length; - this.array = new long[length]; - if (length > 0) { - int last = length-1; - for (int i = 0; i < last; ++i) - this.array[i] = array[i]; - // Do the last write as volatile - unsafe.putLongVolatile(this.array, rawIndex(last), array[last]); - } + // Visibility guaranteed by final field guarantees + this.array = array.clone(); } /** @@ -84,7 +72,11 @@ public class AtomicLongArray implements java.io.Serializable { * @return the current value */ public final long get(int i) { - return unsafe.getLongVolatile(array, rawIndex(i)); + return getRaw(checkedByteOffset(i)); + } + + private long getRaw(long offset) { + return unsafe.getLongVolatile(array, offset); } /** @@ -94,10 +86,22 @@ public class AtomicLongArray implements java.io.Serializable { * @param newValue the new value */ public final void set(int i, long newValue) { - unsafe.putLongVolatile(array, rawIndex(i), newValue); + unsafe.putLongVolatile(array, checkedByteOffset(i), newValue); } /** + * Eventually sets the element at position {@code i} to the given value. + * + * @param i the index + * @param newValue the new value + * @since 1.6 + */ + public final void lazySet(int i, long newValue) { + unsafe.putOrderedLong(array, checkedByteOffset(i), newValue); + } + + + /** * Atomically sets the element at position {@code i} to the given value * and returns the old value. * @@ -106,16 +110,17 @@ public class AtomicLongArray implements java.io.Serializable { * @return the previous value */ public final long getAndSet(int i, long newValue) { + long offset = checkedByteOffset(i); while (true) { - long current = get(i); - if (compareAndSet(i, current, newValue)) + long current = getRaw(offset); + if (compareAndSetRaw(offset, current, newValue)) return current; } } /** - * Atomically sets the value to the given updated value - * if the current value {@code ==} the expected value. + * Atomically sets the element at position {@code i} to the given + * updated value if the current value {@code ==} the expected value. * * @param i the index * @param expect the expected value @@ -124,13 +129,16 @@ public class AtomicLongArray implements java.io.Serializable { * the actual value was not equal to the expected value. */ public final boolean compareAndSet(int i, long expect, long update) { - return unsafe.compareAndSwapLong(array, rawIndex(i), - expect, update); + return compareAndSetRaw(checkedByteOffset(i), expect, update); + } + + private boolean compareAndSetRaw(long offset, long expect, long update) { + return unsafe.compareAndSwapLong(array, offset, expect, update); } /** - * Atomically sets the value to the given updated value - * if the current value {@code ==} the expected value. + * Atomically sets the element at position {@code i} to the given + * updated value if the current value {@code ==} the expected value. * * <p>May <a href="package-summary.html#Spurious">fail spuriously</a> * and does not provide ordering guarantees, so is only rarely an @@ -152,12 +160,7 @@ public class AtomicLongArray implements java.io.Serializable { * @return the previous value */ public final long getAndIncrement(int i) { - while (true) { - long current = get(i); - long next = current + 1; - if (compareAndSet(i, current, next)) - return current; - } + return getAndAdd(i, 1); } /** @@ -167,12 +170,7 @@ public class AtomicLongArray implements java.io.Serializable { * @return the previous value */ public final long getAndDecrement(int i) { - while (true) { - long current = get(i); - long next = current - 1; - if (compareAndSet(i, current, next)) - return current; - } + return getAndAdd(i, -1); } /** @@ -183,10 +181,10 @@ public class AtomicLongArray implements java.io.Serializable { * @return the previous value */ public final long getAndAdd(int i, long delta) { + long offset = checkedByteOffset(i); while (true) { - long current = get(i); - long next = current + delta; - if (compareAndSet(i, current, next)) + long current = getRaw(offset); + if (compareAndSetRaw(offset, current, current + delta)) return current; } } @@ -198,12 +196,7 @@ public class AtomicLongArray implements java.io.Serializable { * @return the updated value */ public final long incrementAndGet(int i) { - while (true) { - long current = get(i); - long next = current + 1; - if (compareAndSet(i, current, next)) - return next; - } + return addAndGet(i, 1); } /** @@ -213,12 +206,7 @@ public class AtomicLongArray implements java.io.Serializable { * @return the updated value */ public final long decrementAndGet(int i) { - while (true) { - long current = get(i); - long next = current - 1; - if (compareAndSet(i, current, next)) - return next; - } + return addAndGet(i, -1); } /** @@ -229,22 +217,32 @@ public class AtomicLongArray implements java.io.Serializable { * @return the updated value */ public long addAndGet(int i, long delta) { + long offset = checkedByteOffset(i); while (true) { - long current = get(i); + long current = getRaw(offset); long next = current + delta; - if (compareAndSet(i, current, next)) + if (compareAndSetRaw(offset, current, next)) return next; } } /** * Returns the String representation of the current values of array. - * @return the String representation of the current values of array. + * @return the String representation of the current values of array */ public String toString() { - if (array.length > 0) // force volatile read - get(0); - return Arrays.toString(array); + int iMax = array.length - 1; + if (iMax == -1) + return "[]"; + + StringBuilder b = new StringBuilder(); + b.append('['); + for (int i = 0; ; i++) { + b.append(getRaw(byteOffset(i))); + if (i == iMax) + return b.append(']').toString(); + b.append(", "); + } } } diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java index d97c2e4..427a9e1 100644 --- a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java +++ b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java @@ -5,12 +5,10 @@ */ package java.util.concurrent.atomic; +import dalvik.system.VMStack; import sun.misc.Unsafe; import java.lang.reflect.*; -import org.apache.harmony.kernel.vm.VM; -import dalvik.system.VMStack; - /** * A reflection-based utility that enables atomic updates to * designated {@code volatile long} fields of designated classes. @@ -103,6 +101,16 @@ public abstract class AtomicLongFieldUpdater<T> { public abstract void set(T obj, long newValue); /** + * Eventually sets the field of the given object managed by this + * updater to the given updated value. + * + * @param obj An object whose field to set + * @param newValue the new value + * @since 1.6 + */ + public abstract void lazySet(T obj, long newValue); + + /** * Gets the current value held in the field of the given object managed * by this updater. * @@ -226,9 +234,7 @@ public abstract class AtomicLongFieldUpdater<T> { } private static class CASUpdater<T> extends AtomicLongFieldUpdater<T> { - // BEGIN android-changed - private static final Unsafe unsafe = UnsafeAccess.THE_ONE; - // END android-changed + private static final Unsafe unsafe = UnsafeAccess.THE_ONE; // android-changed private final long offset; private final Class<T> tclass; private final Class cclass; @@ -239,10 +245,9 @@ public abstract class AtomicLongFieldUpdater<T> { int modifiers = 0; try { field = tclass.getDeclaredField(fieldName); - // BEGIN android-changed - caller = VMStack.getStackClass2(); - // END android-changed + caller = VMStack.getStackClass2(); // android-changed modifiers = field.getModifiers(); + // BEGIN android-added SecurityManager smgr = System.getSecurityManager(); if (smgr != null) { int type = Modifier.isPublic(modifiers) @@ -250,6 +255,12 @@ public abstract class AtomicLongFieldUpdater<T> { smgr.checkMemberAccess(tclass, type); smgr.checkPackageAccess(tclass.getPackage().getName()); } + // END android-added + // BEGIN android-removed + // sun.reflect.misc.ReflectUtil.ensureMemberAccess( + // caller, tclass, null, modifiers); + // sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); + // END android-removed } catch (Exception ex) { throw new RuntimeException(ex); } @@ -289,6 +300,11 @@ public abstract class AtomicLongFieldUpdater<T> { unsafe.putLongVolatile(obj, offset, newValue); } + public void lazySet(T obj, long newValue) { + if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); + unsafe.putOrderedLong(obj, offset, newValue); + } + public long get(T obj) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); return unsafe.getLongVolatile(obj, offset); @@ -312,9 +328,7 @@ public abstract class AtomicLongFieldUpdater<T> { private static class LockedUpdater<T> extends AtomicLongFieldUpdater<T> { - // BEGIN android-changed - private static final Unsafe unsafe = UnsafeAccess.THE_ONE; - // END android-changed + private static final Unsafe unsafe = UnsafeAccess.THE_ONE; // android-changed private final long offset; private final Class<T> tclass; private final Class cclass; @@ -325,10 +339,9 @@ public abstract class AtomicLongFieldUpdater<T> { int modifiers = 0; try { field = tclass.getDeclaredField(fieldName); - // BEGIN android-changed - caller = VMStack.getStackClass2(); - // END android-changed + caller = VMStack.getStackClass2(); // android-changed modifiers = field.getModifiers(); + // BEGIN android-added SecurityManager smgr = System.getSecurityManager(); if (smgr != null) { int type = Modifier.isPublic(modifiers) @@ -336,6 +349,12 @@ public abstract class AtomicLongFieldUpdater<T> { smgr.checkMemberAccess(tclass, type); smgr.checkPackageAccess(tclass.getPackage().getName()); } + // END android-added + // BEGIN android-removed + // sun.reflect.misc.ReflectUtil.ensureMemberAccess( + // caller, tclass, null, modifiers); + // sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); + // END android-removed } catch (Exception ex) { throw new RuntimeException(ex); } diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicReference.java b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicReference.java index 1de9b1c..f041bbd 100644 --- a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicReference.java +++ b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicReference.java @@ -18,9 +18,7 @@ import sun.misc.Unsafe; public class AtomicReference<V> implements java.io.Serializable { private static final long serialVersionUID = -1848883965231344442L; - // BEGIN android-changed - private static final Unsafe unsafe = UnsafeAccess.THE_ONE; - // END android-changed + private static final Unsafe unsafe = UnsafeAccess.THE_ONE; // android-changed private static final long valueOffset; static { @@ -66,6 +64,16 @@ public class AtomicReference<V> implements java.io.Serializable { } /** + * Eventually sets to the given value. + * + * @param newValue the new value + * @since 1.6 + */ + public final void lazySet(V newValue) { + unsafe.putOrderedObject(this, valueOffset, newValue); + } + + /** * Atomically sets the value to the given updated value * if the current value {@code ==} the expected value. * @param expect the expected value diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicReferenceArray.java b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicReferenceArray.java index fff6a1e..2501c2b 100644 --- a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicReferenceArray.java +++ b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicReferenceArray.java @@ -20,31 +20,30 @@ import java.util.*; public class AtomicReferenceArray<E> implements java.io.Serializable { private static final long serialVersionUID = -6209656149925076980L; - // BEGIN android-changed - private static final Unsafe unsafe = UnsafeAccess.THE_ONE; - // END android-changed + private static final Unsafe unsafe = UnsafeAccess.THE_ONE; // android-changed private static final int base = unsafe.arrayBaseOffset(Object[].class); private static final int scale = unsafe.arrayIndexScale(Object[].class); private final Object[] array; - private long rawIndex(int i) { + private long checkedByteOffset(int i) { if (i < 0 || i >= array.length) throw new IndexOutOfBoundsException("index " + i); - // BEGIN android-changed - // avoid memory corruption + + return byteOffset(i); + } + + private static long byteOffset(int i) { return base + (long) i * scale; - // END android-changed } /** - * Creates a new AtomicReferenceArray of given length. + * Creates a new AtomicReferenceArray of the given length, with all + * elements initially zero. + * * @param length the length of the array */ public AtomicReferenceArray(int length) { array = new Object[length]; - // must perform at least one volatile write to conform to JMM - if (length > 0) - unsafe.putObjectVolatile(array, rawIndex(0), null); } /** @@ -55,18 +54,8 @@ public class AtomicReferenceArray<E> implements java.io.Serializable { * @throws NullPointerException if array is null */ public AtomicReferenceArray(E[] array) { - if (array == null) - throw new NullPointerException(); - int length = array.length; - this.array = new Object[length]; - if (length > 0) { - int last = length-1; - for (int i = 0; i < last; ++i) - this.array[i] = array[i]; - // Do the last write as volatile - E e = array[last]; - unsafe.putObjectVolatile(this.array, rawIndex(last), e); - } + // Visibility guaranteed by final field guarantees + this.array = array.clone(); } /** @@ -85,7 +74,11 @@ public class AtomicReferenceArray<E> implements java.io.Serializable { * @return the current value */ public final E get(int i) { - return (E) unsafe.getObjectVolatile(array, rawIndex(i)); + return getRaw(checkedByteOffset(i)); + } + + private E getRaw(long offset) { + return (E) unsafe.getObjectVolatile(array, offset); } /** @@ -95,9 +88,21 @@ public class AtomicReferenceArray<E> implements java.io.Serializable { * @param newValue the new value */ public final void set(int i, E newValue) { - unsafe.putObjectVolatile(array, rawIndex(i), newValue); + unsafe.putObjectVolatile(array, checkedByteOffset(i), newValue); + } + + /** + * Eventually sets the element at position {@code i} to the given value. + * + * @param i the index + * @param newValue the new value + * @since 1.6 + */ + public final void lazySet(int i, E newValue) { + unsafe.putOrderedObject(array, checkedByteOffset(i), newValue); } + /** * Atomically sets the element at position {@code i} to the given * value and returns the old value. @@ -107,9 +112,10 @@ public class AtomicReferenceArray<E> implements java.io.Serializable { * @return the previous value */ public final E getAndSet(int i, E newValue) { + long offset = checkedByteOffset(i); while (true) { - E current = get(i); - if (compareAndSet(i, current, newValue)) + E current = (E) getRaw(offset); + if (compareAndSetRaw(offset, current, newValue)) return current; } } @@ -117,6 +123,7 @@ public class AtomicReferenceArray<E> implements java.io.Serializable { /** * Atomically sets the element at position {@code i} to the given * updated value if the current value {@code ==} the expected value. + * * @param i the index * @param expect the expected value * @param update the new value @@ -124,8 +131,11 @@ public class AtomicReferenceArray<E> implements java.io.Serializable { * the actual value was not equal to the expected value. */ public final boolean compareAndSet(int i, E expect, E update) { - return unsafe.compareAndSwapObject(array, rawIndex(i), - expect, update); + return compareAndSetRaw(checkedByteOffset(i), expect, update); + } + + private boolean compareAndSetRaw(long offset, E expect, E update) { + return unsafe.compareAndSwapObject(array, offset, expect, update); } /** @@ -147,12 +157,21 @@ public class AtomicReferenceArray<E> implements java.io.Serializable { /** * Returns the String representation of the current values of array. - * @return the String representation of the current values of array. + * @return the String representation of the current values of array */ public String toString() { - if (array.length > 0) // force volatile read - get(0); - return Arrays.toString(array); + int iMax = array.length - 1; + if (iMax == -1) + return "[]"; + + StringBuilder b = new StringBuilder(); + b.append('['); + for (int i = 0; ; i++) { + b.append(getRaw(byteOffset(i))); + if (i == iMax) + return b.append(']').toString(); + b.append(", "); + } } } diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java index fae134f..e53f2e9 100644 --- a/concurrent/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java +++ b/concurrent/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java @@ -5,12 +5,10 @@ */ package java.util.concurrent.atomic; +import dalvik.system.VMStack; import sun.misc.Unsafe; import java.lang.reflect.*; -import org.apache.harmony.kernel.vm.VM; -import dalvik.system.VMStack; - /** * A reflection-based utility that enables atomic updates to * designated {@code volatile} reference fields of designated @@ -118,6 +116,16 @@ public abstract class AtomicReferenceFieldUpdater<T, V> { public abstract void set(T obj, V newValue); /** + * Eventually sets the field of the given object managed by this + * updater to the given updated value. + * + * @param obj An object whose field to set + * @param newValue the new value + * @since 1.6 + */ + public abstract void lazySet(T obj, V newValue); + + /** * Gets the current value held in the field of the given object managed * by this updater. * @@ -144,9 +152,7 @@ public abstract class AtomicReferenceFieldUpdater<T, V> { private static final class AtomicReferenceFieldUpdaterImpl<T,V> extends AtomicReferenceFieldUpdater<T,V> { - // BEGIN android-changed - private static final Unsafe unsafe = UnsafeAccess.THE_ONE; - // END android-changed + private static final Unsafe unsafe = Unsafe.getUnsafe(); private final long offset; private final Class<T> tclass; private final Class<V> vclass; @@ -173,10 +179,9 @@ public abstract class AtomicReferenceFieldUpdater<T, V> { int modifiers = 0; try { field = tclass.getDeclaredField(fieldName); - // BEGIN android-changed - caller = VMStack.getStackClass2(); - // END android-changed + caller = VMStack.getStackClass2(); // android-changed modifiers = field.getModifiers(); + // BEGIN android-added SecurityManager smgr = System.getSecurityManager(); if (smgr != null) { int type = Modifier.isPublic(modifiers) @@ -184,6 +189,12 @@ public abstract class AtomicReferenceFieldUpdater<T, V> { smgr.checkMemberAccess(tclass, type); smgr.checkPackageAccess(tclass.getPackage().getName()); } + // END android-added + // BEGIN android-removed + // sun.reflect.misc.ReflectUtil.ensureMemberAccess( + // caller, tclass, null, modifiers); + // sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); + // END android-removed fieldClass = field.getType(); } catch (Exception ex) { throw new RuntimeException(ex); @@ -245,6 +256,14 @@ public abstract class AtomicReferenceFieldUpdater<T, V> { unsafe.putObjectVolatile(obj, offset, newValue); } + public void lazySet(T obj, V newValue) { + if (obj == null || obj.getClass() != tclass || cclass != null || + (newValue != null && vclass != null && + vclass != newValue.getClass())) + updateCheck(obj, newValue); + unsafe.putOrderedObject(obj, offset, newValue); + } + public V get(T obj) { if (obj == null || obj.getClass() != tclass || cclass != null) targetCheck(obj); diff --git a/concurrent/src/main/java/java/util/concurrent/atomic/package-info.java b/concurrent/src/main/java/java/util/concurrent/atomic/package-info.java index 2252e5c..4a4375d 100644 --- a/concurrent/src/main/java/java/util/concurrent/atomic/package-info.java +++ b/concurrent/src/main/java/java/util/concurrent/atomic/package-info.java @@ -63,6 +63,14 @@ * <li> {@code set} has the memory effects of writing (assigning) a * {@code volatile} variable. * + * <li> {@code lazySet} has the memory effects of writing (assigning) + * a {@code volatile} variable except that it permits reorderings with + * subsequent (but not previous) memory actions that do not themselves + * impose reordering constraints with ordinary non-{@code volatile} + * writes. Among other usage contexts, {@code lazySet} may apply when + * nulling out, for the sake of garbage collection, a reference that is + * never accessed again. + * * <li>{@code weakCompareAndSet} atomically reads and conditionally * writes a variable but does <em>not</em> * create any happens-before orderings, so provides no guarantees diff --git a/concurrent/src/main/java/java/util/concurrent/locks/AbstractOwnableSynchronizer.java b/concurrent/src/main/java/java/util/concurrent/locks/AbstractOwnableSynchronizer.java index bf2fe16..f3780e5 100644 --- a/concurrent/src/main/java/java/util/concurrent/locks/AbstractOwnableSynchronizer.java +++ b/concurrent/src/main/java/java/util/concurrent/locks/AbstractOwnableSynchronizer.java @@ -15,10 +15,11 @@ package java.util.concurrent.locks; * appropriately maintained values to help control and monitor access * and provide diagnostics. * + * @since 1.6 * @author Doug Lea */ -abstract class AbstractOwnableSynchronizer - implements java.io.Serializable { +public abstract class AbstractOwnableSynchronizer + implements java.io.Serializable { /** Use serial ID even though all fields transient. */ private static final long serialVersionUID = 3737899427754241961L; @@ -53,4 +54,4 @@ abstract class AbstractOwnableSynchronizer protected final Thread getExclusiveOwnerThread() { return exclusiveOwnerThread; } -}
\ No newline at end of file +} diff --git a/concurrent/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java b/concurrent/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java new file mode 100644 index 0000000..d805259 --- /dev/null +++ b/concurrent/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java @@ -0,0 +1,2073 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package java.util.concurrent.locks; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; +import sun.misc.Unsafe; + +/** + * A version of {@link AbstractQueuedSynchronizer} in + * which synchronization state is maintained as a <tt>long</tt>. + * This class has exactly the same structure, properties, and methods + * as <tt>AbstractQueuedSynchronizer</tt> with the exception + * that all state-related parameters and results are defined + * as <tt>long</tt> rather than <tt>int</tt>. This class + * may be useful when creating synchronizers such as + * multilevel locks and barriers that require + * 64 bits of state. + * + * <p>See {@link AbstractQueuedSynchronizer} for usage + * notes and examples. + * + * @since 1.6 + * @author Doug Lea + */ +public abstract class AbstractQueuedLongSynchronizer + extends AbstractOwnableSynchronizer + implements java.io.Serializable { + + private static final long serialVersionUID = 7373984972572414692L; + + /* + To keep sources in sync, the remainder of this source file is + exactly cloned from AbstractQueuedSynchronizer, replacing class + name and changing ints related with sync state to longs. Please + keep it that way. + */ + + /** + * Creates a new <tt>AbstractQueuedLongSynchronizer</tt> instance + * with initial synchronization state of zero. + */ + protected AbstractQueuedLongSynchronizer() { } + + /** + * Wait queue node class. + * + * <p>The wait queue is a variant of a "CLH" (Craig, Landin, and + * Hagersten) lock queue. CLH locks are normally used for + * spinlocks. We instead use them for blocking synchronizers, but + * use the same basic tactic of holding some of the control + * information about a thread in the predecessor of its node. A + * "status" field in each node keeps track of whether a thread + * should block. A node is signalled when its predecessor + * releases. Each node of the queue otherwise serves as a + * specific-notification-style monitor holding a single waiting + * thread. The status field does NOT control whether threads are + * granted locks etc though. A thread may try to acquire if it is + * first in the queue. But being first does not guarantee success; + * it only gives the right to contend. So the currently released + * contender thread may need to rewait. + * + * <p>To enqueue into a CLH lock, you atomically splice it in as new + * tail. To dequeue, you just set the head field. + * <pre> + * +------+ prev +-----+ +-----+ + * head | | <---- | | <---- | | tail + * +------+ +-----+ +-----+ + * </pre> + * + * <p>Insertion into a CLH queue requires only a single atomic + * operation on "tail", so there is a simple atomic point of + * demarcation from unqueued to queued. Similarly, dequeing + * involves only updating the "head". However, it takes a bit + * more work for nodes to determine who their successors are, + * in part to deal with possible cancellation due to timeouts + * and interrupts. + * + * <p>The "prev" links (not used in original CLH locks), are mainly + * needed to handle cancellation. If a node is cancelled, its + * successor is (normally) relinked to a non-cancelled + * predecessor. For explanation of similar mechanics in the case + * of spin locks, see the papers by Scott and Scherer at + * http://www.cs.rochester.edu/u/scott/synchronization/ + * + * <p>We also use "next" links to implement blocking mechanics. + * The thread id for each node is kept in its own node, so a + * predecessor signals the next node to wake up by traversing + * next link to determine which thread it is. Determination of + * successor must avoid races with newly queued nodes to set + * the "next" fields of their predecessors. This is solved + * when necessary by checking backwards from the atomically + * updated "tail" when a node's successor appears to be null. + * (Or, said differently, the next-links are an optimization + * so that we don't usually need a backward scan.) + * + * <p>Cancellation introduces some conservatism to the basic + * algorithms. Since we must poll for cancellation of other + * nodes, we can miss noticing whether a cancelled node is + * ahead or behind us. This is dealt with by always unparking + * successors upon cancellation, allowing them to stabilize on + * a new predecessor, unless we can identify an uncancelled + * predecessor who will carry this responsibility. + * + * <p>CLH queues need a dummy header node to get started. But + * we don't create them on construction, because it would be wasted + * effort if there is never contention. Instead, the node + * is constructed and head and tail pointers are set upon first + * contention. + * + * <p>Threads waiting on Conditions use the same nodes, but + * use an additional link. Conditions only need to link nodes + * in simple (non-concurrent) linked queues because they are + * only accessed when exclusively held. Upon await, a node is + * inserted into a condition queue. Upon signal, the node is + * transferred to the main queue. A special value of status + * field is used to mark which queue a node is on. + * + * <p>Thanks go to Dave Dice, Mark Moir, Victor Luchangco, Bill + * Scherer and Michael Scott, along with members of JSR-166 + * expert group, for helpful ideas, discussions, and critiques + * on the design of this class. + */ + static final class Node { + /** Marker to indicate a node is waiting in shared mode */ + static final Node SHARED = new Node(); + /** Marker to indicate a node is waiting in exclusive mode */ + static final Node EXCLUSIVE = null; + + /** waitStatus value to indicate thread has cancelled */ + static final int CANCELLED = 1; + /** waitStatus value to indicate successor's thread needs unparking */ + static final int SIGNAL = -1; + /** waitStatus value to indicate thread is waiting on condition */ + static final int CONDITION = -2; + /** + * waitStatus value to indicate the next acquireShared should + * unconditionally propagate + */ + static final int PROPAGATE = -3; + + /** + * Status field, taking on only the values: + * SIGNAL: The successor of this node is (or will soon be) + * blocked (via park), so the current node must + * unpark its successor when it releases or + * cancels. To avoid races, acquire methods must + * first indicate they need a signal, + * then retry the atomic acquire, and then, + * on failure, block. + * CANCELLED: This node is cancelled due to timeout or interrupt. + * Nodes never leave this state. In particular, + * a thread with cancelled node never again blocks. + * CONDITION: This node is currently on a condition queue. + * It will not be used as a sync queue node + * until transferred, at which time the status + * will be set to 0. (Use of this value here has + * nothing to do with the other uses of the + * field, but simplifies mechanics.) + * PROPAGATE: A releaseShared should be propagated to other + * nodes. This is set (for head node only) in + * doReleaseShared to ensure propagation + * continues, even if other operations have + * since intervened. + * 0: None of the above + * + * The values are arranged numerically to simplify use. + * Non-negative values mean that a node doesn't need to + * signal. So, most code doesn't need to check for particular + * values, just for sign. + * + * The field is initialized to 0 for normal sync nodes, and + * CONDITION for condition nodes. It is modified using CAS + * (or when possible, unconditional volatile writes). + */ + volatile int waitStatus; + + /** + * Link to predecessor node that current node/thread relies on + * for checking waitStatus. Assigned during enqueing, and nulled + * out (for sake of GC) only upon dequeuing. Also, upon + * cancellation of a predecessor, we short-circuit while + * finding a non-cancelled one, which will always exist + * because the head node is never cancelled: A node becomes + * head only as a result of successful acquire. A + * cancelled thread never succeeds in acquiring, and a thread only + * cancels itself, not any other node. + */ + volatile Node prev; + + /** + * Link to the successor node that the current node/thread + * unparks upon release. Assigned during enqueuing, adjusted + * when bypassing cancelled predecessors, and nulled out (for + * sake of GC) when dequeued. The enq operation does not + * assign next field of a predecessor until after attachment, + * so seeing a null next field does not necessarily mean that + * node is at end of queue. However, if a next field appears + * to be null, we can scan prev's from the tail to + * double-check. The next field of cancelled nodes is set to + * point to the node itself instead of null, to make life + * easier for isOnSyncQueue. + */ + volatile Node next; + + /** + * The thread that enqueued this node. Initialized on + * construction and nulled out after use. + */ + volatile Thread thread; + + /** + * Link to next node waiting on condition, or the special + * value SHARED. Because condition queues are accessed only + * when holding in exclusive mode, we just need a simple + * linked queue to hold nodes while they are waiting on + * conditions. They are then transferred to the queue to + * re-acquire. And because conditions can only be exclusive, + * we save a field by using special value to indicate shared + * mode. + */ + Node nextWaiter; + + /** + * Returns true if node is waiting in shared mode + */ + final boolean isShared() { + return nextWaiter == SHARED; + } + + /** + * Returns previous node, or throws NullPointerException if null. + * Use when predecessor cannot be null. The null check could + * be elided, but is present to help the VM. + * + * @return the predecessor of this node + */ + final Node predecessor() throws NullPointerException { + Node p = prev; + if (p == null) + throw new NullPointerException(); + else + return p; + } + + Node() { // Used to establish initial head or SHARED marker + } + + Node(Thread thread, Node mode) { // Used by addWaiter + this.nextWaiter = mode; + this.thread = thread; + } + + Node(Thread thread, int waitStatus) { // Used by Condition + this.waitStatus = waitStatus; + this.thread = thread; + } + } + + /** + * Head of the wait queue, lazily initialized. Except for + * initialization, it is modified only via method setHead. Note: + * If head exists, its waitStatus is guaranteed not to be + * CANCELLED. + */ + private transient volatile Node head; + + /** + * Tail of the wait queue, lazily initialized. Modified only via + * method enq to add new wait node. + */ + private transient volatile Node tail; + + /** + * The synchronization state. + */ + private volatile long state; + + /** + * Returns the current value of synchronization state. + * This operation has memory semantics of a <tt>volatile</tt> read. + * @return current state value + */ + protected final long getState() { + return state; + } + + /** + * Sets the value of synchronization state. + * This operation has memory semantics of a <tt>volatile</tt> write. + * @param newState the new state value + */ + protected final void setState(long newState) { + state = newState; + } + + /** + * Atomically sets synchronization state to the given updated + * value if the current state value equals the expected value. + * This operation has memory semantics of a <tt>volatile</tt> read + * and write. + * + * @param expect the expected value + * @param update the new value + * @return true if successful. False return indicates that the actual + * value was not equal to the expected value. + */ + protected final boolean compareAndSetState(long expect, long update) { + // See below for intrinsics setup to support this + return unsafe.compareAndSwapLong(this, stateOffset, expect, update); + } + + // Queuing utilities + + /** + * The number of nanoseconds for which it is faster to spin + * rather than to use timed park. A rough estimate suffices + * to improve responsiveness with very short timeouts. + */ + static final long spinForTimeoutThreshold = 1000L; + + /** + * Inserts node into queue, initializing if necessary. See picture above. + * @param node the node to insert + * @return node's predecessor + */ + private Node enq(final Node node) { + for (;;) { + Node t = tail; + if (t == null) { // Must initialize + if (compareAndSetHead(new Node())) + tail = head; + } else { + node.prev = t; + if (compareAndSetTail(t, node)) { + t.next = node; + return t; + } + } + } + } + + /** + * Creates and enqueues node for current thread and given mode. + * + * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared + * @return the new node + */ + private Node addWaiter(Node mode) { + Node node = new Node(Thread.currentThread(), mode); + // Try the fast path of enq; backup to full enq on failure + Node pred = tail; + if (pred != null) { + node.prev = pred; + if (compareAndSetTail(pred, node)) { + pred.next = node; + return node; + } + } + enq(node); + return node; + } + + /** + * Sets head of queue to be node, thus dequeuing. Called only by + * acquire methods. Also nulls out unused fields for sake of GC + * and to suppress unnecessary signals and traversals. + * + * @param node the node + */ + private void setHead(Node node) { + head = node; + node.thread = null; + node.prev = null; + } + + /** + * Wakes up node's successor, if one exists. + * + * @param node the node + */ + private void unparkSuccessor(Node node) { + /* + * If status is negative (i.e., possibly needing signal) try + * to clear in anticipation of signalling. It is OK if this + * fails or if status is changed by waiting thread. + */ + int ws = node.waitStatus; + if (ws < 0) + compareAndSetWaitStatus(node, ws, 0); + + /* + * Thread to unpark is held in successor, which is normally + * just the next node. But if cancelled or apparently null, + * traverse backwards from tail to find the actual + * non-cancelled successor. + */ + Node s = node.next; + if (s == null || s.waitStatus > 0) { + s = null; + for (Node t = tail; t != null && t != node; t = t.prev) + if (t.waitStatus <= 0) + s = t; + } + if (s != null) + LockSupport.unpark(s.thread); + } + + /** + * Release action for shared mode -- signal successor and ensure + * propagation. (Note: For exclusive mode, release just amounts + * to calling unparkSuccessor of head if it needs signal.) + */ + private void doReleaseShared() { + /* + * Ensure that a release propagates, even if there are other + * in-progress acquires/releases. This proceeds in the usual + * way of trying to unparkSuccessor of head if it needs + * signal. But if it does not, status is set to PROPAGATE to + * ensure that upon release, propagation continues. + * Additionally, we must loop in case a new node is added + * while we are doing this. Also, unlike other uses of + * unparkSuccessor, we need to know if CAS to reset status + * fails, if so rechecking. + */ + for (;;) { + Node h = head; + if (h != null && h != tail) { + int ws = h.waitStatus; + if (ws == Node.SIGNAL) { + if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0)) + continue; // loop to recheck cases + unparkSuccessor(h); + } + else if (ws == 0 && + !compareAndSetWaitStatus(h, 0, Node.PROPAGATE)) + continue; // loop on failed CAS + } + if (h == head) // loop if head changed + break; + } + } + + /** + * Sets head of queue, and checks if successor may be waiting + * in shared mode, if so propagating if either propagate > 0 or + * PROPAGATE status was set. + * + * @param node the node + * @param propagate the return value from a tryAcquireShared + */ + private void setHeadAndPropagate(Node node, long propagate) { + Node h = head; // Record old head for check below + setHead(node); + /* + * Try to signal next queued node if: + * Propagation was indicated by caller, + * or was recorded (as h.waitStatus) by a previous operation + * (note: this uses sign-check of waitStatus because + * PROPAGATE status may transition to SIGNAL.) + * and + * The next node is waiting in shared mode, + * or we don't know, because it appears null + * + * The conservatism in both of these checks may cause + * unnecessary wake-ups, but only when there are multiple + * racing acquires/releases, so most need signals now or soon + * anyway. + */ + if (propagate > 0 || h == null || h.waitStatus < 0) { + Node s = node.next; + if (s == null || s.isShared()) + doReleaseShared(); + } + } + + // Utilities for various versions of acquire + + /** + * Cancels an ongoing attempt to acquire. + * + * @param node the node + */ + private void cancelAcquire(Node node) { + // Ignore if node doesn't exist + if (node == null) + return; + + node.thread = null; + + // Skip cancelled predecessors + Node pred = node.prev; + while (pred.waitStatus > 0) + node.prev = pred = pred.prev; + + // predNext is the apparent node to unsplice. CASes below will + // fail if not, in which case, we lost race vs another cancel + // or signal, so no further action is necessary. + Node predNext = pred.next; + + // Can use unconditional write instead of CAS here. + // After this atomic step, other Nodes can skip past us. + // Before, we are free of interference from other threads. + node.waitStatus = Node.CANCELLED; + + // If we are the tail, remove ourselves. + if (node == tail && compareAndSetTail(node, pred)) { + compareAndSetNext(pred, predNext, null); + } else { + // If successor needs signal, try to set pred's next-link + // so it will get one. Otherwise wake it up to propagate. + int ws; + if (pred != head && + ((ws = pred.waitStatus) == Node.SIGNAL || + (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) && + pred.thread != null) { + Node next = node.next; + if (next != null && next.waitStatus <= 0) + compareAndSetNext(pred, predNext, next); + } else { + unparkSuccessor(node); + } + + node.next = node; // help GC + } + } + + /** + * Checks and updates status for a node that failed to acquire. + * Returns true if thread should block. This is the main signal + * control in all acquire loops. Requires that pred == node.prev + * + * @param pred node's predecessor holding status + * @param node the node + * @return {@code true} if thread should block + */ + private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) { + int ws = pred.waitStatus; + if (ws == Node.SIGNAL) + /* + * This node has already set status asking a release + * to signal it, so it can safely park. + */ + return true; + if (ws > 0) { + /* + * Predecessor was cancelled. Skip over predecessors and + * indicate retry. + */ + do { + node.prev = pred = pred.prev; + } while (pred.waitStatus > 0); + pred.next = node; + } else { + /* + * waitStatus must be 0 or PROPAGATE. Indicate that we + * need a signal, but don't park yet. Caller will need to + * retry to make sure it cannot acquire before parking. + */ + compareAndSetWaitStatus(pred, ws, Node.SIGNAL); + } + return false; + } + + /** + * Convenience method to interrupt current thread. + */ + private static void selfInterrupt() { + Thread.currentThread().interrupt(); + } + + /** + * Convenience method to park and then check if interrupted + * + * @return {@code true} if interrupted + */ + private final boolean parkAndCheckInterrupt() { + LockSupport.park(this); + return Thread.interrupted(); + } + + /* + * Various flavors of acquire, varying in exclusive/shared and + * control modes. Each is mostly the same, but annoyingly + * different. Only a little bit of factoring is possible due to + * interactions of exception mechanics (including ensuring that we + * cancel if tryAcquire throws exception) and other control, at + * least not without hurting performance too much. + */ + + /** + * Acquires in exclusive uninterruptible mode for thread already in + * queue. Used by condition wait methods as well as acquire. + * + * @param node the node + * @param arg the acquire argument + * @return {@code true} if interrupted while waiting + */ + final boolean acquireQueued(final Node node, long arg) { + boolean failed = true; + try { + boolean interrupted = false; + for (;;) { + final Node p = node.predecessor(); + if (p == head && tryAcquire(arg)) { + setHead(node); + p.next = null; // help GC + failed = false; + return interrupted; + } + if (shouldParkAfterFailedAcquire(p, node) && + parkAndCheckInterrupt()) + interrupted = true; + } + } finally { + if (failed) + cancelAcquire(node); + } + } + + /** + * Acquires in exclusive interruptible mode. + * @param arg the acquire argument + */ + private void doAcquireInterruptibly(long arg) + throws InterruptedException { + final Node node = addWaiter(Node.EXCLUSIVE); + boolean failed = true; + try { + for (;;) { + final Node p = node.predecessor(); + if (p == head && tryAcquire(arg)) { + setHead(node); + p.next = null; // help GC + failed = false; + return; + } + if (shouldParkAfterFailedAcquire(p, node) && + parkAndCheckInterrupt()) + throw new InterruptedException(); + } + } finally { + if (failed) + cancelAcquire(node); + } + } + + /** + * Acquires in exclusive timed mode. + * + * @param arg the acquire argument + * @param nanosTimeout max wait time + * @return {@code true} if acquired + */ + private boolean doAcquireNanos(long arg, long nanosTimeout) + throws InterruptedException { + long lastTime = System.nanoTime(); + final Node node = addWaiter(Node.EXCLUSIVE); + boolean failed = true; + try { + for (;;) { + final Node p = node.predecessor(); + if (p == head && tryAcquire(arg)) { + setHead(node); + p.next = null; // help GC + failed = false; + return true; + } + if (nanosTimeout <= 0) + return false; + if (shouldParkAfterFailedAcquire(p, node) && + nanosTimeout > spinForTimeoutThreshold) + LockSupport.parkNanos(this, nanosTimeout); + long now = System.nanoTime(); + nanosTimeout -= now - lastTime; + lastTime = now; + if (Thread.interrupted()) + throw new InterruptedException(); + } + } finally { + if (failed) + cancelAcquire(node); + } + } + + /** + * Acquires in shared uninterruptible mode. + * @param arg the acquire argument + */ + private void doAcquireShared(long arg) { + final Node node = addWaiter(Node.SHARED); + boolean failed = true; + try { + boolean interrupted = false; + for (;;) { + final Node p = node.predecessor(); + if (p == head) { + long r = tryAcquireShared(arg); + if (r >= 0) { + setHeadAndPropagate(node, r); + p.next = null; // help GC + if (interrupted) + selfInterrupt(); + failed = false; + return; + } + } + if (shouldParkAfterFailedAcquire(p, node) && + parkAndCheckInterrupt()) + interrupted = true; + } + } finally { + if (failed) + cancelAcquire(node); + } + } + + /** + * Acquires in shared interruptible mode. + * @param arg the acquire argument + */ + private void doAcquireSharedInterruptibly(long arg) + throws InterruptedException { + final Node node = addWaiter(Node.SHARED); + boolean failed = true; + try { + for (;;) { + final Node p = node.predecessor(); + if (p == head) { + long r = tryAcquireShared(arg); + if (r >= 0) { + setHeadAndPropagate(node, r); + p.next = null; // help GC + failed = false; + return; + } + } + if (shouldParkAfterFailedAcquire(p, node) && + parkAndCheckInterrupt()) + throw new InterruptedException(); + } + } finally { + if (failed) + cancelAcquire(node); + } + } + + /** + * Acquires in shared timed mode. + * + * @param arg the acquire argument + * @param nanosTimeout max wait time + * @return {@code true} if acquired + */ + private boolean doAcquireSharedNanos(long arg, long nanosTimeout) + throws InterruptedException { + + long lastTime = System.nanoTime(); + final Node node = addWaiter(Node.SHARED); + boolean failed = true; + try { + for (;;) { + final Node p = node.predecessor(); + if (p == head) { + long r = tryAcquireShared(arg); + if (r >= 0) { + setHeadAndPropagate(node, r); + p.next = null; // help GC + failed = false; + return true; + } + } + if (nanosTimeout <= 0) + return false; + if (shouldParkAfterFailedAcquire(p, node) && + nanosTimeout > spinForTimeoutThreshold) + LockSupport.parkNanos(this, nanosTimeout); + long now = System.nanoTime(); + nanosTimeout -= now - lastTime; + lastTime = now; + if (Thread.interrupted()) + throw new InterruptedException(); + } + } finally { + if (failed) + cancelAcquire(node); + } + } + + // Main exported methods + + /** + * Attempts to acquire in exclusive mode. This method should query + * if the state of the object permits it to be acquired in the + * exclusive mode, and if so to acquire it. + * + * <p>This method is always invoked by the thread performing + * acquire. If this method reports failure, the acquire method + * may queue the thread, if it is not already queued, until it is + * signalled by a release from some other thread. This can be used + * to implement method {@link Lock#tryLock()}. + * + * <p>The default + * implementation throws {@link UnsupportedOperationException}. + * + * @param arg the acquire argument. This value is always the one + * passed to an acquire method, or is the value saved on entry + * to a condition wait. The value is otherwise uninterpreted + * and can represent anything you like. + * @return {@code true} if successful. Upon success, this object has + * been acquired. + * @throws IllegalMonitorStateException if acquiring would place this + * synchronizer in an illegal state. This exception must be + * thrown in a consistent fashion for synchronization to work + * correctly. + * @throws UnsupportedOperationException if exclusive mode is not supported + */ + protected boolean tryAcquire(long arg) { + throw new UnsupportedOperationException(); + } + + /** + * Attempts to set the state to reflect a release in exclusive + * mode. + * + * <p>This method is always invoked by the thread performing release. + * + * <p>The default implementation throws + * {@link UnsupportedOperationException}. + * + * @param arg the release argument. This value is always the one + * passed to a release method, or the current state value upon + * entry to a condition wait. The value is otherwise + * uninterpreted and can represent anything you like. + * @return {@code true} if this object is now in a fully released + * state, so that any waiting threads may attempt to acquire; + * and {@code false} otherwise. + * @throws IllegalMonitorStateException if releasing would place this + * synchronizer in an illegal state. This exception must be + * thrown in a consistent fashion for synchronization to work + * correctly. + * @throws UnsupportedOperationException if exclusive mode is not supported + */ + protected boolean tryRelease(long arg) { + throw new UnsupportedOperationException(); + } + + /** + * Attempts to acquire in shared mode. This method should query if + * the state of the object permits it to be acquired in the shared + * mode, and if so to acquire it. + * + * <p>This method is always invoked by the thread performing + * acquire. If this method reports failure, the acquire method + * may queue the thread, if it is not already queued, until it is + * signalled by a release from some other thread. + * + * <p>The default implementation throws {@link + * UnsupportedOperationException}. + * + * @param arg the acquire argument. This value is always the one + * passed to an acquire method, or is the value saved on entry + * to a condition wait. The value is otherwise uninterpreted + * and can represent anything you like. + * @return a negative value on failure; zero if acquisition in shared + * mode succeeded but no subsequent shared-mode acquire can + * succeed; and a positive value if acquisition in shared + * mode succeeded and subsequent shared-mode acquires might + * also succeed, in which case a subsequent waiting thread + * must check availability. (Support for three different + * return values enables this method to be used in contexts + * where acquires only sometimes act exclusively.) Upon + * success, this object has been acquired. + * @throws IllegalMonitorStateException if acquiring would place this + * synchronizer in an illegal state. This exception must be + * thrown in a consistent fashion for synchronization to work + * correctly. + * @throws UnsupportedOperationException if shared mode is not supported + */ + protected long tryAcquireShared(long arg) { + throw new UnsupportedOperationException(); + } + + /** + * Attempts to set the state to reflect a release in shared mode. + * + * <p>This method is always invoked by the thread performing release. + * + * <p>The default implementation throws + * {@link UnsupportedOperationException}. + * + * @param arg the release argument. This value is always the one + * passed to a release method, or the current state value upon + * entry to a condition wait. The value is otherwise + * uninterpreted and can represent anything you like. + * @return {@code true} if this release of shared mode may permit a + * waiting acquire (shared or exclusive) to succeed; and + * {@code false} otherwise + * @throws IllegalMonitorStateException if releasing would place this + * synchronizer in an illegal state. This exception must be + * thrown in a consistent fashion for synchronization to work + * correctly. + * @throws UnsupportedOperationException if shared mode is not supported + */ + protected boolean tryReleaseShared(long arg) { + throw new UnsupportedOperationException(); + } + + /** + * Returns {@code true} if synchronization is held exclusively with + * respect to the current (calling) thread. This method is invoked + * upon each call to a non-waiting {@link ConditionObject} method. + * (Waiting methods instead invoke {@link #release}.) + * + * <p>The default implementation throws {@link + * UnsupportedOperationException}. This method is invoked + * internally only within {@link ConditionObject} methods, so need + * not be defined if conditions are not used. + * + * @return {@code true} if synchronization is held exclusively; + * {@code false} otherwise + * @throws UnsupportedOperationException if conditions are not supported + */ + protected boolean isHeldExclusively() { + throw new UnsupportedOperationException(); + } + + /** + * Acquires in exclusive mode, ignoring interrupts. Implemented + * by invoking at least once {@link #tryAcquire}, + * returning on success. Otherwise the thread is queued, possibly + * repeatedly blocking and unblocking, invoking {@link + * #tryAcquire} until success. This method can be used + * to implement method {@link Lock#lock}. + * + * @param arg the acquire argument. This value is conveyed to + * {@link #tryAcquire} but is otherwise uninterpreted and + * can represent anything you like. + */ + public final void acquire(long arg) { + if (!tryAcquire(arg) && + acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) + selfInterrupt(); + } + + /** + * Acquires in exclusive mode, aborting if interrupted. + * Implemented by first checking interrupt status, then invoking + * at least once {@link #tryAcquire}, returning on + * success. Otherwise the thread is queued, possibly repeatedly + * blocking and unblocking, invoking {@link #tryAcquire} + * until success or the thread is interrupted. This method can be + * used to implement method {@link Lock#lockInterruptibly}. + * + * @param arg the acquire argument. This value is conveyed to + * {@link #tryAcquire} but is otherwise uninterpreted and + * can represent anything you like. + * @throws InterruptedException if the current thread is interrupted + */ + public final void acquireInterruptibly(long arg) throws InterruptedException { + if (Thread.interrupted()) + throw new InterruptedException(); + if (!tryAcquire(arg)) + doAcquireInterruptibly(arg); + } + + /** + * Attempts to acquire in exclusive mode, aborting if interrupted, + * and failing if the given timeout elapses. Implemented by first + * checking interrupt status, then invoking at least once {@link + * #tryAcquire}, returning on success. Otherwise, the thread is + * queued, possibly repeatedly blocking and unblocking, invoking + * {@link #tryAcquire} until success or the thread is interrupted + * or the timeout elapses. This method can be used to implement + * method {@link Lock#tryLock(long, TimeUnit)}. + * + * @param arg the acquire argument. This value is conveyed to + * {@link #tryAcquire} but is otherwise uninterpreted and + * can represent anything you like. + * @param nanosTimeout the maximum number of nanoseconds to wait + * @return {@code true} if acquired; {@code false} if timed out + * @throws InterruptedException if the current thread is interrupted + */ + public final boolean tryAcquireNanos(long arg, long nanosTimeout) throws InterruptedException { + if (Thread.interrupted()) + throw new InterruptedException(); + return tryAcquire(arg) || + doAcquireNanos(arg, nanosTimeout); + } + + /** + * Releases in exclusive mode. Implemented by unblocking one or + * more threads if {@link #tryRelease} returns true. + * This method can be used to implement method {@link Lock#unlock}. + * + * @param arg the release argument. This value is conveyed to + * {@link #tryRelease} but is otherwise uninterpreted and + * can represent anything you like. + * @return the value returned from {@link #tryRelease} + */ + public final boolean release(long arg) { + if (tryRelease(arg)) { + Node h = head; + if (h != null && h.waitStatus != 0) + unparkSuccessor(h); + return true; + } + return false; + } + + /** + * Acquires in shared mode, ignoring interrupts. Implemented by + * first invoking at least once {@link #tryAcquireShared}, + * returning on success. Otherwise the thread is queued, possibly + * repeatedly blocking and unblocking, invoking {@link + * #tryAcquireShared} until success. + * + * @param arg the acquire argument. This value is conveyed to + * {@link #tryAcquireShared} but is otherwise uninterpreted + * and can represent anything you like. + */ + public final void acquireShared(long arg) { + if (tryAcquireShared(arg) < 0) + doAcquireShared(arg); + } + + /** + * Acquires in shared mode, aborting if interrupted. Implemented + * by first checking interrupt status, then invoking at least once + * {@link #tryAcquireShared}, returning on success. Otherwise the + * thread is queued, possibly repeatedly blocking and unblocking, + * invoking {@link #tryAcquireShared} until success or the thread + * is interrupted. + * @param arg the acquire argument + * This value is conveyed to {@link #tryAcquireShared} but is + * otherwise uninterpreted and can represent anything + * you like. + * @throws InterruptedException if the current thread is interrupted + */ + public final void acquireSharedInterruptibly(long arg) throws InterruptedException { + if (Thread.interrupted()) + throw new InterruptedException(); + if (tryAcquireShared(arg) < 0) + doAcquireSharedInterruptibly(arg); + } + + /** + * Attempts to acquire in shared mode, aborting if interrupted, and + * failing if the given timeout elapses. Implemented by first + * checking interrupt status, then invoking at least once {@link + * #tryAcquireShared}, returning on success. Otherwise, the + * thread is queued, possibly repeatedly blocking and unblocking, + * invoking {@link #tryAcquireShared} until success or the thread + * is interrupted or the timeout elapses. + * + * @param arg the acquire argument. This value is conveyed to + * {@link #tryAcquireShared} but is otherwise uninterpreted + * and can represent anything you like. + * @param nanosTimeout the maximum number of nanoseconds to wait + * @return {@code true} if acquired; {@code false} if timed out + * @throws InterruptedException if the current thread is interrupted + */ + public final boolean tryAcquireSharedNanos(long arg, long nanosTimeout) throws InterruptedException { + if (Thread.interrupted()) + throw new InterruptedException(); + return tryAcquireShared(arg) >= 0 || + doAcquireSharedNanos(arg, nanosTimeout); + } + + /** + * Releases in shared mode. Implemented by unblocking one or more + * threads if {@link #tryReleaseShared} returns true. + * + * @param arg the release argument. This value is conveyed to + * {@link #tryReleaseShared} but is otherwise uninterpreted + * and can represent anything you like. + * @return the value returned from {@link #tryReleaseShared} + */ + public final boolean releaseShared(long arg) { + if (tryReleaseShared(arg)) { + doReleaseShared(); + return true; + } + return false; + } + + // Queue inspection methods + + /** + * Queries whether any threads are waiting to acquire. Note that + * because cancellations due to interrupts and timeouts may occur + * at any time, a {@code true} return does not guarantee that any + * other thread will ever acquire. + * + * <p>In this implementation, this operation returns in + * constant time. + * + * @return {@code true} if there may be other threads waiting to acquire + */ + public final boolean hasQueuedThreads() { + return head != tail; + } + + /** + * Queries whether any threads have ever contended to acquire this + * synchronizer; that is if an acquire method has ever blocked. + * + * <p>In this implementation, this operation returns in + * constant time. + * + * @return {@code true} if there has ever been contention + */ + public final boolean hasContended() { + return head != null; + } + + /** + * Returns the first (longest-waiting) thread in the queue, or + * {@code null} if no threads are currently queued. + * + * <p>In this implementation, this operation normally returns in + * constant time, but may iterate upon contention if other threads are + * concurrently modifying the queue. + * + * @return the first (longest-waiting) thread in the queue, or + * {@code null} if no threads are currently queued + */ + public final Thread getFirstQueuedThread() { + // handle only fast path, else relay + return (head == tail) ? null : fullGetFirstQueuedThread(); + } + + /** + * Version of getFirstQueuedThread called when fastpath fails + */ + private Thread fullGetFirstQueuedThread() { + /* + * The first node is normally head.next. Try to get its + * thread field, ensuring consistent reads: If thread + * field is nulled out or s.prev is no longer head, then + * some other thread(s) concurrently performed setHead in + * between some of our reads. We try this twice before + * resorting to traversal. + */ + Node h, s; + Thread st; + if (((h = head) != null && (s = h.next) != null && + s.prev == head && (st = s.thread) != null) || + ((h = head) != null && (s = h.next) != null && + s.prev == head && (st = s.thread) != null)) + return st; + + /* + * Head's next field might not have been set yet, or may have + * been unset after setHead. So we must check to see if tail + * is actually first node. If not, we continue on, safely + * traversing from tail back to head to find first, + * guaranteeing termination. + */ + + Node t = tail; + Thread firstThread = null; + while (t != null && t != head) { + Thread tt = t.thread; + if (tt != null) + firstThread = tt; + t = t.prev; + } + return firstThread; + } + + /** + * Returns true if the given thread is currently queued. + * + * <p>This implementation traverses the queue to determine + * presence of the given thread. + * + * @param thread the thread + * @return {@code true} if the given thread is on the queue + * @throws NullPointerException if the thread is null + */ + public final boolean isQueued(Thread thread) { + if (thread == null) + throw new NullPointerException(); + for (Node p = tail; p != null; p = p.prev) + if (p.thread == thread) + return true; + return false; + } + + /** + * Returns {@code true} if the apparent first queued thread, if one + * exists, is waiting in exclusive mode. If this method returns + * {@code true}, and the current thread is attempting to acquire in + * shared mode (that is, this method is invoked from {@link + * #tryAcquireShared}) then it is guaranteed that the current thread + * is not the first queued thread. Used only as a heuristic in + * ReentrantReadWriteLock. + */ + final boolean apparentlyFirstQueuedIsExclusive() { + Node h, s; + return (h = head) != null && + (s = h.next) != null && + !s.isShared() && + s.thread != null; + } + + /** + * Queries whether any threads have been waiting to acquire longer + * than the current thread. + * + * <p>An invocation of this method is equivalent to (but may be + * more efficient than): + * <pre> {@code + * getFirstQueuedThread() != Thread.currentThread() && + * hasQueuedThreads()}</pre> + * + * <p>Note that because cancellations due to interrupts and + * timeouts may occur at any time, a {@code true} return does not + * guarantee that some other thread will acquire before the current + * thread. Likewise, it is possible for another thread to win a + * race to enqueue after this method has returned {@code false}, + * due to the queue being empty. + * + * <p>This method is designed to be used by a fair synchronizer to + * avoid <a href="AbstractQueuedSynchronizer#barging">barging</a>. + * Such a synchronizer's {@link #tryAcquire} method should return + * {@code false}, and its {@link #tryAcquireShared} method should + * return a negative value, if this method returns {@code true} + * (unless this is a reentrant acquire). For example, the {@code + * tryAcquire} method for a fair, reentrant, exclusive mode + * synchronizer might look like this: + * + * <pre> {@code + * protected boolean tryAcquire(int arg) { + * if (isHeldExclusively()) { + * // A reentrant acquire; increment hold count + * return true; + * } else if (hasQueuedPredecessors()) { + * return false; + * } else { + * // try to acquire normally + * } + * }}</pre> + * + * @return {@code true} if there is a queued thread preceding the + * current thread, and {@code false} if the current thread + * is at the head of the queue or the queue is empty + * @since 1.7 + */ + /*public*/ final boolean hasQueuedPredecessors() { // android-changed + // The correctness of this depends on head being initialized + // before tail and on head.next being accurate if the current + // thread is first in queue. + Node t = tail; // Read fields in reverse initialization order + Node h = head; + Node s; + return h != t && + ((s = h.next) == null || s.thread != Thread.currentThread()); + } + + + // Instrumentation and monitoring methods + + /** + * Returns an estimate of the number of threads waiting to + * acquire. The value is only an estimate because the number of + * threads may change dynamically while this method traverses + * internal data structures. This method is designed for use in + * monitoring system state, not for synchronization + * control. + * + * @return the estimated number of threads waiting to acquire + */ + public final int getQueueLength() { + int n = 0; + for (Node p = tail; p != null; p = p.prev) { + if (p.thread != null) + ++n; + } + return n; + } + + /** + * Returns a collection containing threads that may be waiting to + * acquire. Because the actual set of threads may change + * dynamically while constructing this result, the returned + * collection is only a best-effort estimate. The elements of the + * returned collection are in no particular order. This method is + * designed to facilitate construction of subclasses that provide + * more extensive monitoring facilities. + * + * @return the collection of threads + */ + public final Collection<Thread> getQueuedThreads() { + ArrayList<Thread> list = new ArrayList<Thread>(); + for (Node p = tail; p != null; p = p.prev) { + Thread t = p.thread; + if (t != null) + list.add(t); + } + return list; + } + + /** + * Returns a collection containing threads that may be waiting to + * acquire in exclusive mode. This has the same properties + * as {@link #getQueuedThreads} except that it only returns + * those threads waiting due to an exclusive acquire. + * + * @return the collection of threads + */ + public final Collection<Thread> getExclusiveQueuedThreads() { + ArrayList<Thread> list = new ArrayList<Thread>(); + for (Node p = tail; p != null; p = p.prev) { + if (!p.isShared()) { + Thread t = p.thread; + if (t != null) + list.add(t); + } + } + return list; + } + + /** + * Returns a collection containing threads that may be waiting to + * acquire in shared mode. This has the same properties + * as {@link #getQueuedThreads} except that it only returns + * those threads waiting due to a shared acquire. + * + * @return the collection of threads + */ + public final Collection<Thread> getSharedQueuedThreads() { + ArrayList<Thread> list = new ArrayList<Thread>(); + for (Node p = tail; p != null; p = p.prev) { + if (p.isShared()) { + Thread t = p.thread; + if (t != null) + list.add(t); + } + } + return list; + } + + /** + * Returns a string identifying this synchronizer, as well as its state. + * The state, in brackets, includes the String {@code "State ="} + * followed by the current value of {@link #getState}, and either + * {@code "nonempty"} or {@code "empty"} depending on whether the + * queue is empty. + * + * @return a string identifying this synchronizer, as well as its state + */ + public String toString() { + long s = getState(); + String q = hasQueuedThreads() ? "non" : ""; + return super.toString() + + "[State = " + s + ", " + q + "empty queue]"; + } + + + // Internal support methods for Conditions + + /** + * Returns true if a node, always one that was initially placed on + * a condition queue, is now waiting to reacquire on sync queue. + * @param node the node + * @return true if is reacquiring + */ + final boolean isOnSyncQueue(Node node) { + if (node.waitStatus == Node.CONDITION || node.prev == null) + return false; + if (node.next != null) // If has successor, it must be on queue + return true; + /* + * node.prev can be non-null, but not yet on queue because + * the CAS to place it on queue can fail. So we have to + * traverse from tail to make sure it actually made it. It + * will always be near the tail in calls to this method, and + * unless the CAS failed (which is unlikely), it will be + * there, so we hardly ever traverse much. + */ + return findNodeFromTail(node); + } + + /** + * Returns true if node is on sync queue by searching backwards from tail. + * Called only when needed by isOnSyncQueue. + * @return true if present + */ + private boolean findNodeFromTail(Node node) { + Node t = tail; + for (;;) { + if (t == node) + return true; + if (t == null) + return false; + t = t.prev; + } + } + + /** + * Transfers a node from a condition queue onto sync queue. + * Returns true if successful. + * @param node the node + * @return true if successfully transferred (else the node was + * cancelled before signal). + */ + final boolean transferForSignal(Node node) { + /* + * If cannot change waitStatus, the node has been cancelled. + */ + if (!compareAndSetWaitStatus(node, Node.CONDITION, 0)) + return false; + + /* + * Splice onto queue and try to set waitStatus of predecessor to + * indicate that thread is (probably) waiting. If cancelled or + * attempt to set waitStatus fails, wake up to resync (in which + * case the waitStatus can be transiently and harmlessly wrong). + */ + Node p = enq(node); + int ws = p.waitStatus; + if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL)) + LockSupport.unpark(node.thread); + return true; + } + + /** + * Transfers node, if necessary, to sync queue after a cancelled + * wait. Returns true if thread was cancelled before being + * signalled. + * @param current the waiting thread + * @param node its node + * @return true if cancelled before the node was signalled + */ + final boolean transferAfterCancelledWait(Node node) { + if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) { + enq(node); + return true; + } + /* + * If we lost out to a signal(), then we can't proceed + * until it finishes its enq(). Cancelling during an + * incomplete transfer is both rare and transient, so just + * spin. + */ + while (!isOnSyncQueue(node)) + Thread.yield(); + return false; + } + + /** + * Invokes release with current state value; returns saved state. + * Cancels node and throws exception on failure. + * @param node the condition node for this wait + * @return previous sync state + */ + final long fullyRelease(Node node) { + boolean failed = true; + try { + long savedState = getState(); + if (release(savedState)) { + failed = false; + return savedState; + } else { + throw new IllegalMonitorStateException(); + } + } finally { + if (failed) + node.waitStatus = Node.CANCELLED; + } + } + + // Instrumentation methods for conditions + + /** + * Queries whether the given ConditionObject + * uses this synchronizer as its lock. + * + * @param condition the condition + * @return <tt>true</tt> if owned + * @throws NullPointerException if the condition is null + */ + public final boolean owns(ConditionObject condition) { + if (condition == null) + throw new NullPointerException(); + return condition.isOwnedBy(this); + } + + /** + * Queries whether any threads are waiting on the given condition + * associated with this synchronizer. Note that because timeouts + * and interrupts may occur at any time, a <tt>true</tt> return + * does not guarantee that a future <tt>signal</tt> will awaken + * any threads. This method is designed primarily for use in + * monitoring of the system state. + * + * @param condition the condition + * @return <tt>true</tt> if there are any waiting threads + * @throws IllegalMonitorStateException if exclusive synchronization + * is not held + * @throws IllegalArgumentException if the given condition is + * not associated with this synchronizer + * @throws NullPointerException if the condition is null + */ + public final boolean hasWaiters(ConditionObject condition) { + if (!owns(condition)) + throw new IllegalArgumentException("Not owner"); + return condition.hasWaiters(); + } + + /** + * Returns an estimate of the number of threads waiting on the + * given condition associated with this synchronizer. Note that + * because timeouts and interrupts may occur at any time, the + * estimate serves only as an upper bound on the actual number of + * waiters. This method is designed for use in monitoring of the + * system state, not for synchronization control. + * + * @param condition the condition + * @return the estimated number of waiting threads + * @throws IllegalMonitorStateException if exclusive synchronization + * is not held + * @throws IllegalArgumentException if the given condition is + * not associated with this synchronizer + * @throws NullPointerException if the condition is null + */ + public final int getWaitQueueLength(ConditionObject condition) { + if (!owns(condition)) + throw new IllegalArgumentException("Not owner"); + return condition.getWaitQueueLength(); + } + + /** + * Returns a collection containing those threads that may be + * waiting on the given condition associated with this + * synchronizer. Because the actual set of threads may change + * dynamically while constructing this result, the returned + * collection is only a best-effort estimate. The elements of the + * returned collection are in no particular order. + * + * @param condition the condition + * @return the collection of threads + * @throws IllegalMonitorStateException if exclusive synchronization + * is not held + * @throws IllegalArgumentException if the given condition is + * not associated with this synchronizer + * @throws NullPointerException if the condition is null + */ + public final Collection<Thread> getWaitingThreads(ConditionObject condition) { + if (!owns(condition)) + throw new IllegalArgumentException("Not owner"); + return condition.getWaitingThreads(); + } + + /** + * Condition implementation for a {@link + * AbstractQueuedLongSynchronizer} serving as the basis of a {@link + * Lock} implementation. + * + * <p>Method documentation for this class describes mechanics, + * not behavioral specifications from the point of view of Lock + * and Condition users. Exported versions of this class will in + * general need to be accompanied by documentation describing + * condition semantics that rely on those of the associated + * <tt>AbstractQueuedLongSynchronizer</tt>. + * + * <p>This class is Serializable, but all fields are transient, + * so deserialized conditions have no waiters. + * + * @since 1.6 + */ + public class ConditionObject implements Condition, java.io.Serializable { + private static final long serialVersionUID = 1173984872572414699L; + /** First node of condition queue. */ + private transient Node firstWaiter; + /** Last node of condition queue. */ + private transient Node lastWaiter; + + /** + * Creates a new <tt>ConditionObject</tt> instance. + */ + public ConditionObject() { } + + // Internal methods + + /** + * Adds a new waiter to wait queue. + * @return its new wait node + */ + private Node addConditionWaiter() { + Node t = lastWaiter; + // If lastWaiter is cancelled, clean out. + if (t != null && t.waitStatus != Node.CONDITION) { + unlinkCancelledWaiters(); + t = lastWaiter; + } + Node node = new Node(Thread.currentThread(), Node.CONDITION); + if (t == null) + firstWaiter = node; + else + t.nextWaiter = node; + lastWaiter = node; + return node; + } + + /** + * Removes and transfers nodes until hit non-cancelled one or + * null. Split out from signal in part to encourage compilers + * to inline the case of no waiters. + * @param first (non-null) the first node on condition queue + */ + private void doSignal(Node first) { + do { + if ( (firstWaiter = first.nextWaiter) == null) + lastWaiter = null; + first.nextWaiter = null; + } while (!transferForSignal(first) && + (first = firstWaiter) != null); + } + + /** + * Removes and transfers all nodes. + * @param first (non-null) the first node on condition queue + */ + private void doSignalAll(Node first) { + lastWaiter = firstWaiter = null; + do { + Node next = first.nextWaiter; + first.nextWaiter = null; + transferForSignal(first); + first = next; + } while (first != null); + } + + /** + * Unlinks cancelled waiter nodes from condition queue. + * Called only while holding lock. This is called when + * cancellation occurred during condition wait, and upon + * insertion of a new waiter when lastWaiter is seen to have + * been cancelled. This method is needed to avoid garbage + * retention in the absence of signals. So even though it may + * require a full traversal, it comes into play only when + * timeouts or cancellations occur in the absence of + * signals. It traverses all nodes rather than stopping at a + * particular target to unlink all pointers to garbage nodes + * without requiring many re-traversals during cancellation + * storms. + */ + private void unlinkCancelledWaiters() { + Node t = firstWaiter; + Node trail = null; + while (t != null) { + Node next = t.nextWaiter; + if (t.waitStatus != Node.CONDITION) { + t.nextWaiter = null; + if (trail == null) + firstWaiter = next; + else + trail.nextWaiter = next; + if (next == null) + lastWaiter = trail; + } + else + trail = t; + t = next; + } + } + + // public methods + + /** + * Moves the longest-waiting thread, if one exists, from the + * wait queue for this condition to the wait queue for the + * owning lock. + * + * @throws IllegalMonitorStateException if {@link #isHeldExclusively} + * returns {@code false} + */ + public final void signal() { + if (!isHeldExclusively()) + throw new IllegalMonitorStateException(); + Node first = firstWaiter; + if (first != null) + doSignal(first); + } + + /** + * Moves all threads from the wait queue for this condition to + * the wait queue for the owning lock. + * + * @throws IllegalMonitorStateException if {@link #isHeldExclusively} + * returns {@code false} + */ + public final void signalAll() { + if (!isHeldExclusively()) + throw new IllegalMonitorStateException(); + Node first = firstWaiter; + if (first != null) + doSignalAll(first); + } + + /** + * Implements uninterruptible condition wait. + * <ol> + * <li> Save lock state returned by {@link #getState}. + * <li> Invoke {@link #release} with + * saved state as argument, throwing + * IllegalMonitorStateException if it fails. + * <li> Block until signalled. + * <li> Reacquire by invoking specialized version of + * {@link #acquire} with saved state as argument. + * </ol> + */ + public final void awaitUninterruptibly() { + Node node = addConditionWaiter(); + long savedState = fullyRelease(node); + boolean interrupted = false; + while (!isOnSyncQueue(node)) { + LockSupport.park(this); + if (Thread.interrupted()) + interrupted = true; + } + if (acquireQueued(node, savedState) || interrupted) + selfInterrupt(); + } + + /* + * For interruptible waits, we need to track whether to throw + * InterruptedException, if interrupted while blocked on + * condition, versus reinterrupt current thread, if + * interrupted while blocked waiting to re-acquire. + */ + + /** Mode meaning to reinterrupt on exit from wait */ + private static final int REINTERRUPT = 1; + /** Mode meaning to throw InterruptedException on exit from wait */ + private static final int THROW_IE = -1; + + /** + * Checks for interrupt, returning THROW_IE if interrupted + * before signalled, REINTERRUPT if after signalled, or + * 0 if not interrupted. + */ + private int checkInterruptWhileWaiting(Node node) { + return Thread.interrupted() ? + (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) : + 0; + } + + /** + * Throws InterruptedException, reinterrupts current thread, or + * does nothing, depending on mode. + */ + private void reportInterruptAfterWait(int interruptMode) + throws InterruptedException { + if (interruptMode == THROW_IE) + throw new InterruptedException(); + else if (interruptMode == REINTERRUPT) + selfInterrupt(); + } + + /** + * Implements interruptible condition wait. + * <ol> + * <li> If current thread is interrupted, throw InterruptedException. + * <li> Save lock state returned by {@link #getState}. + * <li> Invoke {@link #release} with + * saved state as argument, throwing + * IllegalMonitorStateException if it fails. + * <li> Block until signalled or interrupted. + * <li> Reacquire by invoking specialized version of + * {@link #acquire} with saved state as argument. + * <li> If interrupted while blocked in step 4, throw InterruptedException. + * </ol> + */ + public final void await() throws InterruptedException { + if (Thread.interrupted()) + throw new InterruptedException(); + Node node = addConditionWaiter(); + long savedState = fullyRelease(node); + int interruptMode = 0; + while (!isOnSyncQueue(node)) { + LockSupport.park(this); + if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) + break; + } + if (acquireQueued(node, savedState) && interruptMode != THROW_IE) + interruptMode = REINTERRUPT; + if (node.nextWaiter != null) // clean up if cancelled + unlinkCancelledWaiters(); + if (interruptMode != 0) + reportInterruptAfterWait(interruptMode); + } + + /** + * Implements timed condition wait. + * <ol> + * <li> If current thread is interrupted, throw InterruptedException. + * <li> Save lock state returned by {@link #getState}. + * <li> Invoke {@link #release} with + * saved state as argument, throwing + * IllegalMonitorStateException if it fails. + * <li> Block until signalled, interrupted, or timed out. + * <li> Reacquire by invoking specialized version of + * {@link #acquire} with saved state as argument. + * <li> If interrupted while blocked in step 4, throw InterruptedException. + * </ol> + */ + public final long awaitNanos(long nanosTimeout) throws InterruptedException { + if (Thread.interrupted()) + throw new InterruptedException(); + Node node = addConditionWaiter(); + long savedState = fullyRelease(node); + long lastTime = System.nanoTime(); + int interruptMode = 0; + while (!isOnSyncQueue(node)) { + if (nanosTimeout <= 0L) { + transferAfterCancelledWait(node); + break; + } + LockSupport.parkNanos(this, nanosTimeout); + if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) + break; + + long now = System.nanoTime(); + nanosTimeout -= now - lastTime; + lastTime = now; + } + if (acquireQueued(node, savedState) && interruptMode != THROW_IE) + interruptMode = REINTERRUPT; + if (node.nextWaiter != null) + unlinkCancelledWaiters(); + if (interruptMode != 0) + reportInterruptAfterWait(interruptMode); + return nanosTimeout - (System.nanoTime() - lastTime); + } + + /** + * Implements absolute timed condition wait. + * <ol> + * <li> If current thread is interrupted, throw InterruptedException. + * <li> Save lock state returned by {@link #getState}. + * <li> Invoke {@link #release} with + * saved state as argument, throwing + * IllegalMonitorStateException if it fails. + * <li> Block until signalled, interrupted, or timed out. + * <li> Reacquire by invoking specialized version of + * {@link #acquire} with saved state as argument. + * <li> If interrupted while blocked in step 4, throw InterruptedException. + * <li> If timed out while blocked in step 4, return false, else true. + * </ol> + */ + public final boolean awaitUntil(Date deadline) throws InterruptedException { + if (deadline == null) + throw new NullPointerException(); + long abstime = deadline.getTime(); + if (Thread.interrupted()) + throw new InterruptedException(); + Node node = addConditionWaiter(); + long savedState = fullyRelease(node); + boolean timedout = false; + int interruptMode = 0; + while (!isOnSyncQueue(node)) { + if (System.currentTimeMillis() > abstime) { + timedout = transferAfterCancelledWait(node); + break; + } + LockSupport.parkUntil(this, abstime); + if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) + break; + } + if (acquireQueued(node, savedState) && interruptMode != THROW_IE) + interruptMode = REINTERRUPT; + if (node.nextWaiter != null) + unlinkCancelledWaiters(); + if (interruptMode != 0) + reportInterruptAfterWait(interruptMode); + return !timedout; + } + + /** + * Implements timed condition wait. + * <ol> + * <li> If current thread is interrupted, throw InterruptedException. + * <li> Save lock state returned by {@link #getState}. + * <li> Invoke {@link #release} with + * saved state as argument, throwing + * IllegalMonitorStateException if it fails. + * <li> Block until signalled, interrupted, or timed out. + * <li> Reacquire by invoking specialized version of + * {@link #acquire} with saved state as argument. + * <li> If interrupted while blocked in step 4, throw InterruptedException. + * <li> If timed out while blocked in step 4, return false, else true. + * </ol> + */ + public final boolean await(long time, TimeUnit unit) throws InterruptedException { + if (unit == null) + throw new NullPointerException(); + long nanosTimeout = unit.toNanos(time); + if (Thread.interrupted()) + throw new InterruptedException(); + Node node = addConditionWaiter(); + long savedState = fullyRelease(node); + long lastTime = System.nanoTime(); + boolean timedout = false; + int interruptMode = 0; + while (!isOnSyncQueue(node)) { + if (nanosTimeout <= 0L) { + timedout = transferAfterCancelledWait(node); + break; + } + if (nanosTimeout >= spinForTimeoutThreshold) + LockSupport.parkNanos(this, nanosTimeout); + if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) + break; + long now = System.nanoTime(); + nanosTimeout -= now - lastTime; + lastTime = now; + } + if (acquireQueued(node, savedState) && interruptMode != THROW_IE) + interruptMode = REINTERRUPT; + if (node.nextWaiter != null) + unlinkCancelledWaiters(); + if (interruptMode != 0) + reportInterruptAfterWait(interruptMode); + return !timedout; + } + + // support for instrumentation + + /** + * Returns true if this condition was created by the given + * synchronization object. + * + * @return {@code true} if owned + */ + final boolean isOwnedBy(AbstractQueuedLongSynchronizer sync) { + return sync == AbstractQueuedLongSynchronizer.this; + } + + /** + * Queries whether any threads are waiting on this condition. + * Implements {@link AbstractQueuedLongSynchronizer#hasWaiters}. + * + * @return {@code true} if there are any waiting threads + * @throws IllegalMonitorStateException if {@link #isHeldExclusively} + * returns {@code false} + */ + protected final boolean hasWaiters() { + if (!isHeldExclusively()) + throw new IllegalMonitorStateException(); + for (Node w = firstWaiter; w != null; w = w.nextWaiter) { + if (w.waitStatus == Node.CONDITION) + return true; + } + return false; + } + + /** + * Returns an estimate of the number of threads waiting on + * this condition. + * Implements {@link AbstractQueuedLongSynchronizer#getWaitQueueLength}. + * + * @return the estimated number of waiting threads + * @throws IllegalMonitorStateException if {@link #isHeldExclusively} + * returns {@code false} + */ + protected final int getWaitQueueLength() { + if (!isHeldExclusively()) + throw new IllegalMonitorStateException(); + int n = 0; + for (Node w = firstWaiter; w != null; w = w.nextWaiter) { + if (w.waitStatus == Node.CONDITION) + ++n; + } + return n; + } + + /** + * Returns a collection containing those threads that may be + * waiting on this Condition. + * Implements {@link AbstractQueuedLongSynchronizer#getWaitingThreads}. + * + * @return the collection of threads + * @throws IllegalMonitorStateException if {@link #isHeldExclusively} + * returns {@code false} + */ + protected final Collection<Thread> getWaitingThreads() { + if (!isHeldExclusively()) + throw new IllegalMonitorStateException(); + ArrayList<Thread> list = new ArrayList<Thread>(); + for (Node w = firstWaiter; w != null; w = w.nextWaiter) { + if (w.waitStatus == Node.CONDITION) { + Thread t = w.thread; + if (t != null) + list.add(t); + } + } + return list; + } + } + + /** + * Setup to support compareAndSet. We need to natively implement + * this here: For the sake of permitting future enhancements, we + * cannot explicitly subclass AtomicLong, which would be + * efficient and useful otherwise. So, as the lesser of evils, we + * natively implement using hotspot intrinsics API. And while we + * are at it, we do the same for other CASable fields (which could + * otherwise be done with atomic field updaters). + */ + private static final Unsafe unsafe = Unsafe.getUnsafe(); + private static final long stateOffset; + private static final long headOffset; + private static final long tailOffset; + private static final long waitStatusOffset; + private static final long nextOffset; + + static { + try { + stateOffset = unsafe.objectFieldOffset + (AbstractQueuedLongSynchronizer.class.getDeclaredField("state")); + headOffset = unsafe.objectFieldOffset + (AbstractQueuedLongSynchronizer.class.getDeclaredField("head")); + tailOffset = unsafe.objectFieldOffset + (AbstractQueuedLongSynchronizer.class.getDeclaredField("tail")); + waitStatusOffset = unsafe.objectFieldOffset + (Node.class.getDeclaredField("waitStatus")); + nextOffset = unsafe.objectFieldOffset + (Node.class.getDeclaredField("next")); + + } catch (Exception ex) { throw new Error(ex); } + } + + /** + * CAS head field. Used only by enq. + */ + private final boolean compareAndSetHead(Node update) { + return unsafe.compareAndSwapObject(this, headOffset, null, update); + } + + /** + * CAS tail field. Used only by enq. + */ + private final boolean compareAndSetTail(Node expect, Node update) { + return unsafe.compareAndSwapObject(this, tailOffset, expect, update); + } + + /** + * CAS waitStatus field of a node. + */ + private final static boolean compareAndSetWaitStatus(Node node, + int expect, + int update) { + return unsafe.compareAndSwapInt(node, waitStatusOffset, + expect, update); + } + + /** + * CAS next field of a node. + */ + private final static boolean compareAndSetNext(Node node, + Node expect, + Node update) { + return unsafe.compareAndSwapObject(node, nextOffset, expect, update); + } +} diff --git a/concurrent/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java b/concurrent/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java index 8b9821e..66498e3 100644 --- a/concurrent/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java +++ b/concurrent/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java @@ -94,6 +94,12 @@ import sun.misc.Unsafe; * means of using this class. All other methods are declared * <tt>final</tt> because they cannot be independently varied. * + * <p>You may also find the inherited methods from {@link + * AbstractOwnableSynchronizer} useful to keep track of the thread + * owning an exclusive synchronizer. You are encouraged to use them + * -- this enables monitoring and diagnostic tools to assist users in + * determining which threads hold locks. + * * <p>Even though this class is based on an internal FIFO queue, it * does not automatically enforce FIFO acquisition policies. The core * of exclusive synchronization takes the form: @@ -119,8 +125,9 @@ import sun.misc.Unsafe; * disable barging by internally invoking one or more of the inspection * methods, thereby providing a <em>fair</em> FIFO acquisition order. * In particular, most fair synchronizers can define <tt>tryAcquire</tt> - * to return <tt>false</tt> if predecessors are queued. Other variations - * are possible. + * to return <tt>false</tt> if {@link #hasQueuedPredecessors} (a method + * specifically designed to be used by fair synchronizers) returns + * <tt>true</tt>. Other variations are possible. * * <p>Throughput and scalability are generally highest for the * default barging (also known as <em>greedy</em>, @@ -152,7 +159,10 @@ import sun.misc.Unsafe; * * <p>Here is a non-reentrant mutual exclusion lock class that uses * the value zero to represent the unlocked state, and one to - * represent the locked state. It also supports conditions and exposes + * represent the locked state. While a non-reentrant lock + * does not strictly require recording of the current owner + * thread, this class does so anyway to make usage easier to monitor. + * It also supports conditions and exposes * one of the instrumentation methods: * * <pre> @@ -168,13 +178,18 @@ import sun.misc.Unsafe; * // Acquire the lock if state is zero * public boolean tryAcquire(int acquires) { * assert acquires == 1; // Otherwise unused - * return compareAndSetState(0, 1); + * if (compareAndSetState(0, 1)) { + * setExclusiveOwnerThread(Thread.currentThread()); + * return true; + * } + * return false; * } * * // Release the lock by setting state to zero * protected boolean tryRelease(int releases) { * assert releases == 1; // Otherwise unused * if (getState() == 0) throw new IllegalMonitorStateException(); + * setExclusiveOwnerThread(null); * setState(0); * return true; * } @@ -787,7 +802,7 @@ public abstract class AbstractQueuedSynchronizer * @return {@code true} if interrupted */ private final boolean parkAndCheckInterrupt() { - LockSupport.park(); + LockSupport.park(this); return Thread.interrupted(); } @@ -882,7 +897,7 @@ public abstract class AbstractQueuedSynchronizer return false; if (shouldParkAfterFailedAcquire(p, node) && nanosTimeout > spinForTimeoutThreshold) - LockSupport.parkNanos(nanosTimeout); + LockSupport.parkNanos(this, nanosTimeout); long now = System.nanoTime(); nanosTimeout -= now - lastTime; lastTime = now; @@ -986,7 +1001,7 @@ public abstract class AbstractQueuedSynchronizer return false; if (shouldParkAfterFailedAcquire(p, node) && nanosTimeout > spinForTimeoutThreshold) - LockSupport.parkNanos(nanosTimeout); + LockSupport.parkNanos(this, nanosTimeout); long now = System.nanoTime(); nanosTimeout -= now - lastTime; lastTime = now; @@ -1458,8 +1473,10 @@ public abstract class AbstractQueuedSynchronizer * @return {@code true} if there is a queued thread preceding the * current thread, and {@code false} if the current thread * is at the head of the queue or the queue is empty + * @since 1.7 + * @hide */ - final boolean hasQueuedPredecessors() { + public final boolean hasQueuedPredecessors() { // The correctness of this depends on head being initialized // before tail and on head.next being accurate if the current // thread is first in queue. @@ -1926,7 +1943,7 @@ public abstract class AbstractQueuedSynchronizer int savedState = fullyRelease(node); boolean interrupted = false; while (!isOnSyncQueue(node)) { - LockSupport.park(); + LockSupport.park(this); if (Thread.interrupted()) interrupted = true; } @@ -1993,7 +2010,7 @@ public abstract class AbstractQueuedSynchronizer int savedState = fullyRelease(node); int interruptMode = 0; while (!isOnSyncQueue(node)) { - LockSupport.park(); + LockSupport.park(this); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; } @@ -2040,7 +2057,7 @@ public abstract class AbstractQueuedSynchronizer transferAfterCancelledWait(node); break; } - LockSupport.parkNanos(nanosTimeout); + LockSupport.parkNanos(this, nanosTimeout); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; @@ -2094,7 +2111,7 @@ public abstract class AbstractQueuedSynchronizer timedout = transferAfterCancelledWait(node); break; } - LockSupport.parkUntil(abstime); + LockSupport.parkUntil(this, abstime); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; } @@ -2146,7 +2163,7 @@ public abstract class AbstractQueuedSynchronizer break; } if (nanosTimeout >= spinForTimeoutThreshold) - LockSupport.parkNanos(nanosTimeout); + LockSupport.parkNanos(this, nanosTimeout); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; long now = System.nanoTime(); diff --git a/concurrent/src/main/java/java/util/concurrent/locks/Condition.java b/concurrent/src/main/java/java/util/concurrent/locks/Condition.java index 03be58f..d75de51 100644 --- a/concurrent/src/main/java/java/util/concurrent/locks/Condition.java +++ b/concurrent/src/main/java/java/util/concurrent/locks/Condition.java @@ -421,6 +421,15 @@ public interface Condition { * <p>If any threads are waiting on this condition then one * is selected for waking up. That thread must then re-acquire the * lock before returning from {@code await}. + * + * <p><b>Implementation Considerations</b> + * + * <p>The current thread is assumed to hold the lock associated + * with this {@code Condition} when this method is called. It is + * up to the implementation to determine if this is the case and + * if not, how to respond. Typically, an exception will be thrown + * (such as {@link IllegalMonitorStateException}) and the + * implementation must document that fact. */ void signal(); @@ -430,6 +439,15 @@ public interface Condition { * <p>If any threads are waiting on this condition then they are * all woken up. Each thread must re-acquire the lock before it can * return from {@code await}. + * + * <p><b>Implementation Considerations</b> + * + * <p>The current thread is assumed to hold the lock associated + * with this {@code Condition} when this method is called. It is + * up to the implementation to determine if this is the case and + * if not, how to respond. Typically, an exception will be thrown + * (such as {@link IllegalMonitorStateException}) and the + * implementation must document that fact. */ void signalAll(); } diff --git a/concurrent/src/main/java/java/util/concurrent/locks/LockSupport.java b/concurrent/src/main/java/java/util/concurrent/locks/LockSupport.java index b55b874..ac9a94f 100644 --- a/concurrent/src/main/java/java/util/concurrent/locks/LockSupport.java +++ b/concurrent/src/main/java/java/util/concurrent/locks/LockSupport.java @@ -36,6 +36,15 @@ import sun.misc.Unsafe; * spinning, but must be paired with an {@code unpark} to be * effective. * + * <p>The three forms of {@code park} each also support a + * {@code blocker} object parameter. This object is recorded while + * the thread is blocked to permit monitoring and diagnostic tools to + * identify the reasons that threads are blocked. (Such tools may + * access blockers using method {@link #getBlocker}.) The use of these + * forms rather than the original forms without this parameter is + * strongly encouraged. The normal argument to supply as a + * {@code blocker} within a lock implementation is {@code this}. + * * <p>These methods are designed to be used as tools for creating * higher-level synchronization utilities, and are not in themselves * useful for most concurrency control applications. The {@code park} @@ -78,13 +87,25 @@ import sun.misc.Unsafe; * } * }}</pre> */ -@SuppressWarnings("all") + public class LockSupport { private LockSupport() {} // Cannot be instantiated. - // BEGIN android-changed - private static final Unsafe unsafe = UnsafeAccess.THE_ONE; - // END android-changed + // Hotspot implementation via intrinsics API + private static final Unsafe unsafe = UnsafeAccess.THE_ONE; // android-changed + private static final long parkBlockerOffset; + + static { + try { + parkBlockerOffset = unsafe.objectFieldOffset + (java.lang.Thread.class.getDeclaredField("parkBlocker")); + } catch (Exception ex) { throw new Error(ex); } + } + + private static void setBlocker(Thread t, Object arg) { + // Even though volatile, hotspot doesn't need a write barrier here. + unsafe.putObject(t, parkBlockerOffset, arg); + } /** * Makes available the permit for the given thread, if it @@ -106,6 +127,136 @@ public class LockSupport { * Disables the current thread for thread scheduling purposes unless the * permit is available. * + * <p>If the permit is available then it is consumed and the call returns + * immediately; otherwise + * the current thread becomes disabled for thread scheduling + * purposes and lies dormant until one of three things happens: + * + * <ul> + * <li>Some other thread invokes {@link #unpark unpark} with the + * current thread as the target; or + * + * <li>Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread; or + * + * <li>The call spuriously (that is, for no reason) returns. + * </ul> + * + * <p>This method does <em>not</em> report which of these caused the + * method to return. Callers should re-check the conditions which caused + * the thread to park in the first place. Callers may also determine, + * for example, the interrupt status of the thread upon return. + * + * @param blocker the synchronization object responsible for this + * thread parking + * @since 1.6 + */ + public static void park(Object blocker) { + Thread t = Thread.currentThread(); + setBlocker(t, blocker); + unsafe.park(false, 0L); + setBlocker(t, null); + } + + /** + * Disables the current thread for thread scheduling purposes, for up to + * the specified waiting time, unless the permit is available. + * + * <p>If the permit is available then it is consumed and the call + * returns immediately; otherwise the current thread becomes disabled + * for thread scheduling purposes and lies dormant until one of four + * things happens: + * + * <ul> + * <li>Some other thread invokes {@link #unpark unpark} with the + * current thread as the target; or + * + * <li>Some other thread {@linkplain Thread#interrupt interrupts} the current + * thread; or + * + * <li>The specified waiting time elapses; or + * + * <li>The call spuriously (that is, for no reason) returns. + * </ul> + * + * <p>This method does <em>not</em> report which of these caused the + * method to return. Callers should re-check the conditions which caused + * the thread to park in the first place. Callers may also determine, + * for example, the interrupt status of the thread, or the elapsed time + * upon return. + * + * @param blocker the synchronization object responsible for this + * thread parking + * @param nanos the maximum number of nanoseconds to wait + * @since 1.6 + */ + public static void parkNanos(Object blocker, long nanos) { + if (nanos > 0) { + Thread t = Thread.currentThread(); + setBlocker(t, blocker); + unsafe.park(false, nanos); + setBlocker(t, null); + } + } + + /** + * Disables the current thread for thread scheduling purposes, until + * the specified deadline, unless the permit is available. + * + * <p>If the permit is available then it is consumed and the call + * returns immediately; otherwise the current thread becomes disabled + * for thread scheduling purposes and lies dormant until one of four + * things happens: + * + * <ul> + * <li>Some other thread invokes {@link #unpark unpark} with the + * current thread as the target; or + * + * <li>Some other thread {@linkplain Thread#interrupt interrupts} the + * current thread; or + * + * <li>The specified deadline passes; or + * + * <li>The call spuriously (that is, for no reason) returns. + * </ul> + * + * <p>This method does <em>not</em> report which of these caused the + * method to return. Callers should re-check the conditions which caused + * the thread to park in the first place. Callers may also determine, + * for example, the interrupt status of the thread, or the current time + * upon return. + * + * @param blocker the synchronization object responsible for this + * thread parking + * @param deadline the absolute time, in milliseconds from the Epoch, + * to wait until + * @since 1.6 + */ + public static void parkUntil(Object blocker, long deadline) { + Thread t = Thread.currentThread(); + setBlocker(t, blocker); + unsafe.park(true, deadline); + setBlocker(t, null); + } + + /** + * Returns the blocker object supplied to the most recent + * invocation of a park method that has not yet unblocked, or null + * if not blocked. The value returned is just a momentary + * snapshot -- the thread may have since unblocked or blocked on a + * different blocker object. + * + * @return the blocker + * @since 1.6 + */ + public static Object getBlocker(Thread t) { + return unsafe.getObjectVolatile(t, parkBlockerOffset); + } + + /** + * Disables the current thread for thread scheduling purposes unless the + * permit is available. + * * <p>If the permit is available then it is consumed and the call * returns immediately; otherwise the current thread becomes disabled * for thread scheduling purposes and lies dormant until one of three diff --git a/concurrent/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java b/concurrent/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java index c923944..bfaff06 100644 --- a/concurrent/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java +++ b/concurrent/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java @@ -1161,6 +1161,32 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab "[Locked by thread " + o.getName() + "]"); } + /** + * Queries if this write lock is held by the current thread. + * Identical in effect to {@link + * ReentrantReadWriteLock#isWriteLockedByCurrentThread}. + * + * @return {@code true} if the current thread holds this lock and + * {@code false} otherwise + * @since 1.6 + */ + public boolean isHeldByCurrentThread() { + return sync.isHeldExclusively(); + } + + /** + * Queries the number of holds on this write lock by the current + * thread. A thread has a hold on a lock for each lock action + * that is not matched by an unlock action. Identical in effect + * to {@link ReentrantReadWriteLock#getWriteHoldCount}. + * + * @return the number of holds on this lock by the current thread, + * or zero if this lock is not held by the current thread + * @since 1.6 + */ + public int getHoldCount() { + return sync.getWriteHoldCount(); + } } // Instrumentation and status @@ -1236,6 +1262,19 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab } /** + * Queries the number of reentrant read holds on this lock by the + * current thread. A reader thread has a hold on a lock for + * each lock action that is not matched by an unlock action. + * + * @return the number of holds on the read lock by the current thread, + * or zero if the read lock is not held by the current thread + * @since 1.6 + */ + public int getReadHoldCount() { + return sync.getReadHoldCount(); + } + + /** * Returns a collection containing threads that may be waiting to * acquire the write lock. Because the actual set of threads may * change dynamically while constructing this result, the returned diff --git a/concurrent/src/main/java/java/util/concurrent/locks/package-info.java b/concurrent/src/main/java/java/util/concurrent/locks/package-info.java index 801ee9b..860acdd 100644 --- a/concurrent/src/main/java/java/util/concurrent/locks/package-info.java +++ b/concurrent/src/main/java/java/util/concurrent/locks/package-info.java @@ -34,10 +34,16 @@ * * <p>The {@link java.util.concurrent.locks.AbstractQueuedSynchronizer} * class serves as a useful superclass for defining locks and other - * synchronizers that rely on queuing blocked threads. The - * {@link java.util.concurrent.locks.LockSupport} class provides - * lower-level blocking and unblocking support that is useful for those - * developers implementing their own customized lock classes. + * synchronizers that rely on queuing blocked threads. The {@link + * java.util.concurrent.locks.AbstractQueuedLongSynchronizer} class + * provides the same functionality but extends support to 64 bits of + * synchronization state. Both extend class {@link + * java.util.concurrent.locks.AbstractOwnableSynchronizer}, a simple + * class that helps record the thread currently holding exclusive + * synchronization. The {@link java.util.concurrent.locks.LockSupport} + * class provides lower-level blocking and unblocking support that is + * useful for those developers implementing their own customized lock + * classes. * * @since 1.5 */ diff --git a/concurrent/src/main/java/java/util/concurrent/package-info.java b/concurrent/src/main/java/java/util/concurrent/package-info.java index d49ef25..dd3a22d 100644 --- a/concurrent/src/main/java/java/util/concurrent/package-info.java +++ b/concurrent/src/main/java/java/util/concurrent/package-info.java @@ -41,6 +41,10 @@ * a function, allows determination of whether execution has * completed, and provides a means to cancel execution. * + * A {@link java.util.concurrent.RunnableFuture} is a {@code Future} + * that possesses a {@code run} method that upon execution, + * sets its results. + * * <p> * * <b>Implementations.</b> @@ -59,6 +63,13 @@ * assists in coordinating the processing of groups of * asynchronous tasks. * + * <p>Class {@link java.util.concurrent.ForkJoinPool} provides an + * Executor primarily designed for processing instances of {@link + * java.util.concurrent.ForkJoinTask} and its subclasses. These + * classes employ a work-stealing scheduler that attains high + * throughput for tasks conforming to restrictions that often hold in + * computation-intensive parallel processing. + * * <h2>Queues</h2> * * The {@link java.util.concurrent.ConcurrentLinkedQueue} class @@ -77,6 +88,18 @@ * for producer-consumer, messaging, parallel tasking, and * related concurrent designs. * + * <p> Extended interface {@link java.util.concurrent.TransferQueue}, + * and implementation {@link java.util.concurrent.LinkedTransferQueue} + * introduce a synchronous {@code transfer} method (along with related + * features) in which a producer may optionally block awaiting its + * consumer. + * + * <p>The {@link java.util.concurrent.BlockingDeque} interface + * extends {@code BlockingQueue} to support both FIFO and LIFO + * (stack-based) operations. + * Class {@link java.util.concurrent.LinkedBlockingDeque} + * provides an implementation. + * * <h2>Timing</h2> * * The {@link java.util.concurrent.TimeUnit} class provides @@ -97,28 +120,45 @@ * * <h2>Synchronizers</h2> * - * Four classes aid common special-purpose synchronization idioms. - * {@link java.util.concurrent.Semaphore} is a classic concurrency tool. - * {@link java.util.concurrent.CountDownLatch} is a very simple yet very - * common utility for blocking until a given number of signals, events, - * or conditions hold. A {@link java.util.concurrent.CyclicBarrier} is a - * resettable multiway synchronization point useful in some styles of - * parallel programming. An {@link java.util.concurrent.Exchanger} allows - * two threads to exchange objects at a rendezvous point, and is useful - * in several pipeline designs. + * Five classes aid common special-purpose synchronization idioms. + * <ul> + * + * <li>{@link java.util.concurrent.Semaphore} is a classic concurrency tool. + * + * <li>{@link java.util.concurrent.CountDownLatch} is a very simple yet + * very common utility for blocking until a given number of signals, + * events, or conditions hold. + * + * <li>A {@link java.util.concurrent.CyclicBarrier} is a resettable + * multiway synchronization point useful in some styles of parallel + * programming. + * + * <li>A {@link java.util.concurrent.Phaser} provides + * a more flexible form of barrier that may be used to control phased + * computation among multiple threads. + * + * <li>An {@link java.util.concurrent.Exchanger} allows two threads to + * exchange objects at a rendezvous point, and is useful in several + * pipeline designs. + * + * </ul> * * <h2>Concurrent Collections</h2> * * Besides Queues, this package supplies Collection implementations * designed for use in multithreaded contexts: * {@link java.util.concurrent.ConcurrentHashMap}, + * {@link java.util.concurrent.ConcurrentSkipListMap}, + * {@link java.util.concurrent.ConcurrentSkipListSet}, * {@link java.util.concurrent.CopyOnWriteArrayList}, and * {@link java.util.concurrent.CopyOnWriteArraySet}. * When many threads are expected to access a given collection, a * {@code ConcurrentHashMap} is normally preferable to a synchronized - * {@code HashMap}. A {@code CopyOnWriteArrayList} is preferable to a - * synchronized {@code ArrayList} when the expected number of reads and - * traversals greatly outnumber the number of updates to a list. + * {@code HashMap}, and a {@code ConcurrentSkipListMap} is normally + * preferable to a synchronized {@code TreeMap}. + * A {@code CopyOnWriteArrayList} is preferable to a synchronized + * {@code ArrayList} when the expected number of reads and traversals + * greatly outnumber the number of updates to a list. * <p>The "Concurrent" prefix used with some classes in this package * is a shorthand indicating several differences from similar @@ -216,7 +256,8 @@ * in each thread <i>happen-before</i> those subsequent to the * corresponding {@code exchange()} in another thread. * - * <li>Actions prior to calling {@code CyclicBarrier.await} + * <li>Actions prior to calling {@code CyclicBarrier.await} and + * {@code Phaser.awaitAdvance} (as well as its variants) * <i>happen-before</i> actions performed by the barrier action, and * actions performed by the barrier action <i>happen-before</i> actions * subsequent to a successful return from the corresponding {@code await} diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/AbstractExecutorServiceTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/AbstractExecutorServiceTest.java index b80fe64..a8db7ad 100644 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/AbstractExecutorServiceTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/AbstractExecutorServiceTest.java @@ -2,24 +2,25 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.*; import java.util.concurrent.*; +import static java.util.concurrent.TimeUnit.MILLISECONDS; import java.math.BigInteger; import java.security.*; -public class AbstractExecutorServiceTest extends JSR166TestCase{ +public class AbstractExecutorServiceTest extends JSR166TestCase { public static Test suite() { return new TestSuite(AbstractExecutorServiceTest.class); } - /** + /** * A no-frills implementation of AbstractExecutorService, designed * to test the submit methods only. */ @@ -36,188 +37,106 @@ public class AbstractExecutorServiceTest extends JSR166TestCase{ /** * execute(runnable) runs it to completion */ - public void testExecuteRunnable() { - try { - ExecutorService e = new DirectExecutorService(); - TrackedShortRunnable task = new TrackedShortRunnable(); - assertFalse(task.done); - Future<?> future = e.submit(task); - future.get(); - assertTrue(task.done); - } - catch (ExecutionException ex) { - unexpectedException(); - } - catch (InterruptedException ex) { - unexpectedException(); - } + public void testExecuteRunnable() throws Exception { + ExecutorService e = new DirectExecutorService(); + TrackedShortRunnable task = new TrackedShortRunnable(); + assertFalse(task.done); + Future<?> future = e.submit(task); + future.get(); + assertTrue(task.done); } /** * Completed submit(callable) returns result */ - public void testSubmitCallable() { - try { - ExecutorService e = new DirectExecutorService(); - Future<String> future = e.submit(new StringTask()); - String result = future.get(); - assertSame(TEST_STRING, result); - } - catch (ExecutionException ex) { - unexpectedException(); - } - catch (InterruptedException ex) { - unexpectedException(); - } + public void testSubmitCallable() throws Exception { + ExecutorService e = new DirectExecutorService(); + Future<String> future = e.submit(new StringTask()); + String result = future.get(); + assertSame(TEST_STRING, result); } /** * Completed submit(runnable) returns successfully */ - public void testSubmitRunnable() { - try { - ExecutorService e = new DirectExecutorService(); - Future<?> future = e.submit(new NoOpRunnable()); - future.get(); - assertTrue(future.isDone()); - } - catch (ExecutionException ex) { - unexpectedException(); - } - catch (InterruptedException ex) { - unexpectedException(); - } + public void testSubmitRunnable() throws Exception { + ExecutorService e = new DirectExecutorService(); + Future<?> future = e.submit(new NoOpRunnable()); + future.get(); + assertTrue(future.isDone()); } /** * Completed submit(runnable, result) returns result */ - public void testSubmitRunnable2() { - try { - ExecutorService e = new DirectExecutorService(); - Future<String> future = e.submit(new NoOpRunnable(), TEST_STRING); - String result = future.get(); - assertSame(TEST_STRING, result); - } - catch (ExecutionException ex) { - unexpectedException(); - } - catch (InterruptedException ex) { - unexpectedException(); - } + public void testSubmitRunnable2() throws Exception { + ExecutorService e = new DirectExecutorService(); + Future<String> future = e.submit(new NoOpRunnable(), TEST_STRING); + String result = future.get(); + assertSame(TEST_STRING, result); } /** - * A submitted privileged action to completion + * A submitted privileged action runs to completion */ - public void testSubmitPrivilegedAction() { - Policy savedPolicy = null; - try { - savedPolicy = Policy.getPolicy(); - AdjustablePolicy policy = new AdjustablePolicy(); - policy.addPermission(new RuntimePermission("getContextClassLoader")); - policy.addPermission(new RuntimePermission("setContextClassLoader")); - Policy.setPolicy(policy); - } catch(AccessControlException ok) { - return; - } - try { - ExecutorService e = new DirectExecutorService(); - Future future = e.submit(Executors.callable(new PrivilegedAction() { + public void testSubmitPrivilegedAction() throws Exception { + Runnable r = new CheckedRunnable() { + public void realRun() throws Exception { + ExecutorService e = new DirectExecutorService(); + Future future = e.submit(Executors.callable(new PrivilegedAction() { public Object run() { return TEST_STRING; }})); - Object result = future.get(); - assertSame(TEST_STRING, result); - } - catch (ExecutionException ex) { - unexpectedException(); - } - catch (InterruptedException ex) { - unexpectedException(); - } - finally { - try { - Policy.setPolicy(savedPolicy); - } catch(AccessControlException ok) { - return; - } - } + assertSame(TEST_STRING, future.get()); + }}; + + runWithPermissions(r, + new RuntimePermission("getClassLoader"), + new RuntimePermission("setContextClassLoader"), + new RuntimePermission("modifyThread")); } /** - * A submitted a privileged exception action runs to completion + * A submitted privileged exception action runs to completion */ - public void testSubmitPrivilegedExceptionAction() { - Policy savedPolicy = null; - try { - savedPolicy = Policy.getPolicy(); - AdjustablePolicy policy = new AdjustablePolicy(); - policy.addPermission(new RuntimePermission("getContextClassLoader")); - policy.addPermission(new RuntimePermission("setContextClassLoader")); - Policy.setPolicy(policy); - } catch(AccessControlException ok) { - return; - } - - try { - ExecutorService e = new DirectExecutorService(); - Future future = e.submit(Executors.callable(new PrivilegedExceptionAction() { + public void testSubmitPrivilegedExceptionAction() throws Exception { + Runnable r = new CheckedRunnable() { + public void realRun() throws Exception { + ExecutorService e = new DirectExecutorService(); + Future future = e.submit(Executors.callable(new PrivilegedExceptionAction() { public Object run() { return TEST_STRING; }})); - Object result = future.get(); - assertSame(TEST_STRING, result); - } - catch (ExecutionException ex) { - unexpectedException(); - } - catch (InterruptedException ex) { - unexpectedException(); - } - finally { - Policy.setPolicy(savedPolicy); - } + assertSame(TEST_STRING, future.get()); + }}; + + runWithPermissions(r); } /** * A submitted failed privileged exception action reports exception */ - public void testSubmitFailedPrivilegedExceptionAction() { - Policy savedPolicy = null; - try { - savedPolicy = Policy.getPolicy(); - AdjustablePolicy policy = new AdjustablePolicy(); - policy.addPermission(new RuntimePermission("getContextClassLoader")); - policy.addPermission(new RuntimePermission("setContextClassLoader")); - Policy.setPolicy(policy); - } catch(AccessControlException ok) { - return; - } - - - try { - ExecutorService e = new DirectExecutorService(); - Future future = e.submit(Executors.callable(new PrivilegedExceptionAction() { + public void testSubmitFailedPrivilegedExceptionAction() throws Exception { + Runnable r = new CheckedRunnable() { + public void realRun() throws Exception { + ExecutorService e = new DirectExecutorService(); + Future future = e.submit(Executors.callable(new PrivilegedExceptionAction() { public Object run() throws Exception { throw new IndexOutOfBoundsException(); }})); - Object result = future.get(); - shouldThrow(); - } - catch (ExecutionException success) { - } - catch (InterruptedException ex) { - unexpectedException(); - } - finally { - Policy.setPolicy(savedPolicy); - } + try { + future.get(); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof IndexOutOfBoundsException); + }}}; + + runWithPermissions(r); } /** @@ -226,15 +145,9 @@ public class AbstractExecutorServiceTest extends JSR166TestCase{ public void testExecuteNullRunnable() { try { ExecutorService e = new DirectExecutorService(); - TrackedShortRunnable task = null; - Future<?> future = e.submit(task); + e.submit((Runnable) null); shouldThrow(); - } - catch (NullPointerException success) { - } - catch (Exception ex) { - unexpectedException(); - } + } catch (NullPointerException success) {} } @@ -244,15 +157,9 @@ public class AbstractExecutorServiceTest extends JSR166TestCase{ public void testSubmitNullCallable() { try { ExecutorService e = new DirectExecutorService(); - StringTask t = null; - Future<String> future = e.submit(t); + e.submit((Callable) null); shouldThrow(); - } - catch (NullPointerException success) { - } - catch (Exception ex) { - unexpectedException(); - } + } catch (NullPointerException success) {} } /** @@ -260,15 +167,22 @@ public class AbstractExecutorServiceTest extends JSR166TestCase{ * executor is saturated. */ public void testExecute1() { - ThreadPoolExecutor p = new ThreadPoolExecutor(1,1, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1)); + ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 1, + 60, TimeUnit.SECONDS, + new ArrayBlockingQueue<Runnable>(1)); try { - - for(int i = 0; i < 5; ++i){ + for (int i = 0; i < 2; ++i) p.submit(new MediumRunnable()); + for (int i = 0; i < 2; ++i) { + try { + p.submit(new MediumRunnable()); + shouldThrow(); + } catch (RejectedExecutionException success) {} } - shouldThrow(); - } catch(RejectedExecutionException success){} - joinPool(p); + } finally { + joinPool(p); + } } /** @@ -276,14 +190,22 @@ public class AbstractExecutorServiceTest extends JSR166TestCase{ * if executor is saturated. */ public void testExecute2() { - ThreadPoolExecutor p = new ThreadPoolExecutor(1,1, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1)); + ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 1, + 60, TimeUnit.SECONDS, + new ArrayBlockingQueue<Runnable>(1)); try { - for(int i = 0; i < 5; ++i) { - p.submit(new SmallCallable()); + for (int i = 0; i < 2; ++i) + p.submit(new MediumRunnable()); + for (int i = 0; i < 2; ++i) { + try { + p.submit(new SmallCallable()); + shouldThrow(); + } catch (RejectedExecutionException success) {} } - shouldThrow(); - } catch(RejectedExecutionException e){} - joinPool(p); + } finally { + joinPool(p); + } } @@ -291,75 +213,43 @@ public class AbstractExecutorServiceTest extends JSR166TestCase{ * Blocking on submit(callable) throws InterruptedException if * caller interrupted. */ - public void testInterruptedSubmit() { + public void testInterruptedSubmit() throws InterruptedException { final ThreadPoolExecutor p = new ThreadPoolExecutor(1,1,60, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10)); - Thread t = new Thread(new Runnable() { - public void run() { - try { - p.submit(new Callable<Object>() { - public Object call() { - try { - Thread.sleep(MEDIUM_DELAY_MS); - shouldThrow(); - } catch(InterruptedException e){ - } - return null; - } - }).get(); - } catch(InterruptedException success){ - } catch(Exception e) { - unexpectedException(); - } - - } - }); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - } catch(Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws Exception { + p.submit(new CheckedCallable<Object>() { + public Object realCall() + throws InterruptedException { + Thread.sleep(SMALL_DELAY_MS); + return null; + }}).get(); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); joinPool(p); } /** - * get of submitted callable throws Exception if callable + * get of submitted callable throws InterruptedException if callable * interrupted */ - public void testSubmitIE() { - final ThreadPoolExecutor p = new ThreadPoolExecutor(1,1,60, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10)); - - final Callable c = new Callable() { - public Object call() { - try { - p.submit(new SmallCallable()).get(); - shouldThrow(); - } catch(InterruptedException e){} - catch(RejectedExecutionException e2){} - catch(ExecutionException e3){} - return Boolean.TRUE; - } - }; - - - - Thread t = new Thread(new Runnable() { - public void run() { - try { - c.call(); - } catch(Exception e){} - } - }); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } catch(InterruptedException e){ - unexpectedException(); - } - + public void testSubmitIE() throws InterruptedException { + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 1, + 60, TimeUnit.SECONDS, + new ArrayBlockingQueue<Runnable>(10)); + + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws Exception { + p.submit(new SmallCallable()).get(); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); joinPool(p); } @@ -367,26 +257,20 @@ public class AbstractExecutorServiceTest extends JSR166TestCase{ * get of submit(callable) throws ExecutionException if callable * throws exception */ - public void testSubmitEE() { - ThreadPoolExecutor p = new ThreadPoolExecutor(1,1,60, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10)); + public void testSubmitEE() throws InterruptedException { + ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 1, + 60, TimeUnit.SECONDS, + new ArrayBlockingQueue<Runnable>(10)); - try { - Callable c = new Callable() { - public Object call() { - int i = 5/0; - return Boolean.TRUE; - } - }; - - for(int i =0; i < 5; i++){ - p.submit(c).get(); - } + Callable c = new Callable() { + public Object call() { return 5/0; }}; + try { + p.submit(c).get(); shouldThrow(); - } - catch(ExecutionException success){ - } catch(Exception e) { - unexpectedException(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof ArithmeticException); } joinPool(p); } @@ -394,13 +278,13 @@ public class AbstractExecutorServiceTest extends JSR166TestCase{ /** * invokeAny(null) throws NPE */ - public void testInvokeAny1() { + public void testInvokeAny1() + throws InterruptedException, ExecutionException { ExecutorService e = new DirectExecutorService(); try { e.invokeAny(null); + shouldThrow(); } catch (NullPointerException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -409,13 +293,13 @@ public class AbstractExecutorServiceTest extends JSR166TestCase{ /** * invokeAny(empty collection) throws IAE */ - public void testInvokeAny2() { + public void testInvokeAny2() + throws InterruptedException, ExecutionException { ExecutorService e = new DirectExecutorService(); try { e.invokeAny(new ArrayList<Callable<String>>()); + shouldThrow(); } catch (IllegalArgumentException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -424,17 +308,16 @@ public class AbstractExecutorServiceTest extends JSR166TestCase{ /** * invokeAny(c) throws NPE if c has null elements */ - public void testInvokeAny3() { + public void testInvokeAny3() throws Exception { ExecutorService e = new DirectExecutorService(); + List<Callable<Integer>> l = new ArrayList<Callable<Integer>>(); + l.add(new Callable<Integer>() { + public Integer call() { return 5/0; }}); + l.add(null); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); - l.add(new StringTask()); - l.add(null); e.invokeAny(l); + shouldThrow(); } catch (NullPointerException success) { - } catch(Exception ex) { - ex.printStackTrace(); - unexpectedException(); } finally { joinPool(e); } @@ -443,15 +326,15 @@ public class AbstractExecutorServiceTest extends JSR166TestCase{ /** * invokeAny(c) throws ExecutionException if no task in c completes */ - public void testInvokeAny4() { + public void testInvokeAny4() throws InterruptedException { ExecutorService e = new DirectExecutorService(); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new NPETask()); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); - l.add(new NPETask()); e.invokeAny(l); - } catch(ExecutionException success) { - } catch(Exception ex) { - unexpectedException(); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); } finally { joinPool(e); } @@ -460,17 +343,14 @@ public class AbstractExecutorServiceTest extends JSR166TestCase{ /** * invokeAny(c) returns result of some task in c if at least one completes */ - public void testInvokeAny5() { + public void testInvokeAny5() throws Exception { ExecutorService e = new DirectExecutorService(); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); + List<Callable<String>> l = new ArrayList<Callable<String>>(); l.add(new StringTask()); l.add(new StringTask()); String result = e.invokeAny(l); assertSame(TEST_STRING, result); - } catch (ExecutionException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -479,13 +359,12 @@ public class AbstractExecutorServiceTest extends JSR166TestCase{ /** * invokeAll(null) throws NPE */ - public void testInvokeAll1() { + public void testInvokeAll1() throws InterruptedException { ExecutorService e = new DirectExecutorService(); try { e.invokeAll(null); + shouldThrow(); } catch (NullPointerException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -494,13 +373,11 @@ public class AbstractExecutorServiceTest extends JSR166TestCase{ /** * invokeAll(empty collection) returns empty collection */ - public void testInvokeAll2() { + public void testInvokeAll2() throws InterruptedException { ExecutorService e = new DirectExecutorService(); try { List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>()); assertTrue(r.isEmpty()); - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -509,16 +386,15 @@ public class AbstractExecutorServiceTest extends JSR166TestCase{ /** * invokeAll(c) throws NPE if c has null elements */ - public void testInvokeAll3() { + public void testInvokeAll3() throws InterruptedException { ExecutorService e = new DirectExecutorService(); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new StringTask()); + l.add(null); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); - l.add(new StringTask()); - l.add(null); e.invokeAll(l); + shouldThrow(); } catch (NullPointerException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -527,18 +403,19 @@ public class AbstractExecutorServiceTest extends JSR166TestCase{ /** * get of returned element of invokeAll(c) throws exception on failed task */ - public void testInvokeAll4() { + public void testInvokeAll4() throws Exception { ExecutorService e = new DirectExecutorService(); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); + List<Callable<String>> l = new ArrayList<Callable<String>>(); l.add(new NPETask()); - List<Future<String>> result = e.invokeAll(l); - assertEquals(1, result.size()); - for (Iterator<Future<String>> it = result.iterator(); it.hasNext();) - it.next().get(); - } catch(ExecutionException success) { - } catch(Exception ex) { - unexpectedException(); + List<Future<String>> futures = e.invokeAll(l); + assertEquals(1, futures.size()); + try { + futures.get(0).get(); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } } finally { joinPool(e); } @@ -547,19 +424,16 @@ public class AbstractExecutorServiceTest extends JSR166TestCase{ /** * invokeAll(c) returns results of all completed tasks in c */ - public void testInvokeAll5() { + public void testInvokeAll5() throws Exception { ExecutorService e = new DirectExecutorService(); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); + List<Callable<String>> l = new ArrayList<Callable<String>>(); l.add(new StringTask()); l.add(new StringTask()); - List<Future<String>> result = e.invokeAll(l); - assertEquals(2, result.size()); - for (Iterator<Future<String>> it = result.iterator(); it.hasNext();) - assertSame(TEST_STRING, it.next().get()); - } catch (ExecutionException success) { - } catch(Exception ex) { - unexpectedException(); + List<Future<String>> futures = e.invokeAll(l); + assertEquals(2, futures.size()); + for (Future<String> future : futures) + assertSame(TEST_STRING, future.get()); } finally { joinPool(e); } @@ -569,13 +443,12 @@ public class AbstractExecutorServiceTest extends JSR166TestCase{ /** * timed invokeAny(null) throws NPE */ - public void testTimedInvokeAny1() { + public void testTimedInvokeAny1() throws Exception { ExecutorService e = new DirectExecutorService(); try { - e.invokeAny(null, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); + e.invokeAny(null, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); } catch (NullPointerException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -584,15 +457,14 @@ public class AbstractExecutorServiceTest extends JSR166TestCase{ /** * timed invokeAny(null time unit) throws NPE */ - public void testTimedInvokeAnyNullTimeUnit() { + public void testTimedInvokeAnyNullTimeUnit() throws Exception { ExecutorService e = new DirectExecutorService(); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new StringTask()); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); - l.add(new StringTask()); e.invokeAny(l, MEDIUM_DELAY_MS, null); + shouldThrow(); } catch (NullPointerException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -601,13 +473,12 @@ public class AbstractExecutorServiceTest extends JSR166TestCase{ /** * timed invokeAny(empty collection) throws IAE */ - public void testTimedInvokeAny2() { + public void testTimedInvokeAny2() throws Exception { ExecutorService e = new DirectExecutorService(); try { - e.invokeAny(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); + e.invokeAny(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); } catch (IllegalArgumentException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -616,17 +487,16 @@ public class AbstractExecutorServiceTest extends JSR166TestCase{ /** * timed invokeAny(c) throws NPE if c has null elements */ - public void testTimedInvokeAny3() { + public void testTimedInvokeAny3() throws Exception { ExecutorService e = new DirectExecutorService(); + List<Callable<Integer>> l = new ArrayList<Callable<Integer>>(); + l.add(new Callable<Integer>() { + public Integer call() { return 5/0; }}); + l.add(null); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); - l.add(new StringTask()); - l.add(null); - e.invokeAny(l, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); + e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); } catch (NullPointerException success) { - } catch(Exception ex) { - ex.printStackTrace(); - unexpectedException(); } finally { joinPool(e); } @@ -635,15 +505,15 @@ public class AbstractExecutorServiceTest extends JSR166TestCase{ /** * timed invokeAny(c) throws ExecutionException if no task completes */ - public void testTimedInvokeAny4() { + public void testTimedInvokeAny4() throws Exception { ExecutorService e = new DirectExecutorService(); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new NPETask()); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); - l.add(new NPETask()); - e.invokeAny(l, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); - } catch(ExecutionException success) { - } catch(Exception ex) { - unexpectedException(); + e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); } finally { joinPool(e); } @@ -652,17 +522,14 @@ public class AbstractExecutorServiceTest extends JSR166TestCase{ /** * timed invokeAny(c) returns result of some task in c */ - public void testTimedInvokeAny5() { + public void testTimedInvokeAny5() throws Exception { ExecutorService e = new DirectExecutorService(); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); + List<Callable<String>> l = new ArrayList<Callable<String>>(); l.add(new StringTask()); l.add(new StringTask()); - String result = e.invokeAny(l, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); + String result = e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS); assertSame(TEST_STRING, result); - } catch (ExecutionException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -671,13 +538,12 @@ public class AbstractExecutorServiceTest extends JSR166TestCase{ /** * timed invokeAll(null) throws NPE */ - public void testTimedInvokeAll1() { + public void testTimedInvokeAll1() throws InterruptedException { ExecutorService e = new DirectExecutorService(); try { - e.invokeAll(null, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); + e.invokeAll(null, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); } catch (NullPointerException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -686,15 +552,14 @@ public class AbstractExecutorServiceTest extends JSR166TestCase{ /** * timed invokeAll(null time unit) throws NPE */ - public void testTimedInvokeAllNullTimeUnit() { + public void testTimedInvokeAllNullTimeUnit() throws InterruptedException { ExecutorService e = new DirectExecutorService(); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new StringTask()); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); - l.add(new StringTask()); e.invokeAll(l, MEDIUM_DELAY_MS, null); + shouldThrow(); } catch (NullPointerException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -703,13 +568,11 @@ public class AbstractExecutorServiceTest extends JSR166TestCase{ /** * timed invokeAll(empty collection) returns empty collection */ - public void testTimedInvokeAll2() { + public void testTimedInvokeAll2() throws InterruptedException { ExecutorService e = new DirectExecutorService(); try { - List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); + List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS); assertTrue(r.isEmpty()); - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -718,16 +581,15 @@ public class AbstractExecutorServiceTest extends JSR166TestCase{ /** * timed invokeAll(c) throws NPE if c has null elements */ - public void testTimedInvokeAll3() { + public void testTimedInvokeAll3() throws InterruptedException { ExecutorService e = new DirectExecutorService(); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new StringTask()); + l.add(null); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); - l.add(new StringTask()); - l.add(null); - e.invokeAll(l, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); + e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); } catch (NullPointerException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -736,18 +598,20 @@ public class AbstractExecutorServiceTest extends JSR166TestCase{ /** * get of returned element of invokeAll(c) throws exception on failed task */ - public void testTimedInvokeAll4() { + public void testTimedInvokeAll4() throws Exception { ExecutorService e = new DirectExecutorService(); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); + List<Callable<String>> l = new ArrayList<Callable<String>>(); l.add(new NPETask()); - List<Future<String>> result = e.invokeAll(l, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); - assertEquals(1, result.size()); - for (Iterator<Future<String>> it = result.iterator(); it.hasNext();) - it.next().get(); - } catch(ExecutionException success) { - } catch(Exception ex) { - unexpectedException(); + List<Future<String>> futures = + e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS); + assertEquals(1, futures.size()); + try { + futures.get(0).get(); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } } finally { joinPool(e); } @@ -756,19 +620,17 @@ public class AbstractExecutorServiceTest extends JSR166TestCase{ /** * timed invokeAll(c) returns results of all completed tasks in c */ - public void testTimedInvokeAll5() { + public void testTimedInvokeAll5() throws Exception { ExecutorService e = new DirectExecutorService(); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); + List<Callable<String>> l = new ArrayList<Callable<String>>(); l.add(new StringTask()); l.add(new StringTask()); - List<Future<String>> result = e.invokeAll(l, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); - assertEquals(2, result.size()); - for (Iterator<Future<String>> it = result.iterator(); it.hasNext();) - assertSame(TEST_STRING, it.next().get()); - } catch (ExecutionException success) { - } catch(Exception ex) { - unexpectedException(); + List<Future<String>> futures = + e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS); + assertEquals(2, futures.size()); + for (Future<String> future : futures) + assertSame(TEST_STRING, future.get()); } finally { joinPool(e); } @@ -777,16 +639,17 @@ public class AbstractExecutorServiceTest extends JSR166TestCase{ /** * timed invokeAll cancels tasks not completed by timeout */ - public void testTimedInvokeAll6() { + public void testTimedInvokeAll6() throws InterruptedException { ExecutorService e = new DirectExecutorService(); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); + List<Callable<String>> l = new ArrayList<Callable<String>>(); l.add(new StringTask()); l.add(Executors.callable(new MediumPossiblyInterruptedRunnable(), TEST_STRING)); l.add(new StringTask()); - List<Future<String>> result = e.invokeAll(l, SMALL_DELAY_MS, TimeUnit.MILLISECONDS); - assertEquals(3, result.size()); - Iterator<Future<String>> it = result.iterator(); + List<Future<String>> futures = + e.invokeAll(l, SMALL_DELAY_MS, MILLISECONDS); + assertEquals(3, futures.size()); + Iterator<Future<String>> it = futures.iterator(); Future<String> f1 = it.next(); Future<String> f2 = it.next(); Future<String> f3 = it.next(); @@ -795,8 +658,6 @@ public class AbstractExecutorServiceTest extends JSR166TestCase{ assertTrue(f2.isDone()); assertTrue(f3.isDone()); assertTrue(f3.isCancelled()); - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/AbstractQueueTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/AbstractQueueTest.java index 660fec9..9bb206b 100644 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/AbstractQueueTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/AbstractQueueTest.java @@ -2,11 +2,11 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.*; @@ -20,9 +20,9 @@ public class AbstractQueueTest extends JSR166TestCase { } static class Succeed extends AbstractQueue<Integer> { - public boolean offer(Integer x) { + public boolean offer(Integer x) { if (x == null) throw new NullPointerException(); - return true; + return true; } public Integer peek() { return one; } public Integer poll() { return one; } @@ -31,9 +31,9 @@ public class AbstractQueueTest extends JSR166TestCase { } static class Fail extends AbstractQueue<Integer> { - public boolean offer(Integer x) { + public boolean offer(Integer x) { if (x == null) throw new NullPointerException(); - return false; + return false; } public Integer peek() { return null; } public Integer poll() { return null; } @@ -57,8 +57,7 @@ public class AbstractQueueTest extends JSR166TestCase { try { q.add(one); shouldThrow(); - } catch (IllegalStateException success) { - } + } catch (IllegalStateException success) {} } /** @@ -69,8 +68,7 @@ public class AbstractQueueTest extends JSR166TestCase { try { q.add(null); shouldThrow(); - } catch (NullPointerException success) { - } + } catch (NullPointerException success) {} } /** @@ -89,8 +87,7 @@ public class AbstractQueueTest extends JSR166TestCase { try { q.remove(); shouldThrow(); - } catch (NoSuchElementException success) { - } + } catch (NoSuchElementException success) {} } @@ -110,8 +107,7 @@ public class AbstractQueueTest extends JSR166TestCase { try { q.element(); shouldThrow(); - } catch (NoSuchElementException success) { - } + } catch (NoSuchElementException success) {} } /** @@ -122,8 +118,7 @@ public class AbstractQueueTest extends JSR166TestCase { Succeed q = new Succeed(); q.addAll(null); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** @@ -134,8 +129,7 @@ public class AbstractQueueTest extends JSR166TestCase { Succeed q = new Succeed(); q.addAll(q); shouldThrow(); - } - catch (IllegalArgumentException success) {} + } catch (IllegalArgumentException success) {} } @@ -148,8 +142,7 @@ public class AbstractQueueTest extends JSR166TestCase { Integer[] ints = new Integer[SIZE]; q.addAll(Arrays.asList(ints)); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** * addAll of a collection with any null elements throws NPE after @@ -163,8 +156,7 @@ public class AbstractQueueTest extends JSR166TestCase { ints[i] = new Integer(i); q.addAll(Arrays.asList(ints)); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** * addAll throws ISE if an add fails @@ -177,8 +169,7 @@ public class AbstractQueueTest extends JSR166TestCase { ints[i] = new Integer(i); q.addAll(Arrays.asList(ints)); shouldThrow(); - } - catch (IllegalStateException success) {} + } catch (IllegalStateException success) {} } } diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/AbstractQueuedLongSynchronizerTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/AbstractQueuedLongSynchronizerTest.java new file mode 100644 index 0000000..43a4bd1 --- /dev/null +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/AbstractQueuedLongSynchronizerTest.java @@ -0,0 +1,1025 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +package tests.api.java.util.concurrent; // android-added + +import junit.framework.*; +import java.util.*; +import java.util.concurrent.*; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import java.util.concurrent.locks.*; +import java.io.*; + +public class AbstractQueuedLongSynchronizerTest extends JSR166TestCase { + public static Test suite() { + return new TestSuite(AbstractQueuedLongSynchronizerTest.class); + } + + /** + * A simple mutex class, adapted from the + * AbstractQueuedLongSynchronizer javadoc. Exclusive acquire tests + * exercise this as a sample user extension. Other + * methods/features of AbstractQueuedLongSynchronizerTest are tested + * via other test classes, including those for ReentrantLock, + * ReentrantReadWriteLock, and Semaphore + */ + static class Mutex extends AbstractQueuedLongSynchronizer { + // Use value > 32 bits for locked state + static final long LOCKED = 1 << 48; + public boolean isHeldExclusively() { + return getState() == LOCKED; + } + + public boolean tryAcquire(long acquires) { + return compareAndSetState(0, LOCKED); + } + + public boolean tryRelease(long releases) { + if (getState() == 0) throw new IllegalMonitorStateException(); + setState(0); + return true; + } + + public AbstractQueuedLongSynchronizer.ConditionObject newCondition() { return new AbstractQueuedLongSynchronizer.ConditionObject(); } + + } + + + /** + * A simple latch class, to test shared mode. + */ + static class BooleanLatch extends AbstractQueuedLongSynchronizer { + public boolean isSignalled() { return getState() != 0; } + + public long tryAcquireShared(long ignore) { + return isSignalled()? 1 : -1; + } + + public boolean tryReleaseShared(long ignore) { + setState(1 << 62); + return true; + } + } + + /** + * A runnable calling acquireInterruptibly that does not expect to + * be interrupted. + */ + class InterruptibleSyncRunnable extends CheckedRunnable { + final Mutex sync; + InterruptibleSyncRunnable(Mutex l) { sync = l; } + public void realRun() throws InterruptedException { + sync.acquireInterruptibly(1); + } + } + + + /** + * A runnable calling acquireInterruptibly that expects to be + * interrupted. + */ + class InterruptedSyncRunnable extends CheckedInterruptedRunnable { + final Mutex sync; + InterruptedSyncRunnable(Mutex l) { sync = l; } + public void realRun() throws InterruptedException { + sync.acquireInterruptibly(1); + } + } + + /** + * isHeldExclusively is false upon construction + */ + public void testIsHeldExclusively() { + Mutex rl = new Mutex(); + assertFalse(rl.isHeldExclusively()); + } + + /** + * acquiring released sync succeeds + */ + public void testAcquire() { + Mutex rl = new Mutex(); + rl.acquire(1); + assertTrue(rl.isHeldExclusively()); + rl.release(1); + assertFalse(rl.isHeldExclusively()); + } + + /** + * tryAcquire on an released sync succeeds + */ + public void testTryAcquire() { + Mutex rl = new Mutex(); + assertTrue(rl.tryAcquire(1)); + assertTrue(rl.isHeldExclusively()); + rl.release(1); + } + + /** + * hasQueuedThreads reports whether there are waiting threads + */ + public void testhasQueuedThreads() throws InterruptedException { + final Mutex sync = new Mutex(); + Thread t1 = new Thread(new InterruptedSyncRunnable(sync)); + Thread t2 = new Thread(new InterruptibleSyncRunnable(sync)); + assertFalse(sync.hasQueuedThreads()); + sync.acquire(1); + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.hasQueuedThreads()); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.hasQueuedThreads()); + t1.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.hasQueuedThreads()); + sync.release(1); + Thread.sleep(SHORT_DELAY_MS); + assertFalse(sync.hasQueuedThreads()); + t1.join(); + t2.join(); + } + + /** + * isQueued(null) throws NPE + */ + public void testIsQueuedNPE() { + final Mutex sync = new Mutex(); + try { + sync.isQueued(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * isQueued reports whether a thread is queued. + */ + public void testIsQueued() throws InterruptedException { + final Mutex sync = new Mutex(); + Thread t1 = new Thread(new InterruptedSyncRunnable(sync)); + Thread t2 = new Thread(new InterruptibleSyncRunnable(sync)); + assertFalse(sync.isQueued(t1)); + assertFalse(sync.isQueued(t2)); + sync.acquire(1); + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.isQueued(t1)); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.isQueued(t1)); + assertTrue(sync.isQueued(t2)); + t1.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + assertFalse(sync.isQueued(t1)); + assertTrue(sync.isQueued(t2)); + sync.release(1); + Thread.sleep(SHORT_DELAY_MS); + assertFalse(sync.isQueued(t1)); + Thread.sleep(SHORT_DELAY_MS); + assertFalse(sync.isQueued(t2)); + t1.join(); + t2.join(); + } + + /** + * getFirstQueuedThread returns first waiting thread or null if none + */ + public void testGetFirstQueuedThread() throws InterruptedException { + final Mutex sync = new Mutex(); + Thread t1 = new Thread(new InterruptedSyncRunnable(sync)); + Thread t2 = new Thread(new InterruptibleSyncRunnable(sync)); + assertNull(sync.getFirstQueuedThread()); + sync.acquire(1); + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(t1, sync.getFirstQueuedThread()); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(t1, sync.getFirstQueuedThread()); + t1.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(t2, sync.getFirstQueuedThread()); + sync.release(1); + Thread.sleep(SHORT_DELAY_MS); + assertNull(sync.getFirstQueuedThread()); + t1.join(); + t2.join(); + } + + + /** + * hasContended reports false if no thread has ever blocked, else true + */ + public void testHasContended() throws InterruptedException { + final Mutex sync = new Mutex(); + Thread t1 = new Thread(new InterruptedSyncRunnable(sync)); + Thread t2 = new Thread(new InterruptibleSyncRunnable(sync)); + assertFalse(sync.hasContended()); + sync.acquire(1); + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.hasContended()); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.hasContended()); + t1.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.hasContended()); + sync.release(1); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.hasContended()); + t1.join(); + t2.join(); + } + + /** + * getQueuedThreads includes waiting threads + */ + public void testGetQueuedThreads() throws InterruptedException { + final Mutex sync = new Mutex(); + Thread t1 = new Thread(new InterruptedSyncRunnable(sync)); + Thread t2 = new Thread(new InterruptibleSyncRunnable(sync)); + assertTrue(sync.getQueuedThreads().isEmpty()); + sync.acquire(1); + assertTrue(sync.getQueuedThreads().isEmpty()); + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.getQueuedThreads().contains(t1)); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.getQueuedThreads().contains(t1)); + assertTrue(sync.getQueuedThreads().contains(t2)); + t1.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + assertFalse(sync.getQueuedThreads().contains(t1)); + assertTrue(sync.getQueuedThreads().contains(t2)); + sync.release(1); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.getQueuedThreads().isEmpty()); + t1.join(); + t2.join(); + } + + /** + * getExclusiveQueuedThreads includes waiting threads + */ + public void testGetExclusiveQueuedThreads() throws InterruptedException { + final Mutex sync = new Mutex(); + Thread t1 = new Thread(new InterruptedSyncRunnable(sync)); + Thread t2 = new Thread(new InterruptibleSyncRunnable(sync)); + assertTrue(sync.getExclusiveQueuedThreads().isEmpty()); + sync.acquire(1); + assertTrue(sync.getExclusiveQueuedThreads().isEmpty()); + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.getExclusiveQueuedThreads().contains(t1)); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.getExclusiveQueuedThreads().contains(t1)); + assertTrue(sync.getExclusiveQueuedThreads().contains(t2)); + t1.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + assertFalse(sync.getExclusiveQueuedThreads().contains(t1)); + assertTrue(sync.getExclusiveQueuedThreads().contains(t2)); + sync.release(1); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.getExclusiveQueuedThreads().isEmpty()); + t1.join(); + t2.join(); + } + + /** + * getSharedQueuedThreads does not include exclusively waiting threads + */ + public void testGetSharedQueuedThreads() throws InterruptedException { + final Mutex sync = new Mutex(); + Thread t1 = new Thread(new InterruptedSyncRunnable(sync)); + Thread t2 = new Thread(new InterruptibleSyncRunnable(sync)); + assertTrue(sync.getSharedQueuedThreads().isEmpty()); + sync.acquire(1); + assertTrue(sync.getSharedQueuedThreads().isEmpty()); + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.getSharedQueuedThreads().isEmpty()); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.getSharedQueuedThreads().isEmpty()); + t1.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.getSharedQueuedThreads().isEmpty()); + sync.release(1); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.getSharedQueuedThreads().isEmpty()); + t1.join(); + t2.join(); + } + + /** + * tryAcquireNanos is interruptible. + */ + public void testInterruptedException2() throws InterruptedException { + final Mutex sync = new Mutex(); + sync.acquire(1); + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + sync.tryAcquireNanos(1, MILLISECONDS.toNanos(MEDIUM_DELAY_MS)); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); + } + + + /** + * TryAcquire on exclusively held sync fails + */ + public void testTryAcquireWhenSynced() throws InterruptedException { + final Mutex sync = new Mutex(); + sync.acquire(1); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + threadAssertFalse(sync.tryAcquire(1)); + }}); + + t.start(); + t.join(); + sync.release(1); + } + + /** + * tryAcquireNanos on an exclusively held sync times out + */ + public void testAcquireNanos_Timeout() throws InterruptedException { + final Mutex sync = new Mutex(); + sync.acquire(1); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + long nanos = MILLISECONDS.toNanos(SHORT_DELAY_MS); + assertFalse(sync.tryAcquireNanos(1, nanos)); + }}); + + t.start(); + t.join(); + sync.release(1); + } + + + /** + * getState is true when acquired and false when not + */ + public void testGetState() throws InterruptedException { + final Mutex sync = new Mutex(); + sync.acquire(1); + assertTrue(sync.isHeldExclusively()); + sync.release(1); + assertFalse(sync.isHeldExclusively()); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(1); + Thread.sleep(SMALL_DELAY_MS); + sync.release(1); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.isHeldExclusively()); + t.join(); + assertFalse(sync.isHeldExclusively()); + } + + + /** + * acquireInterruptibly is interruptible. + */ + public void testAcquireInterruptibly1() throws InterruptedException { + final Mutex sync = new Mutex(); + sync.acquire(1); + Thread t = new Thread(new InterruptedSyncRunnable(sync)); + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + sync.release(1); + t.join(); + } + + /** + * acquireInterruptibly succeeds when released, else is interruptible + */ + public void testAcquireInterruptibly2() throws InterruptedException { + final Mutex sync = new Mutex(); + sync.acquireInterruptibly(1); + Thread t = new Thread(new InterruptedSyncRunnable(sync)); + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + assertTrue(sync.isHeldExclusively()); + t.join(); + } + + /** + * owns is true for a condition created by sync else false + */ + public void testOwns() { + final Mutex sync = new Mutex(); + final AbstractQueuedLongSynchronizer.ConditionObject c = sync.newCondition(); + final Mutex sync2 = new Mutex(); + assertTrue(sync.owns(c)); + assertFalse(sync2.owns(c)); + } + + /** + * Calling await without holding sync throws IllegalMonitorStateException + */ + public void testAwait_IllegalMonitor() throws InterruptedException { + final Mutex sync = new Mutex(); + final AbstractQueuedLongSynchronizer.ConditionObject c = sync.newCondition(); + try { + c.await(); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + } + + /** + * Calling signal without holding sync throws IllegalMonitorStateException + */ + public void testSignal_IllegalMonitor() throws InterruptedException { + final Mutex sync = new Mutex(); + final AbstractQueuedLongSynchronizer.ConditionObject c = sync.newCondition(); + try { + c.signal(); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + } + + /** + * awaitNanos without a signal times out + */ + public void testAwaitNanos_Timeout() throws InterruptedException { + final Mutex sync = new Mutex(); + final AbstractQueuedLongSynchronizer.ConditionObject c = sync.newCondition(); + sync.acquire(1); + long t = c.awaitNanos(100); + assertTrue(t <= 0); + sync.release(1); + } + + /** + * Timed await without a signal times out + */ + public void testAwait_Timeout() throws InterruptedException { + final Mutex sync = new Mutex(); + final AbstractQueuedLongSynchronizer.ConditionObject c = sync.newCondition(); + sync.acquire(1); + assertFalse(c.await(SHORT_DELAY_MS, MILLISECONDS)); + sync.release(1); + } + + /** + * awaitUntil without a signal times out + */ + public void testAwaitUntil_Timeout() throws InterruptedException { + final Mutex sync = new Mutex(); + final AbstractQueuedLongSynchronizer.ConditionObject c = sync.newCondition(); + sync.acquire(1); + java.util.Date d = new java.util.Date(); + assertFalse(c.awaitUntil(new java.util.Date(d.getTime() + 10))); + sync.release(1); + } + + /** + * await returns when signalled + */ + public void testAwait() throws InterruptedException { + final Mutex sync = new Mutex(); + final AbstractQueuedLongSynchronizer.ConditionObject c = sync.newCondition(); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(1); + c.await(); + sync.release(1); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + sync.acquire(1); + c.signal(); + sync.release(1); + t.join(SHORT_DELAY_MS); + assertFalse(t.isAlive()); + } + + + + /** + * hasWaiters throws NPE if null + */ + public void testHasWaitersNPE() { + final Mutex sync = new Mutex(); + try { + sync.hasWaiters(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * getWaitQueueLength throws NPE if null + */ + public void testGetWaitQueueLengthNPE() { + final Mutex sync = new Mutex(); + try { + sync.getWaitQueueLength(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + + /** + * getWaitingThreads throws NPE if null + */ + public void testGetWaitingThreadsNPE() { + final Mutex sync = new Mutex(); + try { + sync.getWaitingThreads(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + + /** + * hasWaiters throws IAE if not owned + */ + public void testHasWaitersIAE() { + final Mutex sync = new Mutex(); + final AbstractQueuedLongSynchronizer.ConditionObject c = sync.newCondition(); + final Mutex sync2 = new Mutex(); + try { + sync2.hasWaiters(c); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * hasWaiters throws IMSE if not synced + */ + public void testHasWaitersIMSE() { + final Mutex sync = new Mutex(); + final AbstractQueuedLongSynchronizer.ConditionObject c = sync.newCondition(); + try { + sync.hasWaiters(c); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + } + + + /** + * getWaitQueueLength throws IAE if not owned + */ + public void testGetWaitQueueLengthIAE() { + final Mutex sync = new Mutex(); + final AbstractQueuedLongSynchronizer.ConditionObject c = sync.newCondition(); + final Mutex sync2 = new Mutex(); + try { + sync2.getWaitQueueLength(c); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * getWaitQueueLength throws IMSE if not synced + */ + public void testGetWaitQueueLengthIMSE() { + final Mutex sync = new Mutex(); + final AbstractQueuedLongSynchronizer.ConditionObject c = sync.newCondition(); + try { + sync.getWaitQueueLength(c); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + } + + + /** + * getWaitingThreads throws IAE if not owned + */ + public void testGetWaitingThreadsIAE() { + final Mutex sync = new Mutex(); + final AbstractQueuedLongSynchronizer.ConditionObject c = sync.newCondition(); + final Mutex sync2 = new Mutex(); + try { + sync2.getWaitingThreads(c); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * getWaitingThreads throws IMSE if not synced + */ + public void testGetWaitingThreadsIMSE() { + final Mutex sync = new Mutex(); + final AbstractQueuedLongSynchronizer.ConditionObject c = sync.newCondition(); + try { + sync.getWaitingThreads(c); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + } + + + + /** + * hasWaiters returns true when a thread is waiting, else false + */ + public void testHasWaiters() throws InterruptedException { + final Mutex sync = new Mutex(); + final AbstractQueuedLongSynchronizer.ConditionObject c = sync.newCondition(); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(1); + threadAssertFalse(sync.hasWaiters(c)); + threadAssertEquals(0, sync.getWaitQueueLength(c)); + c.await(); + sync.release(1); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + sync.acquire(1); + assertTrue(sync.hasWaiters(c)); + assertEquals(1, sync.getWaitQueueLength(c)); + c.signal(); + sync.release(1); + Thread.sleep(SHORT_DELAY_MS); + sync.acquire(1); + assertFalse(sync.hasWaiters(c)); + assertEquals(0, sync.getWaitQueueLength(c)); + sync.release(1); + t.join(SHORT_DELAY_MS); + assertFalse(t.isAlive()); + } + + /** + * getWaitQueueLength returns number of waiting threads + */ + public void testGetWaitQueueLength() throws InterruptedException { + final Mutex sync = new Mutex(); + final AbstractQueuedLongSynchronizer.ConditionObject c = sync.newCondition(); + Thread t1 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(1); + threadAssertFalse(sync.hasWaiters(c)); + threadAssertEquals(0, sync.getWaitQueueLength(c)); + c.await(); + sync.release(1); + }}); + + Thread t2 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(1); + threadAssertTrue(sync.hasWaiters(c)); + threadAssertEquals(1, sync.getWaitQueueLength(c)); + c.await(); + sync.release(1); + }}); + + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + sync.acquire(1); + assertTrue(sync.hasWaiters(c)); + assertEquals(2, sync.getWaitQueueLength(c)); + c.signalAll(); + sync.release(1); + Thread.sleep(SHORT_DELAY_MS); + sync.acquire(1); + assertFalse(sync.hasWaiters(c)); + assertEquals(0, sync.getWaitQueueLength(c)); + sync.release(1); + t1.join(SHORT_DELAY_MS); + t2.join(SHORT_DELAY_MS); + assertFalse(t1.isAlive()); + assertFalse(t2.isAlive()); + } + + /** + * getWaitingThreads returns only and all waiting threads + */ + public void testGetWaitingThreads() throws InterruptedException { + final Mutex sync = new Mutex(); + final AbstractQueuedLongSynchronizer.ConditionObject c = sync.newCondition(); + Thread t1 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(1); + threadAssertTrue(sync.getWaitingThreads(c).isEmpty()); + c.await(); + sync.release(1); + }}); + + Thread t2 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(1); + threadAssertFalse(sync.getWaitingThreads(c).isEmpty()); + c.await(); + sync.release(1); + }}); + + sync.acquire(1); + assertTrue(sync.getWaitingThreads(c).isEmpty()); + sync.release(1); + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + sync.acquire(1); + assertTrue(sync.hasWaiters(c)); + assertTrue(sync.getWaitingThreads(c).contains(t1)); + assertTrue(sync.getWaitingThreads(c).contains(t2)); + c.signalAll(); + sync.release(1); + Thread.sleep(SHORT_DELAY_MS); + sync.acquire(1); + assertFalse(sync.hasWaiters(c)); + assertTrue(sync.getWaitingThreads(c).isEmpty()); + sync.release(1); + t1.join(SHORT_DELAY_MS); + t2.join(SHORT_DELAY_MS); + assertFalse(t1.isAlive()); + assertFalse(t2.isAlive()); + } + + + + /** + * awaitUninterruptibly doesn't abort on interrupt + */ + public void testAwaitUninterruptibly() throws InterruptedException { + final Mutex sync = new Mutex(); + final AbstractQueuedLongSynchronizer.ConditionObject c = sync.newCondition(); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + sync.acquire(1); + c.awaitUninterruptibly(); + sync.release(1); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + sync.acquire(1); + c.signal(); + sync.release(1); + t.join(SHORT_DELAY_MS); + assertFalse(t.isAlive()); + } + + /** + * await is interruptible + */ + public void testAwait_Interrupt() throws InterruptedException { + final Mutex sync = new Mutex(); + final AbstractQueuedLongSynchronizer.ConditionObject c = sync.newCondition(); + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(1); + c.await(); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(SHORT_DELAY_MS); + assertFalse(t.isAlive()); + } + + /** + * awaitNanos is interruptible + */ + public void testAwaitNanos_Interrupt() throws InterruptedException { + final Mutex sync = new Mutex(); + final AbstractQueuedLongSynchronizer.ConditionObject c = sync.newCondition(); + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(1); + c.awaitNanos(MILLISECONDS.toNanos(LONG_DELAY_MS)); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(SHORT_DELAY_MS); + assertFalse(t.isAlive()); + } + + /** + * awaitUntil is interruptible + */ + public void testAwaitUntil_Interrupt() throws InterruptedException { + final Mutex sync = new Mutex(); + final AbstractQueuedLongSynchronizer.ConditionObject c = sync.newCondition(); + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(1); + java.util.Date d = new java.util.Date(); + c.awaitUntil(new java.util.Date(d.getTime() + 10000)); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(SHORT_DELAY_MS); + assertFalse(t.isAlive()); + } + + /** + * signalAll wakes up all threads + */ + public void testSignalAll() throws InterruptedException { + final Mutex sync = new Mutex(); + final AbstractQueuedLongSynchronizer.ConditionObject c = sync.newCondition(); + Thread t1 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(1); + c.await(); + sync.release(1); + }}); + + Thread t2 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(1); + c.await(); + sync.release(1); + }}); + + t1.start(); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + sync.acquire(1); + c.signalAll(); + sync.release(1); + t1.join(SHORT_DELAY_MS); + t2.join(SHORT_DELAY_MS); + assertFalse(t1.isAlive()); + assertFalse(t2.isAlive()); + } + + + /** + * toString indicates current state + */ + public void testToString() { + Mutex sync = new Mutex(); + String us = sync.toString(); + assertTrue(us.indexOf("State = 0") >= 0); + sync.acquire(1); + String ls = sync.toString(); + assertTrue(ls.indexOf("State = " + Mutex.LOCKED) >= 0); + } + + /** + * A serialized AQS deserializes with current state + */ + public void testSerialization() throws Exception { + Mutex l = new Mutex(); + l.acquire(1); + assertTrue(l.isHeldExclusively()); + + ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); + ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); + out.writeObject(l); + out.close(); + + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); + Mutex r = (Mutex) in.readObject(); + assertTrue(r.isHeldExclusively()); + } + + + /** + * tryReleaseShared setting state changes getState + */ + public void testGetStateWithReleaseShared() { + final BooleanLatch l = new BooleanLatch(); + assertFalse(l.isSignalled()); + l.releaseShared(0); + assertTrue(l.isSignalled()); + } + + /** + * releaseShared has no effect when already signalled + */ + public void testReleaseShared() { + final BooleanLatch l = new BooleanLatch(); + assertFalse(l.isSignalled()); + l.releaseShared(0); + assertTrue(l.isSignalled()); + l.releaseShared(0); + assertTrue(l.isSignalled()); + } + + /** + * acquireSharedInterruptibly returns after release, but not before + */ + public void testAcquireSharedInterruptibly() throws InterruptedException { + final BooleanLatch l = new BooleanLatch(); + + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadAssertFalse(l.isSignalled()); + l.acquireSharedInterruptibly(0); + threadAssertTrue(l.isSignalled()); + }}); + + t.start(); + assertFalse(l.isSignalled()); + Thread.sleep(SHORT_DELAY_MS); + l.releaseShared(0); + assertTrue(l.isSignalled()); + t.join(); + } + + + /** + * acquireSharedTimed returns after release + */ + public void testAsquireSharedTimed() throws InterruptedException { + final BooleanLatch l = new BooleanLatch(); + + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(l.isSignalled()); + long nanos = MILLISECONDS.toNanos(MEDIUM_DELAY_MS); + assertTrue(l.tryAcquireSharedNanos(0, nanos)); + assertTrue(l.isSignalled()); + }}); + + t.start(); + assertFalse(l.isSignalled()); + Thread.sleep(SHORT_DELAY_MS); + l.releaseShared(0); + assertTrue(l.isSignalled()); + t.join(); + } + + /** + * acquireSharedInterruptibly throws IE if interrupted before released + */ + public void testAcquireSharedInterruptibly_InterruptedException() throws InterruptedException { + final BooleanLatch l = new BooleanLatch(); + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + threadAssertFalse(l.isSignalled()); + l.acquireSharedInterruptibly(0); + }}); + + t.start(); + assertFalse(l.isSignalled()); + t.interrupt(); + t.join(); + } + + /** + * acquireSharedTimed throws IE if interrupted before released + */ + public void testAcquireSharedNanos_InterruptedException() throws InterruptedException { + final BooleanLatch l = new BooleanLatch(); + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(l.isSignalled()); + long nanos = MILLISECONDS.toNanos(SMALL_DELAY_MS); + l.tryAcquireSharedNanos(0, nanos); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + assertFalse(l.isSignalled()); + t.interrupt(); + t.join(); + } + + /** + * acquireSharedTimed times out if not released before timeout + */ + public void testAcquireSharedNanos_Timeout() throws InterruptedException { + final BooleanLatch l = new BooleanLatch(); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(l.isSignalled()); + long nanos = MILLISECONDS.toNanos(SMALL_DELAY_MS); + assertFalse(l.tryAcquireSharedNanos(0, nanos)); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + assertFalse(l.isSignalled()); + t.join(); + } + +} diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/AbstractQueuedSynchronizerTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/AbstractQueuedSynchronizerTest.java index e2cfe92..a5b6554 100644 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/AbstractQueuedSynchronizerTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/AbstractQueuedSynchronizerTest.java @@ -2,8 +2,8 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ package tests.api.java.util.concurrent; @@ -11,6 +11,7 @@ package tests.api.java.util.concurrent; import junit.framework.*; import java.util.*; import java.util.concurrent.*; +import static java.util.concurrent.TimeUnit.MILLISECONDS; import java.util.concurrent.locks.*; import java.io.*; @@ -29,33 +30,33 @@ public class AbstractQueuedSynchronizerTest extends JSR166TestCase { */ static class Mutex extends AbstractQueuedSynchronizer { public boolean isHeldExclusively() { return getState() == 1; } - + public boolean tryAcquire(int acquires) { - assertTrue(acquires == 1); + assertTrue(acquires == 1); return compareAndSetState(0, 1); } - + public boolean tryRelease(int releases) { if (getState() == 0) throw new IllegalMonitorStateException(); setState(0); return true; } - + public AbstractQueuedSynchronizer.ConditionObject newCondition() { return new AbstractQueuedSynchronizer.ConditionObject(); } } - + /** * A simple latch class, to test shared mode. */ - static class BooleanLatch extends AbstractQueuedSynchronizer { + static class BooleanLatch extends AbstractQueuedSynchronizer { public boolean isSignalled() { return getState() != 0; } public int tryAcquireShared(int ignore) { return isSignalled()? 1 : -1; } - + public boolean tryReleaseShared(int ignore) { setState(1); return true; @@ -63,46 +64,42 @@ public class AbstractQueuedSynchronizerTest extends JSR166TestCase { } /** - * A runnable calling acquireInterruptibly + * A runnable calling acquireInterruptibly that does not expect to + * be interrupted. */ - class InterruptibleSyncRunnable implements Runnable { + class InterruptibleSyncRunnable extends CheckedRunnable { final Mutex sync; InterruptibleSyncRunnable(Mutex l) { sync = l; } - public void run() { - try { - sync.acquireInterruptibly(1); - } catch(InterruptedException success){} + public void realRun() throws InterruptedException { + sync.acquireInterruptibly(1); } } /** * A runnable calling acquireInterruptibly that expects to be - * interrupted + * interrupted. */ - class InterruptedSyncRunnable implements Runnable { + class InterruptedSyncRunnable extends CheckedInterruptedRunnable { final Mutex sync; InterruptedSyncRunnable(Mutex l) { sync = l; } - public void run() { - try { - sync.acquireInterruptibly(1); - threadShouldThrow(); - } catch(InterruptedException success){} + public void realRun() throws InterruptedException { + sync.acquireInterruptibly(1); } } /** * isHeldExclusively is false upon construction */ - public void testIsHeldExclusively() { + public void testIsHeldExclusively() { Mutex rl = new Mutex(); assertFalse(rl.isHeldExclusively()); } - + /** * acquiring released sync succeeds */ - public void testAcquire() { + public void testAcquire() { Mutex rl = new Mutex(); rl.acquire(1); assertTrue(rl.isHeldExclusively()); @@ -113,7 +110,7 @@ public class AbstractQueuedSynchronizerTest extends JSR166TestCase { /** * tryAcquire on an released sync succeeds */ - public void testTryAcquire() { + public void testTryAcquire() { Mutex rl = new Mutex(); assertTrue(rl.tryAcquire(1)); assertTrue(rl.isHeldExclusively()); @@ -123,378 +120,314 @@ public class AbstractQueuedSynchronizerTest extends JSR166TestCase { /** * hasQueuedThreads reports whether there are waiting threads */ - public void testhasQueuedThreads() { + public void testhasQueuedThreads() throws InterruptedException { final Mutex sync = new Mutex(); Thread t1 = new Thread(new InterruptedSyncRunnable(sync)); Thread t2 = new Thread(new InterruptibleSyncRunnable(sync)); - try { - assertFalse(sync.hasQueuedThreads()); - sync.acquire(1); - t1.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(sync.hasQueuedThreads()); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(sync.hasQueuedThreads()); - t1.interrupt(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(sync.hasQueuedThreads()); - sync.release(1); - Thread.sleep(SHORT_DELAY_MS); - assertFalse(sync.hasQueuedThreads()); - t1.join(); - t2.join(); - } catch(Exception e){ - unexpectedException(); - } - } + assertFalse(sync.hasQueuedThreads()); + sync.acquire(1); + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.hasQueuedThreads()); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.hasQueuedThreads()); + t1.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.hasQueuedThreads()); + sync.release(1); + Thread.sleep(SHORT_DELAY_MS); + assertFalse(sync.hasQueuedThreads()); + t1.join(); + t2.join(); + } /** * isQueued(null) throws NPE */ - public void testIsQueuedNPE() { + public void testIsQueuedNPE() { final Mutex sync = new Mutex(); try { sync.isQueued(null); shouldThrow(); - } catch (NullPointerException success) { - } + } catch (NullPointerException success) {} } /** * isQueued reports whether a thread is queued. */ - public void testIsQueued() { + public void testIsQueued() throws InterruptedException { final Mutex sync = new Mutex(); Thread t1 = new Thread(new InterruptedSyncRunnable(sync)); Thread t2 = new Thread(new InterruptibleSyncRunnable(sync)); - try { - assertFalse(sync.isQueued(t1)); - assertFalse(sync.isQueued(t2)); - sync.acquire(1); - t1.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(sync.isQueued(t1)); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(sync.isQueued(t1)); - assertTrue(sync.isQueued(t2)); - t1.interrupt(); - Thread.sleep(SHORT_DELAY_MS); - assertFalse(sync.isQueued(t1)); - assertTrue(sync.isQueued(t2)); - sync.release(1); - Thread.sleep(SHORT_DELAY_MS); - assertFalse(sync.isQueued(t1)); - Thread.sleep(SHORT_DELAY_MS); - assertFalse(sync.isQueued(t2)); - t1.join(); - t2.join(); - } catch(Exception e){ - unexpectedException(); - } - } + assertFalse(sync.isQueued(t1)); + assertFalse(sync.isQueued(t2)); + sync.acquire(1); + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.isQueued(t1)); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.isQueued(t1)); + assertTrue(sync.isQueued(t2)); + t1.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + assertFalse(sync.isQueued(t1)); + assertTrue(sync.isQueued(t2)); + sync.release(1); + Thread.sleep(SHORT_DELAY_MS); + assertFalse(sync.isQueued(t1)); + Thread.sleep(SHORT_DELAY_MS); + assertFalse(sync.isQueued(t2)); + t1.join(); + t2.join(); + } /** * getFirstQueuedThread returns first waiting thread or null if none */ - public void testGetFirstQueuedThread() { + public void testGetFirstQueuedThread() throws InterruptedException { final Mutex sync = new Mutex(); Thread t1 = new Thread(new InterruptedSyncRunnable(sync)); Thread t2 = new Thread(new InterruptibleSyncRunnable(sync)); - try { - assertNull(sync.getFirstQueuedThread()); - sync.acquire(1); - t1.start(); - Thread.sleep(SHORT_DELAY_MS); - assertEquals(t1, sync.getFirstQueuedThread()); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - assertEquals(t1, sync.getFirstQueuedThread()); - t1.interrupt(); - Thread.sleep(SHORT_DELAY_MS); - Thread.sleep(SHORT_DELAY_MS); - assertEquals(t2, sync.getFirstQueuedThread()); - sync.release(1); - Thread.sleep(SHORT_DELAY_MS); - assertNull(sync.getFirstQueuedThread()); - t1.join(); - t2.join(); - } catch(Exception e){ - unexpectedException(); - } - } + assertNull(sync.getFirstQueuedThread()); + sync.acquire(1); + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(t1, sync.getFirstQueuedThread()); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(t1, sync.getFirstQueuedThread()); + t1.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(t2, sync.getFirstQueuedThread()); + sync.release(1); + Thread.sleep(SHORT_DELAY_MS); + assertNull(sync.getFirstQueuedThread()); + t1.join(); + t2.join(); + } /** * hasContended reports false if no thread has ever blocked, else true */ - public void testHasContended() { + public void testHasContended() throws InterruptedException { final Mutex sync = new Mutex(); Thread t1 = new Thread(new InterruptedSyncRunnable(sync)); Thread t2 = new Thread(new InterruptibleSyncRunnable(sync)); - try { - assertFalse(sync.hasContended()); - sync.acquire(1); - t1.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(sync.hasContended()); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(sync.hasContended()); - t1.interrupt(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(sync.hasContended()); - sync.release(1); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(sync.hasContended()); - t1.join(); - t2.join(); - } catch(Exception e){ - unexpectedException(); - } - } + assertFalse(sync.hasContended()); + sync.acquire(1); + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.hasContended()); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.hasContended()); + t1.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.hasContended()); + sync.release(1); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.hasContended()); + t1.join(); + t2.join(); + } /** * getQueuedThreads includes waiting threads */ - public void testGetQueuedThreads() { + public void testGetQueuedThreads() throws InterruptedException { final Mutex sync = new Mutex(); Thread t1 = new Thread(new InterruptedSyncRunnable(sync)); Thread t2 = new Thread(new InterruptibleSyncRunnable(sync)); - try { - assertTrue(sync.getQueuedThreads().isEmpty()); - sync.acquire(1); - assertTrue(sync.getQueuedThreads().isEmpty()); - t1.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(sync.getQueuedThreads().contains(t1)); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(sync.getQueuedThreads().contains(t1)); - assertTrue(sync.getQueuedThreads().contains(t2)); - t1.interrupt(); - Thread.sleep(SHORT_DELAY_MS); - assertFalse(sync.getQueuedThreads().contains(t1)); - assertTrue(sync.getQueuedThreads().contains(t2)); - sync.release(1); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(sync.getQueuedThreads().isEmpty()); - t1.join(); - t2.join(); - } catch(Exception e){ - unexpectedException(); - } - } + assertTrue(sync.getQueuedThreads().isEmpty()); + sync.acquire(1); + assertTrue(sync.getQueuedThreads().isEmpty()); + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.getQueuedThreads().contains(t1)); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.getQueuedThreads().contains(t1)); + assertTrue(sync.getQueuedThreads().contains(t2)); + t1.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + assertFalse(sync.getQueuedThreads().contains(t1)); + assertTrue(sync.getQueuedThreads().contains(t2)); + sync.release(1); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.getQueuedThreads().isEmpty()); + t1.join(); + t2.join(); + } /** * getExclusiveQueuedThreads includes waiting threads */ - public void testGetExclusiveQueuedThreads() { + public void testGetExclusiveQueuedThreads() throws InterruptedException { final Mutex sync = new Mutex(); Thread t1 = new Thread(new InterruptedSyncRunnable(sync)); Thread t2 = new Thread(new InterruptibleSyncRunnable(sync)); - try { - assertTrue(sync.getExclusiveQueuedThreads().isEmpty()); - sync.acquire(1); - assertTrue(sync.getExclusiveQueuedThreads().isEmpty()); - t1.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(sync.getExclusiveQueuedThreads().contains(t1)); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(sync.getExclusiveQueuedThreads().contains(t1)); - assertTrue(sync.getExclusiveQueuedThreads().contains(t2)); - t1.interrupt(); - Thread.sleep(SHORT_DELAY_MS); - assertFalse(sync.getExclusiveQueuedThreads().contains(t1)); - assertTrue(sync.getExclusiveQueuedThreads().contains(t2)); - sync.release(1); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(sync.getExclusiveQueuedThreads().isEmpty()); - t1.join(); - t2.join(); - } catch(Exception e){ - unexpectedException(); - } - } + assertTrue(sync.getExclusiveQueuedThreads().isEmpty()); + sync.acquire(1); + assertTrue(sync.getExclusiveQueuedThreads().isEmpty()); + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.getExclusiveQueuedThreads().contains(t1)); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.getExclusiveQueuedThreads().contains(t1)); + assertTrue(sync.getExclusiveQueuedThreads().contains(t2)); + t1.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + assertFalse(sync.getExclusiveQueuedThreads().contains(t1)); + assertTrue(sync.getExclusiveQueuedThreads().contains(t2)); + sync.release(1); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.getExclusiveQueuedThreads().isEmpty()); + t1.join(); + t2.join(); + } /** * getSharedQueuedThreads does not include exclusively waiting threads */ - public void testGetSharedQueuedThreads() { + public void testGetSharedQueuedThreads() throws InterruptedException { final Mutex sync = new Mutex(); Thread t1 = new Thread(new InterruptedSyncRunnable(sync)); Thread t2 = new Thread(new InterruptibleSyncRunnable(sync)); - try { - assertTrue(sync.getSharedQueuedThreads().isEmpty()); - sync.acquire(1); - assertTrue(sync.getSharedQueuedThreads().isEmpty()); - t1.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(sync.getSharedQueuedThreads().isEmpty()); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(sync.getSharedQueuedThreads().isEmpty()); - t1.interrupt(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(sync.getSharedQueuedThreads().isEmpty()); - sync.release(1); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(sync.getSharedQueuedThreads().isEmpty()); - t1.join(); - t2.join(); - } catch(Exception e){ - unexpectedException(); - } - } + assertTrue(sync.getSharedQueuedThreads().isEmpty()); + sync.acquire(1); + assertTrue(sync.getSharedQueuedThreads().isEmpty()); + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.getSharedQueuedThreads().isEmpty()); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.getSharedQueuedThreads().isEmpty()); + t1.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.getSharedQueuedThreads().isEmpty()); + sync.release(1); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.getSharedQueuedThreads().isEmpty()); + t1.join(); + t2.join(); + } /** * tryAcquireNanos is interruptible. */ - public void testInterruptedException2() { + public void testInterruptedException2() throws InterruptedException { final Mutex sync = new Mutex(); sync.acquire(1); - Thread t = new Thread(new Runnable() { - public void run() { - try { - sync.tryAcquireNanos(1, MEDIUM_DELAY_MS * 1000 * 1000); - threadShouldThrow(); - } catch(InterruptedException success){} - } - }); - try { - t.start(); - t.interrupt(); - } catch(Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + sync.tryAcquireNanos(1, MILLISECONDS.toNanos(MEDIUM_DELAY_MS)); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } /** * TryAcquire on exclusively held sync fails */ - public void testTryAcquireWhenSynced() { + public void testTryAcquireWhenSynced() throws InterruptedException { final Mutex sync = new Mutex(); sync.acquire(1); - Thread t = new Thread(new Runnable() { - public void run() { - threadAssertFalse(sync.tryAcquire(1)); - } - }); - try { - t.start(); - t.join(); - sync.release(1); - } catch(Exception e){ - unexpectedException(); - } - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + threadAssertFalse(sync.tryAcquire(1)); + }}); + + t.start(); + t.join(); + sync.release(1); + } /** * tryAcquireNanos on an exclusively held sync times out */ - public void testAcquireNanos_Timeout() { + public void testAcquireNanos_Timeout() throws InterruptedException { final Mutex sync = new Mutex(); sync.acquire(1); - Thread t = new Thread(new Runnable() { - public void run() { - try { - threadAssertFalse(sync.tryAcquireNanos(1, 1000 * 1000)); - } catch (Exception ex) { - threadUnexpectedException(); - } - } - }); - try { - t.start(); - t.join(); - sync.release(1); - } catch(Exception e){ - unexpectedException(); - } - } - - + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + long nanos = MILLISECONDS.toNanos(SHORT_DELAY_MS); + assertFalse(sync.tryAcquireNanos(1, nanos)); + }}); + + t.start(); + t.join(); + sync.release(1); + } + + /** * getState is true when acquired and false when not */ - public void testGetState() { + public void testGetState() throws InterruptedException { final Mutex sync = new Mutex(); sync.acquire(1); assertTrue(sync.isHeldExclusively()); sync.release(1); assertFalse(sync.isHeldExclusively()); - Thread t = new Thread(new Runnable() { - public void run() { - sync.acquire(1); - try { - Thread.sleep(SMALL_DELAY_MS); - } - catch(Exception e) { - threadUnexpectedException(); - } - sync.release(1); - } - }); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(sync.isHeldExclusively()); - t.join(); - assertFalse(sync.isHeldExclusively()); - } catch(Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(1); + Thread.sleep(SMALL_DELAY_MS); + sync.release(1); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.isHeldExclusively()); + t.join(); + assertFalse(sync.isHeldExclusively()); } /** * acquireInterruptibly is interruptible. */ - public void testAcquireInterruptibly1() { + public void testAcquireInterruptibly1() throws InterruptedException { final Mutex sync = new Mutex(); sync.acquire(1); Thread t = new Thread(new InterruptedSyncRunnable(sync)); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - Thread.sleep(SHORT_DELAY_MS); - sync.release(1); - t.join(); - } catch(Exception e){ - unexpectedException(); - } - } + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + sync.release(1); + t.join(); + } /** * acquireInterruptibly succeeds when released, else is interruptible */ - public void testAcquireInterruptibly2() { - final Mutex sync = new Mutex(); - try { - sync.acquireInterruptibly(1); - } catch(Exception e) { - unexpectedException(); - } + public void testAcquireInterruptibly2() throws InterruptedException { + final Mutex sync = new Mutex(); + sync.acquireInterruptibly(1); Thread t = new Thread(new InterruptedSyncRunnable(sync)); - try { - t.start(); - t.interrupt(); - assertTrue(sync.isHeldExclusively()); - t.join(); - } catch(Exception e){ - unexpectedException(); - } + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + assertTrue(sync.isHeldExclusively()); + t.join(); } /** * owns is true for a condition created by sync else false */ public void testOwns() { - final Mutex sync = new Mutex(); + final Mutex sync = new Mutex(); final AbstractQueuedSynchronizer.ConditionObject c = sync.newCondition(); final Mutex sync2 = new Mutex(); assertTrue(sync.owns(c)); @@ -504,118 +437,82 @@ public class AbstractQueuedSynchronizerTest extends JSR166TestCase { /** * Calling await without holding sync throws IllegalMonitorStateException */ - public void testAwait_IllegalMonitor() { - final Mutex sync = new Mutex(); + public void testAwait_IllegalMonitor() throws InterruptedException { + final Mutex sync = new Mutex(); final AbstractQueuedSynchronizer.ConditionObject c = sync.newCondition(); try { c.await(); shouldThrow(); - } - catch (IllegalMonitorStateException success) { - } - catch (Exception ex) { - unexpectedException(); - } + } catch (IllegalMonitorStateException success) {} } /** * Calling signal without holding sync throws IllegalMonitorStateException */ public void testSignal_IllegalMonitor() { - final Mutex sync = new Mutex(); + final Mutex sync = new Mutex(); final AbstractQueuedSynchronizer.ConditionObject c = sync.newCondition(); try { c.signal(); shouldThrow(); - } - catch (IllegalMonitorStateException success) { - } - catch (Exception ex) { - unexpectedException(); - } + } catch (IllegalMonitorStateException success) {} } /** * awaitNanos without a signal times out */ - public void testAwaitNanos_Timeout() { - final Mutex sync = new Mutex(); + public void testAwaitNanos_Timeout() throws InterruptedException { + final Mutex sync = new Mutex(); final AbstractQueuedSynchronizer.ConditionObject c = sync.newCondition(); - try { - sync.acquire(1); - long t = c.awaitNanos(100); - assertTrue(t <= 0); - sync.release(1); - } - catch (Exception ex) { - unexpectedException(); - } + sync.acquire(1); + long t = c.awaitNanos(100); + assertTrue(t <= 0); + sync.release(1); } /** * Timed await without a signal times out */ - public void testAwait_Timeout() { - final Mutex sync = new Mutex(); + public void testAwait_Timeout() throws InterruptedException { + final Mutex sync = new Mutex(); final AbstractQueuedSynchronizer.ConditionObject c = sync.newCondition(); - try { - sync.acquire(1); - assertFalse(c.await(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - sync.release(1); - } - catch (Exception ex) { - unexpectedException(); - } + sync.acquire(1); + assertFalse(c.await(SHORT_DELAY_MS, MILLISECONDS)); + sync.release(1); } /** * awaitUntil without a signal times out */ - public void testAwaitUntil_Timeout() { - final Mutex sync = new Mutex(); + public void testAwaitUntil_Timeout() throws InterruptedException { + final Mutex sync = new Mutex(); final AbstractQueuedSynchronizer.ConditionObject c = sync.newCondition(); - try { - sync.acquire(1); - java.util.Date d = new java.util.Date(); - assertFalse(c.awaitUntil(new java.util.Date(d.getTime() + 10))); - sync.release(1); - } - catch (Exception ex) { - unexpectedException(); - } + sync.acquire(1); + java.util.Date d = new java.util.Date(); + assertFalse(c.awaitUntil(new java.util.Date(d.getTime() + 10))); + sync.release(1); } /** * await returns when signalled */ - public void testAwait() { - final Mutex sync = new Mutex(); + public void testAwait() throws InterruptedException { + final Mutex sync = new Mutex(); final AbstractQueuedSynchronizer.ConditionObject c = sync.newCondition(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - sync.acquire(1); - c.await(); - sync.release(1); - } - catch(InterruptedException e) { - threadUnexpectedException(); - } - } - }); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(1); + c.await(); + sync.release(1); + }}); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - sync.acquire(1); - c.signal(); - sync.release(1); - t.join(SHORT_DELAY_MS); - assertFalse(t.isAlive()); - } - catch (Exception ex) { - unexpectedException(); - } + t.start(); + Thread.sleep(SHORT_DELAY_MS); + sync.acquire(1); + c.signal(); + sync.release(1); + t.join(SHORT_DELAY_MS); + assertFalse(t.isAlive()); } @@ -628,10 +525,7 @@ public class AbstractQueuedSynchronizerTest extends JSR166TestCase { try { sync.hasWaiters(null); shouldThrow(); - } catch (NullPointerException success) { - } catch (Exception ex) { - unexpectedException(); - } + } catch (NullPointerException success) {} } /** @@ -642,10 +536,7 @@ public class AbstractQueuedSynchronizerTest extends JSR166TestCase { try { sync.getWaitQueueLength(null); shouldThrow(); - } catch (NullPointerException success) { - } catch (Exception ex) { - unexpectedException(); - } + } catch (NullPointerException success) {} } @@ -657,10 +548,7 @@ public class AbstractQueuedSynchronizerTest extends JSR166TestCase { try { sync.getWaitingThreads(null); shouldThrow(); - } catch (NullPointerException success) { - } catch (Exception ex) { - unexpectedException(); - } + } catch (NullPointerException success) {} } @@ -669,15 +557,12 @@ public class AbstractQueuedSynchronizerTest extends JSR166TestCase { */ public void testHasWaitersIAE() { final Mutex sync = new Mutex(); - final AbstractQueuedSynchronizer.ConditionObject c = (sync.newCondition()); + final AbstractQueuedSynchronizer.ConditionObject c = sync.newCondition(); final Mutex sync2 = new Mutex(); try { sync2.hasWaiters(c); shouldThrow(); - } catch (IllegalArgumentException success) { - } catch (Exception ex) { - unexpectedException(); - } + } catch (IllegalArgumentException success) {} } /** @@ -685,14 +570,11 @@ public class AbstractQueuedSynchronizerTest extends JSR166TestCase { */ public void testHasWaitersIMSE() { final Mutex sync = new Mutex(); - final AbstractQueuedSynchronizer.ConditionObject c = (sync.newCondition()); + final AbstractQueuedSynchronizer.ConditionObject c = sync.newCondition(); try { sync.hasWaiters(c); shouldThrow(); - } catch (IllegalMonitorStateException success) { - } catch (Exception ex) { - unexpectedException(); - } + } catch (IllegalMonitorStateException success) {} } @@ -701,15 +583,12 @@ public class AbstractQueuedSynchronizerTest extends JSR166TestCase { */ public void testGetWaitQueueLengthIAE() { final Mutex sync = new Mutex(); - final AbstractQueuedSynchronizer.ConditionObject c = (sync.newCondition()); + final AbstractQueuedSynchronizer.ConditionObject c = sync.newCondition(); final Mutex sync2 = new Mutex(); try { sync2.getWaitQueueLength(c); shouldThrow(); - } catch (IllegalArgumentException success) { - } catch (Exception ex) { - unexpectedException(); - } + } catch (IllegalArgumentException success) {} } /** @@ -717,14 +596,11 @@ public class AbstractQueuedSynchronizerTest extends JSR166TestCase { */ public void testGetWaitQueueLengthIMSE() { final Mutex sync = new Mutex(); - final AbstractQueuedSynchronizer.ConditionObject c = (sync.newCondition()); + final AbstractQueuedSynchronizer.ConditionObject c = sync.newCondition(); try { sync.getWaitQueueLength(c); shouldThrow(); - } catch (IllegalMonitorStateException success) { - } catch (Exception ex) { - unexpectedException(); - } + } catch (IllegalMonitorStateException success) {} } @@ -732,31 +608,25 @@ public class AbstractQueuedSynchronizerTest extends JSR166TestCase { * getWaitingThreads throws IAE if not owned */ public void testGetWaitingThreadsIAE() { - final Mutex sync = new Mutex(); - final AbstractQueuedSynchronizer.ConditionObject c = (sync.newCondition()); - final Mutex sync2 = new Mutex(); + final Mutex sync = new Mutex(); + final AbstractQueuedSynchronizer.ConditionObject c = sync.newCondition(); + final Mutex sync2 = new Mutex(); try { sync2.getWaitingThreads(c); shouldThrow(); - } catch (IllegalArgumentException success) { - } catch (Exception ex) { - unexpectedException(); - } + } catch (IllegalArgumentException success) {} } /** * getWaitingThreads throws IMSE if not synced */ public void testGetWaitingThreadsIMSE() { - final Mutex sync = new Mutex(); - final AbstractQueuedSynchronizer.ConditionObject c = (sync.newCondition()); + final Mutex sync = new Mutex(); + final AbstractQueuedSynchronizer.ConditionObject c = sync.newCondition(); try { sync.getWaitingThreads(c); shouldThrow(); - } catch (IllegalMonitorStateException success) { - } catch (Exception ex) { - unexpectedException(); - } + } catch (IllegalMonitorStateException success) {} } @@ -764,167 +634,122 @@ public class AbstractQueuedSynchronizerTest extends JSR166TestCase { /** * hasWaiters returns true when a thread is waiting, else false */ - public void testHasWaiters() { - final Mutex sync = new Mutex(); + public void testHasWaiters() throws InterruptedException { + final Mutex sync = new Mutex(); final AbstractQueuedSynchronizer.ConditionObject c = sync.newCondition(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - sync.acquire(1); - threadAssertFalse(sync.hasWaiters(c)); - threadAssertEquals(0, sync.getWaitQueueLength(c)); - c.await(); - sync.release(1); - } - catch(InterruptedException e) { - threadUnexpectedException(); - } - } - }); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(1); + threadAssertFalse(sync.hasWaiters(c)); + threadAssertEquals(0, sync.getWaitQueueLength(c)); + c.await(); + sync.release(1); + }}); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - sync.acquire(1); - assertTrue(sync.hasWaiters(c)); - assertEquals(1, sync.getWaitQueueLength(c)); - c.signal(); - sync.release(1); - Thread.sleep(SHORT_DELAY_MS); - sync.acquire(1); - assertFalse(sync.hasWaiters(c)); - assertEquals(0, sync.getWaitQueueLength(c)); - sync.release(1); - t.join(SHORT_DELAY_MS); - assertFalse(t.isAlive()); - } - catch (Exception ex) { - unexpectedException(); - } + t.start(); + Thread.sleep(SHORT_DELAY_MS); + sync.acquire(1); + assertTrue(sync.hasWaiters(c)); + assertEquals(1, sync.getWaitQueueLength(c)); + c.signal(); + sync.release(1); + Thread.sleep(SHORT_DELAY_MS); + sync.acquire(1); + assertFalse(sync.hasWaiters(c)); + assertEquals(0, sync.getWaitQueueLength(c)); + sync.release(1); + t.join(SHORT_DELAY_MS); + assertFalse(t.isAlive()); } /** * getWaitQueueLength returns number of waiting threads */ - public void testGetWaitQueueLength() { - final Mutex sync = new Mutex(); + public void testGetWaitQueueLength() throws InterruptedException { + final Mutex sync = new Mutex(); final AbstractQueuedSynchronizer.ConditionObject c = sync.newCondition(); - Thread t1 = new Thread(new Runnable() { - public void run() { - try { - sync.acquire(1); - threadAssertFalse(sync.hasWaiters(c)); - threadAssertEquals(0, sync.getWaitQueueLength(c)); - c.await(); - sync.release(1); - } - catch(InterruptedException e) { - threadUnexpectedException(); - } - } - }); - - Thread t2 = new Thread(new Runnable() { - public void run() { - try { - sync.acquire(1); - threadAssertTrue(sync.hasWaiters(c)); - threadAssertEquals(1, sync.getWaitQueueLength(c)); - c.await(); - sync.release(1); - } - catch(InterruptedException e) { - threadUnexpectedException(); - } - } - }); - - try { - t1.start(); - Thread.sleep(SHORT_DELAY_MS); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - sync.acquire(1); - assertTrue(sync.hasWaiters(c)); - assertEquals(2, sync.getWaitQueueLength(c)); - c.signalAll(); - sync.release(1); - Thread.sleep(SHORT_DELAY_MS); - sync.acquire(1); - assertFalse(sync.hasWaiters(c)); - assertEquals(0, sync.getWaitQueueLength(c)); - sync.release(1); - t1.join(SHORT_DELAY_MS); - t2.join(SHORT_DELAY_MS); - assertFalse(t1.isAlive()); - assertFalse(t2.isAlive()); - } - catch (Exception ex) { - unexpectedException(); - } + Thread t1 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(1); + threadAssertFalse(sync.hasWaiters(c)); + threadAssertEquals(0, sync.getWaitQueueLength(c)); + c.await(); + sync.release(1); + }}); + + Thread t2 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(1); + threadAssertTrue(sync.hasWaiters(c)); + threadAssertEquals(1, sync.getWaitQueueLength(c)); + c.await(); + sync.release(1); + }}); + + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + sync.acquire(1); + assertTrue(sync.hasWaiters(c)); + assertEquals(2, sync.getWaitQueueLength(c)); + c.signalAll(); + sync.release(1); + Thread.sleep(SHORT_DELAY_MS); + sync.acquire(1); + assertFalse(sync.hasWaiters(c)); + assertEquals(0, sync.getWaitQueueLength(c)); + sync.release(1); + t1.join(SHORT_DELAY_MS); + t2.join(SHORT_DELAY_MS); + assertFalse(t1.isAlive()); + assertFalse(t2.isAlive()); } /** * getWaitingThreads returns only and all waiting threads */ - public void testGetWaitingThreads() { - final Mutex sync = new Mutex(); + public void testGetWaitingThreads() throws InterruptedException { + final Mutex sync = new Mutex(); final AbstractQueuedSynchronizer.ConditionObject c = sync.newCondition(); - Thread t1 = new Thread(new Runnable() { - public void run() { - try { - sync.acquire(1); - threadAssertTrue(sync.getWaitingThreads(c).isEmpty()); - c.await(); - sync.release(1); - } - catch(InterruptedException e) { - threadUnexpectedException(); - } - } - }); - - Thread t2 = new Thread(new Runnable() { - public void run() { - try { - sync.acquire(1); - threadAssertFalse(sync.getWaitingThreads(c).isEmpty()); - c.await(); - sync.release(1); - } - catch(InterruptedException e) { - threadUnexpectedException(); - } - } - }); + Thread t1 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(1); + threadAssertTrue(sync.getWaitingThreads(c).isEmpty()); + c.await(); + sync.release(1); + }}); + + Thread t2 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(1); + threadAssertFalse(sync.getWaitingThreads(c).isEmpty()); + c.await(); + sync.release(1); + }}); - try { - sync.acquire(1); - assertTrue(sync.getWaitingThreads(c).isEmpty()); - sync.release(1); - t1.start(); - Thread.sleep(SHORT_DELAY_MS); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - sync.acquire(1); - assertTrue(sync.hasWaiters(c)); - assertTrue(sync.getWaitingThreads(c).contains(t1)); - assertTrue(sync.getWaitingThreads(c).contains(t2)); - c.signalAll(); - sync.release(1); - Thread.sleep(SHORT_DELAY_MS); - sync.acquire(1); - assertFalse(sync.hasWaiters(c)); - assertTrue(sync.getWaitingThreads(c).isEmpty()); - sync.release(1); - t1.join(SHORT_DELAY_MS); - t2.join(SHORT_DELAY_MS); - assertFalse(t1.isAlive()); - assertFalse(t2.isAlive()); - } - catch (Exception ex) { - unexpectedException(); - } + sync.acquire(1); + assertTrue(sync.getWaitingThreads(c).isEmpty()); + sync.release(1); + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + sync.acquire(1); + assertTrue(sync.hasWaiters(c)); + assertTrue(sync.getWaitingThreads(c).contains(t1)); + assertTrue(sync.getWaitingThreads(c).contains(t2)); + c.signalAll(); + sync.release(1); + Thread.sleep(SHORT_DELAY_MS); + sync.acquire(1); + assertFalse(sync.hasWaiters(c)); + assertTrue(sync.getWaitingThreads(c).isEmpty()); + sync.release(1); + t1.join(SHORT_DELAY_MS); + t2.join(SHORT_DELAY_MS); + assertFalse(t1.isAlive()); + assertFalse(t2.isAlive()); } @@ -932,175 +757,114 @@ public class AbstractQueuedSynchronizerTest extends JSR166TestCase { /** * awaitUninterruptibly doesn't abort on interrupt */ - public void testAwaitUninterruptibly() { - final Mutex sync = new Mutex(); + public void testAwaitUninterruptibly() throws InterruptedException { + final Mutex sync = new Mutex(); final AbstractQueuedSynchronizer.ConditionObject c = sync.newCondition(); - Thread t = new Thread(new Runnable() { - public void run() { - sync.acquire(1); - c.awaitUninterruptibly(); - sync.release(1); - } - }); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + sync.acquire(1); + c.awaitUninterruptibly(); + sync.release(1); + }}); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - sync.acquire(1); - c.signal(); - sync.release(1); - t.join(SHORT_DELAY_MS); - assertFalse(t.isAlive()); - } - catch (Exception ex) { - unexpectedException(); - } + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + sync.acquire(1); + c.signal(); + sync.release(1); + t.join(SHORT_DELAY_MS); + assertFalse(t.isAlive()); } /** * await is interruptible */ - public void testAwait_Interrupt() { - final Mutex sync = new Mutex(); + public void testAwait_Interrupt() throws InterruptedException { + final Mutex sync = new Mutex(); final AbstractQueuedSynchronizer.ConditionObject c = sync.newCondition(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - sync.acquire(1); - c.await(); - sync.release(1); - threadShouldThrow(); - } - catch(InterruptedException success) { - } - } - }); + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(1); + c.await(); + }}); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(SHORT_DELAY_MS); - assertFalse(t.isAlive()); - } - catch (Exception ex) { - unexpectedException(); - } + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(SHORT_DELAY_MS); + assertFalse(t.isAlive()); } /** * awaitNanos is interruptible */ - public void testAwaitNanos_Interrupt() { - final Mutex sync = new Mutex(); + public void testAwaitNanos_Interrupt() throws InterruptedException { + final Mutex sync = new Mutex(); final AbstractQueuedSynchronizer.ConditionObject c = sync.newCondition(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - sync.acquire(1); - c.awaitNanos(1000 * 1000 * 1000); // 1 sec - sync.release(1); - threadShouldThrow(); - } - catch(InterruptedException success) { - } - } - }); + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(1); + c.awaitNanos(MILLISECONDS.toNanos(LONG_DELAY_MS)); + }}); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(SHORT_DELAY_MS); - assertFalse(t.isAlive()); - } - catch (Exception ex) { - unexpectedException(); - } + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(SHORT_DELAY_MS); + assertFalse(t.isAlive()); } /** * awaitUntil is interruptible */ - public void testAwaitUntil_Interrupt() { - final Mutex sync = new Mutex(); + public void testAwaitUntil_Interrupt() throws InterruptedException { + final Mutex sync = new Mutex(); final AbstractQueuedSynchronizer.ConditionObject c = sync.newCondition(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - sync.acquire(1); - java.util.Date d = new java.util.Date(); - c.awaitUntil(new java.util.Date(d.getTime() + 10000)); - sync.release(1); - threadShouldThrow(); - } - catch(InterruptedException success) { - } - } - }); + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(1); + java.util.Date d = new java.util.Date(); + c.awaitUntil(new java.util.Date(d.getTime() + 10000)); + }}); - try { - t.start(); - // BEGIN android-changed - Thread.sleep(SMALL_DELAY_MS); // SHORT_DELAY_MS was flaky on Android - t.interrupt(); - t.join(SMALL_DELAY_MS); // SHORT_DELAY_MS was flaky on Android - // END android-changed - assertFalse(t.isAlive()); - } - catch (Exception ex) { - unexpectedException(); - } + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(SHORT_DELAY_MS); + assertFalse(t.isAlive()); } /** * signalAll wakes up all threads */ - public void testSignalAll() { - final Mutex sync = new Mutex(); + public void testSignalAll() throws InterruptedException { + final Mutex sync = new Mutex(); final AbstractQueuedSynchronizer.ConditionObject c = sync.newCondition(); - Thread t1 = new Thread(new Runnable() { - public void run() { - try { - sync.acquire(1); - c.await(); - sync.release(1); - } - catch(InterruptedException e) { - threadUnexpectedException(); - } - } - }); - - Thread t2 = new Thread(new Runnable() { - public void run() { - try { - sync.acquire(1); - c.await(); - sync.release(1); - } - catch(InterruptedException e) { - threadUnexpectedException(); - } - } - }); - - try { - t1.start(); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - sync.acquire(1); - c.signalAll(); - sync.release(1); - t1.join(SHORT_DELAY_MS); - t2.join(SHORT_DELAY_MS); - assertFalse(t1.isAlive()); - assertFalse(t2.isAlive()); - } - catch (Exception ex) { - unexpectedException(); - } + Thread t1 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(1); + c.await(); + sync.release(1); + }}); + + Thread t2 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(1); + c.await(); + sync.release(1); + }}); + + t1.start(); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + sync.acquire(1); + c.signalAll(); + sync.release(1); + t1.join(SHORT_DELAY_MS); + t2.join(SHORT_DELAY_MS); + assertFalse(t1.isAlive()); + assertFalse(t2.isAlive()); } @@ -1119,25 +883,20 @@ public class AbstractQueuedSynchronizerTest extends JSR166TestCase { /** * A serialized AQS deserializes with current state */ - public void testSerialization() { + public void testSerialization() throws Exception { Mutex l = new Mutex(); l.acquire(1); assertTrue(l.isHeldExclusively()); - try { - ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); - ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); - out.writeObject(l); - out.close(); - - ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); - ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); - Mutex r = (Mutex) in.readObject(); - assertTrue(r.isHeldExclusively()); - } catch(Exception e){ - e.printStackTrace(); - unexpectedException(); - } + ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); + ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); + out.writeObject(l); + out.close(); + + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); + Mutex r = (Mutex) in.readObject(); + assertTrue(r.isHeldExclusively()); } @@ -1166,136 +925,99 @@ public class AbstractQueuedSynchronizerTest extends JSR166TestCase { /** * acquireSharedInterruptibly returns after release, but not before */ - public void testAcquireSharedInterruptibly() { + public void testAcquireSharedInterruptibly() throws InterruptedException { final BooleanLatch l = new BooleanLatch(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - threadAssertFalse(l.isSignalled()); - l.acquireSharedInterruptibly(0); - threadAssertTrue(l.isSignalled()); - } catch(InterruptedException e){ - threadUnexpectedException(); - } - } - }); - try { - t.start(); - assertFalse(l.isSignalled()); - Thread.sleep(SHORT_DELAY_MS); - l.releaseShared(0); - assertTrue(l.isSignalled()); - t.join(); - } catch (InterruptedException e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadAssertFalse(l.isSignalled()); + l.acquireSharedInterruptibly(0); + threadAssertTrue(l.isSignalled()); + }}); + + t.start(); + assertFalse(l.isSignalled()); + Thread.sleep(SHORT_DELAY_MS); + l.releaseShared(0); + assertTrue(l.isSignalled()); + t.join(); } - + /** * acquireSharedTimed returns after release */ - public void testAsquireSharedTimed() { + public void testAsquireSharedTimed() throws InterruptedException { final BooleanLatch l = new BooleanLatch(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - threadAssertFalse(l.isSignalled()); - threadAssertTrue(l.tryAcquireSharedNanos(0, MEDIUM_DELAY_MS* 1000 * 1000)); - threadAssertTrue(l.isSignalled()); - - } catch(InterruptedException e){ - threadUnexpectedException(); - } - } - }); - try { - t.start(); - assertFalse(l.isSignalled()); - Thread.sleep(SHORT_DELAY_MS); - l.releaseShared(0); - assertTrue(l.isSignalled()); - t.join(); - } catch (InterruptedException e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(l.isSignalled()); + long nanos = MILLISECONDS.toNanos(MEDIUM_DELAY_MS); + assertTrue(l.tryAcquireSharedNanos(0, nanos)); + assertTrue(l.isSignalled()); + }}); + + t.start(); + assertFalse(l.isSignalled()); + Thread.sleep(SHORT_DELAY_MS); + l.releaseShared(0); + assertTrue(l.isSignalled()); + t.join(); } - + /** * acquireSharedInterruptibly throws IE if interrupted before released */ - public void testAcquireSharedInterruptibly_InterruptedException() { + public void testAcquireSharedInterruptibly_InterruptedException() throws InterruptedException { final BooleanLatch l = new BooleanLatch(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - threadAssertFalse(l.isSignalled()); - l.acquireSharedInterruptibly(0); - threadShouldThrow(); - } catch(InterruptedException success){} - } - }); + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + threadAssertFalse(l.isSignalled()); + l.acquireSharedInterruptibly(0); + }}); + t.start(); - try { - assertFalse(l.isSignalled()); - t.interrupt(); - t.join(); - } catch (InterruptedException e){ - unexpectedException(); - } + assertFalse(l.isSignalled()); + t.interrupt(); + t.join(); } /** * acquireSharedTimed throws IE if interrupted before released */ - public void testAcquireSharedNanos_InterruptedException() { + public void testAcquireSharedNanos_InterruptedException() throws InterruptedException { final BooleanLatch l = new BooleanLatch(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - threadAssertFalse(l.isSignalled()); - l.tryAcquireSharedNanos(0, SMALL_DELAY_MS* 1000 * 1000); - threadShouldThrow(); - } catch(InterruptedException success){} - } - }); + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(l.isSignalled()); + long nanos = MILLISECONDS.toNanos(SMALL_DELAY_MS); + l.tryAcquireSharedNanos(0, nanos); + }}); + t.start(); - try { - Thread.sleep(SHORT_DELAY_MS); - assertFalse(l.isSignalled()); - t.interrupt(); - t.join(); - } catch (InterruptedException e){ - unexpectedException(); - } + Thread.sleep(SHORT_DELAY_MS); + assertFalse(l.isSignalled()); + t.interrupt(); + t.join(); } /** * acquireSharedTimed times out if not released before timeout */ - public void testAcquireSharedNanos_Timeout() { + public void testAcquireSharedNanos_Timeout() throws InterruptedException { final BooleanLatch l = new BooleanLatch(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - threadAssertFalse(l.isSignalled()); - threadAssertFalse(l.tryAcquireSharedNanos(0, SMALL_DELAY_MS* 1000 * 1000)); - } catch(InterruptedException ie){ - threadUnexpectedException(); - } - } - }); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(l.isSignalled()); + long nanos = MILLISECONDS.toNanos(SMALL_DELAY_MS); + assertFalse(l.tryAcquireSharedNanos(0, nanos)); + }}); + t.start(); - try { - Thread.sleep(SHORT_DELAY_MS); - assertFalse(l.isSignalled()); - t.join(); - } catch (InterruptedException e){ - unexpectedException(); - } + Thread.sleep(SHORT_DELAY_MS); + assertFalse(l.isSignalled()); + t.join(); } - } diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/ArrayBlockingQueueTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/ArrayBlockingQueueTest.java index 1deea2c..8fc5cb6 100755 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/ArrayBlockingQueueTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/ArrayBlockingQueueTest.java @@ -2,15 +2,16 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.*; import java.util.concurrent.*; +import static java.util.concurrent.TimeUnit.MILLISECONDS; import java.io.*; public class ArrayBlockingQueueTest extends JSR166TestCase { @@ -25,14 +26,14 @@ public class ArrayBlockingQueueTest extends JSR166TestCase { private ArrayBlockingQueue populatedQueue(int n) { ArrayBlockingQueue q = new ArrayBlockingQueue(n); assertTrue(q.isEmpty()); - for(int i = 0; i < n; i++) + for (int i = 0; i < n; i++) assertTrue(q.offer(new Integer(i))); assertFalse(q.isEmpty()); assertEquals(0, q.remainingCapacity()); assertEquals(n, q.size()); return q; } - + /** * A new queue has the indicated capacity */ @@ -41,14 +42,13 @@ public class ArrayBlockingQueueTest extends JSR166TestCase { } /** - * Constructor throws IAE if capacity argument nonpositive + * Constructor throws IAE if capacity argument nonpositive */ public void testConstructor2() { try { ArrayBlockingQueue q = new ArrayBlockingQueue(0); shouldThrow(); - } - catch (IllegalArgumentException success) {} + } catch (IllegalArgumentException success) {} } /** @@ -58,8 +58,7 @@ public class ArrayBlockingQueueTest extends JSR166TestCase { try { ArrayBlockingQueue q = new ArrayBlockingQueue(1, true, null); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** @@ -70,8 +69,7 @@ public class ArrayBlockingQueueTest extends JSR166TestCase { Integer[] ints = new Integer[SIZE]; ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE, false, Arrays.asList(ints)); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** @@ -84,8 +82,7 @@ public class ArrayBlockingQueueTest extends JSR166TestCase { ints[i] = new Integer(i); ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE, false, Arrays.asList(ints)); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** @@ -98,23 +95,19 @@ public class ArrayBlockingQueueTest extends JSR166TestCase { ints[i] = new Integer(i); ArrayBlockingQueue q = new ArrayBlockingQueue(1, false, Arrays.asList(ints)); shouldThrow(); - } - catch (IllegalArgumentException success) {} + } catch (IllegalArgumentException success) {} } /** * Queue contains all elements of collection used to initialize */ public void testConstructor7() { - try { - Integer[] ints = new Integer[SIZE]; - for (int i = 0; i < SIZE; ++i) - ints[i] = new Integer(i); - ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE, true, Arrays.asList(ints)); - for (int i = 0; i < SIZE; ++i) - assertEquals(ints[i], q.poll()); - } - finally {} + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE, true, Arrays.asList(ints)); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.poll()); } /** @@ -157,7 +150,7 @@ public class ArrayBlockingQueueTest extends JSR166TestCase { ArrayBlockingQueue q = new ArrayBlockingQueue(1); q.offer(null); shouldThrow(); - } catch (NullPointerException success) { } + } catch (NullPointerException success) {} } /** @@ -168,7 +161,7 @@ public class ArrayBlockingQueueTest extends JSR166TestCase { ArrayBlockingQueue q = new ArrayBlockingQueue(1); q.add(null); shouldThrow(); - } catch (NullPointerException success) { } + } catch (NullPointerException success) {} } /** @@ -191,8 +184,8 @@ public class ArrayBlockingQueueTest extends JSR166TestCase { } assertEquals(0, q.remainingCapacity()); q.add(new Integer(SIZE)); - } catch (IllegalStateException success){ - } + shouldThrow(); + } catch (IllegalStateException success) {} } /** @@ -203,8 +196,7 @@ public class ArrayBlockingQueueTest extends JSR166TestCase { ArrayBlockingQueue q = new ArrayBlockingQueue(1); q.addAll(null); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** @@ -215,8 +207,7 @@ public class ArrayBlockingQueueTest extends JSR166TestCase { ArrayBlockingQueue q = populatedQueue(SIZE); q.addAll(q); shouldThrow(); - } - catch (IllegalArgumentException success) {} + } catch (IllegalArgumentException success) {} } @@ -229,8 +220,7 @@ public class ArrayBlockingQueueTest extends JSR166TestCase { Integer[] ints = new Integer[SIZE]; q.addAll(Arrays.asList(ints)); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** * addAll of a collection with any null elements throws NPE after @@ -244,8 +234,7 @@ public class ArrayBlockingQueueTest extends JSR166TestCase { ints[i] = new Integer(i); q.addAll(Arrays.asList(ints)); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** * addAll throws ISE if not enough room @@ -258,214 +247,166 @@ public class ArrayBlockingQueueTest extends JSR166TestCase { ints[i] = new Integer(i); q.addAll(Arrays.asList(ints)); shouldThrow(); - } - catch (IllegalStateException success) {} + } catch (IllegalStateException success) {} } /** * Queue contains all elements, in traversal order, of successful addAll */ public void testAddAll5() { - try { - Integer[] empty = new Integer[0]; - Integer[] ints = new Integer[SIZE]; - for (int i = 0; i < SIZE; ++i) - ints[i] = new Integer(i); - ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE); - assertFalse(q.addAll(Arrays.asList(empty))); - assertTrue(q.addAll(Arrays.asList(ints))); - for (int i = 0; i < SIZE; ++i) - assertEquals(ints[i], q.poll()); - } - finally {} + Integer[] empty = new Integer[0]; + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE); + assertFalse(q.addAll(Arrays.asList(empty))); + assertTrue(q.addAll(Arrays.asList(ints))); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.poll()); } /** * put(null) throws NPE */ - public void testPutNull() { + public void testPutNull() throws InterruptedException { try { ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE); q.put(null); shouldThrow(); - } - catch (NullPointerException success){ - } - catch (InterruptedException ie) { - unexpectedException(); - } + } catch (NullPointerException success) {} } /** * all elements successfully put are contained */ - public void testPut() { - try { - ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE); - for (int i = 0; i < SIZE; ++i) { - Integer I = new Integer(i); - q.put(I); - assertTrue(q.contains(I)); - } - assertEquals(0, q.remainingCapacity()); - } - catch (InterruptedException ie) { - unexpectedException(); + public void testPut() throws InterruptedException { + ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + Integer I = new Integer(i); + q.put(I); + assertTrue(q.contains(I)); } + assertEquals(0, q.remainingCapacity()); } /** * put blocks interruptibly if full */ - public void testBlockingPut() { + public void testBlockingPut() throws InterruptedException { final ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE); - Thread t = new Thread(new Runnable() { - public void run() { - int added = 0; - try { - for (int i = 0; i < SIZE; ++i) { - q.put(new Integer(i)); - ++added; - } - q.put(new Integer(SIZE)); - threadShouldThrow(); - } catch (InterruptedException ie){ - threadAssertEquals(added, SIZE); - } - }}); - try { - t.start(); - Thread.sleep(MEDIUM_DELAY_MS); - t.interrupt(); - t.join(); - } - catch (InterruptedException ie) { - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < SIZE; ++i) + q.put(i); + assertEquals(SIZE, q.size()); + assertEquals(0, q.remainingCapacity()); + try { + q.put(99); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); + assertEquals(SIZE, q.size()); + assertEquals(0, q.remainingCapacity()); } /** * put blocks waiting for take when full */ - public void testPutWithTake() { - final ArrayBlockingQueue q = new ArrayBlockingQueue(2); - Thread t = new Thread(new Runnable() { - public void run() { - int added = 0; - try { - q.put(new Object()); - ++added; - q.put(new Object()); - ++added; - q.put(new Object()); - ++added; - q.put(new Object()); - ++added; - threadShouldThrow(); - } catch (InterruptedException e){ - threadAssertTrue(added >= 2); - } - } - }); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - q.take(); - t.interrupt(); - t.join(); - } catch (Exception e){ - unexpectedException(); - } + public void testPutWithTake() throws InterruptedException { + final int capacity = 2; + final ArrayBlockingQueue q = new ArrayBlockingQueue(capacity); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < capacity + 1; i++) + q.put(i); + try { + q.put(99); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(q.remainingCapacity(), 0); + assertEquals(0, q.take()); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); + assertEquals(q.remainingCapacity(), 0); } /** * timed offer times out if full and elements not taken */ - public void testTimedOffer() { + public void testTimedOffer() throws InterruptedException { final ArrayBlockingQueue q = new ArrayBlockingQueue(2); - Thread t = new Thread(new Runnable() { - public void run() { - try { - q.put(new Object()); - q.put(new Object()); - threadAssertFalse(q.offer(new Object(), SHORT_DELAY_MS/2, TimeUnit.MILLISECONDS)); - q.offer(new Object(), LONG_DELAY_MS, TimeUnit.MILLISECONDS); - threadShouldThrow(); - } catch (InterruptedException success){} - } - }); - - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } catch (Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + q.put(new Object()); + q.put(new Object()); + assertFalse(q.offer(new Object(), SHORT_DELAY_MS/2, MILLISECONDS)); + try { + q.offer(new Object(), LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } /** * take retrieves elements in FIFO order */ - public void testTake() { - try { - ArrayBlockingQueue q = populatedQueue(SIZE); - for (int i = 0; i < SIZE; ++i) { - assertEquals(i, ((Integer)q.take()).intValue()); - } - } catch (InterruptedException e){ - unexpectedException(); - } + public void testTake() throws InterruptedException { + ArrayBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.take()); + } } /** * take blocks interruptibly when empty */ - public void testTakeFromEmpty() { + public void testTakeFromEmpty() throws InterruptedException { final ArrayBlockingQueue q = new ArrayBlockingQueue(2); - Thread t = new Thread(new Runnable() { - public void run() { - try { - q.take(); - threadShouldThrow(); - } catch (InterruptedException success){ } - } - }); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } catch (Exception e){ - unexpectedException(); - } + Thread t = new ThreadShouldThrow(InterruptedException.class) { + public void realRun() throws InterruptedException { + q.take(); + }}; + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } /** * Take removes existing elements until empty, then blocks interruptibly */ - public void testBlockingTake() { - Thread t = new Thread(new Runnable() { - public void run() { - try { - ArrayBlockingQueue q = populatedQueue(SIZE); - for (int i = 0; i < SIZE; ++i) { - threadAssertEquals(i, ((Integer)q.take()).intValue()); - } - q.take(); - threadShouldThrow(); - } catch (InterruptedException success){ - } - }}); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } - catch (InterruptedException ie) { - unexpectedException(); - } + public void testBlockingTake() throws InterruptedException { + final ArrayBlockingQueue q = populatedQueue(SIZE); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.take()); + } + try { + q.take(); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } @@ -475,7 +416,7 @@ public class ArrayBlockingQueueTest extends JSR166TestCase { public void testPoll() { ArrayBlockingQueue q = populatedQueue(SIZE); for (int i = 0; i < SIZE; ++i) { - assertEquals(i, ((Integer)q.poll()).intValue()); + assertEquals(i, q.poll()); } assertNull(q.poll()); } @@ -483,86 +424,70 @@ public class ArrayBlockingQueueTest extends JSR166TestCase { /** * timed pool with zero timeout succeeds when non-empty, else times out */ - public void testTimedPoll0() { - try { - ArrayBlockingQueue q = populatedQueue(SIZE); - for (int i = 0; i < SIZE; ++i) { - assertEquals(i, ((Integer)q.poll(0, TimeUnit.MILLISECONDS)).intValue()); - } - assertNull(q.poll(0, TimeUnit.MILLISECONDS)); - } catch (InterruptedException e){ - unexpectedException(); - } + public void testTimedPoll0() throws InterruptedException { + ArrayBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.poll(0, MILLISECONDS)); + } + assertNull(q.poll(0, MILLISECONDS)); } /** * timed pool with nonzero timeout succeeds when non-empty, else times out */ - public void testTimedPoll() { - try { - ArrayBlockingQueue q = populatedQueue(SIZE); - for (int i = 0; i < SIZE; ++i) { - assertEquals(i, ((Integer)q.poll(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)).intValue()); - } - assertNull(q.poll(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - } catch (InterruptedException e){ - unexpectedException(); - } + public void testTimedPoll() throws InterruptedException { + ArrayBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.poll(SHORT_DELAY_MS, MILLISECONDS)); + } + assertNull(q.poll(SHORT_DELAY_MS, MILLISECONDS)); } /** * Interrupted timed poll throws InterruptedException instead of * returning timeout status */ - public void testInterruptedTimedPoll() { - Thread t = new Thread(new Runnable() { - public void run() { - try { - ArrayBlockingQueue q = populatedQueue(SIZE); - for (int i = 0; i < SIZE; ++i) { - threadAssertEquals(i, ((Integer)q.poll(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)).intValue()); - } - threadAssertNull(q.poll(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - } catch (InterruptedException success){ - } - }}); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } - catch (InterruptedException ie) { - unexpectedException(); - } + public void testInterruptedTimedPoll() throws InterruptedException { + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + ArrayBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.poll(SHORT_DELAY_MS, MILLISECONDS));; + } + try { + q.poll(SMALL_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } /** * timed poll before a delayed offer fails; after offer succeeds; * on interruption throws */ - public void testTimedPollWithOffer() { + public void testTimedPollWithOffer() throws InterruptedException { final ArrayBlockingQueue q = new ArrayBlockingQueue(2); - Thread t = new Thread(new Runnable() { - public void run() { - try { - threadAssertNull(q.poll(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - q.poll(LONG_DELAY_MS, TimeUnit.MILLISECONDS); - q.poll(LONG_DELAY_MS, TimeUnit.MILLISECONDS); - threadShouldThrow(); - } catch (InterruptedException success) { } - } - }); - try { - t.start(); - Thread.sleep(SMALL_DELAY_MS); - assertTrue(q.offer(zero, SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - t.interrupt(); - t.join(); - } catch (Exception e){ - unexpectedException(); - } - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertNull(q.poll(SHORT_DELAY_MS, MILLISECONDS)); + assertSame(zero, q.poll(LONG_DELAY_MS, MILLISECONDS)); + try { + q.poll(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + t.start(); + Thread.sleep(SMALL_DELAY_MS); + assertTrue(q.offer(zero, SHORT_DELAY_MS, MILLISECONDS)); + t.interrupt(); + t.join(); + } /** @@ -571,10 +496,10 @@ public class ArrayBlockingQueueTest extends JSR166TestCase { public void testPeek() { ArrayBlockingQueue q = populatedQueue(SIZE); for (int i = 0; i < SIZE; ++i) { - assertEquals(i, ((Integer)q.peek()).intValue()); - q.poll(); + assertEquals(i, q.peek()); + assertEquals(i, q.poll()); assertTrue(q.peek() == null || - i != ((Integer)q.peek()).intValue()); + !q.peek().equals(i)); } assertNull(q.peek()); } @@ -585,14 +510,13 @@ public class ArrayBlockingQueueTest extends JSR166TestCase { public void testElement() { ArrayBlockingQueue q = populatedQueue(SIZE); for (int i = 0; i < SIZE; ++i) { - assertEquals(i, ((Integer)q.element()).intValue()); - q.poll(); + assertEquals(i, q.element()); + assertEquals(i, q.poll()); } try { q.element(); shouldThrow(); - } - catch (NoSuchElementException success) {} + } catch (NoSuchElementException success) {} } /** @@ -601,13 +525,12 @@ public class ArrayBlockingQueueTest extends JSR166TestCase { public void testRemove() { ArrayBlockingQueue q = populatedQueue(SIZE); for (int i = 0; i < SIZE; ++i) { - assertEquals(i, ((Integer)q.remove()).intValue()); + assertEquals(i, q.remove()); } try { q.remove(); shouldThrow(); - } catch (NoSuchElementException success){ - } + } catch (NoSuchElementException success) {} } /** @@ -624,7 +547,7 @@ public class ArrayBlockingQueueTest extends JSR166TestCase { } assertTrue(q.isEmpty()); } - + /** * contains(x) reports true when elements added but not yet removed */ @@ -632,7 +555,7 @@ public class ArrayBlockingQueueTest extends JSR166TestCase { ArrayBlockingQueue q = populatedQueue(SIZE); for (int i = 0; i < SIZE; ++i) { assertTrue(q.contains(new Integer(i))); - q.poll(); + assertEquals(i, q.poll()); assertFalse(q.contains(new Integer(i))); } } @@ -705,68 +628,56 @@ public class ArrayBlockingQueueTest extends JSR166TestCase { /** * toArray contains all elements */ - public void testToArray() { + public void testToArray() throws InterruptedException { ArrayBlockingQueue q = populatedQueue(SIZE); Object[] o = q.toArray(); - try { - for(int i = 0; i < o.length; i++) + for (int i = 0; i < o.length; i++) assertEquals(o[i], q.take()); - } catch (InterruptedException e){ - unexpectedException(); - } } /** * toArray(a) contains all elements */ - public void testToArray2() { + public void testToArray2() throws InterruptedException { ArrayBlockingQueue q = populatedQueue(SIZE); Integer[] ints = new Integer[SIZE]; ints = (Integer[])q.toArray(ints); - try { - for(int i = 0; i < ints.length; i++) - assertEquals(ints[i], q.take()); - } catch (InterruptedException e){ - unexpectedException(); - } + for (int i = 0; i < ints.length; i++) + assertEquals(ints[i], q.take()); } /** * toArray(null) throws NPE */ public void testToArray_BadArg() { + ArrayBlockingQueue q = populatedQueue(SIZE); try { - ArrayBlockingQueue q = populatedQueue(SIZE); Object o[] = q.toArray(null); shouldThrow(); - } catch(NullPointerException success){} + } catch (NullPointerException success) {} } /** * toArray with incompatible array type throws CCE */ public void testToArray1_BadArg() { + ArrayBlockingQueue q = populatedQueue(SIZE); try { - ArrayBlockingQueue q = populatedQueue(SIZE); - Object o[] = q.toArray(new String[10] ); + Object o[] = q.toArray(new String[10]); shouldThrow(); - } catch(ArrayStoreException success){} + } catch (ArrayStoreException success) {} } - + /** * iterator iterates through all elements */ - public void testIterator() { + public void testIterator() throws InterruptedException { ArrayBlockingQueue q = populatedQueue(SIZE); Iterator it = q.iterator(); - try { - while(it.hasNext()){ - assertEquals(it.next(), q.take()); - } - } catch (InterruptedException e){ - unexpectedException(); - } + while (it.hasNext()) { + assertEquals(it.next(), q.take()); + } } /** @@ -781,10 +692,10 @@ public class ArrayBlockingQueueTest extends JSR166TestCase { Iterator it = q.iterator(); it.next(); it.remove(); - + it = q.iterator(); - assertEquals(it.next(), one); - assertEquals(it.next(), three); + assertSame(it.next(), one); + assertSame(it.next(), three); assertFalse(it.hasNext()); } @@ -801,8 +712,7 @@ public class ArrayBlockingQueueTest extends JSR166TestCase { int k = 0; for (Iterator it = q.iterator(); it.hasNext();) { - int i = ((Integer)(it.next())).intValue(); - assertEquals(++k, i); + assertEquals(++k, it.next()); } assertEquals(3, k); } @@ -815,14 +725,9 @@ public class ArrayBlockingQueueTest extends JSR166TestCase { q.add(one); q.add(two); q.add(three); - try { - for (Iterator it = q.iterator(); it.hasNext();) { - q.remove(); - it.next(); - } - } - catch (ConcurrentModificationException e) { - unexpectedException(); + for (Iterator it = q.iterator(); it.hasNext();) { + q.remove(); + it.next(); } assertEquals(0, q.size()); } @@ -837,7 +742,7 @@ public class ArrayBlockingQueueTest extends JSR166TestCase { for (int i = 0; i < SIZE; ++i) { assertTrue(s.indexOf(String.valueOf(i)) >= 0); } - } + } /** @@ -848,33 +753,20 @@ public class ArrayBlockingQueueTest extends JSR166TestCase { q.add(one); q.add(two); ExecutorService executor = Executors.newFixedThreadPool(2); - executor.execute(new Runnable() { - public void run() { - threadAssertFalse(q.offer(three)); - try { - threadAssertTrue(q.offer(three, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS)); - threadAssertEquals(0, q.remainingCapacity()); - } - catch (InterruptedException e) { - threadUnexpectedException(); - } - } - }); + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(q.offer(three)); + assertTrue(q.offer(three, MEDIUM_DELAY_MS, MILLISECONDS)); + assertEquals(0, q.remainingCapacity()); + }}); + + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + Thread.sleep(SMALL_DELAY_MS); + assertSame(one, q.take()); + }}); - executor.execute(new Runnable() { - public void run() { - try { - Thread.sleep(SMALL_DELAY_MS); - threadAssertEquals(one, q.take()); - } - catch (InterruptedException e) { - threadUnexpectedException(); - } - } - }); - joinPool(executor); - } /** @@ -883,91 +775,73 @@ public class ArrayBlockingQueueTest extends JSR166TestCase { public void testPollInExecutor() { final ArrayBlockingQueue q = new ArrayBlockingQueue(2); ExecutorService executor = Executors.newFixedThreadPool(2); - executor.execute(new Runnable() { - public void run() { - threadAssertNull(q.poll()); - try { - threadAssertTrue(null != q.poll(MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS)); - threadAssertTrue(q.isEmpty()); - } - catch (InterruptedException e) { - threadUnexpectedException(); - } - } - }); + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertNull(q.poll()); + assertSame(one, q.poll(MEDIUM_DELAY_MS, MILLISECONDS)); + assertTrue(q.isEmpty()); + }}); + + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + Thread.sleep(SMALL_DELAY_MS); + q.put(one); + }}); - executor.execute(new Runnable() { - public void run() { - try { - Thread.sleep(SMALL_DELAY_MS); - q.put(one); - } - catch (InterruptedException e) { - threadUnexpectedException(); - } - } - }); - joinPool(executor); } /** * A deserialized serialized queue has same elements in same order */ - public void testSerialization() { + public void testSerialization() throws Exception { ArrayBlockingQueue q = populatedQueue(SIZE); - try { - ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); - ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); - out.writeObject(q); - out.close(); - - ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); - ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); - ArrayBlockingQueue r = (ArrayBlockingQueue)in.readObject(); - assertEquals(q.size(), r.size()); - while (!q.isEmpty()) - assertEquals(q.remove(), r.remove()); - } catch(Exception e){ - unexpectedException(); - } + ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); + ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); + out.writeObject(q); + out.close(); + + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); + ArrayBlockingQueue r = (ArrayBlockingQueue)in.readObject(); + assertEquals(q.size(), r.size()); + while (!q.isEmpty()) + assertEquals(q.remove(), r.remove()); } /** * drainTo(null) throws NPE - */ + */ public void testDrainToNull() { ArrayBlockingQueue q = populatedQueue(SIZE); try { q.drainTo(null); shouldThrow(); - } catch(NullPointerException success) { - } + } catch (NullPointerException success) {} } /** * drainTo(this) throws IAE - */ + */ public void testDrainToSelf() { ArrayBlockingQueue q = populatedQueue(SIZE); try { q.drainTo(q); shouldThrow(); - } catch(IllegalArgumentException success) { - } + } catch (IllegalArgumentException success) {} } /** * drainTo(c) empties queue into another collection c - */ + */ public void testDrainTo() { ArrayBlockingQueue q = populatedQueue(SIZE); ArrayList l = new ArrayList(); q.drainTo(l); assertEquals(q.size(), 0); assertEquals(l.size(), SIZE); - for (int i = 0; i < SIZE; ++i) + for (int i = 0; i < SIZE; ++i) assertEquals(l.get(i), new Integer(i)); q.add(zero); q.add(one); @@ -978,80 +852,69 @@ public class ArrayBlockingQueueTest extends JSR166TestCase { q.drainTo(l); assertEquals(q.size(), 0); assertEquals(l.size(), 2); - for (int i = 0; i < 2; ++i) + for (int i = 0; i < 2; ++i) assertEquals(l.get(i), new Integer(i)); } /** * drainTo empties full queue, unblocking a waiting put. - */ - public void testDrainToWithActivePut() { + */ + public void testDrainToWithActivePut() throws InterruptedException { final ArrayBlockingQueue q = populatedQueue(SIZE); - Thread t = new Thread(new Runnable() { - public void run() { - try { - q.put(new Integer(SIZE+1)); - } catch (InterruptedException ie){ - threadUnexpectedException(); - } - } - }); - try { - t.start(); - ArrayList l = new ArrayList(); - q.drainTo(l); - assertTrue(l.size() >= SIZE); - for (int i = 0; i < SIZE; ++i) - assertEquals(l.get(i), new Integer(i)); - t.join(); - assertTrue(q.size() + l.size() >= SIZE); - } catch(Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + q.put(new Integer(SIZE+1)); + }}); + + t.start(); + ArrayList l = new ArrayList(); + q.drainTo(l); + assertTrue(l.size() >= SIZE); + for (int i = 0; i < SIZE; ++i) + assertEquals(l.get(i), new Integer(i)); + t.join(); + assertTrue(q.size() + l.size() >= SIZE); } /** * drainTo(null, n) throws NPE - */ + */ public void testDrainToNullN() { ArrayBlockingQueue q = populatedQueue(SIZE); try { q.drainTo(null, 0); shouldThrow(); - } catch(NullPointerException success) { - } + } catch (NullPointerException success) {} } /** * drainTo(this, n) throws IAE - */ + */ public void testDrainToSelfN() { ArrayBlockingQueue q = populatedQueue(SIZE); try { q.drainTo(q, 0); shouldThrow(); - } catch(IllegalArgumentException success) { - } + } catch (IllegalArgumentException success) {} } /** * drainTo(c, n) empties first max {n, size} elements of queue into c - */ + */ public void testDrainToN() { ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE*2); for (int i = 0; i < SIZE + 2; ++i) { - for(int j = 0; j < SIZE; j++) + for (int j = 0; j < SIZE; j++) assertTrue(q.offer(new Integer(j))); ArrayList l = new ArrayList(); q.drainTo(l, i); int k = (i < SIZE)? i : SIZE; assertEquals(l.size(), k); assertEquals(q.size(), SIZE-k); - for (int j = 0; j < k; ++j) + for (int j = 0; j < k; ++j) assertEquals(l.get(j), new Integer(j)); while (q.poll() != null) ; } } - } diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/ArrayDequeTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/ArrayDequeTest.java new file mode 100644 index 0000000..cec1d58 --- /dev/null +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/ArrayDequeTest.java @@ -0,0 +1,630 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package tests.api.java.util.concurrent; // android-added + +import junit.framework.*; +import java.util.*; +import java.util.concurrent.*; + +public class ArrayDequeTest extends JSR166TestCase { + public static Test suite() { + return new TestSuite(ArrayDequeTest.class); + } + + /** + * Create a queue of given size containing consecutive + * Integers 0 ... n. + */ + private ArrayDeque populatedDeque(int n) { + ArrayDeque q = new ArrayDeque(); + assertTrue(q.isEmpty()); + for (int i = 0; i < n; ++i) + assertTrue(q.offerLast(new Integer(i))); + assertFalse(q.isEmpty()); + assertEquals(n, q.size()); + return q; + } + + /** + * new queue is empty + */ + public void testConstructor1() { + assertEquals(0, new ArrayDeque().size()); + } + + /** + * Initializing from null Collection throws NPE + */ + public void testConstructor3() { + try { + ArrayDeque q = new ArrayDeque((Collection)null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Queue contains all elements of collection used to initialize + + */ + public void testConstructor6() { + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + ArrayDeque q = new ArrayDeque(Arrays.asList(ints)); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.pollFirst()); + } + + /** + * isEmpty is true before add, false after + */ + public void testEmpty() { + ArrayDeque q = new ArrayDeque(); + assertTrue(q.isEmpty()); + q.add(new Integer(1)); + assertFalse(q.isEmpty()); + q.add(new Integer(2)); + q.removeFirst(); + q.removeFirst(); + assertTrue(q.isEmpty()); + } + + /** + * size changes when elements added and removed + */ + public void testSize() { + ArrayDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(SIZE-i, q.size()); + q.removeFirst(); + } + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.size()); + q.add(new Integer(i)); + } + } + + /** + * push(null) throws NPE + */ + public void testPushNull() { + try { + ArrayDeque q = new ArrayDeque(1); + q.push(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * peekFirst returns element inserted with push + */ + public void testPush() { + ArrayDeque q = populatedDeque(3); + q.pollLast(); + q.push(four); + assertSame(four, q.peekFirst()); + } + + /** + * pop removes next element, or throws NSEE if empty + */ + public void testPop() { + ArrayDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.pop()); + } + try { + q.pop(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * offer(null) throws NPE + */ + public void testOfferFirstNull() { + try { + ArrayDeque q = new ArrayDeque(); + q.offerFirst(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * OfferFirst succeeds + */ + public void testOfferFirst() { + ArrayDeque q = new ArrayDeque(); + assertTrue(q.offerFirst(new Integer(0))); + assertTrue(q.offerFirst(new Integer(1))); + } + + /** + * OfferLast succeeds + */ + public void testOfferLast() { + ArrayDeque q = new ArrayDeque(); + assertTrue(q.offerLast(new Integer(0))); + assertTrue(q.offerLast(new Integer(1))); + } + + /** + * add succeeds + */ + public void testAdd() { + ArrayDeque q = new ArrayDeque(); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.size()); + assertTrue(q.add(new Integer(i))); + } + } + + /** + * addAll(null) throws NPE + */ + public void testAddAll1() { + try { + ArrayDeque q = new ArrayDeque(); + q.addAll(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Queue contains all elements, in traversal order, of successful addAll + */ + public void testAddAll5() { + Integer[] empty = new Integer[0]; + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + ArrayDeque q = new ArrayDeque(); + assertFalse(q.addAll(Arrays.asList(empty))); + assertTrue(q.addAll(Arrays.asList(ints))); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.pollFirst()); + } + + /** + * pollFirst succeeds unless empty + */ + public void testPollFirst() { + ArrayDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.pollFirst()); + } + assertNull(q.pollFirst()); + } + + /** + * pollLast succeeds unless empty + */ + public void testPollLast() { + ArrayDeque q = populatedDeque(SIZE); + for (int i = SIZE-1; i >= 0; --i) { + assertEquals(i, q.pollLast()); + } + assertNull(q.pollLast()); + } + + /** + * poll succeeds unless empty + */ + public void testPoll() { + ArrayDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.poll()); + } + assertNull(q.poll()); + } + + /** + * remove removes next element, or throws NSEE if empty + */ + public void testRemove() { + ArrayDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.remove()); + } + try { + q.remove(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * peekFirst returns next element, or null if empty + */ + public void testPeekFirst() { + ArrayDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.peekFirst()); + assertEquals(i, q.pollFirst()); + assertTrue(q.peekFirst() == null || + !q.peekFirst().equals(i)); + } + assertNull(q.peekFirst()); + } + + /** + * peek returns next element, or null if empty + */ + public void testPeek() { + ArrayDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.peek()); + assertEquals(i, q.poll()); + assertTrue(q.peek() == null || + !q.peek().equals(i)); + } + assertNull(q.peek()); + } + + /** + * peekLast returns next element, or null if empty + */ + public void testPeekLast() { + ArrayDeque q = populatedDeque(SIZE); + for (int i = SIZE-1; i >= 0; --i) { + assertEquals(i, q.peekLast()); + assertEquals(i, q.pollLast()); + assertTrue(q.peekLast() == null || + !q.peekLast().equals(i)); + } + assertNull(q.peekLast()); + } + + /** + * getFirst returns next getFirst, or throws NSEE if empty + */ + public void testFirstElement() { + ArrayDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.getFirst()); + assertEquals(i, q.pollFirst()); + } + try { + q.getFirst(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * getLast returns next element, or throws NSEE if empty + */ + public void testLastElement() { + ArrayDeque q = populatedDeque(SIZE); + for (int i = SIZE-1; i >= 0; --i) { + assertEquals(i, q.getLast()); + assertEquals(i, q.pollLast()); + } + try { + q.getLast(); + shouldThrow(); + } catch (NoSuchElementException success) {} + assertNull(q.peekLast()); + } + + + /** + * removeFirst removes next element, or throws NSEE if empty + */ + public void testRemoveFirst() { + ArrayDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.removeFirst()); + } + try { + q.removeFirst(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * removeFirstOccurrence(x) removes x and returns true if present + */ + public void testRemoveFirstOccurrence() { + ArrayDeque q = populatedDeque(SIZE); + for (int i = 1; i < SIZE; i+=2) { + assertTrue(q.removeFirstOccurrence(new Integer(i))); + } + for (int i = 0; i < SIZE; i+=2) { + assertTrue(q.removeFirstOccurrence(new Integer(i))); + assertFalse(q.removeFirstOccurrence(new Integer(i+1))); + } + assertTrue(q.isEmpty()); + } + + /** + * removeLastOccurrence(x) removes x and returns true if present + */ + public void testRemoveLastOccurrence() { + ArrayDeque q = populatedDeque(SIZE); + for (int i = 1; i < SIZE; i+=2) { + assertTrue(q.removeLastOccurrence(new Integer(i))); + } + for (int i = 0; i < SIZE; i+=2) { + assertTrue(q.removeLastOccurrence(new Integer(i))); + assertFalse(q.removeLastOccurrence(new Integer(i+1))); + } + assertTrue(q.isEmpty()); + } + + /** + * contains(x) reports true when elements added but not yet removed + */ + public void testContains() { + ArrayDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.contains(new Integer(i))); + assertEquals(i, q.pollFirst()); + assertFalse(q.contains(new Integer(i))); + } + } + + /** + * clear removes all elements + */ + public void testClear() { + ArrayDeque q = populatedDeque(SIZE); + q.clear(); + assertTrue(q.isEmpty()); + assertEquals(0, q.size()); + assertTrue(q.add(new Integer(1))); + assertFalse(q.isEmpty()); + q.clear(); + assertTrue(q.isEmpty()); + } + + /** + * containsAll(c) is true when c contains a subset of elements + */ + public void testContainsAll() { + ArrayDeque q = populatedDeque(SIZE); + ArrayDeque p = new ArrayDeque(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.containsAll(p)); + assertFalse(p.containsAll(q)); + assertTrue(p.add(new Integer(i))); + } + assertTrue(p.containsAll(q)); + } + + /** + * retainAll(c) retains only those elements of c and reports true if changed + */ + public void testRetainAll() { + ArrayDeque q = populatedDeque(SIZE); + ArrayDeque p = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + boolean changed = q.retainAll(p); + assertEquals(changed, (i > 0)); + assertTrue(q.containsAll(p)); + assertEquals(SIZE-i, q.size()); + p.removeFirst(); + } + } + + /** + * removeAll(c) removes only those elements of c and reports true if changed + */ + public void testRemoveAll() { + for (int i = 1; i < SIZE; ++i) { + ArrayDeque q = populatedDeque(SIZE); + ArrayDeque p = populatedDeque(i); + assertTrue(q.removeAll(p)); + assertEquals(SIZE-i, q.size()); + for (int j = 0; j < i; ++j) { + assertFalse(q.contains(p.removeFirst())); + } + } + } + + /** + * toArray contains all elements + */ + public void testToArray() { + ArrayDeque q = populatedDeque(SIZE); + Object[] o = q.toArray(); + Arrays.sort(o); + for (int i = 0; i < o.length; i++) + assertEquals(o[i], q.pollFirst()); + } + + /** + * toArray(a) contains all elements + */ + public void testToArray2() { + ArrayDeque q = populatedDeque(SIZE); + Integer[] ints = new Integer[SIZE]; + ints = (Integer[])q.toArray(ints); + Arrays.sort(ints); + for (int i = 0; i < ints.length; i++) + assertEquals(ints[i], q.pollFirst()); + } + + /** + * toArray(null) throws NPE + */ + public void testToArray_BadArg() { + ArrayDeque l = new ArrayDeque(); + l.add(new Object()); + try { + Object o[] = l.toArray(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * toArray with incompatible array type throws CCE + */ + public void testToArray1_BadArg() { + ArrayDeque l = new ArrayDeque(); + l.add(new Integer(5)); + try { + Object o[] = l.toArray(new String[10]); + shouldThrow(); + } catch (ArrayStoreException success) {} + } + + /** + * iterator iterates through all elements + */ + public void testIterator() { + ArrayDeque q = populatedDeque(SIZE); + int i = 0; + Iterator it = q.iterator(); + while (it.hasNext()) { + assertTrue(q.contains(it.next())); + ++i; + } + assertEquals(i, SIZE); + } + + /** + * iterator ordering is FIFO + */ + public void testIteratorOrdering() { + final ArrayDeque q = new ArrayDeque(); + q.add(new Integer(1)); + q.add(new Integer(2)); + q.add(new Integer(3)); + int k = 0; + for (Iterator it = q.iterator(); it.hasNext();) { + assertEquals(++k, it.next()); + } + + assertEquals(3, k); + } + + /** + * iterator.remove removes current element + */ + public void testIteratorRemove () { + final ArrayDeque q = new ArrayDeque(); + final Random rng = new Random(); + for (int iters = 0; iters < 100; ++iters) { + int max = rng.nextInt(5) + 2; + int split = rng.nextInt(max-1) + 1; + for (int j = 1; j <= max; ++j) + q.add(new Integer(j)); + Iterator it = q.iterator(); + for (int j = 1; j <= split; ++j) + assertEquals(it.next(), new Integer(j)); + it.remove(); + assertEquals(it.next(), new Integer(split+1)); + for (int j = 1; j <= split; ++j) + q.remove(new Integer(j)); + it = q.iterator(); + for (int j = split+1; j <= max; ++j) { + assertEquals(it.next(), new Integer(j)); + it.remove(); + } + assertFalse(it.hasNext()); + assertTrue(q.isEmpty()); + } + } + + /** + * Descending iterator iterates through all elements + */ + public void testDescendingIterator() { + ArrayDeque q = populatedDeque(SIZE); + int i = 0; + Iterator it = q.descendingIterator(); + while (it.hasNext()) { + assertTrue(q.contains(it.next())); + ++i; + } + assertEquals(i, SIZE); + assertFalse(it.hasNext()); + try { + it.next(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * Descending iterator ordering is reverse FIFO + */ + public void testDescendingIteratorOrdering() { + final ArrayDeque q = new ArrayDeque(); + for (int iters = 0; iters < 100; ++iters) { + q.add(new Integer(3)); + q.add(new Integer(2)); + q.add(new Integer(1)); + int k = 0; + for (Iterator it = q.descendingIterator(); it.hasNext();) { + assertEquals(++k, it.next()); + } + + assertEquals(3, k); + q.remove(); + q.remove(); + q.remove(); + } + } + + /** + * descendingIterator.remove removes current element + */ + public void testDescendingIteratorRemove () { + final ArrayDeque q = new ArrayDeque(); + final Random rng = new Random(); + for (int iters = 0; iters < 100; ++iters) { + int max = rng.nextInt(5) + 2; + int split = rng.nextInt(max-1) + 1; + for (int j = max; j >= 1; --j) + q.add(new Integer(j)); + Iterator it = q.descendingIterator(); + for (int j = 1; j <= split; ++j) + assertEquals(it.next(), new Integer(j)); + it.remove(); + assertEquals(it.next(), new Integer(split+1)); + for (int j = 1; j <= split; ++j) + q.remove(new Integer(j)); + it = q.descendingIterator(); + for (int j = split+1; j <= max; ++j) { + assertEquals(it.next(), new Integer(j)); + it.remove(); + } + assertFalse(it.hasNext()); + assertTrue(q.isEmpty()); + } + } + + + /** + * toString contains toStrings of elements + */ + public void testToString() { + ArrayDeque q = populatedDeque(SIZE); + String s = q.toString(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(s.indexOf(String.valueOf(i)) >= 0); + } + } + + /** + * peekFirst returns element inserted with addFirst + */ + public void testAddFirst() { + ArrayDeque q = populatedDeque(3); + q.addFirst(four); + assertSame(four, q.peekFirst()); + } + + /** + * peekLast returns element inserted with addLast + */ + public void testAddLast() { + ArrayDeque q = populatedDeque(3); + q.addLast(four); + assertSame(four, q.peekLast()); + } + +} diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicBooleanTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicBooleanTest.java index c76196b..b2d91b8 100755 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicBooleanTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicBooleanTest.java @@ -2,11 +2,11 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.concurrent.atomic.*; @@ -21,8 +21,8 @@ public class AtomicBooleanTest extends JSR166TestCase { * constructor initializes to given value */ public void testConstructor() { - AtomicBoolean ai = new AtomicBoolean(true); - assertEquals(true,ai.get()); + assertTrue(new AtomicBoolean(true).get()); + assertFalse(new AtomicBoolean(false).get()); } /** @@ -30,7 +30,7 @@ public class AtomicBooleanTest extends JSR166TestCase { */ public void testConstructor2() { AtomicBoolean ai = new AtomicBoolean(); - assertEquals(false,ai.get()); + assertFalse(ai.get()); } /** @@ -38,12 +38,23 @@ public class AtomicBooleanTest extends JSR166TestCase { */ public void testGetSet() { AtomicBoolean ai = new AtomicBoolean(true); - assertEquals(true,ai.get()); + assertTrue(ai.get()); ai.set(false); - assertEquals(false,ai.get()); + assertFalse(ai.get()); ai.set(true); - assertEquals(true,ai.get()); - + assertTrue(ai.get()); + } + + /** + * get returns the last value lazySet in same thread + */ + public void testGetLazySet() { + AtomicBoolean ai = new AtomicBoolean(true); + assertTrue(ai.get()); + ai.lazySet(false); + assertFalse(ai.get()); + ai.lazySet(true); + assertTrue(ai.get()); } /** @@ -52,48 +63,44 @@ public class AtomicBooleanTest extends JSR166TestCase { public void testCompareAndSet() { AtomicBoolean ai = new AtomicBoolean(true); assertTrue(ai.compareAndSet(true,false)); - assertEquals(false,ai.get()); + assertFalse(ai.get()); assertTrue(ai.compareAndSet(false,false)); - assertEquals(false,ai.get()); + assertFalse(ai.get()); assertFalse(ai.compareAndSet(true,false)); - assertFalse((ai.get())); + assertFalse(ai.get()); assertTrue(ai.compareAndSet(false,true)); - assertEquals(true,ai.get()); + assertTrue(ai.get()); } /** * compareAndSet in one thread enables another waiting for value * to succeed */ - public void testCompareAndSetInMultipleThreads() { + public void testCompareAndSetInMultipleThreads() throws Exception { final AtomicBoolean ai = new AtomicBoolean(true); - Thread t = new Thread(new Runnable() { - public void run() { - while(!ai.compareAndSet(false, true)) Thread.yield(); - }}); - try { - t.start(); - assertTrue(ai.compareAndSet(true, false)); - t.join(LONG_DELAY_MS); - assertFalse(t.isAlive()); - } - catch(Exception e) { - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + while (!ai.compareAndSet(false, true)) Thread.yield(); + }}); + + t.start(); + assertTrue(ai.compareAndSet(true, false)); + t.join(LONG_DELAY_MS); + assertFalse(t.isAlive()); } /** * repeated weakCompareAndSet succeeds in changing value when equal - * to expected + * to expected */ public void testWeakCompareAndSet() { AtomicBoolean ai = new AtomicBoolean(true); - while(!ai.weakCompareAndSet(true,false)); - assertEquals(false,ai.get()); - while(!ai.weakCompareAndSet(false,false)); - assertEquals(false,ai.get()); - while(!ai.weakCompareAndSet(false,true)); - assertEquals(true,ai.get()); + while (!ai.weakCompareAndSet(true,false)); + assertFalse(ai.get()); + while (!ai.weakCompareAndSet(false,false)); + assertFalse(ai.get()); + while (!ai.weakCompareAndSet(false,true)); + assertTrue(ai.get()); } /** @@ -104,37 +111,32 @@ public class AtomicBooleanTest extends JSR166TestCase { assertEquals(true,ai.getAndSet(false)); assertEquals(false,ai.getAndSet(false)); assertEquals(false,ai.getAndSet(true)); - assertEquals(true,ai.get()); + assertTrue(ai.get()); } /** * a deserialized serialized atomic holds same value */ - public void testSerialization() { + public void testSerialization() throws Exception { AtomicBoolean l = new AtomicBoolean(); - try { - l.set(true); - ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); - ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); - out.writeObject(l); - out.close(); - - ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); - ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); - AtomicBoolean r = (AtomicBoolean) in.readObject(); - assertEquals(l.get(), r.get()); - } catch(Exception e){ - e.printStackTrace(); - unexpectedException(); - } + l.set(true); + ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); + ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); + out.writeObject(l); + out.close(); + + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); + AtomicBoolean r = (AtomicBoolean) in.readObject(); + assertEquals(l.get(), r.get()); } /** * toString returns current value. - */ + */ public void testToString() { - AtomicBoolean ai = new AtomicBoolean(); + AtomicBoolean ai = new AtomicBoolean(); assertEquals(ai.toString(), Boolean.toString(false)); ai.set(true); assertEquals(ai.toString(), Boolean.toString(true)); diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicIntegerArrayTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicIntegerArrayTest.java index d8afe4e..838296d 100644 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicIntegerArrayTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicIntegerArrayTest.java @@ -2,11 +2,11 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.concurrent.atomic.*; @@ -24,7 +24,7 @@ public class AtomicIntegerArrayTest extends JSR166TestCase { */ public void testConstructor() { AtomicIntegerArray ai = new AtomicIntegerArray(SIZE); - for (int i = 0; i < SIZE; ++i) + for (int i = 0; i < SIZE; ++i) assertEquals(0,ai.get(i)); } @@ -35,10 +35,8 @@ public class AtomicIntegerArrayTest extends JSR166TestCase { try { int[] a = null; AtomicIntegerArray ai = new AtomicIntegerArray(a); - } catch (NullPointerException success) { - } catch (Exception ex) { - unexpectedException(); - } + shouldThrow(); + } catch (NullPointerException success) {} } /** @@ -48,30 +46,34 @@ public class AtomicIntegerArrayTest extends JSR166TestCase { int[] a = { 17, 3, -42, 99, -7}; AtomicIntegerArray ai = new AtomicIntegerArray(a); assertEquals(a.length, ai.length()); - for (int i = 0; i < a.length; ++i) + for (int i = 0; i < a.length; ++i) assertEquals(a[i], ai.get(i)); } /** * get and set for out of bound indices throw IndexOutOfBoundsException */ - public void testIndexing(){ + public void testIndexing() { AtomicIntegerArray ai = new AtomicIntegerArray(SIZE); try { ai.get(SIZE); - } catch(IndexOutOfBoundsException success){ + shouldThrow(); + } catch (IndexOutOfBoundsException success) { } try { ai.get(-1); - } catch(IndexOutOfBoundsException success){ + shouldThrow(); + } catch (IndexOutOfBoundsException success) { } try { ai.set(SIZE, 0); - } catch(IndexOutOfBoundsException success){ + shouldThrow(); + } catch (IndexOutOfBoundsException success) { } try { ai.set(-1, 0); - } catch(IndexOutOfBoundsException success){ + shouldThrow(); + } catch (IndexOutOfBoundsException success) { } } @@ -79,7 +81,7 @@ public class AtomicIntegerArrayTest extends JSR166TestCase { * get returns the last value set at index */ public void testGetSet() { - AtomicIntegerArray ai = new AtomicIntegerArray(SIZE); + AtomicIntegerArray ai = new AtomicIntegerArray(SIZE); for (int i = 0; i < SIZE; ++i) { ai.set(i, 1); assertEquals(1,ai.get(i)); @@ -91,17 +93,32 @@ public class AtomicIntegerArrayTest extends JSR166TestCase { } /** + * get returns the last value lazySet at index by same thread + */ + public void testGetLazySet() { + AtomicIntegerArray ai = new AtomicIntegerArray(SIZE); + for (int i = 0; i < SIZE; ++i) { + ai.lazySet(i, 1); + assertEquals(1,ai.get(i)); + ai.lazySet(i, 2); + assertEquals(2,ai.get(i)); + ai.lazySet(i, -3); + assertEquals(-3,ai.get(i)); + } + } + + /** * compareAndSet succeeds in changing value if equal to expected else fails */ public void testCompareAndSet() { - AtomicIntegerArray ai = new AtomicIntegerArray(SIZE); + AtomicIntegerArray ai = new AtomicIntegerArray(SIZE); for (int i = 0; i < SIZE; ++i) { ai.set(i, 1); assertTrue(ai.compareAndSet(i, 1,2)); assertTrue(ai.compareAndSet(i, 2,-4)); assertEquals(-4,ai.get(i)); assertFalse(ai.compareAndSet(i, -5,7)); - assertFalse((7 == ai.get(i))); + assertEquals(-4,ai.get(i)); assertTrue(ai.compareAndSet(i, -4,7)); assertEquals(7,ai.get(i)); } @@ -111,37 +128,34 @@ public class AtomicIntegerArrayTest extends JSR166TestCase { * compareAndSet in one thread enables another waiting for value * to succeed */ - public void testCompareAndSetInMultipleThreads() { + public void testCompareAndSetInMultipleThreads() throws Exception { final AtomicIntegerArray a = new AtomicIntegerArray(1); a.set(0, 1); - Thread t = new Thread(new Runnable() { - public void run() { - while(!a.compareAndSet(0, 2, 3)) Thread.yield(); - }}); - try { - t.start(); - assertTrue(a.compareAndSet(0, 1, 2)); - t.join(LONG_DELAY_MS); - assertFalse(t.isAlive()); - assertEquals(a.get(0), 3); - } - catch(Exception e) { - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + while (!a.compareAndSet(0, 2, 3)) + Thread.yield(); + }}); + + t.start(); + assertTrue(a.compareAndSet(0, 1, 2)); + t.join(LONG_DELAY_MS); + assertFalse(t.isAlive()); + assertEquals(a.get(0), 3); } /** * repeated weakCompareAndSet succeeds in changing value when equal - * to expected + * to expected */ public void testWeakCompareAndSet() { - AtomicIntegerArray ai = new AtomicIntegerArray(SIZE); + AtomicIntegerArray ai = new AtomicIntegerArray(SIZE); for (int i = 0; i < SIZE; ++i) { ai.set(i, 1); - while(!ai.weakCompareAndSet(i, 1,2)); - while(!ai.weakCompareAndSet(i, 2,-4)); + while (!ai.weakCompareAndSet(i, 1,2)); + while (!ai.weakCompareAndSet(i, 2,-4)); assertEquals(-4,ai.get(i)); - while(!ai.weakCompareAndSet(i, -4,7)); + while (!ai.weakCompareAndSet(i, -4,7)); assertEquals(7,ai.get(i)); } } @@ -150,7 +164,7 @@ public class AtomicIntegerArrayTest extends JSR166TestCase { * getAndSet returns previous value and sets to given value at given index */ public void testGetAndSet() { - AtomicIntegerArray ai = new AtomicIntegerArray(SIZE); + AtomicIntegerArray ai = new AtomicIntegerArray(SIZE); for (int i = 0; i < SIZE; ++i) { ai.set(i, 1); assertEquals(1,ai.getAndSet(i,0)); @@ -163,7 +177,7 @@ public class AtomicIntegerArrayTest extends JSR166TestCase { * getAndAdd returns previous value and adds given value */ public void testGetAndAdd() { - AtomicIntegerArray ai = new AtomicIntegerArray(SIZE); + AtomicIntegerArray ai = new AtomicIntegerArray(SIZE); for (int i = 0; i < SIZE; ++i) { ai.set(i, 1); assertEquals(1,ai.getAndAdd(i,2)); @@ -177,7 +191,7 @@ public class AtomicIntegerArrayTest extends JSR166TestCase { * getAndDecrement returns previous value and decrements */ public void testGetAndDecrement() { - AtomicIntegerArray ai = new AtomicIntegerArray(SIZE); + AtomicIntegerArray ai = new AtomicIntegerArray(SIZE); for (int i = 0; i < SIZE; ++i) { ai.set(i, 1); assertEquals(1,ai.getAndDecrement(i)); @@ -190,7 +204,7 @@ public class AtomicIntegerArrayTest extends JSR166TestCase { * getAndIncrement returns previous value and increments */ public void testGetAndIncrement() { - AtomicIntegerArray ai = new AtomicIntegerArray(SIZE); + AtomicIntegerArray ai = new AtomicIntegerArray(SIZE); for (int i = 0; i < SIZE; ++i) { ai.set(i, 1); assertEquals(1,ai.getAndIncrement(i)); @@ -207,7 +221,7 @@ public class AtomicIntegerArrayTest extends JSR166TestCase { * addAndGet adds given value to current, and returns current value */ public void testAddAndGet() { - AtomicIntegerArray ai = new AtomicIntegerArray(SIZE); + AtomicIntegerArray ai = new AtomicIntegerArray(SIZE); for (int i = 0; i < SIZE; ++i) { ai.set(i, 1); assertEquals(3,ai.addAndGet(i,2)); @@ -221,7 +235,7 @@ public class AtomicIntegerArrayTest extends JSR166TestCase { * decrementAndGet decrements and returns current value */ public void testDecrementAndGet() { - AtomicIntegerArray ai = new AtomicIntegerArray(SIZE); + AtomicIntegerArray ai = new AtomicIntegerArray(SIZE); for (int i = 0; i < SIZE; ++i) { ai.set(i, 1); assertEquals(0,ai.decrementAndGet(i)); @@ -235,7 +249,7 @@ public class AtomicIntegerArrayTest extends JSR166TestCase { * incrementAndGet increments and returns current value */ public void testIncrementAndGet() { - AtomicIntegerArray ai = new AtomicIntegerArray(SIZE); + AtomicIntegerArray ai = new AtomicIntegerArray(SIZE); for (int i = 0; i < SIZE; ++i) { ai.set(i, 1); assertEquals(2,ai.incrementAndGet(i)); @@ -249,7 +263,7 @@ public class AtomicIntegerArrayTest extends JSR166TestCase { } static final int COUNTDOWN = 100000; - + class Counter implements Runnable { final AtomicIntegerArray ai; volatile int counts; @@ -276,57 +290,47 @@ public class AtomicIntegerArrayTest extends JSR166TestCase { * Multiple threads using same array of counters successfully * update a number of times equal to total count */ - public void testCountingInMultipleThreads() { - try { - final AtomicIntegerArray ai = new AtomicIntegerArray(SIZE); - for (int i = 0; i < SIZE; ++i) - ai.set(i, COUNTDOWN); - Counter c1 = new Counter(ai); - Counter c2 = new Counter(ai); - Thread t1 = new Thread(c1); - Thread t2 = new Thread(c2); - t1.start(); - t2.start(); - t1.join(); - t2.join(); - assertEquals(c1.counts+c2.counts, SIZE * COUNTDOWN); - } - catch(InterruptedException ie) { - unexpectedException(); - } + public void testCountingInMultipleThreads() throws InterruptedException { + final AtomicIntegerArray ai = new AtomicIntegerArray(SIZE); + for (int i = 0; i < SIZE; ++i) + ai.set(i, COUNTDOWN); + Counter c1 = new Counter(ai); + Counter c2 = new Counter(ai); + Thread t1 = new Thread(c1); + Thread t2 = new Thread(c2); + t1.start(); + t2.start(); + t1.join(); + t2.join(); + assertEquals(c1.counts+c2.counts, SIZE * COUNTDOWN); } /** * a deserialized serialized array holds same values */ - public void testSerialization() { - AtomicIntegerArray l = new AtomicIntegerArray(SIZE); - for (int i = 0; i < SIZE; ++i) + public void testSerialization() throws Exception { + AtomicIntegerArray l = new AtomicIntegerArray(SIZE); + for (int i = 0; i < SIZE; ++i) l.set(i, -i); - try { - ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); - ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); - out.writeObject(l); - out.close(); + ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); + ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); + out.writeObject(l); + out.close(); - ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); - ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); - AtomicIntegerArray r = (AtomicIntegerArray) in.readObject(); - for (int i = 0; i < SIZE; ++i) { - assertEquals(l.get(i), r.get(i)); - } - } catch(Exception e){ - e.printStackTrace(); - unexpectedException(); + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); + AtomicIntegerArray r = (AtomicIntegerArray) in.readObject(); + for (int i = 0; i < SIZE; ++i) { + assertEquals(l.get(i), r.get(i)); } } /** * toString returns current value. - */ + */ public void testToString() { int[] a = { 17, 3, -42, 99, -7}; AtomicIntegerArray ai = new AtomicIntegerArray(a); diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicIntegerFieldUpdaterTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicIntegerFieldUpdaterTest.java index a4ec85e..383e30b 100755 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicIntegerFieldUpdaterTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicIntegerFieldUpdaterTest.java @@ -2,11 +2,11 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import java.util.concurrent.atomic.*; import junit.framework.*; @@ -24,60 +24,36 @@ public class AtomicIntegerFieldUpdaterTest extends JSR166TestCase { * Construction with non-existent field throws RuntimeException */ public void testConstructor() { - try{ - AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> + try { + AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> a = AtomicIntegerFieldUpdater.newUpdater (AtomicIntegerFieldUpdaterTest.class, "y"); shouldThrow(); - } - catch (RuntimeException rt) {} + } catch (RuntimeException success) {} } /** * construction with field not of given type throws RuntimeException */ public void testConstructor2() { - try{ - AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> + try { + AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> a = AtomicIntegerFieldUpdater.newUpdater (AtomicIntegerFieldUpdaterTest.class, "z"); shouldThrow(); - } - catch (RuntimeException rt) {} + } catch (RuntimeException success) {} } /** * construction with non-volatile field throws RuntimeException */ public void testConstructor3() { - try{ - AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> + try { + AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> a = AtomicIntegerFieldUpdater.newUpdater (AtomicIntegerFieldUpdaterTest.class, "w"); shouldThrow(); - } - catch (RuntimeException rt) {} - } - - static class Base { - protected volatile int f = 0; - } - static class Sub1 extends Base { - AtomicIntegerFieldUpdater<Base> fUpdater - = AtomicIntegerFieldUpdater.newUpdater(Base.class, "f"); - } - static class Sub2 extends Base {} - - public void testProtectedFieldOnAnotherSubtype() { - Sub1 sub1 = new Sub1(); - Sub2 sub2 = new Sub2(); - - sub1.fUpdater.set(sub1, 1); - try { - sub1.fUpdater.set(sub2, 2); - shouldThrow(); - } - catch (RuntimeException rt) {} + } catch (RuntimeException success) {} } /** @@ -96,7 +72,24 @@ public class AtomicIntegerFieldUpdaterTest extends JSR166TestCase { assertEquals(2,a.get(this)); a.set(this,-3); assertEquals(-3,a.get(this)); - + } + + /** + * get returns the last value lazySet by same thread + */ + public void testGetLazySet() { + AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> a; + try { + a = AtomicIntegerFieldUpdater.newUpdater(AtomicIntegerFieldUpdaterTest.class, "x"); + } catch (RuntimeException ok) { + return; + } + x = 1; + assertEquals(1,a.get(this)); + a.lazySet(this,2); + assertEquals(2,a.get(this)); + a.lazySet(this,-3); + assertEquals(-3,a.get(this)); } /** @@ -114,7 +107,7 @@ public class AtomicIntegerFieldUpdaterTest extends JSR166TestCase { assertTrue(a.compareAndSet(this,2,-4)); assertEquals(-4,a.get(this)); assertFalse(a.compareAndSet(this,-5,7)); - assertFalse((7 == a.get(this))); + assertEquals(-4,a.get(this)); assertTrue(a.compareAndSet(this,-4,7)); assertEquals(7,a.get(this)); } @@ -124,7 +117,7 @@ public class AtomicIntegerFieldUpdaterTest extends JSR166TestCase { * compareAndSet in one thread enables another waiting for value * to succeed */ - public void testCompareAndSetInMultipleThreads() { + public void testCompareAndSetInMultipleThreads() throws Exception { x = 1; final AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest>a; try { @@ -133,25 +126,22 @@ public class AtomicIntegerFieldUpdaterTest extends JSR166TestCase { return; } - Thread t = new Thread(new Runnable() { - public void run() { - while(!a.compareAndSet(AtomicIntegerFieldUpdaterTest.this, 2, 3)) Thread.yield(); - }}); - try { - t.start(); - assertTrue(a.compareAndSet(this, 1, 2)); - t.join(LONG_DELAY_MS); - assertFalse(t.isAlive()); - assertEquals(a.get(this), 3); - } - catch(Exception e) { - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + while (!a.compareAndSet(AtomicIntegerFieldUpdaterTest.this, 2, 3)) + Thread.yield(); + }}); + + t.start(); + assertTrue(a.compareAndSet(this, 1, 2)); + t.join(LONG_DELAY_MS); + assertFalse(t.isAlive()); + assertEquals(a.get(this), 3); } /** * repeated weakCompareAndSet succeeds in changing value when equal - * to expected + * to expected */ public void testWeakCompareAndSet() { AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> a; @@ -161,10 +151,10 @@ public class AtomicIntegerFieldUpdaterTest extends JSR166TestCase { return; } x = 1; - while(!a.weakCompareAndSet(this,1,2)); - while(!a.weakCompareAndSet(this,2,-4)); + while (!a.weakCompareAndSet(this,1,2)); + while (!a.weakCompareAndSet(this,2,-4)); assertEquals(-4,a.get(this)); - while(!a.weakCompareAndSet(this,-4,7)); + while (!a.weakCompareAndSet(this,-4,7)); assertEquals(7,a.get(this)); } diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicIntegerTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicIntegerTest.java index a6b2a17..a2f3b4b 100755 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicIntegerTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicIntegerTest.java @@ -2,11 +2,11 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.concurrent.atomic.*; @@ -17,10 +17,14 @@ public class AtomicIntegerTest extends JSR166TestCase { return new TestSuite(AtomicIntegerTest.class); } + final int[] VALUES = { + Integer.MIN_VALUE, -1, 0, 1, 42, Integer.MAX_VALUE, + }; + /** * constructor initializes to given value */ - public void testConstructor(){ + public void testConstructor() { AtomicInteger ai = new AtomicInteger(1); assertEquals(1,ai.get()); } @@ -28,7 +32,7 @@ public class AtomicIntegerTest extends JSR166TestCase { /** * default constructed initializes to zero */ - public void testConstructor2(){ + public void testConstructor2() { AtomicInteger ai = new AtomicInteger(); assertEquals(0,ai.get()); } @@ -36,26 +40,37 @@ public class AtomicIntegerTest extends JSR166TestCase { /** * get returns the last value set */ - public void testGetSet(){ + public void testGetSet() { AtomicInteger ai = new AtomicInteger(1); assertEquals(1,ai.get()); ai.set(2); assertEquals(2,ai.get()); ai.set(-3); assertEquals(-3,ai.get()); - + } + + /** + * get returns the last value lazySet in same thread + */ + public void testGetLazySet() { + AtomicInteger ai = new AtomicInteger(1); + assertEquals(1,ai.get()); + ai.lazySet(2); + assertEquals(2,ai.get()); + ai.lazySet(-3); + assertEquals(-3,ai.get()); } /** * compareAndSet succeeds in changing value if equal to expected else fails */ - public void testCompareAndSet(){ + public void testCompareAndSet() { AtomicInteger ai = new AtomicInteger(1); assertTrue(ai.compareAndSet(1,2)); assertTrue(ai.compareAndSet(2,-4)); assertEquals(-4,ai.get()); assertFalse(ai.compareAndSet(-5,7)); - assertFalse((7 == ai.get())); + assertEquals(-4,ai.get()); assertTrue(ai.compareAndSet(-4,7)); assertEquals(7,ai.get()); } @@ -64,41 +79,38 @@ public class AtomicIntegerTest extends JSR166TestCase { * compareAndSet in one thread enables another waiting for value * to succeed */ - public void testCompareAndSetInMultipleThreads() { + public void testCompareAndSetInMultipleThreads() throws Exception { final AtomicInteger ai = new AtomicInteger(1); - Thread t = new Thread(new Runnable() { - public void run() { - while(!ai.compareAndSet(2, 3)) Thread.yield(); - }}); - try { - t.start(); - assertTrue(ai.compareAndSet(1, 2)); - t.join(LONG_DELAY_MS); - assertFalse(t.isAlive()); - assertEquals(ai.get(), 3); - } - catch(Exception e) { - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + while (!ai.compareAndSet(2, 3)) + Thread.yield(); + }}); + + t.start(); + assertTrue(ai.compareAndSet(1, 2)); + t.join(LONG_DELAY_MS); + assertFalse(t.isAlive()); + assertEquals(ai.get(), 3); } /** * repeated weakCompareAndSet succeeds in changing value when equal - * to expected + * to expected */ - public void testWeakCompareAndSet(){ + public void testWeakCompareAndSet() { AtomicInteger ai = new AtomicInteger(1); - while(!ai.weakCompareAndSet(1,2)); - while(!ai.weakCompareAndSet(2,-4)); + while (!ai.weakCompareAndSet(1,2)); + while (!ai.weakCompareAndSet(2,-4)); assertEquals(-4,ai.get()); - while(!ai.weakCompareAndSet(-4,7)); + while (!ai.weakCompareAndSet(-4,7)); assertEquals(7,ai.get()); } /** * getAndSet returns previous value and sets to given value */ - public void testGetAndSet(){ + public void testGetAndSet() { AtomicInteger ai = new AtomicInteger(1); assertEquals(1,ai.getAndSet(0)); assertEquals(0,ai.getAndSet(-10)); @@ -108,7 +120,7 @@ public class AtomicIntegerTest extends JSR166TestCase { /** * getAndAdd returns previous value and adds given value */ - public void testGetAndAdd(){ + public void testGetAndAdd() { AtomicInteger ai = new AtomicInteger(1); assertEquals(1,ai.getAndAdd(2)); assertEquals(3,ai.get()); @@ -119,7 +131,7 @@ public class AtomicIntegerTest extends JSR166TestCase { /** * getAndDecrement returns previous value and decrements */ - public void testGetAndDecrement(){ + public void testGetAndDecrement() { AtomicInteger ai = new AtomicInteger(1); assertEquals(1,ai.getAndDecrement()); assertEquals(0,ai.getAndDecrement()); @@ -129,7 +141,7 @@ public class AtomicIntegerTest extends JSR166TestCase { /** * getAndIncrement returns previous value and increments */ - public void testGetAndIncrement(){ + public void testGetAndIncrement() { AtomicInteger ai = new AtomicInteger(1); assertEquals(1,ai.getAndIncrement()); assertEquals(2,ai.get()); @@ -143,7 +155,7 @@ public class AtomicIntegerTest extends JSR166TestCase { /** * addAndGet adds given value to current, and returns current value */ - public void testAddAndGet(){ + public void testAddAndGet() { AtomicInteger ai = new AtomicInteger(1); assertEquals(3,ai.addAndGet(2)); assertEquals(3,ai.get()); @@ -154,7 +166,7 @@ public class AtomicIntegerTest extends JSR166TestCase { /** * decrementAndGet decrements and returns current value */ - public void testDecrementAndGet(){ + public void testDecrementAndGet() { AtomicInteger ai = new AtomicInteger(1); assertEquals(0,ai.decrementAndGet()); assertEquals(-1,ai.decrementAndGet()); @@ -165,7 +177,7 @@ public class AtomicIntegerTest extends JSR166TestCase { /** * incrementAndGet increments and returns current value */ - public void testIncrementAndGet(){ + public void testIncrementAndGet() { AtomicInteger ai = new AtomicInteger(1); assertEquals(2,ai.incrementAndGet()); assertEquals(2,ai.get()); @@ -179,81 +191,79 @@ public class AtomicIntegerTest extends JSR166TestCase { /** * a deserialized serialized atomic holds same value */ - public void testSerialization() { + public void testSerialization() throws Exception { AtomicInteger l = new AtomicInteger(); - try { - l.set(22); - ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); - ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); - out.writeObject(l); - out.close(); + l.set(22); + ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); + ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); + out.writeObject(l); + out.close(); - ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); - ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); - AtomicInteger r = (AtomicInteger) in.readObject(); - assertEquals(l.get(), r.get()); - } catch(Exception e){ - unexpectedException(); - } + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); + AtomicInteger r = (AtomicInteger) in.readObject(); + assertEquals(l.get(), r.get()); } /** * toString returns current value. - */ + */ public void testToString() { AtomicInteger ai = new AtomicInteger(); - for (int i = -12; i < 6; ++i) { - ai.set(i); - assertEquals(ai.toString(), Integer.toString(i)); + assertEquals("0", ai.toString()); + for (int x : VALUES) { + ai.set(x); + assertEquals(ai.toString(), Integer.toString(x)); } } /** * intValue returns current value. - */ + */ public void testIntValue() { AtomicInteger ai = new AtomicInteger(); - for (int i = -12; i < 6; ++i) { - ai.set(i); - assertEquals(i, ai.intValue()); + assertEquals(0, ai.intValue()); + for (int x : VALUES) { + ai.set(x); + assertEquals(x, ai.intValue()); } } - /** * longValue returns current value. - */ + */ public void testLongValue() { AtomicInteger ai = new AtomicInteger(); - for (int i = -12; i < 6; ++i) { - ai.set(i); - assertEquals((long)i, ai.longValue()); + assertEquals(0L, ai.longValue()); + for (int x : VALUES) { + ai.set(x); + assertEquals((long)x, ai.longValue()); } } /** * floatValue returns current value. - */ + */ public void testFloatValue() { AtomicInteger ai = new AtomicInteger(); - for (int i = -12; i < 6; ++i) { - ai.set(i); - assertEquals((float)i, ai.floatValue()); + assertEquals(0.0f, ai.floatValue()); + for (int x : VALUES) { + ai.set(x); + assertEquals((float)x, ai.floatValue()); } } /** * doubleValue returns current value. - */ + */ public void testDoubleValue() { AtomicInteger ai = new AtomicInteger(); - for (int i = -12; i < 6; ++i) { - ai.set(i); - assertEquals((double)i, ai.doubleValue()); + assertEquals(0.0d, ai.doubleValue()); + for (int x : VALUES) { + ai.set(x); + assertEquals((double)x, ai.doubleValue()); } } - - } diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicLongArrayTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicLongArrayTest.java index 262d273..88e0984 100644 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicLongArrayTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicLongArrayTest.java @@ -2,11 +2,11 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.concurrent.atomic.*; @@ -21,9 +21,9 @@ public class AtomicLongArrayTest extends JSR166TestCase { /** * constructor creates array of given size with all elements zero */ - public void testConstructor(){ + public void testConstructor() { AtomicLongArray ai = new AtomicLongArray(SIZE); - for (int i = 0; i < SIZE; ++i) + for (int i = 0; i < SIZE; ++i) assertEquals(0,ai.get(i)); } @@ -34,10 +34,8 @@ public class AtomicLongArrayTest extends JSR166TestCase { try { long[] a = null; AtomicLongArray ai = new AtomicLongArray(a); - } catch (NullPointerException success) { - } catch (Exception ex) { - unexpectedException(); - } + shouldThrow(); + } catch (NullPointerException success) {} } /** @@ -47,38 +45,42 @@ public class AtomicLongArrayTest extends JSR166TestCase { long[] a = { 17L, 3L, -42L, 99L, -7L}; AtomicLongArray ai = new AtomicLongArray(a); assertEquals(a.length, ai.length()); - for (int i = 0; i < a.length; ++i) + for (int i = 0; i < a.length; ++i) assertEquals(a[i], ai.get(i)); } /** * get and set for out of bound indices throw IndexOutOfBoundsException */ - public void testIndexing(){ + public void testIndexing() { AtomicLongArray ai = new AtomicLongArray(SIZE); try { ai.get(SIZE); - } catch(IndexOutOfBoundsException success){ + shouldThrow(); + } catch (IndexOutOfBoundsException success) { } try { ai.get(-1); - } catch(IndexOutOfBoundsException success){ + shouldThrow(); + } catch (IndexOutOfBoundsException success) { } try { ai.set(SIZE, 0); - } catch(IndexOutOfBoundsException success){ + shouldThrow(); + } catch (IndexOutOfBoundsException success) { } try { ai.set(-1, 0); - } catch(IndexOutOfBoundsException success){ + shouldThrow(); + } catch (IndexOutOfBoundsException success) { } } /** * get returns the last value set at index */ - public void testGetSet(){ - AtomicLongArray ai = new AtomicLongArray(SIZE); + public void testGetSet() { + AtomicLongArray ai = new AtomicLongArray(SIZE); for (int i = 0; i < SIZE; ++i) { ai.set(i, 1); assertEquals(1,ai.get(i)); @@ -90,17 +92,32 @@ public class AtomicLongArrayTest extends JSR166TestCase { } /** + * get returns the last value lazySet at index by same thread + */ + public void testGetLazySet() { + AtomicLongArray ai = new AtomicLongArray(SIZE); + for (int i = 0; i < SIZE; ++i) { + ai.lazySet(i, 1); + assertEquals(1,ai.get(i)); + ai.lazySet(i, 2); + assertEquals(2,ai.get(i)); + ai.lazySet(i, -3); + assertEquals(-3,ai.get(i)); + } + } + + /** * compareAndSet succeeds in changing value if equal to expected else fails */ - public void testCompareAndSet(){ - AtomicLongArray ai = new AtomicLongArray(SIZE); + public void testCompareAndSet() { + AtomicLongArray ai = new AtomicLongArray(SIZE); for (int i = 0; i < SIZE; ++i) { ai.set(i, 1); assertTrue(ai.compareAndSet(i, 1,2)); assertTrue(ai.compareAndSet(i, 2,-4)); assertEquals(-4,ai.get(i)); assertFalse(ai.compareAndSet(i, -5,7)); - assertFalse((7 == ai.get(i))); + assertEquals(-4,ai.get(i)); assertTrue(ai.compareAndSet(i, -4,7)); assertEquals(7,ai.get(i)); } @@ -110,37 +127,34 @@ public class AtomicLongArrayTest extends JSR166TestCase { * compareAndSet in one thread enables another waiting for value * to succeed */ - public void testCompareAndSetInMultipleThreads() { + public void testCompareAndSetInMultipleThreads() throws InterruptedException { final AtomicLongArray a = new AtomicLongArray(1); a.set(0, 1); - Thread t = new Thread(new Runnable() { - public void run() { - while(!a.compareAndSet(0, 2, 3)) Thread.yield(); - }}); - try { - t.start(); - assertTrue(a.compareAndSet(0, 1, 2)); - t.join(LONG_DELAY_MS); - assertFalse(t.isAlive()); - assertEquals(a.get(0), 3); - } - catch(Exception e) { - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + while (!a.compareAndSet(0, 2, 3)) + Thread.yield(); + }}); + + t.start(); + assertTrue(a.compareAndSet(0, 1, 2)); + t.join(LONG_DELAY_MS); + assertFalse(t.isAlive()); + assertEquals(a.get(0), 3); } /** * repeated weakCompareAndSet succeeds in changing value when equal - * to expected + * to expected */ - public void testWeakCompareAndSet(){ - AtomicLongArray ai = new AtomicLongArray(SIZE); + public void testWeakCompareAndSet() { + AtomicLongArray ai = new AtomicLongArray(SIZE); for (int i = 0; i < SIZE; ++i) { ai.set(i, 1); - while(!ai.weakCompareAndSet(i, 1,2)); - while(!ai.weakCompareAndSet(i, 2,-4)); + while (!ai.weakCompareAndSet(i, 1,2)); + while (!ai.weakCompareAndSet(i, 2,-4)); assertEquals(-4,ai.get(i)); - while(!ai.weakCompareAndSet(i, -4,7)); + while (!ai.weakCompareAndSet(i, -4,7)); assertEquals(7,ai.get(i)); } } @@ -148,8 +162,8 @@ public class AtomicLongArrayTest extends JSR166TestCase { /** * getAndSet returns previous value and sets to given value at given index */ - public void testGetAndSet(){ - AtomicLongArray ai = new AtomicLongArray(SIZE); + public void testGetAndSet() { + AtomicLongArray ai = new AtomicLongArray(SIZE); for (int i = 0; i < SIZE; ++i) { ai.set(i, 1); assertEquals(1,ai.getAndSet(i,0)); @@ -161,8 +175,8 @@ public class AtomicLongArrayTest extends JSR166TestCase { /** * getAndAdd returns previous value and adds given value */ - public void testGetAndAdd(){ - AtomicLongArray ai = new AtomicLongArray(SIZE); + public void testGetAndAdd() { + AtomicLongArray ai = new AtomicLongArray(SIZE); for (int i = 0; i < SIZE; ++i) { ai.set(i, 1); assertEquals(1,ai.getAndAdd(i,2)); @@ -175,8 +189,8 @@ public class AtomicLongArrayTest extends JSR166TestCase { /** * getAndDecrement returns previous value and decrements */ - public void testGetAndDecrement(){ - AtomicLongArray ai = new AtomicLongArray(SIZE); + public void testGetAndDecrement() { + AtomicLongArray ai = new AtomicLongArray(SIZE); for (int i = 0; i < SIZE; ++i) { ai.set(i, 1); assertEquals(1,ai.getAndDecrement(i)); @@ -188,8 +202,8 @@ public class AtomicLongArrayTest extends JSR166TestCase { /** * getAndIncrement returns previous value and increments */ - public void testGetAndIncrement(){ - AtomicLongArray ai = new AtomicLongArray(SIZE); + public void testGetAndIncrement() { + AtomicLongArray ai = new AtomicLongArray(SIZE); for (int i = 0; i < SIZE; ++i) { ai.set(i, 1); assertEquals(1,ai.getAndIncrement(i)); @@ -206,7 +220,7 @@ public class AtomicLongArrayTest extends JSR166TestCase { * addAndGet adds given value to current, and returns current value */ public void testAddAndGet() { - AtomicLongArray ai = new AtomicLongArray(SIZE); + AtomicLongArray ai = new AtomicLongArray(SIZE); for (int i = 0; i < SIZE; ++i) { ai.set(i, 1); assertEquals(3,ai.addAndGet(i,2)); @@ -219,8 +233,8 @@ public class AtomicLongArrayTest extends JSR166TestCase { /** * decrementAndGet decrements and returns current value */ - public void testDecrementAndGet(){ - AtomicLongArray ai = new AtomicLongArray(SIZE); + public void testDecrementAndGet() { + AtomicLongArray ai = new AtomicLongArray(SIZE); for (int i = 0; i < SIZE; ++i) { ai.set(i, 1); assertEquals(0,ai.decrementAndGet(i)); @@ -234,7 +248,7 @@ public class AtomicLongArrayTest extends JSR166TestCase { * incrementAndGet increments and returns current value */ public void testIncrementAndGet() { - AtomicLongArray ai = new AtomicLongArray(SIZE); + AtomicLongArray ai = new AtomicLongArray(SIZE); for (int i = 0; i < SIZE; ++i) { ai.set(i, 1); assertEquals(2,ai.incrementAndGet(i)); @@ -248,7 +262,7 @@ public class AtomicLongArrayTest extends JSR166TestCase { } static final long COUNTDOWN = 100000; - + class Counter implements Runnable { final AtomicLongArray ai; volatile long counts; @@ -275,54 +289,45 @@ public class AtomicLongArrayTest extends JSR166TestCase { * Multiple threads using same array of counters successfully * update a number of times equal to total count */ - public void testCountingInMultipleThreads() { - try { - final AtomicLongArray ai = new AtomicLongArray(SIZE); - for (int i = 0; i < SIZE; ++i) - ai.set(i, COUNTDOWN); - Counter c1 = new Counter(ai); - Counter c2 = new Counter(ai); - Thread t1 = new Thread(c1); - Thread t2 = new Thread(c2); - t1.start(); - t2.start(); - t1.join(); - t2.join(); - assertEquals(c1.counts+c2.counts, SIZE * COUNTDOWN); - } - catch(InterruptedException ie) { - unexpectedException(); - } + public void testCountingInMultipleThreads() throws InterruptedException { + final AtomicLongArray ai = new AtomicLongArray(SIZE); + for (int i = 0; i < SIZE; ++i) + ai.set(i, COUNTDOWN); + Counter c1 = new Counter(ai); + Counter c2 = new Counter(ai); + Thread t1 = new Thread(c1); + Thread t2 = new Thread(c2); + t1.start(); + t2.start(); + t1.join(); + t2.join(); + assertEquals(c1.counts+c2.counts, SIZE * COUNTDOWN); } /** * a deserialized serialized array holds same values */ - public void testSerialization() { - AtomicLongArray l = new AtomicLongArray(SIZE); - for (int i = 0; i < SIZE; ++i) + public void testSerialization() throws Exception { + AtomicLongArray l = new AtomicLongArray(SIZE); + for (int i = 0; i < SIZE; ++i) l.set(i, -i); - try { - ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); - ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); - out.writeObject(l); - out.close(); + ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); + ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); + out.writeObject(l); + out.close(); - ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); - ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); - AtomicLongArray r = (AtomicLongArray) in.readObject(); - for (int i = 0; i < SIZE; ++i) { - assertEquals(l.get(i), r.get(i)); - } - } catch(Exception e){ - unexpectedException(); + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); + AtomicLongArray r = (AtomicLongArray) in.readObject(); + for (int i = 0; i < SIZE; ++i) { + assertEquals(l.get(i), r.get(i)); } } /** * toString returns current value. - */ + */ public void testToString() { long[] a = { 17, 3, -42, 99, -7}; AtomicLongArray ai = new AtomicLongArray(a); diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicLongFieldUpdaterTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicLongFieldUpdaterTest.java index bac25dc..491baf4 100755 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicLongFieldUpdaterTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicLongFieldUpdaterTest.java @@ -2,11 +2,11 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import java.util.concurrent.atomic.*; import junit.framework.*; @@ -24,68 +24,61 @@ public class AtomicLongFieldUpdaterTest extends JSR166TestCase { /** * Construction with non-existent field throws RuntimeException */ - public void testConstructor(){ - try{ + public void testConstructor() { + try { AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a = AtomicLongFieldUpdater.newUpdater (AtomicLongFieldUpdaterTest.class, "y"); shouldThrow(); - } - catch (RuntimeException rt) {} + } catch (RuntimeException success) {} } /** * construction with field not of given type throws RuntimeException */ - public void testConstructor2(){ - try{ + public void testConstructor2() { + try { AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a = AtomicLongFieldUpdater.newUpdater (AtomicLongFieldUpdaterTest.class, "z"); shouldThrow(); - } - catch (RuntimeException rt) {} + } catch (RuntimeException success) {} } /** * construction with non-volatile field throws RuntimeException */ - public void testConstructor3(){ - try{ + public void testConstructor3() { + try { AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a = AtomicLongFieldUpdater.newUpdater (AtomicLongFieldUpdaterTest.class, "w"); shouldThrow(); - } - - catch (RuntimeException rt) {} + } catch (RuntimeException success) {} } - static class Base { - protected volatile long f = 0; - } - static class Sub1 extends Base { - AtomicLongFieldUpdater<Base> fUpdater - = AtomicLongFieldUpdater.newUpdater(Base.class, "f"); - } - static class Sub2 extends Base {} - - public void testProtectedFieldOnAnotherSubtype() { - Sub1 sub1 = new Sub1(); - Sub2 sub2 = new Sub2(); - - sub1.fUpdater.set(sub1, 1); + /** + * get returns the last value set or assigned + */ + public void testGetSet() { + AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a; try { - sub1.fUpdater.set(sub2, 2); - shouldThrow(); + a = AtomicLongFieldUpdater.newUpdater(AtomicLongFieldUpdaterTest.class, "x"); + } catch (RuntimeException ok) { + return; } - catch (RuntimeException rt) {} + x = 1; + assertEquals(1,a.get(this)); + a.set(this,2); + assertEquals(2,a.get(this)); + a.set(this,-3); + assertEquals(-3,a.get(this)); } /** - * get returns the last value set or assigned + * get returns the last value lazySet by same thread */ - public void testGetSet(){ + public void testGetLazySet() { AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a; try { a = AtomicLongFieldUpdater.newUpdater(AtomicLongFieldUpdaterTest.class, "x"); @@ -93,17 +86,18 @@ public class AtomicLongFieldUpdaterTest extends JSR166TestCase { return; } x = 1; - assertEquals(1,a.get(this)); - a.set(this,2); - assertEquals(2,a.get(this)); - a.set(this,-3); - assertEquals(-3,a.get(this)); - + assertEquals(1,a.get(this)); + a.lazySet(this,2); + assertEquals(2,a.get(this)); + a.lazySet(this,-3); + assertEquals(-3,a.get(this)); } + + /** * compareAndSet succeeds in changing value if equal to expected else fails */ - public void testCompareAndSet(){ + public void testCompareAndSet() { AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a; try { a = AtomicLongFieldUpdater.newUpdater(AtomicLongFieldUpdaterTest.class, "x"); @@ -115,7 +109,7 @@ public class AtomicLongFieldUpdaterTest extends JSR166TestCase { assertTrue(a.compareAndSet(this,2,-4)); assertEquals(-4,a.get(this)); assertFalse(a.compareAndSet(this,-5,7)); - assertFalse((7 == a.get(this))); + assertEquals(-4,a.get(this)); assertTrue(a.compareAndSet(this,-4,7)); assertEquals(7,a.get(this)); } @@ -125,7 +119,7 @@ public class AtomicLongFieldUpdaterTest extends JSR166TestCase { * compareAndSet in one thread enables another waiting for value * to succeed */ - public void testCompareAndSetInMultipleThreads() { + public void testCompareAndSetInMultipleThreads() throws Exception { x = 1; final AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest>a; try { @@ -134,27 +128,24 @@ public class AtomicLongFieldUpdaterTest extends JSR166TestCase { return; } - Thread t = new Thread(new Runnable() { - public void run() { - while(!a.compareAndSet(AtomicLongFieldUpdaterTest.this, 2, 3)) Thread.yield(); - }}); - try { - t.start(); - assertTrue(a.compareAndSet(this, 1, 2)); - t.join(LONG_DELAY_MS); - assertFalse(t.isAlive()); - assertEquals(a.get(this), 3); - } - catch(Exception e) { - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + while (!a.compareAndSet(AtomicLongFieldUpdaterTest.this, 2, 3)) + Thread.yield(); + }}); + + t.start(); + assertTrue(a.compareAndSet(this, 1, 2)); + t.join(LONG_DELAY_MS); + assertFalse(t.isAlive()); + assertEquals(a.get(this), 3); } /** * repeated weakCompareAndSet succeeds in changing value when equal * to expected */ - public void testWeakCompareAndSet(){ + public void testWeakCompareAndSet() { AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a; try { a = AtomicLongFieldUpdater.newUpdater(AtomicLongFieldUpdaterTest.class, "x"); @@ -162,17 +153,17 @@ public class AtomicLongFieldUpdaterTest extends JSR166TestCase { return; } x = 1; - while(!a.weakCompareAndSet(this,1,2)); - while(!a.weakCompareAndSet(this,2,-4)); + while (!a.weakCompareAndSet(this,1,2)); + while (!a.weakCompareAndSet(this,2,-4)); assertEquals(-4,a.get(this)); - while(!a.weakCompareAndSet(this,-4,7)); + while (!a.weakCompareAndSet(this,-4,7)); assertEquals(7,a.get(this)); } /** * getAndSet returns previous value and sets to given value */ - public void testGetAndSet(){ + public void testGetAndSet() { AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a; try { a = AtomicLongFieldUpdater.newUpdater(AtomicLongFieldUpdaterTest.class, "x"); @@ -188,7 +179,7 @@ public class AtomicLongFieldUpdaterTest extends JSR166TestCase { /** * getAndAdd returns previous value and adds given value */ - public void testGetAndAdd(){ + public void testGetAndAdd() { AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a; try { a = AtomicLongFieldUpdater.newUpdater(AtomicLongFieldUpdaterTest.class, "x"); @@ -205,7 +196,7 @@ public class AtomicLongFieldUpdaterTest extends JSR166TestCase { /** * getAndDecrement returns previous value and decrements */ - public void testGetAndDecrement(){ + public void testGetAndDecrement() { AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a; try { a = AtomicLongFieldUpdater.newUpdater(AtomicLongFieldUpdaterTest.class, "x"); @@ -221,7 +212,7 @@ public class AtomicLongFieldUpdaterTest extends JSR166TestCase { /** * getAndIncrement returns previous value and increments */ - public void testGetAndIncrement(){ + public void testGetAndIncrement() { AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a; try { a = AtomicLongFieldUpdater.newUpdater(AtomicLongFieldUpdaterTest.class, "x"); @@ -241,7 +232,7 @@ public class AtomicLongFieldUpdaterTest extends JSR166TestCase { /** * addAndGet adds given value to current, and returns current value */ - public void testAddAndGet(){ + public void testAddAndGet() { AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a; try { a = AtomicLongFieldUpdater.newUpdater(AtomicLongFieldUpdaterTest.class, "x"); @@ -258,7 +249,7 @@ public class AtomicLongFieldUpdaterTest extends JSR166TestCase { /** * decrementAndGet decrements and returns current value */ - public void testDecrementAndGet(){ + public void testDecrementAndGet() { AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a; try { a = AtomicLongFieldUpdater.newUpdater(AtomicLongFieldUpdaterTest.class, "x"); @@ -275,7 +266,7 @@ public class AtomicLongFieldUpdaterTest extends JSR166TestCase { /** * incrementAndGet increments and returns current value */ - public void testIncrementAndGet(){ + public void testIncrementAndGet() { AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a; try { a = AtomicLongFieldUpdater.newUpdater(AtomicLongFieldUpdaterTest.class, "x"); diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicLongTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicLongTest.java index f4805bf..e73e86e 100755 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicLongTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicLongTest.java @@ -2,11 +2,11 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.concurrent.atomic.*; @@ -17,10 +17,16 @@ public class AtomicLongTest extends JSR166TestCase { return new TestSuite(AtomicLongTest.class); } + final long[] VALUES = { + Long.MIN_VALUE, + Integer.MIN_VALUE, -1, 0, 1, 42, Integer.MAX_VALUE, + Long.MAX_VALUE, + }; + /** * constructor initializes to given value */ - public void testConstructor(){ + public void testConstructor() { AtomicLong ai = new AtomicLong(1); assertEquals(1,ai.get()); } @@ -28,7 +34,7 @@ public class AtomicLongTest extends JSR166TestCase { /** * default constructed initializes to zero */ - public void testConstructor2(){ + public void testConstructor2() { AtomicLong ai = new AtomicLong(); assertEquals(0,ai.get()); } @@ -36,26 +42,37 @@ public class AtomicLongTest extends JSR166TestCase { /** * get returns the last value set */ - public void testGetSet(){ + public void testGetSet() { AtomicLong ai = new AtomicLong(1); assertEquals(1,ai.get()); ai.set(2); assertEquals(2,ai.get()); ai.set(-3); assertEquals(-3,ai.get()); - + } + + /** + * get returns the last value lazySet in same thread + */ + public void testGetLazySet() { + AtomicLong ai = new AtomicLong(1); + assertEquals(1,ai.get()); + ai.lazySet(2); + assertEquals(2,ai.get()); + ai.lazySet(-3); + assertEquals(-3,ai.get()); } /** * compareAndSet succeeds in changing value if equal to expected else fails */ - public void testCompareAndSet(){ + public void testCompareAndSet() { AtomicLong ai = new AtomicLong(1); assertTrue(ai.compareAndSet(1,2)); assertTrue(ai.compareAndSet(2,-4)); assertEquals(-4,ai.get()); assertFalse(ai.compareAndSet(-5,7)); - assertFalse((7 == ai.get())); + assertEquals(-4,ai.get()); assertTrue(ai.compareAndSet(-4,7)); assertEquals(7,ai.get()); } @@ -64,41 +81,38 @@ public class AtomicLongTest extends JSR166TestCase { * compareAndSet in one thread enables another waiting for value * to succeed */ - public void testCompareAndSetInMultipleThreads() { + public void testCompareAndSetInMultipleThreads() throws Exception { final AtomicLong ai = new AtomicLong(1); - Thread t = new Thread(new Runnable() { - public void run() { - while(!ai.compareAndSet(2, 3)) Thread.yield(); - }}); - try { - t.start(); - assertTrue(ai.compareAndSet(1, 2)); - t.join(LONG_DELAY_MS); - assertFalse(t.isAlive()); - assertEquals(ai.get(), 3); - } - catch(Exception e) { - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + while (!ai.compareAndSet(2, 3)) + Thread.yield(); + }}); + + t.start(); + assertTrue(ai.compareAndSet(1, 2)); + t.join(LONG_DELAY_MS); + assertFalse(t.isAlive()); + assertEquals(ai.get(), 3); } /** * repeated weakCompareAndSet succeeds in changing value when equal - * to expected + * to expected */ - public void testWeakCompareAndSet(){ + public void testWeakCompareAndSet() { AtomicLong ai = new AtomicLong(1); - while(!ai.weakCompareAndSet(1,2)); - while(!ai.weakCompareAndSet(2,-4)); + while (!ai.weakCompareAndSet(1,2)); + while (!ai.weakCompareAndSet(2,-4)); assertEquals(-4,ai.get()); - while(!ai.weakCompareAndSet(-4,7)); + while (!ai.weakCompareAndSet(-4,7)); assertEquals(7,ai.get()); } /** * getAndSet returns previous value and sets to given value */ - public void testGetAndSet(){ + public void testGetAndSet() { AtomicLong ai = new AtomicLong(1); assertEquals(1,ai.getAndSet(0)); assertEquals(0,ai.getAndSet(-10)); @@ -108,7 +122,7 @@ public class AtomicLongTest extends JSR166TestCase { /** * getAndAdd returns previous value and adds given value */ - public void testGetAndAdd(){ + public void testGetAndAdd() { AtomicLong ai = new AtomicLong(1); assertEquals(1,ai.getAndAdd(2)); assertEquals(3,ai.get()); @@ -119,7 +133,7 @@ public class AtomicLongTest extends JSR166TestCase { /** * getAndDecrement returns previous value and decrements */ - public void testGetAndDecrement(){ + public void testGetAndDecrement() { AtomicLong ai = new AtomicLong(1); assertEquals(1,ai.getAndDecrement()); assertEquals(0,ai.getAndDecrement()); @@ -129,7 +143,7 @@ public class AtomicLongTest extends JSR166TestCase { /** * getAndIncrement returns previous value and increments */ - public void testGetAndIncrement(){ + public void testGetAndIncrement() { AtomicLong ai = new AtomicLong(1); assertEquals(1,ai.getAndIncrement()); assertEquals(2,ai.get()); @@ -143,7 +157,7 @@ public class AtomicLongTest extends JSR166TestCase { /** * addAndGet adds given value to current, and returns current value */ - public void testAddAndGet(){ + public void testAddAndGet() { AtomicLong ai = new AtomicLong(1); assertEquals(3,ai.addAndGet(2)); assertEquals(3,ai.get()); @@ -154,7 +168,7 @@ public class AtomicLongTest extends JSR166TestCase { /** * decrementAndGet decrements and returns current value */ - public void testDecrementAndGet(){ + public void testDecrementAndGet() { AtomicLong ai = new AtomicLong(1); assertEquals(0,ai.decrementAndGet()); assertEquals(-1,ai.decrementAndGet()); @@ -165,7 +179,7 @@ public class AtomicLongTest extends JSR166TestCase { /** * incrementAndGet increments and returns current value */ - public void testIncrementAndGet(){ + public void testIncrementAndGet() { AtomicLong ai = new AtomicLong(1); assertEquals(2,ai.incrementAndGet()); assertEquals(2,ai.get()); @@ -179,68 +193,79 @@ public class AtomicLongTest extends JSR166TestCase { /** * a deserialized serialized atomic holds same value */ - public void testSerialization() { + public void testSerialization() throws Exception { AtomicLong l = new AtomicLong(); - try { - l.set(-22); - ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); - ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); - out.writeObject(l); - out.close(); - - ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); - ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); - AtomicLong r = (AtomicLong) in.readObject(); - assertEquals(l.get(), r.get()); - } catch(Exception e){ - unexpectedException(); - } + l.set(-22); + ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); + ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); + out.writeObject(l); + out.close(); + + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); + AtomicLong r = (AtomicLong) in.readObject(); + assertEquals(l.get(), r.get()); } /** * toString returns current value. - */ + */ public void testToString() { AtomicLong ai = new AtomicLong(); - for (long i = -12; i < 6; ++i) { + assertEquals("0", ai.toString()); + for (long i : VALUES) { ai.set(i); assertEquals(ai.toString(), Long.toString(i)); } } /** + * intValue returns current value. + */ + public void testIntValue() { + AtomicLong ai = new AtomicLong(); + assertEquals(0, ai.intValue()); + for (long x : VALUES) { + ai.set(x); + assertEquals((int)x, ai.intValue()); + } + } + + /** * longValue returns current value. - */ + */ public void testLongValue() { AtomicLong ai = new AtomicLong(); - for (int i = -12; i < 6; ++i) { - ai.set(i); - assertEquals((long)i, ai.longValue()); + assertEquals(0L, ai.longValue()); + for (long x : VALUES) { + ai.set(x); + assertEquals((long)x, ai.longValue()); } } /** * floatValue returns current value. - */ + */ public void testFloatValue() { AtomicLong ai = new AtomicLong(); - for (int i = -12; i < 6; ++i) { - ai.set(i); - assertEquals((float)i, ai.floatValue()); + assertEquals(0.0f, ai.floatValue()); + for (long x : VALUES) { + ai.set(x); + assertEquals((float)x, ai.floatValue()); } } /** * doubleValue returns current value. - */ + */ public void testDoubleValue() { AtomicLong ai = new AtomicLong(); - for (int i = -12; i < 6; ++i) { - ai.set(i); - assertEquals((double)i, ai.doubleValue()); + assertEquals(0.0d, ai.doubleValue()); + for (long x : VALUES) { + ai.set(x); + assertEquals((double)x, ai.doubleValue()); } } - } diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicMarkableReferenceTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicMarkableReferenceTest.java index 7857dde..72a2337 100755 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicMarkableReferenceTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicMarkableReferenceTest.java @@ -2,65 +2,64 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.concurrent.atomic.*; -public class AtomicMarkableReferenceTest extends JSR166TestCase{ +public class AtomicMarkableReferenceTest extends JSR166TestCase { public static Test suite() { return new TestSuite(AtomicMarkableReferenceTest.class); } - + /** * constructor initializes to given reference and mark */ - public void testConstructor(){ + public void testConstructor() { AtomicMarkableReference ai = new AtomicMarkableReference(one, false); - assertEquals(one,ai.getReference()); + assertSame(one,ai.getReference()); assertFalse(ai.isMarked()); AtomicMarkableReference a2 = new AtomicMarkableReference(null, true); assertNull(a2.getReference()); assertTrue(a2.isMarked()); - } /** * get returns the last values of reference and mark set */ - public void testGetSet(){ + public void testGetSet() { boolean[] mark = new boolean[1]; AtomicMarkableReference ai = new AtomicMarkableReference(one, false); - assertEquals(one,ai.getReference()); + assertSame(one,ai.getReference()); assertFalse(ai.isMarked()); - assertEquals(one, ai.get(mark)); + assertSame(one, ai.get(mark)); assertFalse(mark[0]); ai.set(two, false); - assertEquals(two,ai.getReference()); + assertSame(two,ai.getReference()); assertFalse(ai.isMarked()); - assertEquals(two, ai.get(mark)); + assertSame(two, ai.get(mark)); assertFalse(mark[0]); ai.set(one, true); - assertEquals(one,ai.getReference()); + assertSame(one,ai.getReference()); assertTrue(ai.isMarked()); - assertEquals(one, ai.get(mark)); + assertSame(one, ai.get(mark)); assertTrue(mark[0]); } /** * attemptMark succeeds in single thread */ - public void testAttemptMark(){ + public void testAttemptMark() { boolean[] mark = new boolean[1]; AtomicMarkableReference ai = new AtomicMarkableReference(one, false); assertFalse(ai.isMarked()); assertTrue(ai.attemptMark(one, true)); assertTrue(ai.isMarked()); - assertEquals(one, ai.get(mark)); + assertSame(one, ai.get(mark)); assertTrue(mark[0]); } @@ -68,23 +67,23 @@ public class AtomicMarkableReferenceTest extends JSR166TestCase{ * compareAndSet succeeds in changing values if equal to expected reference * and mark else fails */ - public void testCompareAndSet(){ + public void testCompareAndSet() { boolean[] mark = new boolean[1]; AtomicMarkableReference ai = new AtomicMarkableReference(one, false); - assertEquals(one, ai.get(mark)); + assertSame(one, ai.get(mark)); assertFalse(ai.isMarked()); assertFalse(mark[0]); assertTrue(ai.compareAndSet(one, two, false, false)); - assertEquals(two, ai.get(mark)); + assertSame(two, ai.get(mark)); assertFalse(mark[0]); assertTrue(ai.compareAndSet(two, m3, false, true)); - assertEquals(m3, ai.get(mark)); + assertSame(m3, ai.get(mark)); assertTrue(mark[0]); assertFalse(ai.compareAndSet(two, m3, true, true)); - assertEquals(m3, ai.get(mark)); + assertSame(m3, ai.get(mark)); assertTrue(mark[0]); } @@ -92,65 +91,59 @@ public class AtomicMarkableReferenceTest extends JSR166TestCase{ * compareAndSet in one thread enables another waiting for reference value * to succeed */ - public void testCompareAndSetInMultipleThreads() { + public void testCompareAndSetInMultipleThreads() throws Exception { final AtomicMarkableReference ai = new AtomicMarkableReference(one, false); - Thread t = new Thread(new Runnable() { - public void run() { - while(!ai.compareAndSet(two, three, false, false)) Thread.yield(); - }}); - try { - t.start(); - assertTrue(ai.compareAndSet(one, two, false, false)); - t.join(LONG_DELAY_MS); - assertFalse(t.isAlive()); - assertEquals(ai.getReference(), three); - assertFalse(ai.isMarked()); - } - catch(Exception e) { - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + while (!ai.compareAndSet(two, three, false, false)) + Thread.yield(); + }}); + + t.start(); + assertTrue(ai.compareAndSet(one, two, false, false)); + t.join(LONG_DELAY_MS); + assertFalse(t.isAlive()); + assertSame(ai.getReference(), three); + assertFalse(ai.isMarked()); } /** * compareAndSet in one thread enables another waiting for mark value * to succeed */ - public void testCompareAndSetInMultipleThreads2() { + public void testCompareAndSetInMultipleThreads2() throws Exception { final AtomicMarkableReference ai = new AtomicMarkableReference(one, false); - Thread t = new Thread(new Runnable() { - public void run() { - while(!ai.compareAndSet(one, one, true, false)) Thread.yield(); - }}); - try { - t.start(); - assertTrue(ai.compareAndSet(one, one, false, true)); - t.join(LONG_DELAY_MS); - assertFalse(t.isAlive()); - assertEquals(ai.getReference(), one); - assertFalse(ai.isMarked()); - } - catch(Exception e) { - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + while (!ai.compareAndSet(one, one, true, false)) + Thread.yield(); + }}); + + t.start(); + assertTrue(ai.compareAndSet(one, one, false, true)); + t.join(LONG_DELAY_MS); + assertFalse(t.isAlive()); + assertSame(ai.getReference(), one); + assertFalse(ai.isMarked()); } /** * repeated weakCompareAndSet succeeds in changing values when equal - * to expected + * to expected */ - public void testWeakCompareAndSet(){ + public void testWeakCompareAndSet() { boolean[] mark = new boolean[1]; AtomicMarkableReference ai = new AtomicMarkableReference(one, false); - assertEquals(one, ai.get(mark)); + assertSame(one, ai.get(mark)); assertFalse(ai.isMarked()); assertFalse(mark[0]); - while(!ai.weakCompareAndSet(one, two, false, false)); - assertEquals(two, ai.get(mark)); + while (!ai.weakCompareAndSet(one, two, false, false)); + assertSame(two, ai.get(mark)); assertFalse(mark[0]); - while(!ai.weakCompareAndSet(two, m3, false, true)); - assertEquals(m3, ai.get(mark)); + while (!ai.weakCompareAndSet(two, m3, false, true)); + assertSame(m3, ai.get(mark)); assertTrue(mark[0]); } diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicReferenceArrayTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicReferenceArrayTest.java index 81248cc..25f8474 100644 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicReferenceArrayTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicReferenceArrayTest.java @@ -2,19 +2,18 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.concurrent.atomic.*; import java.io.*; import java.util.*; -public class AtomicReferenceArrayTest extends JSR166TestCase -{ +public class AtomicReferenceArrayTest extends JSR166TestCase { public static Test suite() { return new TestSuite(AtomicReferenceArrayTest.class); } @@ -22,7 +21,7 @@ public class AtomicReferenceArrayTest extends JSR166TestCase /** * constructor creates array of given size with all elements null */ - public void testConstructor(){ + public void testConstructor() { AtomicReferenceArray<Integer> ai = new AtomicReferenceArray<Integer>(SIZE); for (int i = 0; i < SIZE; ++i) { assertNull(ai.get(i)); @@ -36,10 +35,8 @@ public class AtomicReferenceArrayTest extends JSR166TestCase try { Integer[] a = null; AtomicReferenceArray<Integer> ai = new AtomicReferenceArray<Integer>(a); - } catch (NullPointerException success) { - } catch (Exception ex) { - unexpectedException(); - } + shouldThrow(); + } catch (NullPointerException success) {} } /** @@ -49,7 +46,7 @@ public class AtomicReferenceArrayTest extends JSR166TestCase Integer[] a = { two, one, three, four, seven}; AtomicReferenceArray<Integer> ai = new AtomicReferenceArray<Integer>(a); assertEquals(a.length, ai.length()); - for (int i = 0; i < a.length; ++i) + for (int i = 0; i < a.length; ++i) assertEquals(a[i], ai.get(i)); } @@ -57,55 +54,74 @@ public class AtomicReferenceArrayTest extends JSR166TestCase /** * get and set for out of bound indices throw IndexOutOfBoundsException */ - public void testIndexing(){ + public void testIndexing() { AtomicReferenceArray<Integer> ai = new AtomicReferenceArray<Integer>(SIZE); try { ai.get(SIZE); - } catch(IndexOutOfBoundsException success){ + shouldThrow(); + } catch (IndexOutOfBoundsException success) { } try { ai.get(-1); - } catch(IndexOutOfBoundsException success){ + shouldThrow(); + } catch (IndexOutOfBoundsException success) { } try { ai.set(SIZE, null); - } catch(IndexOutOfBoundsException success){ + shouldThrow(); + } catch (IndexOutOfBoundsException success) { } try { ai.set(-1, null); - } catch(IndexOutOfBoundsException success){ + shouldThrow(); + } catch (IndexOutOfBoundsException success) { } } /** * get returns the last value set at index */ - public void testGetSet(){ - AtomicReferenceArray ai = new AtomicReferenceArray(SIZE); + public void testGetSet() { + AtomicReferenceArray ai = new AtomicReferenceArray(SIZE); for (int i = 0; i < SIZE; ++i) { ai.set(i, one); - assertEquals(one,ai.get(i)); + assertSame(one,ai.get(i)); ai.set(i, two); - assertEquals(two,ai.get(i)); + assertSame(two,ai.get(i)); ai.set(i, m3); - assertEquals(m3,ai.get(i)); + assertSame(m3,ai.get(i)); + } + } + + /** + * get returns the last value lazySet at index by same thread + */ + public void testGetLazySet() { + AtomicReferenceArray ai = new AtomicReferenceArray(SIZE); + for (int i = 0; i < SIZE; ++i) { + ai.lazySet(i, one); + assertSame(one,ai.get(i)); + ai.lazySet(i, two); + assertSame(two,ai.get(i)); + ai.lazySet(i, m3); + assertSame(m3,ai.get(i)); } } /** * compareAndSet succeeds in changing value if equal to expected else fails */ - public void testCompareAndSet(){ - AtomicReferenceArray ai = new AtomicReferenceArray(SIZE); + public void testCompareAndSet() { + AtomicReferenceArray ai = new AtomicReferenceArray(SIZE); for (int i = 0; i < SIZE; ++i) { ai.set(i, one); assertTrue(ai.compareAndSet(i, one,two)); assertTrue(ai.compareAndSet(i, two,m4)); - assertEquals(m4,ai.get(i)); + assertSame(m4,ai.get(i)); assertFalse(ai.compareAndSet(i, m5,seven)); - assertFalse((seven.equals(ai.get(i)))); + assertSame(m4,ai.get(i)); assertTrue(ai.compareAndSet(i, m4,seven)); - assertEquals(seven,ai.get(i)); + assertSame(seven,ai.get(i)); } } @@ -113,85 +129,78 @@ public class AtomicReferenceArrayTest extends JSR166TestCase * compareAndSet in one thread enables another waiting for value * to succeed */ - public void testCompareAndSetInMultipleThreads() { + public void testCompareAndSetInMultipleThreads() throws InterruptedException { final AtomicReferenceArray a = new AtomicReferenceArray(1); a.set(0, one); - Thread t = new Thread(new Runnable() { - public void run() { - while(!a.compareAndSet(0, two, three)) Thread.yield(); - }}); - try { - t.start(); - assertTrue(a.compareAndSet(0, one, two)); - t.join(LONG_DELAY_MS); - assertFalse(t.isAlive()); - assertEquals(a.get(0), three); - } - catch(Exception e) { - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + while (!a.compareAndSet(0, two, three)) + Thread.yield(); + }}); + + t.start(); + assertTrue(a.compareAndSet(0, one, two)); + t.join(LONG_DELAY_MS); + assertFalse(t.isAlive()); + assertSame(a.get(0), three); } /** * repeated weakCompareAndSet succeeds in changing value when equal - * to expected + * to expected */ - public void testWeakCompareAndSet(){ - AtomicReferenceArray ai = new AtomicReferenceArray(SIZE); + public void testWeakCompareAndSet() { + AtomicReferenceArray ai = new AtomicReferenceArray(SIZE); for (int i = 0; i < SIZE; ++i) { ai.set(i, one); - while(!ai.weakCompareAndSet(i, one,two)); - while(!ai.weakCompareAndSet(i, two,m4)); - assertEquals(m4,ai.get(i)); - while(!ai.weakCompareAndSet(i, m4,seven)); - assertEquals(seven,ai.get(i)); + while (!ai.weakCompareAndSet(i, one,two)); + while (!ai.weakCompareAndSet(i, two,m4)); + assertSame(m4,ai.get(i)); + while (!ai.weakCompareAndSet(i, m4,seven)); + assertSame(seven,ai.get(i)); } } /** * getAndSet returns previous value and sets to given value at given index */ - public void testGetAndSet(){ - AtomicReferenceArray ai = new AtomicReferenceArray(SIZE); + public void testGetAndSet() { + AtomicReferenceArray ai = new AtomicReferenceArray(SIZE); for (int i = 0; i < SIZE; ++i) { ai.set(i, one); - assertEquals(one,ai.getAndSet(i,zero)); - assertEquals(0,ai.getAndSet(i,m10)); - assertEquals(m10,ai.getAndSet(i,one)); + assertSame(one,ai.getAndSet(i,zero)); + assertSame(zero,ai.getAndSet(i,m10)); + assertSame(m10,ai.getAndSet(i,one)); } } /** * a deserialized serialized array holds same values */ - public void testSerialization() { - AtomicReferenceArray l = new AtomicReferenceArray(SIZE); + public void testSerialization() throws Exception { + AtomicReferenceArray l = new AtomicReferenceArray(SIZE); for (int i = 0; i < SIZE; ++i) { l.set(i, new Integer(-i)); } - try { - ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); - ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); - out.writeObject(l); - out.close(); - - ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); - ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); - AtomicReferenceArray r = (AtomicReferenceArray) in.readObject(); - assertEquals(l.length(), r.length()); - for (int i = 0; i < SIZE; ++i) { - assertEquals(r.get(i), l.get(i)); - } - } catch(Exception e){ - unexpectedException(); + ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); + ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); + out.writeObject(l); + out.close(); + + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); + AtomicReferenceArray r = (AtomicReferenceArray) in.readObject(); + assertEquals(l.length(), r.length()); + for (int i = 0; i < SIZE; ++i) { + assertEquals(r.get(i), l.get(i)); } } /** * toString returns current value. - */ + */ public void testToString() { Integer[] a = { two, one, three, four, seven}; AtomicReferenceArray<Integer> ai = new AtomicReferenceArray<Integer>(a); diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicReferenceFieldUpdaterTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicReferenceFieldUpdaterTest.java index 7f71781..78c321e 100755 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicReferenceFieldUpdaterTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicReferenceFieldUpdaterTest.java @@ -2,17 +2,17 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import java.util.concurrent.atomic.*; import junit.framework.*; import java.util.*; -public class AtomicReferenceFieldUpdaterTest extends JSR166TestCase{ +public class AtomicReferenceFieldUpdaterTest extends JSR166TestCase { volatile Integer x = null; Object z; Integer w; @@ -24,68 +24,62 @@ public class AtomicReferenceFieldUpdaterTest extends JSR166TestCase{ /** * Construction with non-existent field throws RuntimeException */ - public void testConstructor(){ - try{ + public void testConstructor() { + try { AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer> a = AtomicReferenceFieldUpdater.newUpdater (AtomicReferenceFieldUpdaterTest.class, Integer.class, "y"); shouldThrow(); - } - catch (RuntimeException rt) {} + } catch (RuntimeException success) {} } /** * construction with field not of given type throws RuntimeException */ - public void testConstructor2(){ - try{ + public void testConstructor2() { + try { AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer> a = AtomicReferenceFieldUpdater.newUpdater (AtomicReferenceFieldUpdaterTest.class, Integer.class, "z"); shouldThrow(); - } - catch (RuntimeException rt) {} + } catch (RuntimeException success) {} } /** * Constructor with non-volatile field throws exception */ - public void testConstructor3(){ - try{ + public void testConstructor3() { + try { AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer> a = AtomicReferenceFieldUpdater.newUpdater (AtomicReferenceFieldUpdaterTest.class, Integer.class, "w"); shouldThrow(); - } - catch (RuntimeException rt) {} + } catch (RuntimeException success) {} } - static class Base { - protected volatile Object f = null; - } - static class Sub1 extends Base { - AtomicReferenceFieldUpdater<Base, Object> fUpdater - = AtomicReferenceFieldUpdater.newUpdater(Base.class, Object.class, "f"); - } - static class Sub2 extends Base {} - - public void testProtectedFieldOnAnotherSubtype() { - Sub1 sub1 = new Sub1(); - Sub2 sub2 = new Sub2(); - - sub1.fUpdater.set(sub1, "f"); + /** + * get returns the last value set or assigned + */ + public void testGetSet() { + AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer>a; try { - sub1.fUpdater.set(sub2, "g"); - shouldThrow(); + a = AtomicReferenceFieldUpdater.newUpdater(AtomicReferenceFieldUpdaterTest.class, Integer.class, "x"); + } catch (RuntimeException ok) { + return; } - catch (RuntimeException rt) {} + x = one; + assertSame(one,a.get(this)); + a.set(this,two); + assertSame(two,a.get(this)); + a.set(this,m3); + assertSame(m3,a.get(this)); } /** - * get returns the last value set or assigned + * get returns the last value lazySet by same thread */ - public void testGetSet(){ + public void testGetLazySet() { AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer>a; try { a = AtomicReferenceFieldUpdater.newUpdater(AtomicReferenceFieldUpdaterTest.class, Integer.class, "x"); @@ -93,16 +87,17 @@ public class AtomicReferenceFieldUpdaterTest extends JSR166TestCase{ return; } x = one; - assertEquals(one,a.get(this)); - a.set(this,two); - assertEquals(two,a.get(this)); - a.set(this,m3); - assertEquals(m3,a.get(this)); + assertSame(one,a.get(this)); + a.lazySet(this,two); + assertSame(two,a.get(this)); + a.lazySet(this,m3); + assertSame(m3,a.get(this)); } + /** * compareAndSet succeeds in changing value if equal to expected else fails */ - public void testCompareAndSet(){ + public void testCompareAndSet() { AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer>a; try { a = AtomicReferenceFieldUpdater.newUpdater(AtomicReferenceFieldUpdaterTest.class, Integer.class, "x"); @@ -112,18 +107,18 @@ public class AtomicReferenceFieldUpdaterTest extends JSR166TestCase{ x = one; assertTrue(a.compareAndSet(this,one,two)); assertTrue(a.compareAndSet(this,two,m4)); - assertEquals(m4,a.get(this)); + assertSame(m4,a.get(this)); assertFalse(a.compareAndSet(this,m5,seven)); - assertFalse((seven == a.get(this))); + assertFalse(seven == a.get(this)); assertTrue(a.compareAndSet(this,m4,seven)); - assertEquals(seven,a.get(this)); + assertSame(seven,a.get(this)); } /** * compareAndSet in one thread enables another waiting for value * to succeed */ - public void testCompareAndSetInMultipleThreads() { + public void testCompareAndSetInMultipleThreads() throws Exception { x = one; final AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer>a; try { @@ -132,27 +127,24 @@ public class AtomicReferenceFieldUpdaterTest extends JSR166TestCase{ return; } - Thread t = new Thread(new Runnable() { - public void run() { - while(!a.compareAndSet(AtomicReferenceFieldUpdaterTest.this, two, three)) Thread.yield(); - }}); - try { - t.start(); - assertTrue(a.compareAndSet(this, one, two)); - t.join(LONG_DELAY_MS); - assertFalse(t.isAlive()); - assertEquals(a.get(this), three); - } - catch(Exception e) { - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + while (!a.compareAndSet(AtomicReferenceFieldUpdaterTest.this, two, three)) + Thread.yield(); + }}); + + t.start(); + assertTrue(a.compareAndSet(this, one, two)); + t.join(LONG_DELAY_MS); + assertFalse(t.isAlive()); + assertSame(a.get(this), three); } /** * repeated weakCompareAndSet succeeds in changing value when equal * to expected */ - public void testWeakCompareAndSet(){ + public void testWeakCompareAndSet() { AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer>a; try { a = AtomicReferenceFieldUpdater.newUpdater(AtomicReferenceFieldUpdaterTest.class, Integer.class, "x"); @@ -160,17 +152,17 @@ public class AtomicReferenceFieldUpdaterTest extends JSR166TestCase{ return; } x = one; - while(!a.weakCompareAndSet(this,one,two)); - while(!a.weakCompareAndSet(this,two,m4)); - assertEquals(m4,a.get(this)); - while(!a.weakCompareAndSet(this,m4,seven)); - assertEquals(seven,a.get(this)); + while (!a.weakCompareAndSet(this,one,two)); + while (!a.weakCompareAndSet(this,two,m4)); + assertSame(m4,a.get(this)); + while (!a.weakCompareAndSet(this,m4,seven)); + assertSame(seven,a.get(this)); } /** * getAndSet returns previous value and sets to given value */ - public void testGetAndSet(){ + public void testGetAndSet() { AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer>a; try { a = AtomicReferenceFieldUpdater.newUpdater(AtomicReferenceFieldUpdaterTest.class, Integer.class, "x"); @@ -178,9 +170,9 @@ public class AtomicReferenceFieldUpdaterTest extends JSR166TestCase{ return; } x = one; - assertEquals(one,a.getAndSet(this, zero)); - assertEquals(zero,a.getAndSet(this,m10)); - assertEquals(m10,a.getAndSet(this,1)); + assertSame(one,a.getAndSet(this, zero)); + assertSame(zero,a.getAndSet(this,m10)); + assertSame(m10,a.getAndSet(this,1)); } } diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicReferenceTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicReferenceTest.java index bcb4701..5046ee8 100755 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicReferenceTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicReferenceTest.java @@ -2,11 +2,11 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.concurrent.atomic.*; @@ -20,15 +20,15 @@ public class AtomicReferenceTest extends JSR166TestCase { /** * constructor initializes to given value */ - public void testConstructor(){ + public void testConstructor() { AtomicReference ai = new AtomicReference(one); - assertEquals(one,ai.get()); + assertSame(one,ai.get()); } /** * default constructed initializes to null */ - public void testConstructor2(){ + public void testConstructor2() { AtomicReference ai = new AtomicReference(); assertNull(ai.get()); } @@ -36,105 +36,109 @@ public class AtomicReferenceTest extends JSR166TestCase { /** * get returns the last value set */ - public void testGetSet(){ + public void testGetSet() { AtomicReference ai = new AtomicReference(one); - assertEquals(one,ai.get()); + assertSame(one,ai.get()); ai.set(two); - assertEquals(two,ai.get()); + assertSame(two,ai.get()); ai.set(m3); - assertEquals(m3,ai.get()); + assertSame(m3,ai.get()); + } + /** + * get returns the last value lazySet in same thread + */ + public void testGetLazySet() { + AtomicReference ai = new AtomicReference(one); + assertSame(one,ai.get()); + ai.lazySet(two); + assertSame(two,ai.get()); + ai.lazySet(m3); + assertSame(m3,ai.get()); } + /** * compareAndSet succeeds in changing value if equal to expected else fails */ - public void testCompareAndSet(){ + public void testCompareAndSet() { AtomicReference ai = new AtomicReference(one); assertTrue(ai.compareAndSet(one,two)); assertTrue(ai.compareAndSet(two,m4)); - assertEquals(m4,ai.get()); + assertSame(m4,ai.get()); assertFalse(ai.compareAndSet(m5,seven)); - assertFalse((seven.equals(ai.get()))); + assertSame(m4,ai.get()); assertTrue(ai.compareAndSet(m4,seven)); - assertEquals(seven,ai.get()); + assertSame(seven,ai.get()); } /** * compareAndSet in one thread enables another waiting for value * to succeed */ - public void testCompareAndSetInMultipleThreads() { + public void testCompareAndSetInMultipleThreads() throws Exception { final AtomicReference ai = new AtomicReference(one); - Thread t = new Thread(new Runnable() { - public void run() { - while(!ai.compareAndSet(two, three)) Thread.yield(); - }}); - try { - t.start(); - assertTrue(ai.compareAndSet(one, two)); - t.join(LONG_DELAY_MS); - assertFalse(t.isAlive()); - assertEquals(ai.get(), three); - } - catch(Exception e) { - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + while (!ai.compareAndSet(two, three)) + Thread.yield(); + }}); + + t.start(); + assertTrue(ai.compareAndSet(one, two)); + t.join(LONG_DELAY_MS); + assertFalse(t.isAlive()); + assertSame(ai.get(), three); } /** * repeated weakCompareAndSet succeeds in changing value when equal * to expected */ - public void testWeakCompareAndSet(){ + public void testWeakCompareAndSet() { AtomicReference ai = new AtomicReference(one); - while(!ai.weakCompareAndSet(one,two)); - while(!ai.weakCompareAndSet(two,m4)); - assertEquals(m4,ai.get()); - while(!ai.weakCompareAndSet(m4,seven)); - assertEquals(seven,ai.get()); + while (!ai.weakCompareAndSet(one,two)); + while (!ai.weakCompareAndSet(two,m4)); + assertSame(m4,ai.get()); + while (!ai.weakCompareAndSet(m4,seven)); + assertSame(seven,ai.get()); } /** * getAndSet returns previous value and sets to given value */ - public void testGetAndSet(){ + public void testGetAndSet() { AtomicReference ai = new AtomicReference(one); - assertEquals(one,ai.getAndSet(zero)); - assertEquals(zero,ai.getAndSet(m10)); - assertEquals(m10,ai.getAndSet(one)); + assertSame(one,ai.getAndSet(zero)); + assertSame(zero,ai.getAndSet(m10)); + assertSame(m10,ai.getAndSet(one)); } /** * a deserialized serialized atomic holds same value */ - public void testSerialization() { + public void testSerialization() throws Exception { AtomicReference l = new AtomicReference(); - try { - l.set(one); - ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); - ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); - out.writeObject(l); - out.close(); - - ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); - ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); - AtomicReference r = (AtomicReference) in.readObject(); - assertEquals(l.get(), r.get()); - } catch(Exception e){ - unexpectedException(); - } + l.set(one); + ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); + ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); + out.writeObject(l); + out.close(); + + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); + AtomicReference r = (AtomicReference) in.readObject(); + assertEquals(l.get(), r.get()); } /** * toString returns current value. - */ + */ public void testToString() { - AtomicReference<Integer> ai = new AtomicReference<Integer>(one); + AtomicReference<Integer> ai = new AtomicReference<Integer>(one); assertEquals(ai.toString(), one.toString()); ai.set(two); assertEquals(ai.toString(), two.toString()); } } - diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicStampedReferenceTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicStampedReferenceTest.java index 9f4e4f7..ca9b724 100755 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicStampedReferenceTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/AtomicStampedReferenceTest.java @@ -2,65 +2,64 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.concurrent.atomic.*; -public class AtomicStampedReferenceTest extends JSR166TestCase{ +public class AtomicStampedReferenceTest extends JSR166TestCase { public static Test suite() { return new TestSuite(AtomicStampedReferenceTest.class); } - + /** * constructor initializes to given reference and stamp */ - public void testConstructor(){ + public void testConstructor() { AtomicStampedReference ai = new AtomicStampedReference(one, 0); - assertEquals(one,ai.getReference()); + assertSame(one,ai.getReference()); assertEquals(0, ai.getStamp()); AtomicStampedReference a2 = new AtomicStampedReference(null, 1); assertNull(a2.getReference()); assertEquals(1, a2.getStamp()); - } /** * get returns the last values of reference and stamp set */ - public void testGetSet(){ + public void testGetSet() { int[] mark = new int[1]; AtomicStampedReference ai = new AtomicStampedReference(one, 0); - assertEquals(one,ai.getReference()); + assertSame(one,ai.getReference()); assertEquals(0, ai.getStamp()); - assertEquals(one, ai.get(mark)); + assertSame(one, ai.get(mark)); assertEquals(0, mark[0]); ai.set(two, 0); - assertEquals(two,ai.getReference()); + assertSame(two,ai.getReference()); assertEquals(0, ai.getStamp()); - assertEquals(two, ai.get(mark)); + assertSame(two, ai.get(mark)); assertEquals(0, mark[0]); ai.set(one, 1); - assertEquals(one,ai.getReference()); + assertSame(one,ai.getReference()); assertEquals(1, ai.getStamp()); - assertEquals(one, ai.get(mark)); + assertSame(one, ai.get(mark)); assertEquals(1,mark[0]); } /** * attemptStamp succeeds in single thread */ - public void testAttemptStamp(){ + public void testAttemptStamp() { int[] mark = new int[1]; AtomicStampedReference ai = new AtomicStampedReference(one, 0); assertEquals(0, ai.getStamp()); assertTrue(ai.attemptStamp(one, 1)); assertEquals(1, ai.getStamp()); - assertEquals(one, ai.get(mark)); + assertSame(one, ai.get(mark)); assertEquals(1, mark[0]); } @@ -68,23 +67,23 @@ public class AtomicStampedReferenceTest extends JSR166TestCase{ * compareAndSet succeeds in changing values if equal to expected reference * and stamp else fails */ - public void testCompareAndSet(){ + public void testCompareAndSet() { int[] mark = new int[1]; AtomicStampedReference ai = new AtomicStampedReference(one, 0); - assertEquals(one, ai.get(mark)); + assertSame(one, ai.get(mark)); assertEquals(0, ai.getStamp()); assertEquals(0, mark[0]); assertTrue(ai.compareAndSet(one, two, 0, 0)); - assertEquals(two, ai.get(mark)); + assertSame(two, ai.get(mark)); assertEquals(0, mark[0]); assertTrue(ai.compareAndSet(two, m3, 0, 1)); - assertEquals(m3, ai.get(mark)); + assertSame(m3, ai.get(mark)); assertEquals(1, mark[0]); assertFalse(ai.compareAndSet(two, m3, 1, 1)); - assertEquals(m3, ai.get(mark)); + assertSame(m3, ai.get(mark)); assertEquals(1, mark[0]); } @@ -92,65 +91,59 @@ public class AtomicStampedReferenceTest extends JSR166TestCase{ * compareAndSet in one thread enables another waiting for reference value * to succeed */ - public void testCompareAndSetInMultipleThreads() { + public void testCompareAndSetInMultipleThreads() throws Exception { final AtomicStampedReference ai = new AtomicStampedReference(one, 0); - Thread t = new Thread(new Runnable() { - public void run() { - while(!ai.compareAndSet(two, three, 0, 0)) Thread.yield(); - }}); - try { - t.start(); - assertTrue(ai.compareAndSet(one, two, 0, 0)); - t.join(LONG_DELAY_MS); - assertFalse(t.isAlive()); - assertEquals(ai.getReference(), three); - assertEquals(ai.getStamp(), 0); - } - catch(Exception e) { - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + while (!ai.compareAndSet(two, three, 0, 0)) + Thread.yield(); + }}); + + t.start(); + assertTrue(ai.compareAndSet(one, two, 0, 0)); + t.join(LONG_DELAY_MS); + assertFalse(t.isAlive()); + assertSame(ai.getReference(), three); + assertEquals(ai.getStamp(), 0); } /** * compareAndSet in one thread enables another waiting for stamp value * to succeed */ - public void testCompareAndSetInMultipleThreads2() { + public void testCompareAndSetInMultipleThreads2() throws Exception { final AtomicStampedReference ai = new AtomicStampedReference(one, 0); - Thread t = new Thread(new Runnable() { - public void run() { - while(!ai.compareAndSet(one, one, 1, 2)) Thread.yield(); - }}); - try { - t.start(); - assertTrue(ai.compareAndSet(one, one, 0, 1)); - t.join(LONG_DELAY_MS); - assertFalse(t.isAlive()); - assertEquals(ai.getReference(), one); - assertEquals(ai.getStamp(), 2); - } - catch(Exception e) { - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + while (!ai.compareAndSet(one, one, 1, 2)) + Thread.yield(); + }}); + + t.start(); + assertTrue(ai.compareAndSet(one, one, 0, 1)); + t.join(LONG_DELAY_MS); + assertFalse(t.isAlive()); + assertSame(ai.getReference(), one); + assertEquals(ai.getStamp(), 2); } /** * repeated weakCompareAndSet succeeds in changing values when equal - * to expected + * to expected */ - public void testWeakCompareAndSet(){ + public void testWeakCompareAndSet() { int[] mark = new int[1]; AtomicStampedReference ai = new AtomicStampedReference(one, 0); - assertEquals(one, ai.get(mark)); + assertSame(one, ai.get(mark)); assertEquals(0, ai.getStamp ()); assertEquals(0, mark[0]); - while(!ai.weakCompareAndSet(one, two, 0, 0)); - assertEquals(two, ai.get(mark)); + while (!ai.weakCompareAndSet(one, two, 0, 0)); + assertSame(two, ai.get(mark)); assertEquals(0, mark[0]); - while(!ai.weakCompareAndSet(two, m3, 0, 1)); - assertEquals(m3, ai.get(mark)); + while (!ai.weakCompareAndSet(two, m3, 0, 1)); + assertSame(m3, ai.get(mark)); assertEquals(1, mark[0]); } diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/ConcurrentHashMapTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/ConcurrentHashMapTest.java index b7549a4..9b355f5 100755 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/ConcurrentHashMapTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/ConcurrentHashMapTest.java @@ -2,11 +2,11 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.*; @@ -14,7 +14,7 @@ import java.util.concurrent.*; import java.util.Enumeration; import java.io.*; -public class ConcurrentHashMapTest extends JSR166TestCase{ +public class ConcurrentHashMapTest extends JSR166TestCase { public static Test suite() { return new TestSuite(ConcurrentHashMapTest.class); } @@ -80,7 +80,7 @@ public class ConcurrentHashMapTest extends JSR166TestCase{ */ public void testContainsValue() { ConcurrentHashMap map = map5(); - assertTrue(map.containsValue("A")); + assertTrue(map.containsValue("A")); assertFalse(map.containsValue("Z")); } @@ -92,7 +92,7 @@ public class ConcurrentHashMapTest extends JSR166TestCase{ ConcurrentHashMap map = map5(); Enumeration e = map.elements(); int count = 0; - while(e.hasMoreElements()){ + while (e.hasMoreElements()) { count++; e.nextElement(); } @@ -127,7 +127,7 @@ public class ConcurrentHashMapTest extends JSR166TestCase{ ConcurrentHashMap map = map5(); Enumeration e = map.keys(); int count = 0; - while(e.hasMoreElements()){ + while (e.hasMoreElements()) { count++; e.nextElement(); } @@ -153,10 +153,10 @@ public class ConcurrentHashMapTest extends JSR166TestCase{ */ public void testKeySetToArray() { ConcurrentHashMap map = map5(); - Set s = map.keySet(); + Set s = map.keySet(); Object[] ar = s.toArray(); assertTrue(s.containsAll(Arrays.asList(ar))); - assertEquals(5, ar.length); + assertEquals(5, ar.length); ar[0] = m10; assertFalse(s.containsAll(Arrays.asList(ar))); } @@ -166,15 +166,15 @@ public class ConcurrentHashMapTest extends JSR166TestCase{ */ public void testValuesToArray() { ConcurrentHashMap map = map5(); - Collection v = map.values(); + Collection v = map.values(); Object[] ar = v.toArray(); ArrayList s = new ArrayList(Arrays.asList(ar)); - assertEquals(5, ar.length); - assertTrue(s.contains("A")); - assertTrue(s.contains("B")); - assertTrue(s.contains("C")); - assertTrue(s.contains("D")); - assertTrue(s.contains("E")); + assertEquals(5, ar.length); + assertTrue(s.contains("A")); + assertTrue(s.contains("B")); + assertTrue(s.contains("C")); + assertTrue(s.contains("D")); + assertTrue(s.contains("E")); } /** @@ -182,7 +182,7 @@ public class ConcurrentHashMapTest extends JSR166TestCase{ */ public void testEntrySetToArray() { ConcurrentHashMap map = map5(); - Set s = map.entrySet(); + Set s = map.entrySet(); Object[] ar = s.toArray(); assertEquals(5, ar.length); for (int i = 0; i < 5; ++i) { @@ -317,7 +317,6 @@ public class ConcurrentHashMapTest extends JSR166TestCase{ map.remove(four, "A"); assertEquals(4, map.size()); assertTrue(map.containsKey(four)); - } /** @@ -350,7 +349,7 @@ public class ConcurrentHashMapTest extends JSR166TestCase{ try { new ConcurrentHashMap(-1,0,1); shouldThrow(); - } catch(IllegalArgumentException e){} + } catch (IllegalArgumentException success) {} } /** @@ -360,7 +359,7 @@ public class ConcurrentHashMapTest extends JSR166TestCase{ try { new ConcurrentHashMap(1,0,-1); shouldThrow(); - } catch(IllegalArgumentException e){} + } catch (IllegalArgumentException success) {} } /** @@ -370,7 +369,7 @@ public class ConcurrentHashMapTest extends JSR166TestCase{ try { new ConcurrentHashMap(-1); shouldThrow(); - } catch(IllegalArgumentException e){} + } catch (IllegalArgumentException success) {} } /** @@ -381,7 +380,7 @@ public class ConcurrentHashMapTest extends JSR166TestCase{ ConcurrentHashMap c = new ConcurrentHashMap(5); c.get(null); shouldThrow(); - } catch(NullPointerException e){} + } catch (NullPointerException success) {} } /** @@ -392,7 +391,7 @@ public class ConcurrentHashMapTest extends JSR166TestCase{ ConcurrentHashMap c = new ConcurrentHashMap(5); c.containsKey(null); shouldThrow(); - } catch(NullPointerException e){} + } catch (NullPointerException success) {} } /** @@ -403,7 +402,7 @@ public class ConcurrentHashMapTest extends JSR166TestCase{ ConcurrentHashMap c = new ConcurrentHashMap(5); c.containsValue(null); shouldThrow(); - } catch(NullPointerException e){} + } catch (NullPointerException success) {} } /** @@ -414,7 +413,7 @@ public class ConcurrentHashMapTest extends JSR166TestCase{ ConcurrentHashMap c = new ConcurrentHashMap(5); c.contains(null); shouldThrow(); - } catch(NullPointerException e){} + } catch (NullPointerException success) {} } /** @@ -425,7 +424,7 @@ public class ConcurrentHashMapTest extends JSR166TestCase{ ConcurrentHashMap c = new ConcurrentHashMap(5); c.put(null, "whatever"); shouldThrow(); - } catch(NullPointerException e){} + } catch (NullPointerException success) {} } /** @@ -436,7 +435,7 @@ public class ConcurrentHashMapTest extends JSR166TestCase{ ConcurrentHashMap c = new ConcurrentHashMap(5); c.put("whatever", null); shouldThrow(); - } catch(NullPointerException e){} + } catch (NullPointerException success) {} } /** @@ -447,7 +446,7 @@ public class ConcurrentHashMapTest extends JSR166TestCase{ ConcurrentHashMap c = new ConcurrentHashMap(5); c.putIfAbsent(null, "whatever"); shouldThrow(); - } catch(NullPointerException e){} + } catch (NullPointerException success) {} } /** @@ -458,7 +457,7 @@ public class ConcurrentHashMapTest extends JSR166TestCase{ ConcurrentHashMap c = new ConcurrentHashMap(5); c.replace(null, "whatever"); shouldThrow(); - } catch(NullPointerException e){} + } catch (NullPointerException success) {} } /** @@ -469,7 +468,7 @@ public class ConcurrentHashMapTest extends JSR166TestCase{ ConcurrentHashMap c = new ConcurrentHashMap(5); c.replace(null, one, "whatever"); shouldThrow(); - } catch(NullPointerException e){} + } catch (NullPointerException success) {} } /** @@ -480,7 +479,7 @@ public class ConcurrentHashMapTest extends JSR166TestCase{ ConcurrentHashMap c = new ConcurrentHashMap(5); c.putIfAbsent("whatever", null); shouldThrow(); - } catch(NullPointerException e){} + } catch (NullPointerException success) {} } @@ -492,7 +491,7 @@ public class ConcurrentHashMapTest extends JSR166TestCase{ ConcurrentHashMap c = new ConcurrentHashMap(5); c.replace("whatever", null); shouldThrow(); - } catch(NullPointerException e){} + } catch (NullPointerException success) {} } /** @@ -503,7 +502,7 @@ public class ConcurrentHashMapTest extends JSR166TestCase{ ConcurrentHashMap c = new ConcurrentHashMap(5); c.replace("whatever", null, "A"); shouldThrow(); - } catch(NullPointerException e){} + } catch (NullPointerException success) {} } /** @@ -514,7 +513,7 @@ public class ConcurrentHashMapTest extends JSR166TestCase{ ConcurrentHashMap c = new ConcurrentHashMap(5); c.replace("whatever", one, null); shouldThrow(); - } catch(NullPointerException e){} + } catch (NullPointerException success) {} } @@ -527,7 +526,7 @@ public class ConcurrentHashMapTest extends JSR166TestCase{ c.put("sadsdf", "asdads"); c.remove(null); shouldThrow(); - } catch(NullPointerException e){} + } catch (NullPointerException success) {} } /** @@ -539,44 +538,35 @@ public class ConcurrentHashMapTest extends JSR166TestCase{ c.put("sadsdf", "asdads"); c.remove(null, "whatever"); shouldThrow(); - } catch(NullPointerException e){} + } catch (NullPointerException success) {} } /** * remove(x, null) returns false */ public void testRemove3() { - try { - ConcurrentHashMap c = new ConcurrentHashMap(5); - c.put("sadsdf", "asdads"); - assertFalse(c.remove("sadsdf", null)); - } catch(NullPointerException e){ - fail(); - } + ConcurrentHashMap c = new ConcurrentHashMap(5); + c.put("sadsdf", "asdads"); + assertFalse(c.remove("sadsdf", null)); } /** * A deserialized map equals original */ - public void testSerialization() { + public void testSerialization() throws Exception { ConcurrentHashMap q = map5(); - try { - ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); - ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); - out.writeObject(q); - out.close(); - - ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); - ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); - ConcurrentHashMap r = (ConcurrentHashMap)in.readObject(); - assertEquals(q.size(), r.size()); - assertTrue(q.equals(r)); - assertTrue(r.equals(q)); - } catch(Exception e){ - e.printStackTrace(); - unexpectedException(); - } + ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); + ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); + out.writeObject(q); + out.close(); + + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); + ConcurrentHashMap r = (ConcurrentHashMap)in.readObject(); + assertEquals(q.size(), r.size()); + assertTrue(q.equals(r)); + assertTrue(r.equals(q)); } @@ -584,23 +574,23 @@ public class ConcurrentHashMapTest extends JSR166TestCase{ * SetValue of an EntrySet entry sets value in the map. */ public void testSetValueWriteThrough() { - // Adapted from a bug report by Eric Zoerner + // Adapted from a bug report by Eric Zoerner ConcurrentHashMap map = new ConcurrentHashMap(2, 5.0f, 1); assertTrue(map.isEmpty()); for (int i = 0; i < 20; i++) map.put(new Integer(i), new Integer(i)); assertFalse(map.isEmpty()); Map.Entry entry1 = (Map.Entry)map.entrySet().iterator().next(); - + // assert that entry1 is not 16 assertTrue("entry is 16, test not valid", !entry1.getKey().equals(new Integer(16))); - - // remove 16 (a different key) from map + + // remove 16 (a different key) from map // which just happens to cause entry1 to be cloned in map map.remove(new Integer(16)); entry1.setValue("XYZ"); assertTrue(map.containsValue("XYZ")); // fails } - + } diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/ConcurrentLinkedQueueTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/ConcurrentLinkedQueueTest.java index c84dc59..1fbc729 100755 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/ConcurrentLinkedQueueTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/ConcurrentLinkedQueueTest.java @@ -2,11 +2,11 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.*; @@ -25,13 +25,13 @@ public class ConcurrentLinkedQueueTest extends JSR166TestCase { private ConcurrentLinkedQueue populatedQueue(int n) { ConcurrentLinkedQueue q = new ConcurrentLinkedQueue(); assertTrue(q.isEmpty()); - for(int i = 0; i < n; ++i) + for (int i = 0; i < n; ++i) assertTrue(q.offer(new Integer(i))); assertFalse(q.isEmpty()); assertEquals(n, q.size()); return q; } - + /** * new queue is empty */ @@ -46,8 +46,7 @@ public class ConcurrentLinkedQueueTest extends JSR166TestCase { try { ConcurrentLinkedQueue q = new ConcurrentLinkedQueue((Collection)null); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** @@ -58,8 +57,7 @@ public class ConcurrentLinkedQueueTest extends JSR166TestCase { Integer[] ints = new Integer[SIZE]; ConcurrentLinkedQueue q = new ConcurrentLinkedQueue(Arrays.asList(ints)); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** @@ -72,23 +70,19 @@ public class ConcurrentLinkedQueueTest extends JSR166TestCase { ints[i] = new Integer(i); ConcurrentLinkedQueue q = new ConcurrentLinkedQueue(Arrays.asList(ints)); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** * Queue contains all elements of collection used to initialize */ public void testConstructor6() { - try { - Integer[] ints = new Integer[SIZE]; - for (int i = 0; i < SIZE; ++i) - ints[i] = new Integer(i); - ConcurrentLinkedQueue q = new ConcurrentLinkedQueue(Arrays.asList(ints)); - for (int i = 0; i < SIZE; ++i) - assertEquals(ints[i], q.poll()); - } - finally {} + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + ConcurrentLinkedQueue q = new ConcurrentLinkedQueue(Arrays.asList(ints)); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.poll()); } /** @@ -128,7 +122,7 @@ public class ConcurrentLinkedQueueTest extends JSR166TestCase { ConcurrentLinkedQueue q = new ConcurrentLinkedQueue(); q.offer(null); shouldThrow(); - } catch (NullPointerException success) { } + } catch (NullPointerException success) {} } /** @@ -139,7 +133,7 @@ public class ConcurrentLinkedQueueTest extends JSR166TestCase { ConcurrentLinkedQueue q = new ConcurrentLinkedQueue(); q.add(null); shouldThrow(); - } catch (NullPointerException success) { } + } catch (NullPointerException success) {} } @@ -171,8 +165,7 @@ public class ConcurrentLinkedQueueTest extends JSR166TestCase { ConcurrentLinkedQueue q = new ConcurrentLinkedQueue(); q.addAll(null); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** @@ -183,8 +176,7 @@ public class ConcurrentLinkedQueueTest extends JSR166TestCase { ConcurrentLinkedQueue q = populatedQueue(SIZE); q.addAll(q); shouldThrow(); - } - catch (IllegalArgumentException success) {} + } catch (IllegalArgumentException success) {} } /** @@ -196,8 +188,7 @@ public class ConcurrentLinkedQueueTest extends JSR166TestCase { Integer[] ints = new Integer[SIZE]; q.addAll(Arrays.asList(ints)); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** * addAll of a collection with any null elements throws NPE after @@ -211,26 +202,22 @@ public class ConcurrentLinkedQueueTest extends JSR166TestCase { ints[i] = new Integer(i); q.addAll(Arrays.asList(ints)); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** * Queue contains all elements, in traversal order, of successful addAll */ public void testAddAll5() { - try { - Integer[] empty = new Integer[0]; - Integer[] ints = new Integer[SIZE]; - for (int i = 0; i < SIZE; ++i) - ints[i] = new Integer(i); - ConcurrentLinkedQueue q = new ConcurrentLinkedQueue(); - assertFalse(q.addAll(Arrays.asList(empty))); - assertTrue(q.addAll(Arrays.asList(ints))); - for (int i = 0; i < SIZE; ++i) - assertEquals(ints[i], q.poll()); - } - finally {} + Integer[] empty = new Integer[0]; + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + ConcurrentLinkedQueue q = new ConcurrentLinkedQueue(); + assertFalse(q.addAll(Arrays.asList(empty))); + assertTrue(q.addAll(Arrays.asList(ints))); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.poll()); } /** @@ -239,7 +226,7 @@ public class ConcurrentLinkedQueueTest extends JSR166TestCase { public void testPoll() { ConcurrentLinkedQueue q = populatedQueue(SIZE); for (int i = 0; i < SIZE; ++i) { - assertEquals(i, ((Integer)q.poll()).intValue()); + assertEquals(i, q.poll()); } assertNull(q.poll()); } @@ -250,10 +237,10 @@ public class ConcurrentLinkedQueueTest extends JSR166TestCase { public void testPeek() { ConcurrentLinkedQueue q = populatedQueue(SIZE); for (int i = 0; i < SIZE; ++i) { - assertEquals(i, ((Integer)q.peek()).intValue()); - q.poll(); + assertEquals(i, q.peek()); + assertEquals(i, q.poll()); assertTrue(q.peek() == null || - i != ((Integer)q.peek()).intValue()); + !q.peek().equals(i)); } assertNull(q.peek()); } @@ -264,14 +251,13 @@ public class ConcurrentLinkedQueueTest extends JSR166TestCase { public void testElement() { ConcurrentLinkedQueue q = populatedQueue(SIZE); for (int i = 0; i < SIZE; ++i) { - assertEquals(i, ((Integer)q.element()).intValue()); - q.poll(); + assertEquals(i, q.element()); + assertEquals(i, q.poll()); } try { q.element(); shouldThrow(); - } - catch (NoSuchElementException success) {} + } catch (NoSuchElementException success) {} } /** @@ -280,13 +266,12 @@ public class ConcurrentLinkedQueueTest extends JSR166TestCase { public void testRemove() { ConcurrentLinkedQueue q = populatedQueue(SIZE); for (int i = 0; i < SIZE; ++i) { - assertEquals(i, ((Integer)q.remove()).intValue()); + assertEquals(i, q.remove()); } try { q.remove(); shouldThrow(); - } catch (NoSuchElementException success){ - } + } catch (NoSuchElementException success) {} } /** @@ -303,7 +288,7 @@ public class ConcurrentLinkedQueueTest extends JSR166TestCase { } assertTrue(q.isEmpty()); } - + /** * contains(x) reports true when elements added but not yet removed */ @@ -386,7 +371,7 @@ public class ConcurrentLinkedQueueTest extends JSR166TestCase { ConcurrentLinkedQueue q = populatedQueue(SIZE); Object[] o = q.toArray(); Arrays.sort(o); - for(int i = 0; i < o.length; i++) + for (int i = 0; i < o.length; i++) assertEquals(o[i], q.poll()); } @@ -398,7 +383,7 @@ public class ConcurrentLinkedQueueTest extends JSR166TestCase { Integer[] ints = new Integer[SIZE]; ints = (Integer[])q.toArray(ints); Arrays.sort(ints); - for(int i = 0; i < ints.length; i++) + for (int i = 0; i < ints.length; i++) assertEquals(ints[i], q.poll()); } @@ -406,24 +391,24 @@ public class ConcurrentLinkedQueueTest extends JSR166TestCase { * toArray(null) throws NPE */ public void testToArray_BadArg() { + ConcurrentLinkedQueue q = populatedQueue(SIZE); try { - ConcurrentLinkedQueue q = populatedQueue(SIZE); Object o[] = q.toArray(null); shouldThrow(); - } catch(NullPointerException success){} + } catch (NullPointerException success) {} } /** - * toArray with incompatible array type throws CCE + * toArray with incompatible array type throws ArrayStoreException */ public void testToArray1_BadArg() { + ConcurrentLinkedQueue q = populatedQueue(SIZE); try { - ConcurrentLinkedQueue q = populatedQueue(SIZE); - Object o[] = q.toArray(new String[10] ); + Object o[] = q.toArray(new String[10]); shouldThrow(); - } catch(ArrayStoreException success){} + } catch (ArrayStoreException success) {} } - + /** * iterator iterates through all elements */ @@ -431,7 +416,7 @@ public class ConcurrentLinkedQueueTest extends JSR166TestCase { ConcurrentLinkedQueue q = populatedQueue(SIZE); int i = 0; Iterator it = q.iterator(); - while(it.hasNext()) { + while (it.hasNext()) { assertTrue(q.contains(it.next())); ++i; } @@ -449,8 +434,7 @@ public class ConcurrentLinkedQueueTest extends JSR166TestCase { int k = 0; for (Iterator it = q.iterator(); it.hasNext();) { - int i = ((Integer)(it.next())).intValue(); - assertEquals(++k, i); + assertEquals(++k, it.next()); } assertEquals(3, k); @@ -465,14 +449,9 @@ public class ConcurrentLinkedQueueTest extends JSR166TestCase { q.add(two); q.add(three); - try { - for (Iterator it = q.iterator(); it.hasNext();) { - q.remove(); - it.next(); - } - } - catch (ConcurrentModificationException e) { - shouldThrow(); + for (Iterator it = q.iterator(); it.hasNext();) { + q.remove(); + it.next(); } assertEquals("queue should be empty again", 0, q.size()); @@ -490,8 +469,8 @@ public class ConcurrentLinkedQueueTest extends JSR166TestCase { it.next(); it.remove(); it = q.iterator(); - assertEquals(it.next(), two); - assertEquals(it.next(), three); + assertSame(it.next(), two); + assertSame(it.next(), three); assertFalse(it.hasNext()); } @@ -505,28 +484,24 @@ public class ConcurrentLinkedQueueTest extends JSR166TestCase { for (int i = 0; i < SIZE; ++i) { assertTrue(s.indexOf(String.valueOf(i)) >= 0); } - } + } /** * A deserialized serialized queue has same elements in same order */ - public void testSerialization() { + public void testSerialization() throws Exception { ConcurrentLinkedQueue q = populatedQueue(SIZE); - try { - ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); - ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); - out.writeObject(q); - out.close(); - - ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); - ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); - ConcurrentLinkedQueue r = (ConcurrentLinkedQueue)in.readObject(); - assertEquals(q.size(), r.size()); - while (!q.isEmpty()) - assertEquals(q.remove(), r.remove()); - } catch(Exception e){ - unexpectedException(); - } + ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); + ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); + out.writeObject(q); + out.close(); + + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); + ConcurrentLinkedQueue r = (ConcurrentLinkedQueue)in.readObject(); + assertEquals(q.size(), r.size()); + while (!q.isEmpty()) + assertEquals(q.remove(), r.remove()); } } diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/ConcurrentSkipListMapTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/ConcurrentSkipListMapTest.java new file mode 100644 index 0000000..3cf5b75 --- /dev/null +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/ConcurrentSkipListMapTest.java @@ -0,0 +1,1280 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package tests.api.java.util.concurrent; // android-added + +import junit.framework.*; +import java.util.*; +import java.util.concurrent.*; +import java.io.*; + +public class ConcurrentSkipListMapTest extends JSR166TestCase { + public static Test suite() { + return new TestSuite(ConcurrentSkipListMapTest.class); + } + + /** + * Create a map from Integers 1-5 to Strings "A"-"E". + */ + private static ConcurrentSkipListMap map5() { + ConcurrentSkipListMap map = new ConcurrentSkipListMap(); + assertTrue(map.isEmpty()); + map.put(one, "A"); + map.put(five, "E"); + map.put(three, "C"); + map.put(two, "B"); + map.put(four, "D"); + assertFalse(map.isEmpty()); + assertEquals(5, map.size()); + return map; + } + + /** + * clear removes all pairs + */ + public void testClear() { + ConcurrentSkipListMap map = map5(); + map.clear(); + assertEquals(map.size(), 0); + } + + /** + * + */ + public void testConstructFromSorted() { + ConcurrentSkipListMap map = map5(); + ConcurrentSkipListMap map2 = new ConcurrentSkipListMap(map); + assertEquals(map, map2); + } + + /** + * Maps with same contents are equal + */ + public void testEquals() { + ConcurrentSkipListMap map1 = map5(); + ConcurrentSkipListMap map2 = map5(); + assertEquals(map1, map2); + assertEquals(map2, map1); + map1.clear(); + assertFalse(map1.equals(map2)); + assertFalse(map2.equals(map1)); + } + + /** + * containsKey returns true for contained key + */ + public void testContainsKey() { + ConcurrentSkipListMap map = map5(); + assertTrue(map.containsKey(one)); + assertFalse(map.containsKey(zero)); + } + + /** + * containsValue returns true for held values + */ + public void testContainsValue() { + ConcurrentSkipListMap map = map5(); + assertTrue(map.containsValue("A")); + assertFalse(map.containsValue("Z")); + } + + /** + * get returns the correct element at the given key, + * or null if not present + */ + public void testGet() { + ConcurrentSkipListMap map = map5(); + assertEquals("A", (String)map.get(one)); + ConcurrentSkipListMap empty = new ConcurrentSkipListMap(); + assertNull(empty.get(one)); + } + + /** + * isEmpty is true of empty map and false for non-empty + */ + public void testIsEmpty() { + ConcurrentSkipListMap empty = new ConcurrentSkipListMap(); + ConcurrentSkipListMap map = map5(); + assertTrue(empty.isEmpty()); + assertFalse(map.isEmpty()); + } + + /** + * firstKey returns first key + */ + public void testFirstKey() { + ConcurrentSkipListMap map = map5(); + assertEquals(one, map.firstKey()); + } + + /** + * lastKey returns last key + */ + public void testLastKey() { + ConcurrentSkipListMap map = map5(); + assertEquals(five, map.lastKey()); + } + + + /** + * keySet.toArray returns contains all keys + */ + public void testKeySetToArray() { + ConcurrentSkipListMap map = map5(); + Set s = map.keySet(); + Object[] ar = s.toArray(); + assertTrue(s.containsAll(Arrays.asList(ar))); + assertEquals(5, ar.length); + ar[0] = m10; + assertFalse(s.containsAll(Arrays.asList(ar))); + } + + /** + * descendingkeySet.toArray returns contains all keys + */ + public void testDescendingKeySetToArray() { + ConcurrentSkipListMap map = map5(); + Set s = map.descendingKeySet(); + Object[] ar = s.toArray(); + assertEquals(5, ar.length); + assertTrue(s.containsAll(Arrays.asList(ar))); + ar[0] = m10; + assertFalse(s.containsAll(Arrays.asList(ar))); + } + + /** + * keySet returns a Set containing all the keys + */ + public void testKeySet() { + ConcurrentSkipListMap map = map5(); + Set s = map.keySet(); + assertEquals(5, s.size()); + assertTrue(s.contains(one)); + assertTrue(s.contains(two)); + assertTrue(s.contains(three)); + assertTrue(s.contains(four)); + assertTrue(s.contains(five)); + } + + /** + * keySet is ordered + */ + public void testKeySetOrder() { + ConcurrentSkipListMap map = map5(); + Set s = map.keySet(); + Iterator i = s.iterator(); + Integer last = (Integer)i.next(); + assertEquals(last, one); + int count = 1; + while (i.hasNext()) { + Integer k = (Integer)i.next(); + assertTrue(last.compareTo(k) < 0); + last = k; + ++count; + } + assertEquals(count ,5); + } + + /** + * descending iterator of key set is inverse ordered + */ + public void testKeySetDescendingIteratorOrder() { + ConcurrentSkipListMap map = map5(); + NavigableSet s = map.navigableKeySet(); + Iterator i = s.descendingIterator(); + Integer last = (Integer)i.next(); + assertEquals(last, five); + int count = 1; + while (i.hasNext()) { + Integer k = (Integer)i.next(); + assertTrue(last.compareTo(k) > 0); + last = k; + ++count; + } + assertEquals(count ,5); + } + + /** + * descendingKeySet is ordered + */ + public void testDescendingKeySetOrder() { + ConcurrentSkipListMap map = map5(); + Set s = map.descendingKeySet(); + Iterator i = s.iterator(); + Integer last = (Integer)i.next(); + assertEquals(last, five); + int count = 1; + while (i.hasNext()) { + Integer k = (Integer)i.next(); + assertTrue(last.compareTo(k) > 0); + last = k; + ++count; + } + assertEquals(count, 5); + } + + /** + * descending iterator of descendingKeySet is ordered + */ + public void testDescendingKeySetDescendingIteratorOrder() { + ConcurrentSkipListMap map = map5(); + NavigableSet s = map.descendingKeySet(); + Iterator i = s.descendingIterator(); + Integer last = (Integer)i.next(); + assertEquals(last, one); + int count = 1; + while (i.hasNext()) { + Integer k = (Integer)i.next(); + assertTrue(last.compareTo(k) < 0); + last = k; + ++count; + } + assertEquals(count, 5); + } + + /** + * Values.toArray contains all values + */ + public void testValuesToArray() { + ConcurrentSkipListMap map = map5(); + Collection v = map.values(); + Object[] ar = v.toArray(); + ArrayList s = new ArrayList(Arrays.asList(ar)); + assertEquals(5, ar.length); + assertTrue(s.contains("A")); + assertTrue(s.contains("B")); + assertTrue(s.contains("C")); + assertTrue(s.contains("D")); + assertTrue(s.contains("E")); + } + + /** + * values collection contains all values + */ + public void testValues() { + ConcurrentSkipListMap map = map5(); + Collection s = map.values(); + assertEquals(5, s.size()); + assertTrue(s.contains("A")); + assertTrue(s.contains("B")); + assertTrue(s.contains("C")); + assertTrue(s.contains("D")); + assertTrue(s.contains("E")); + } + + /** + * entrySet contains all pairs + */ + public void testEntrySet() { + ConcurrentSkipListMap map = map5(); + Set s = map.entrySet(); + assertEquals(5, s.size()); + Iterator it = s.iterator(); + while (it.hasNext()) { + Map.Entry e = (Map.Entry) it.next(); + assertTrue( + (e.getKey().equals(one) && e.getValue().equals("A")) || + (e.getKey().equals(two) && e.getValue().equals("B")) || + (e.getKey().equals(three) && e.getValue().equals("C")) || + (e.getKey().equals(four) && e.getValue().equals("D")) || + (e.getKey().equals(five) && e.getValue().equals("E"))); + } + } + + /** + * descendingEntrySet contains all pairs + */ + public void testDescendingEntrySet() { + ConcurrentSkipListMap map = map5(); + Set s = map.descendingMap().entrySet(); + assertEquals(5, s.size()); + Iterator it = s.iterator(); + while (it.hasNext()) { + Map.Entry e = (Map.Entry) it.next(); + assertTrue( + (e.getKey().equals(one) && e.getValue().equals("A")) || + (e.getKey().equals(two) && e.getValue().equals("B")) || + (e.getKey().equals(three) && e.getValue().equals("C")) || + (e.getKey().equals(four) && e.getValue().equals("D")) || + (e.getKey().equals(five) && e.getValue().equals("E"))); + } + } + + /** + * entrySet.toArray contains all entries + */ + public void testEntrySetToArray() { + ConcurrentSkipListMap map = map5(); + Set s = map.entrySet(); + Object[] ar = s.toArray(); + assertEquals(5, ar.length); + for (int i = 0; i < 5; ++i) { + assertTrue(map.containsKey(((Map.Entry)(ar[i])).getKey())); + assertTrue(map.containsValue(((Map.Entry)(ar[i])).getValue())); + } + } + + /** + * descendingEntrySet.toArray contains all entries + */ + public void testDescendingEntrySetToArray() { + ConcurrentSkipListMap map = map5(); + Set s = map.descendingMap().entrySet(); + Object[] ar = s.toArray(); + assertEquals(5, ar.length); + for (int i = 0; i < 5; ++i) { + assertTrue(map.containsKey(((Map.Entry)(ar[i])).getKey())); + assertTrue(map.containsValue(((Map.Entry)(ar[i])).getValue())); + } + } + + /** + * putAll adds all key-value pairs from the given map + */ + public void testPutAll() { + ConcurrentSkipListMap empty = new ConcurrentSkipListMap(); + ConcurrentSkipListMap map = map5(); + empty.putAll(map); + assertEquals(5, empty.size()); + assertTrue(empty.containsKey(one)); + assertTrue(empty.containsKey(two)); + assertTrue(empty.containsKey(three)); + assertTrue(empty.containsKey(four)); + assertTrue(empty.containsKey(five)); + } + + /** + * putIfAbsent works when the given key is not present + */ + public void testPutIfAbsent() { + ConcurrentSkipListMap map = map5(); + map.putIfAbsent(six, "Z"); + assertTrue(map.containsKey(six)); + } + + /** + * putIfAbsent does not add the pair if the key is already present + */ + public void testPutIfAbsent2() { + ConcurrentSkipListMap map = map5(); + assertEquals("A", map.putIfAbsent(one, "Z")); + } + + /** + * replace fails when the given key is not present + */ + public void testReplace() { + ConcurrentSkipListMap map = map5(); + assertNull(map.replace(six, "Z")); + assertFalse(map.containsKey(six)); + } + + /** + * replace succeeds if the key is already present + */ + public void testReplace2() { + ConcurrentSkipListMap map = map5(); + assertNotNull(map.replace(one, "Z")); + assertEquals("Z", map.get(one)); + } + + + /** + * replace value fails when the given key not mapped to expected value + */ + public void testReplaceValue() { + ConcurrentSkipListMap map = map5(); + assertEquals("A", map.get(one)); + assertFalse(map.replace(one, "Z", "Z")); + assertEquals("A", map.get(one)); + } + + /** + * replace value succeeds when the given key mapped to expected value + */ + public void testReplaceValue2() { + ConcurrentSkipListMap map = map5(); + assertEquals("A", map.get(one)); + assertTrue(map.replace(one, "A", "Z")); + assertEquals("Z", map.get(one)); + } + + + /** + * remove removes the correct key-value pair from the map + */ + public void testRemove() { + ConcurrentSkipListMap map = map5(); + map.remove(five); + assertEquals(4, map.size()); + assertFalse(map.containsKey(five)); + } + + /** + * remove(key,value) removes only if pair present + */ + public void testRemove2() { + ConcurrentSkipListMap map = map5(); + assertTrue(map.containsKey(five)); + assertEquals("E", map.get(five)); + map.remove(five, "E"); + assertEquals(4, map.size()); + assertFalse(map.containsKey(five)); + map.remove(four, "A"); + assertEquals(4, map.size()); + assertTrue(map.containsKey(four)); + } + + /** + * lowerEntry returns preceding entry. + */ + public void testLowerEntry() { + ConcurrentSkipListMap map = map5(); + Map.Entry e1 = map.lowerEntry(three); + assertEquals(two, e1.getKey()); + + Map.Entry e2 = map.lowerEntry(six); + assertEquals(five, e2.getKey()); + + Map.Entry e3 = map.lowerEntry(one); + assertNull(e3); + + Map.Entry e4 = map.lowerEntry(zero); + assertNull(e4); + } + + /** + * higherEntry returns next entry. + */ + public void testHigherEntry() { + ConcurrentSkipListMap map = map5(); + Map.Entry e1 = map.higherEntry(three); + assertEquals(four, e1.getKey()); + + Map.Entry e2 = map.higherEntry(zero); + assertEquals(one, e2.getKey()); + + Map.Entry e3 = map.higherEntry(five); + assertNull(e3); + + Map.Entry e4 = map.higherEntry(six); + assertNull(e4); + } + + /** + * floorEntry returns preceding entry. + */ + public void testFloorEntry() { + ConcurrentSkipListMap map = map5(); + Map.Entry e1 = map.floorEntry(three); + assertEquals(three, e1.getKey()); + + Map.Entry e2 = map.floorEntry(six); + assertEquals(five, e2.getKey()); + + Map.Entry e3 = map.floorEntry(one); + assertEquals(one, e3.getKey()); + + Map.Entry e4 = map.floorEntry(zero); + assertNull(e4); + } + + /** + * ceilingEntry returns next entry. + */ + public void testCeilingEntry() { + ConcurrentSkipListMap map = map5(); + Map.Entry e1 = map.ceilingEntry(three); + assertEquals(three, e1.getKey()); + + Map.Entry e2 = map.ceilingEntry(zero); + assertEquals(one, e2.getKey()); + + Map.Entry e3 = map.ceilingEntry(five); + assertEquals(five, e3.getKey()); + + Map.Entry e4 = map.ceilingEntry(six); + assertNull(e4); + } + + /** + * lowerEntry, higherEntry, ceilingEntry, and floorEntry return + * immutable entries + */ + public void testEntryImmutablity() { + ConcurrentSkipListMap map = map5(); + Map.Entry e = map.lowerEntry(three); + assertEquals(two, e.getKey()); + try { + e.setValue("X"); + shouldThrow(); + } catch (UnsupportedOperationException success) {} + e = map.higherEntry(zero); + assertEquals(one, e.getKey()); + try { + e.setValue("X"); + shouldThrow(); + } catch (UnsupportedOperationException success) {} + e = map.floorEntry(one); + assertEquals(one, e.getKey()); + try { + e.setValue("X"); + shouldThrow(); + } catch (UnsupportedOperationException success) {} + e = map.ceilingEntry(five); + assertEquals(five, e.getKey()); + try { + e.setValue("X"); + shouldThrow(); + } catch (UnsupportedOperationException success) {} + } + + + + /** + * lowerKey returns preceding element + */ + public void testLowerKey() { + ConcurrentSkipListMap q = map5(); + Object e1 = q.lowerKey(three); + assertEquals(two, e1); + + Object e2 = q.lowerKey(six); + assertEquals(five, e2); + + Object e3 = q.lowerKey(one); + assertNull(e3); + + Object e4 = q.lowerKey(zero); + assertNull(e4); + } + + /** + * higherKey returns next element + */ + public void testHigherKey() { + ConcurrentSkipListMap q = map5(); + Object e1 = q.higherKey(three); + assertEquals(four, e1); + + Object e2 = q.higherKey(zero); + assertEquals(one, e2); + + Object e3 = q.higherKey(five); + assertNull(e3); + + Object e4 = q.higherKey(six); + assertNull(e4); + } + + /** + * floorKey returns preceding element + */ + public void testFloorKey() { + ConcurrentSkipListMap q = map5(); + Object e1 = q.floorKey(three); + assertEquals(three, e1); + + Object e2 = q.floorKey(six); + assertEquals(five, e2); + + Object e3 = q.floorKey(one); + assertEquals(one, e3); + + Object e4 = q.floorKey(zero); + assertNull(e4); + } + + /** + * ceilingKey returns next element + */ + public void testCeilingKey() { + ConcurrentSkipListMap q = map5(); + Object e1 = q.ceilingKey(three); + assertEquals(three, e1); + + Object e2 = q.ceilingKey(zero); + assertEquals(one, e2); + + Object e3 = q.ceilingKey(five); + assertEquals(five, e3); + + Object e4 = q.ceilingKey(six); + assertNull(e4); + } + + /** + * pollFirstEntry returns entries in order + */ + public void testPollFirstEntry() { + ConcurrentSkipListMap map = map5(); + Map.Entry e = map.pollFirstEntry(); + assertEquals(one, e.getKey()); + assertEquals("A", e.getValue()); + e = map.pollFirstEntry(); + assertEquals(two, e.getKey()); + map.put(one, "A"); + e = map.pollFirstEntry(); + assertEquals(one, e.getKey()); + assertEquals("A", e.getValue()); + e = map.pollFirstEntry(); + assertEquals(three, e.getKey()); + map.remove(four); + e = map.pollFirstEntry(); + assertEquals(five, e.getKey()); + try { + e.setValue("A"); + shouldThrow(); + } catch (UnsupportedOperationException success) {} + e = map.pollFirstEntry(); + assertNull(e); + } + + /** + * pollLastEntry returns entries in order + */ + public void testPollLastEntry() { + ConcurrentSkipListMap map = map5(); + Map.Entry e = map.pollLastEntry(); + assertEquals(five, e.getKey()); + assertEquals("E", e.getValue()); + e = map.pollLastEntry(); + assertEquals(four, e.getKey()); + map.put(five, "E"); + e = map.pollLastEntry(); + assertEquals(five, e.getKey()); + assertEquals("E", e.getValue()); + e = map.pollLastEntry(); + assertEquals(three, e.getKey()); + map.remove(two); + e = map.pollLastEntry(); + assertEquals(one, e.getKey()); + try { + e.setValue("E"); + shouldThrow(); + } catch (UnsupportedOperationException success) {} + e = map.pollLastEntry(); + assertNull(e); + } + + /** + * size returns the correct values + */ + public void testSize() { + ConcurrentSkipListMap map = map5(); + ConcurrentSkipListMap empty = new ConcurrentSkipListMap(); + assertEquals(0, empty.size()); + assertEquals(5, map.size()); + } + + /** + * toString contains toString of elements + */ + public void testToString() { + ConcurrentSkipListMap map = map5(); + String s = map.toString(); + for (int i = 1; i <= 5; ++i) { + assertTrue(s.indexOf(String.valueOf(i)) >= 0); + } + } + + // Exception tests + + /** + * get(null) of nonempty map throws NPE + */ + public void testGet_NullPointerException() { + try { + ConcurrentSkipListMap c = map5(); + c.get(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * containsKey(null) of nonempty map throws NPE + */ + public void testContainsKey_NullPointerException() { + try { + ConcurrentSkipListMap c = map5(); + c.containsKey(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * containsValue(null) throws NPE + */ + public void testContainsValue_NullPointerException() { + try { + ConcurrentSkipListMap c = new ConcurrentSkipListMap(); + c.containsValue(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + + /** + * put(null,x) throws NPE + */ + public void testPut1_NullPointerException() { + try { + ConcurrentSkipListMap c = map5(); + c.put(null, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * putIfAbsent(null, x) throws NPE + */ + public void testPutIfAbsent1_NullPointerException() { + try { + ConcurrentSkipListMap c = map5(); + c.putIfAbsent(null, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * replace(null, x) throws NPE + */ + public void testReplace_NullPointerException() { + try { + ConcurrentSkipListMap c = map5(); + c.replace(null, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * replace(null, x, y) throws NPE + */ + public void testReplaceValue_NullPointerException() { + try { + ConcurrentSkipListMap c = map5(); + c.replace(null, one, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * remove(null) throws NPE + */ + public void testRemove1_NullPointerException() { + try { + ConcurrentSkipListMap c = new ConcurrentSkipListMap(); + c.put("sadsdf", "asdads"); + c.remove(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * remove(null, x) throws NPE + */ + public void testRemove2_NullPointerException() { + try { + ConcurrentSkipListMap c = new ConcurrentSkipListMap(); + c.put("sadsdf", "asdads"); + c.remove(null, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * remove(x, null) returns false + */ + public void testRemove3() { + ConcurrentSkipListMap c = new ConcurrentSkipListMap(); + c.put("sadsdf", "asdads"); + assertFalse(c.remove("sadsdf", null)); + } + + /** + * A deserialized map equals original + */ + public void testSerialization() throws Exception { + ConcurrentSkipListMap q = map5(); + + ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); + ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); + out.writeObject(q); + out.close(); + + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); + ConcurrentSkipListMap r = (ConcurrentSkipListMap)in.readObject(); + assertEquals(q.size(), r.size()); + assertTrue(q.equals(r)); + assertTrue(r.equals(q)); + } + + + + /** + * subMap returns map with keys in requested range + */ + public void testSubMapContents() { + ConcurrentSkipListMap map = map5(); + NavigableMap sm = map.subMap(two, true, four, false); + assertEquals(two, sm.firstKey()); + assertEquals(three, sm.lastKey()); + assertEquals(2, sm.size()); + assertFalse(sm.containsKey(one)); + assertTrue(sm.containsKey(two)); + assertTrue(sm.containsKey(three)); + assertFalse(sm.containsKey(four)); + assertFalse(sm.containsKey(five)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + assertFalse(i.hasNext()); + Iterator r = sm.descendingKeySet().iterator(); + k = (Integer)(r.next()); + assertEquals(three, k); + k = (Integer)(r.next()); + assertEquals(two, k); + assertFalse(r.hasNext()); + + Iterator j = sm.keySet().iterator(); + j.next(); + j.remove(); + assertFalse(map.containsKey(two)); + assertEquals(4, map.size()); + assertEquals(1, sm.size()); + assertEquals(three, sm.firstKey()); + assertEquals(three, sm.lastKey()); + assertEquals("C", sm.remove(three)); + assertTrue(sm.isEmpty()); + assertEquals(3, map.size()); + } + + public void testSubMapContents2() { + ConcurrentSkipListMap map = map5(); + NavigableMap sm = map.subMap(two, true, three, false); + assertEquals(1, sm.size()); + assertEquals(two, sm.firstKey()); + assertEquals(two, sm.lastKey()); + assertFalse(sm.containsKey(one)); + assertTrue(sm.containsKey(two)); + assertFalse(sm.containsKey(three)); + assertFalse(sm.containsKey(four)); + assertFalse(sm.containsKey(five)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + assertFalse(i.hasNext()); + Iterator r = sm.descendingKeySet().iterator(); + k = (Integer)(r.next()); + assertEquals(two, k); + assertFalse(r.hasNext()); + + Iterator j = sm.keySet().iterator(); + j.next(); + j.remove(); + assertFalse(map.containsKey(two)); + assertEquals(4, map.size()); + assertEquals(0, sm.size()); + assertTrue(sm.isEmpty()); + assertSame(sm.remove(three), null); + assertEquals(4, map.size()); + } + + /** + * headMap returns map with keys in requested range + */ + public void testHeadMapContents() { + ConcurrentSkipListMap map = map5(); + NavigableMap sm = map.headMap(four, false); + assertTrue(sm.containsKey(one)); + assertTrue(sm.containsKey(two)); + assertTrue(sm.containsKey(three)); + assertFalse(sm.containsKey(four)); + assertFalse(sm.containsKey(five)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(one, k); + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + assertFalse(i.hasNext()); + sm.clear(); + assertTrue(sm.isEmpty()); + assertEquals(2, map.size()); + assertEquals(four, map.firstKey()); + } + + /** + * tailMap returns map with keys in requested range + */ + public void testTailMapContents() { + ConcurrentSkipListMap map = map5(); + NavigableMap sm = map.tailMap(two, true); + assertFalse(sm.containsKey(one)); + assertTrue(sm.containsKey(two)); + assertTrue(sm.containsKey(three)); + assertTrue(sm.containsKey(four)); + assertTrue(sm.containsKey(five)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + k = (Integer)(i.next()); + assertEquals(four, k); + k = (Integer)(i.next()); + assertEquals(five, k); + assertFalse(i.hasNext()); + Iterator r = sm.descendingKeySet().iterator(); + k = (Integer)(r.next()); + assertEquals(five, k); + k = (Integer)(r.next()); + assertEquals(four, k); + k = (Integer)(r.next()); + assertEquals(three, k); + k = (Integer)(r.next()); + assertEquals(two, k); + assertFalse(r.hasNext()); + + Iterator ei = sm.entrySet().iterator(); + Map.Entry e; + e = (Map.Entry)(ei.next()); + assertEquals(two, e.getKey()); + assertEquals("B", e.getValue()); + e = (Map.Entry)(ei.next()); + assertEquals(three, e.getKey()); + assertEquals("C", e.getValue()); + e = (Map.Entry)(ei.next()); + assertEquals(four, e.getKey()); + assertEquals("D", e.getValue()); + e = (Map.Entry)(ei.next()); + assertEquals(five, e.getKey()); + assertEquals("E", e.getValue()); + assertFalse(i.hasNext()); + + NavigableMap ssm = sm.tailMap(four, true); + assertEquals(four, ssm.firstKey()); + assertEquals(five, ssm.lastKey()); + assertEquals("D", ssm.remove(four)); + assertEquals(1, ssm.size()); + assertEquals(3, sm.size()); + assertEquals(4, map.size()); + } + + Random rnd = new Random(666); + BitSet bs; + + /** + * Submaps of submaps subdivide correctly + */ + public void testRecursiveSubMaps() throws Exception { + int mapSize = 1000; + Class cl = ConcurrentSkipListMap.class; + NavigableMap<Integer, Integer> map = newMap(cl); + bs = new BitSet(mapSize); + + populate(map, mapSize); + check(map, 0, mapSize - 1, true); + check(map.descendingMap(), 0, mapSize - 1, false); + + mutateMap(map, 0, mapSize - 1); + check(map, 0, mapSize - 1, true); + check(map.descendingMap(), 0, mapSize - 1, false); + + bashSubMap(map.subMap(0, true, mapSize, false), + 0, mapSize - 1, true); + } + + static NavigableMap<Integer, Integer> newMap(Class cl) throws Exception { + NavigableMap<Integer, Integer> result = + (NavigableMap<Integer, Integer>) cl.newInstance(); + assertEquals(result.size(), 0); + assertFalse(result.keySet().iterator().hasNext()); + return result; + } + + void populate(NavigableMap<Integer, Integer> map, int limit) { + for (int i = 0, n = 2 * limit / 3; i < n; i++) { + int key = rnd.nextInt(limit); + put(map, key); + } + } + + void mutateMap(NavigableMap<Integer, Integer> map, int min, int max) { + int size = map.size(); + int rangeSize = max - min + 1; + + // Remove a bunch of entries directly + for (int i = 0, n = rangeSize / 2; i < n; i++) { + remove(map, min - 5 + rnd.nextInt(rangeSize + 10)); + } + + // Remove a bunch of entries with iterator + for (Iterator<Integer> it = map.keySet().iterator(); it.hasNext(); ) { + if (rnd.nextBoolean()) { + bs.clear(it.next()); + it.remove(); + } + } + + // Add entries till we're back to original size + while (map.size() < size) { + int key = min + rnd.nextInt(rangeSize); + assertTrue(key >= min && key<= max); + put(map, key); + } + } + + void mutateSubMap(NavigableMap<Integer, Integer> map, int min, int max) { + int size = map.size(); + int rangeSize = max - min + 1; + + // Remove a bunch of entries directly + for (int i = 0, n = rangeSize / 2; i < n; i++) { + remove(map, min - 5 + rnd.nextInt(rangeSize + 10)); + } + + // Remove a bunch of entries with iterator + for (Iterator<Integer> it = map.keySet().iterator(); it.hasNext(); ) { + if (rnd.nextBoolean()) { + bs.clear(it.next()); + it.remove(); + } + } + + // Add entries till we're back to original size + while (map.size() < size) { + int key = min - 5 + rnd.nextInt(rangeSize + 10); + if (key >= min && key<= max) { + put(map, key); + } else { + try { + map.put(key, 2 * key); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + } + } + + void put(NavigableMap<Integer, Integer> map, int key) { + if (map.put(key, 2 * key) == null) + bs.set(key); + } + + void remove(NavigableMap<Integer, Integer> map, int key) { + if (map.remove(key) != null) + bs.clear(key); + } + + void bashSubMap(NavigableMap<Integer, Integer> map, + int min, int max, boolean ascending) { + check(map, min, max, ascending); + check(map.descendingMap(), min, max, !ascending); + + mutateSubMap(map, min, max); + check(map, min, max, ascending); + check(map.descendingMap(), min, max, !ascending); + + // Recurse + if (max - min < 2) + return; + int midPoint = (min + max) / 2; + + // headMap - pick direction and endpoint inclusion randomly + boolean incl = rnd.nextBoolean(); + NavigableMap<Integer,Integer> hm = map.headMap(midPoint, incl); + if (ascending) { + if (rnd.nextBoolean()) + bashSubMap(hm, min, midPoint - (incl ? 0 : 1), true); + else + bashSubMap(hm.descendingMap(), min, midPoint - (incl ? 0 : 1), + false); + } else { + if (rnd.nextBoolean()) + bashSubMap(hm, midPoint + (incl ? 0 : 1), max, false); + else + bashSubMap(hm.descendingMap(), midPoint + (incl ? 0 : 1), max, + true); + } + + // tailMap - pick direction and endpoint inclusion randomly + incl = rnd.nextBoolean(); + NavigableMap<Integer,Integer> tm = map.tailMap(midPoint,incl); + if (ascending) { + if (rnd.nextBoolean()) + bashSubMap(tm, midPoint + (incl ? 0 : 1), max, true); + else + bashSubMap(tm.descendingMap(), midPoint + (incl ? 0 : 1), max, + false); + } else { + if (rnd.nextBoolean()) { + bashSubMap(tm, min, midPoint - (incl ? 0 : 1), false); + } else { + bashSubMap(tm.descendingMap(), min, midPoint - (incl ? 0 : 1), + true); + } + } + + // subMap - pick direction and endpoint inclusion randomly + int rangeSize = max - min + 1; + int[] endpoints = new int[2]; + endpoints[0] = min + rnd.nextInt(rangeSize); + endpoints[1] = min + rnd.nextInt(rangeSize); + Arrays.sort(endpoints); + boolean lowIncl = rnd.nextBoolean(); + boolean highIncl = rnd.nextBoolean(); + if (ascending) { + NavigableMap<Integer,Integer> sm = map.subMap( + endpoints[0], lowIncl, endpoints[1], highIncl); + if (rnd.nextBoolean()) + bashSubMap(sm, endpoints[0] + (lowIncl ? 0 : 1), + endpoints[1] - (highIncl ? 0 : 1), true); + else + bashSubMap(sm.descendingMap(), endpoints[0] + (lowIncl ? 0 : 1), + endpoints[1] - (highIncl ? 0 : 1), false); + } else { + NavigableMap<Integer,Integer> sm = map.subMap( + endpoints[1], highIncl, endpoints[0], lowIncl); + if (rnd.nextBoolean()) + bashSubMap(sm, endpoints[0] + (lowIncl ? 0 : 1), + endpoints[1] - (highIncl ? 0 : 1), false); + else + bashSubMap(sm.descendingMap(), endpoints[0] + (lowIncl ? 0 : 1), + endpoints[1] - (highIncl ? 0 : 1), true); + } + } + + /** + * min and max are both inclusive. If max < min, interval is empty. + */ + void check(NavigableMap<Integer, Integer> map, + final int min, final int max, final boolean ascending) { + class ReferenceSet { + int lower(int key) { + return ascending ? lowerAscending(key) : higherAscending(key); + } + int floor(int key) { + return ascending ? floorAscending(key) : ceilingAscending(key); + } + int ceiling(int key) { + return ascending ? ceilingAscending(key) : floorAscending(key); + } + int higher(int key) { + return ascending ? higherAscending(key) : lowerAscending(key); + } + int first() { + return ascending ? firstAscending() : lastAscending(); + } + int last() { + return ascending ? lastAscending() : firstAscending(); + } + int lowerAscending(int key) { + return floorAscending(key - 1); + } + int floorAscending(int key) { + if (key < min) + return -1; + else if (key > max) + key = max; + + // BitSet should support this! Test would run much faster + while (key >= min) { + if (bs.get(key)) + return(key); + key--; + } + return -1; + } + int ceilingAscending(int key) { + if (key < min) + key = min; + else if (key > max) + return -1; + int result = bs.nextSetBit(key); + return result > max ? -1 : result; + } + int higherAscending(int key) { + return ceilingAscending(key + 1); + } + private int firstAscending() { + int result = ceilingAscending(min); + return result > max ? -1 : result; + } + private int lastAscending() { + int result = floorAscending(max); + return result < min ? -1 : result; + } + } + ReferenceSet rs = new ReferenceSet(); + + // Test contents using containsKey + int size = 0; + for (int i = min; i <= max; i++) { + boolean bsContainsI = bs.get(i); + assertEquals(bsContainsI, map.containsKey(i)); + if (bsContainsI) + size++; + } + assertEquals(map.size(), size); + + // Test contents using contains keySet iterator + int size2 = 0; + int previousKey = -1; + for (int key : map.keySet()) { + assertTrue(bs.get(key)); + size2++; + assertTrue(previousKey < 0 || + (ascending ? key - previousKey > 0 : key - previousKey < 0)); + previousKey = key; + } + assertEquals(size2, size); + + // Test navigation ops + for (int key = min - 1; key <= max + 1; key++) { + assertEq(map.lowerKey(key), rs.lower(key)); + assertEq(map.floorKey(key), rs.floor(key)); + assertEq(map.higherKey(key), rs.higher(key)); + assertEq(map.ceilingKey(key), rs.ceiling(key)); + } + + // Test extrema + if (map.size() != 0) { + assertEq(map.firstKey(), rs.first()); + assertEq(map.lastKey(), rs.last()); + } else { + assertEq(rs.first(), -1); + assertEq(rs.last(), -1); + try { + map.firstKey(); + shouldThrow(); + } catch (NoSuchElementException success) {} + try { + map.lastKey(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + } + + static void assertEq(Integer i, int j) { + if (i == null) + assertEquals(j, -1); + else + assertEquals((int) i, j); + } + + static boolean eq(Integer i, int j) { + return i == null ? j == -1 : i == j; + } + +} diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/ConcurrentSkipListSetTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/ConcurrentSkipListSetTest.java new file mode 100644 index 0000000..2d03b3c --- /dev/null +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/ConcurrentSkipListSetTest.java @@ -0,0 +1,961 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package tests.api.java.util.concurrent; // android-added + +import junit.framework.*; +import java.util.*; +import java.util.concurrent.*; +import java.io.*; + +public class ConcurrentSkipListSetTest extends JSR166TestCase { + public static Test suite() { + return new TestSuite(ConcurrentSkipListSetTest.class); + } + + static class MyReverseComparator implements Comparator { + public int compare(Object x, Object y) { + return ((Comparable)y).compareTo(x); + } + } + + /** + * Create a set of given size containing consecutive + * Integers 0 ... n. + */ + private ConcurrentSkipListSet populatedSet(int n) { + ConcurrentSkipListSet q = new ConcurrentSkipListSet(); + assertTrue(q.isEmpty()); + for (int i = n-1; i >= 0; i-=2) + assertTrue(q.add(new Integer(i))); + for (int i = (n & 1); i < n; i+=2) + assertTrue(q.add(new Integer(i))); + assertFalse(q.isEmpty()); + assertEquals(n, q.size()); + return q; + } + + /** + * Create set of first 5 ints + */ + private ConcurrentSkipListSet set5() { + ConcurrentSkipListSet q = new ConcurrentSkipListSet(); + assertTrue(q.isEmpty()); + q.add(one); + q.add(two); + q.add(three); + q.add(four); + q.add(five); + assertEquals(5, q.size()); + return q; + } + + /** + * A new set has unbounded capacity + */ + public void testConstructor1() { + assertEquals(0, new ConcurrentSkipListSet().size()); + } + + /** + * Initializing from null Collection throws NPE + */ + public void testConstructor3() { + try { + ConcurrentSkipListSet q = new ConcurrentSkipListSet((Collection)null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Initializing from Collection of null elements throws NPE + */ + public void testConstructor4() { + try { + Integer[] ints = new Integer[SIZE]; + ConcurrentSkipListSet q = new ConcurrentSkipListSet(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Initializing from Collection with some null elements throws NPE + */ + public void testConstructor5() { + try { + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE-1; ++i) + ints[i] = new Integer(i); + ConcurrentSkipListSet q = new ConcurrentSkipListSet(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Set contains all elements of collection used to initialize + */ + public void testConstructor6() { + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + ConcurrentSkipListSet q = new ConcurrentSkipListSet(Arrays.asList(ints)); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.pollFirst()); + } + + /** + * The comparator used in constructor is used + */ + public void testConstructor7() { + MyReverseComparator cmp = new MyReverseComparator(); + ConcurrentSkipListSet q = new ConcurrentSkipListSet(cmp); + assertEquals(cmp, q.comparator()); + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + q.addAll(Arrays.asList(ints)); + for (int i = SIZE-1; i >= 0; --i) + assertEquals(ints[i], q.pollFirst()); + } + + /** + * isEmpty is true before add, false after + */ + public void testEmpty() { + ConcurrentSkipListSet q = new ConcurrentSkipListSet(); + assertTrue(q.isEmpty()); + q.add(new Integer(1)); + assertFalse(q.isEmpty()); + q.add(new Integer(2)); + q.pollFirst(); + q.pollFirst(); + assertTrue(q.isEmpty()); + } + + /** + * size changes when elements added and removed + */ + public void testSize() { + ConcurrentSkipListSet q = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(SIZE-i, q.size()); + q.pollFirst(); + } + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.size()); + q.add(new Integer(i)); + } + } + + /** + * add(null) throws NPE + */ + public void testAddNull() { + try { + ConcurrentSkipListSet q = new ConcurrentSkipListSet(); + q.add(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Add of comparable element succeeds + */ + public void testAdd() { + ConcurrentSkipListSet q = new ConcurrentSkipListSet(); + assertTrue(q.add(zero)); + assertTrue(q.add(one)); + } + + /** + * Add of duplicate element fails + */ + public void testAddDup() { + ConcurrentSkipListSet q = new ConcurrentSkipListSet(); + assertTrue(q.add(zero)); + assertFalse(q.add(zero)); + } + + /** + * Add of non-Comparable throws CCE + */ + public void testAddNonComparable() { + try { + ConcurrentSkipListSet q = new ConcurrentSkipListSet(); + q.add(new Object()); + q.add(new Object()); + q.add(new Object()); + shouldThrow(); + } catch (ClassCastException success) {} + } + + /** + * addAll(null) throws NPE + */ + public void testAddAll1() { + try { + ConcurrentSkipListSet q = new ConcurrentSkipListSet(); + q.addAll(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + /** + * addAll of a collection with null elements throws NPE + */ + public void testAddAll2() { + try { + ConcurrentSkipListSet q = new ConcurrentSkipListSet(); + Integer[] ints = new Integer[SIZE]; + q.addAll(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + /** + * addAll of a collection with any null elements throws NPE after + * possibly adding some elements + */ + public void testAddAll3() { + try { + ConcurrentSkipListSet q = new ConcurrentSkipListSet(); + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE-1; ++i) + ints[i] = new Integer(i); + q.addAll(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Set contains all elements of successful addAll + */ + public void testAddAll5() { + Integer[] empty = new Integer[0]; + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(SIZE-1-i); + ConcurrentSkipListSet q = new ConcurrentSkipListSet(); + assertFalse(q.addAll(Arrays.asList(empty))); + assertTrue(q.addAll(Arrays.asList(ints))); + for (int i = 0; i < SIZE; ++i) + assertEquals(i, q.pollFirst()); + } + + /** + * pollFirst succeeds unless empty + */ + public void testPollFirst() { + ConcurrentSkipListSet q = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.pollFirst()); + } + assertNull(q.pollFirst()); + } + + /** + * pollLast succeeds unless empty + */ + public void testPollLast() { + ConcurrentSkipListSet q = populatedSet(SIZE); + for (int i = SIZE-1; i >= 0; --i) { + assertEquals(i, q.pollLast()); + } + assertNull(q.pollFirst()); + } + + + /** + * remove(x) removes x and returns true if present + */ + public void testRemoveElement() { + ConcurrentSkipListSet q = populatedSet(SIZE); + for (int i = 1; i < SIZE; i+=2) { + assertTrue(q.remove(new Integer(i))); + } + for (int i = 0; i < SIZE; i+=2) { + assertTrue(q.remove(new Integer(i))); + assertFalse(q.remove(new Integer(i+1))); + } + assertTrue(q.isEmpty()); + } + + /** + * contains(x) reports true when elements added but not yet removed + */ + public void testContains() { + ConcurrentSkipListSet q = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.contains(new Integer(i))); + q.pollFirst(); + assertFalse(q.contains(new Integer(i))); + } + } + + /** + * clear removes all elements + */ + public void testClear() { + ConcurrentSkipListSet q = populatedSet(SIZE); + q.clear(); + assertTrue(q.isEmpty()); + assertEquals(0, q.size()); + q.add(new Integer(1)); + assertFalse(q.isEmpty()); + q.clear(); + assertTrue(q.isEmpty()); + } + + /** + * containsAll(c) is true when c contains a subset of elements + */ + public void testContainsAll() { + ConcurrentSkipListSet q = populatedSet(SIZE); + ConcurrentSkipListSet p = new ConcurrentSkipListSet(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.containsAll(p)); + assertFalse(p.containsAll(q)); + p.add(new Integer(i)); + } + assertTrue(p.containsAll(q)); + } + + /** + * retainAll(c) retains only those elements of c and reports true if changed + */ + public void testRetainAll() { + ConcurrentSkipListSet q = populatedSet(SIZE); + ConcurrentSkipListSet p = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + boolean changed = q.retainAll(p); + if (i == 0) + assertFalse(changed); + else + assertTrue(changed); + + assertTrue(q.containsAll(p)); + assertEquals(SIZE-i, q.size()); + p.pollFirst(); + } + } + + /** + * removeAll(c) removes only those elements of c and reports true if changed + */ + public void testRemoveAll() { + for (int i = 1; i < SIZE; ++i) { + ConcurrentSkipListSet q = populatedSet(SIZE); + ConcurrentSkipListSet p = populatedSet(i); + assertTrue(q.removeAll(p)); + assertEquals(SIZE-i, q.size()); + for (int j = 0; j < i; ++j) { + Integer I = (Integer)(p.pollFirst()); + assertFalse(q.contains(I)); + } + } + } + + + + /** + * lower returns preceding element + */ + public void testLower() { + ConcurrentSkipListSet q = set5(); + Object e1 = q.lower(three); + assertEquals(two, e1); + + Object e2 = q.lower(six); + assertEquals(five, e2); + + Object e3 = q.lower(one); + assertNull(e3); + + Object e4 = q.lower(zero); + assertNull(e4); + } + + /** + * higher returns next element + */ + public void testHigher() { + ConcurrentSkipListSet q = set5(); + Object e1 = q.higher(three); + assertEquals(four, e1); + + Object e2 = q.higher(zero); + assertEquals(one, e2); + + Object e3 = q.higher(five); + assertNull(e3); + + Object e4 = q.higher(six); + assertNull(e4); + } + + /** + * floor returns preceding element + */ + public void testFloor() { + ConcurrentSkipListSet q = set5(); + Object e1 = q.floor(three); + assertEquals(three, e1); + + Object e2 = q.floor(six); + assertEquals(five, e2); + + Object e3 = q.floor(one); + assertEquals(one, e3); + + Object e4 = q.floor(zero); + assertNull(e4); + } + + /** + * ceiling returns next element + */ + public void testCeiling() { + ConcurrentSkipListSet q = set5(); + Object e1 = q.ceiling(three); + assertEquals(three, e1); + + Object e2 = q.ceiling(zero); + assertEquals(one, e2); + + Object e3 = q.ceiling(five); + assertEquals(five, e3); + + Object e4 = q.ceiling(six); + assertNull(e4); + } + + /** + * toArray contains all elements + */ + public void testToArray() { + ConcurrentSkipListSet q = populatedSet(SIZE); + Object[] o = q.toArray(); + Arrays.sort(o); + for (int i = 0; i < o.length; i++) + assertEquals(o[i], q.pollFirst()); + } + + /** + * toArray(a) contains all elements + */ + public void testToArray2() { + ConcurrentSkipListSet q = populatedSet(SIZE); + Integer[] ints = new Integer[SIZE]; + ints = (Integer[])q.toArray(ints); + Arrays.sort(ints); + for (int i = 0; i < ints.length; i++) + assertEquals(ints[i], q.pollFirst()); + } + + /** + * iterator iterates through all elements + */ + public void testIterator() { + ConcurrentSkipListSet q = populatedSet(SIZE); + int i = 0; + Iterator it = q.iterator(); + while (it.hasNext()) { + assertTrue(q.contains(it.next())); + ++i; + } + assertEquals(i, SIZE); + } + + /** + * iterator of empty set has no elements + */ + public void testEmptyIterator() { + ConcurrentSkipListSet q = new ConcurrentSkipListSet(); + int i = 0; + Iterator it = q.iterator(); + while (it.hasNext()) { + assertTrue(q.contains(it.next())); + ++i; + } + assertEquals(i, 0); + } + + /** + * iterator.remove removes current element + */ + public void testIteratorRemove () { + final ConcurrentSkipListSet q = new ConcurrentSkipListSet(); + q.add(new Integer(2)); + q.add(new Integer(1)); + q.add(new Integer(3)); + + Iterator it = q.iterator(); + it.next(); + it.remove(); + + it = q.iterator(); + assertEquals(it.next(), new Integer(2)); + assertEquals(it.next(), new Integer(3)); + assertFalse(it.hasNext()); + } + + + /** + * toString contains toStrings of elements + */ + public void testToString() { + ConcurrentSkipListSet q = populatedSet(SIZE); + String s = q.toString(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(s.indexOf(String.valueOf(i)) >= 0); + } + } + + /** + * A deserialized serialized set has same elements + */ + public void testSerialization() throws Exception { + ConcurrentSkipListSet q = populatedSet(SIZE); + ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); + ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); + out.writeObject(q); + out.close(); + + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); + ConcurrentSkipListSet r = (ConcurrentSkipListSet)in.readObject(); + assertEquals(q.size(), r.size()); + while (!q.isEmpty()) + assertEquals(q.pollFirst(), r.pollFirst()); + } + + /** + * subSet returns set with keys in requested range + */ + public void testSubSetContents() { + ConcurrentSkipListSet set = set5(); + SortedSet sm = set.subSet(two, four); + assertEquals(two, sm.first()); + assertEquals(three, sm.last()); + assertEquals(2, sm.size()); + assertFalse(sm.contains(one)); + assertTrue(sm.contains(two)); + assertTrue(sm.contains(three)); + assertFalse(sm.contains(four)); + assertFalse(sm.contains(five)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + assertFalse(i.hasNext()); + Iterator j = sm.iterator(); + j.next(); + j.remove(); + assertFalse(set.contains(two)); + assertEquals(4, set.size()); + assertEquals(1, sm.size()); + assertEquals(three, sm.first()); + assertEquals(three, sm.last()); + assertTrue(sm.remove(three)); + assertTrue(sm.isEmpty()); + assertEquals(3, set.size()); + } + + public void testSubSetContents2() { + ConcurrentSkipListSet set = set5(); + SortedSet sm = set.subSet(two, three); + assertEquals(1, sm.size()); + assertEquals(two, sm.first()); + assertEquals(two, sm.last()); + assertFalse(sm.contains(one)); + assertTrue(sm.contains(two)); + assertFalse(sm.contains(three)); + assertFalse(sm.contains(four)); + assertFalse(sm.contains(five)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + assertFalse(i.hasNext()); + Iterator j = sm.iterator(); + j.next(); + j.remove(); + assertFalse(set.contains(two)); + assertEquals(4, set.size()); + assertEquals(0, sm.size()); + assertTrue(sm.isEmpty()); + assertFalse(sm.remove(three)); + assertEquals(4, set.size()); + } + + /** + * headSet returns set with keys in requested range + */ + public void testHeadSetContents() { + ConcurrentSkipListSet set = set5(); + SortedSet sm = set.headSet(four); + assertTrue(sm.contains(one)); + assertTrue(sm.contains(two)); + assertTrue(sm.contains(three)); + assertFalse(sm.contains(four)); + assertFalse(sm.contains(five)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(one, k); + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + assertFalse(i.hasNext()); + sm.clear(); + assertTrue(sm.isEmpty()); + assertEquals(2, set.size()); + assertEquals(four, set.first()); + } + + /** + * tailSet returns set with keys in requested range + */ + public void testTailSetContents() { + ConcurrentSkipListSet set = set5(); + SortedSet sm = set.tailSet(two); + assertFalse(sm.contains(one)); + assertTrue(sm.contains(two)); + assertTrue(sm.contains(three)); + assertTrue(sm.contains(four)); + assertTrue(sm.contains(five)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + k = (Integer)(i.next()); + assertEquals(four, k); + k = (Integer)(i.next()); + assertEquals(five, k); + assertFalse(i.hasNext()); + + SortedSet ssm = sm.tailSet(four); + assertEquals(four, ssm.first()); + assertEquals(five, ssm.last()); + assertTrue(ssm.remove(four)); + assertEquals(1, ssm.size()); + assertEquals(3, sm.size()); + assertEquals(4, set.size()); + } + + Random rnd = new Random(666); + BitSet bs; + + /** + * Subsets of subsets subdivide correctly + */ + public void testRecursiveSubSets() throws Exception { + int setSize = 1000; + Class cl = ConcurrentSkipListSet.class; + + NavigableSet<Integer> set = newSet(cl); + bs = new BitSet(setSize); + + populate(set, setSize); + check(set, 0, setSize - 1, true); + check(set.descendingSet(), 0, setSize - 1, false); + + mutateSet(set, 0, setSize - 1); + check(set, 0, setSize - 1, true); + check(set.descendingSet(), 0, setSize - 1, false); + + bashSubSet(set.subSet(0, true, setSize, false), + 0, setSize - 1, true); + } + + static NavigableSet<Integer> newSet(Class cl) throws Exception { + NavigableSet<Integer> result = (NavigableSet<Integer>) cl.newInstance(); + assertEquals(result.size(), 0); + assertFalse(result.iterator().hasNext()); + return result; + } + + void populate(NavigableSet<Integer> set, int limit) { + for (int i = 0, n = 2 * limit / 3; i < n; i++) { + int element = rnd.nextInt(limit); + put(set, element); + } + } + + void mutateSet(NavigableSet<Integer> set, int min, int max) { + int size = set.size(); + int rangeSize = max - min + 1; + + // Remove a bunch of entries directly + for (int i = 0, n = rangeSize / 2; i < n; i++) { + remove(set, min - 5 + rnd.nextInt(rangeSize + 10)); + } + + // Remove a bunch of entries with iterator + for (Iterator<Integer> it = set.iterator(); it.hasNext(); ) { + if (rnd.nextBoolean()) { + bs.clear(it.next()); + it.remove(); + } + } + + // Add entries till we're back to original size + while (set.size() < size) { + int element = min + rnd.nextInt(rangeSize); + assertTrue(element >= min && element<= max); + put(set, element); + } + } + + void mutateSubSet(NavigableSet<Integer> set, int min, int max) { + int size = set.size(); + int rangeSize = max - min + 1; + + // Remove a bunch of entries directly + for (int i = 0, n = rangeSize / 2; i < n; i++) { + remove(set, min - 5 + rnd.nextInt(rangeSize + 10)); + } + + // Remove a bunch of entries with iterator + for (Iterator<Integer> it = set.iterator(); it.hasNext(); ) { + if (rnd.nextBoolean()) { + bs.clear(it.next()); + it.remove(); + } + } + + // Add entries till we're back to original size + while (set.size() < size) { + int element = min - 5 + rnd.nextInt(rangeSize + 10); + if (element >= min && element<= max) { + put(set, element); + } else { + try { + set.add(element); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + } + } + + void put(NavigableSet<Integer> set, int element) { + if (set.add(element)) + bs.set(element); + } + + void remove(NavigableSet<Integer> set, int element) { + if (set.remove(element)) + bs.clear(element); + } + + void bashSubSet(NavigableSet<Integer> set, + int min, int max, boolean ascending) { + check(set, min, max, ascending); + check(set.descendingSet(), min, max, !ascending); + + mutateSubSet(set, min, max); + check(set, min, max, ascending); + check(set.descendingSet(), min, max, !ascending); + + // Recurse + if (max - min < 2) + return; + int midPoint = (min + max) / 2; + + // headSet - pick direction and endpoint inclusion randomly + boolean incl = rnd.nextBoolean(); + NavigableSet<Integer> hm = set.headSet(midPoint, incl); + if (ascending) { + if (rnd.nextBoolean()) + bashSubSet(hm, min, midPoint - (incl ? 0 : 1), true); + else + bashSubSet(hm.descendingSet(), min, midPoint - (incl ? 0 : 1), + false); + } else { + if (rnd.nextBoolean()) + bashSubSet(hm, midPoint + (incl ? 0 : 1), max, false); + else + bashSubSet(hm.descendingSet(), midPoint + (incl ? 0 : 1), max, + true); + } + + // tailSet - pick direction and endpoint inclusion randomly + incl = rnd.nextBoolean(); + NavigableSet<Integer> tm = set.tailSet(midPoint,incl); + if (ascending) { + if (rnd.nextBoolean()) + bashSubSet(tm, midPoint + (incl ? 0 : 1), max, true); + else + bashSubSet(tm.descendingSet(), midPoint + (incl ? 0 : 1), max, + false); + } else { + if (rnd.nextBoolean()) { + bashSubSet(tm, min, midPoint - (incl ? 0 : 1), false); + } else { + bashSubSet(tm.descendingSet(), min, midPoint - (incl ? 0 : 1), + true); + } + } + + // subSet - pick direction and endpoint inclusion randomly + int rangeSize = max - min + 1; + int[] endpoints = new int[2]; + endpoints[0] = min + rnd.nextInt(rangeSize); + endpoints[1] = min + rnd.nextInt(rangeSize); + Arrays.sort(endpoints); + boolean lowIncl = rnd.nextBoolean(); + boolean highIncl = rnd.nextBoolean(); + if (ascending) { + NavigableSet<Integer> sm = set.subSet( + endpoints[0], lowIncl, endpoints[1], highIncl); + if (rnd.nextBoolean()) + bashSubSet(sm, endpoints[0] + (lowIncl ? 0 : 1), + endpoints[1] - (highIncl ? 0 : 1), true); + else + bashSubSet(sm.descendingSet(), endpoints[0] + (lowIncl ? 0 : 1), + endpoints[1] - (highIncl ? 0 : 1), false); + } else { + NavigableSet<Integer> sm = set.subSet( + endpoints[1], highIncl, endpoints[0], lowIncl); + if (rnd.nextBoolean()) + bashSubSet(sm, endpoints[0] + (lowIncl ? 0 : 1), + endpoints[1] - (highIncl ? 0 : 1), false); + else + bashSubSet(sm.descendingSet(), endpoints[0] + (lowIncl ? 0 : 1), + endpoints[1] - (highIncl ? 0 : 1), true); + } + } + + /** + * min and max are both inclusive. If max < min, interval is empty. + */ + void check(NavigableSet<Integer> set, + final int min, final int max, final boolean ascending) { + class ReferenceSet { + int lower(int element) { + return ascending ? + lowerAscending(element) : higherAscending(element); + } + int floor(int element) { + return ascending ? + floorAscending(element) : ceilingAscending(element); + } + int ceiling(int element) { + return ascending ? + ceilingAscending(element) : floorAscending(element); + } + int higher(int element) { + return ascending ? + higherAscending(element) : lowerAscending(element); + } + int first() { + return ascending ? firstAscending() : lastAscending(); + } + int last() { + return ascending ? lastAscending() : firstAscending(); + } + int lowerAscending(int element) { + return floorAscending(element - 1); + } + int floorAscending(int element) { + if (element < min) + return -1; + else if (element > max) + element = max; + + // BitSet should support this! Test would run much faster + while (element >= min) { + if (bs.get(element)) + return(element); + element--; + } + return -1; + } + int ceilingAscending(int element) { + if (element < min) + element = min; + else if (element > max) + return -1; + int result = bs.nextSetBit(element); + return result > max ? -1 : result; + } + int higherAscending(int element) { + return ceilingAscending(element + 1); + } + private int firstAscending() { + int result = ceilingAscending(min); + return result > max ? -1 : result; + } + private int lastAscending() { + int result = floorAscending(max); + return result < min ? -1 : result; + } + } + ReferenceSet rs = new ReferenceSet(); + + // Test contents using containsElement + int size = 0; + for (int i = min; i <= max; i++) { + boolean bsContainsI = bs.get(i); + assertEquals(bsContainsI, set.contains(i)); + if (bsContainsI) + size++; + } + assertEquals(set.size(), size); + + // Test contents using contains elementSet iterator + int size2 = 0; + int previousElement = -1; + for (int element : set) { + assertTrue(bs.get(element)); + size2++; + assertTrue(previousElement < 0 || (ascending ? + element - previousElement > 0 : element - previousElement < 0)); + previousElement = element; + } + assertEquals(size2, size); + + // Test navigation ops + for (int element = min - 1; element <= max + 1; element++) { + assertEq(set.lower(element), rs.lower(element)); + assertEq(set.floor(element), rs.floor(element)); + assertEq(set.higher(element), rs.higher(element)); + assertEq(set.ceiling(element), rs.ceiling(element)); + } + + // Test extrema + if (set.size() != 0) { + assertEq(set.first(), rs.first()); + assertEq(set.last(), rs.last()); + } else { + assertEq(rs.first(), -1); + assertEq(rs.last(), -1); + try { + set.first(); + shouldThrow(); + } catch (NoSuchElementException success) {} + try { + set.last(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + } + + static void assertEq(Integer i, int j) { + if (i == null) + assertEquals(j, -1); + else + assertEquals((int) i, j); + } + + static boolean eq(Integer i, int j) { + return i == null ? j == -1 : i == j; + } + +} diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/ConcurrentSkipListSubMapTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/ConcurrentSkipListSubMapTest.java new file mode 100644 index 0000000..fc70935 --- /dev/null +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/ConcurrentSkipListSubMapTest.java @@ -0,0 +1,1438 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package tests.api.java.util.concurrent; // android-added + +import junit.framework.*; +import java.util.*; +import java.util.concurrent.*; +import java.io.*; + +public class ConcurrentSkipListSubMapTest extends JSR166TestCase { + public static Test suite() { + return new TestSuite(ConcurrentSkipListSubMapTest.class); + } + + /** + * Create a map from Integers 1-5 to Strings "A"-"E". + */ + private static ConcurrentNavigableMap map5() { + ConcurrentSkipListMap map = new ConcurrentSkipListMap(); + assertTrue(map.isEmpty()); + map.put(zero, "Z"); + map.put(one, "A"); + map.put(five, "E"); + map.put(three, "C"); + map.put(two, "B"); + map.put(four, "D"); + map.put(seven, "F"); + assertFalse(map.isEmpty()); + assertEquals(7, map.size()); + return map.subMap(one, true, seven, false); + } + + /** + * Create a map from Integers -5 to -1 to Strings "A"-"E". + */ + private static ConcurrentNavigableMap dmap5() { + ConcurrentSkipListMap map = new ConcurrentSkipListMap(); + assertTrue(map.isEmpty()); + map.put(m1, "A"); + map.put(m5, "E"); + map.put(m3, "C"); + map.put(m2, "B"); + map.put(m4, "D"); + assertFalse(map.isEmpty()); + assertEquals(5, map.size()); + return map.descendingMap(); + } + + private static ConcurrentNavigableMap map0() { + ConcurrentSkipListMap map = new ConcurrentSkipListMap(); + assertTrue(map.isEmpty()); + return map.tailMap(one, true); + } + + private static ConcurrentNavigableMap dmap0() { + ConcurrentSkipListMap map = new ConcurrentSkipListMap(); + assertTrue(map.isEmpty()); + return map; + } + + /** + * clear removes all pairs + */ + public void testClear() { + ConcurrentNavigableMap map = map5(); + map.clear(); + assertEquals(map.size(), 0); + } + + + /** + * Maps with same contents are equal + */ + public void testEquals() { + ConcurrentNavigableMap map1 = map5(); + ConcurrentNavigableMap map2 = map5(); + assertEquals(map1, map2); + assertEquals(map2, map1); + map1.clear(); + assertFalse(map1.equals(map2)); + assertFalse(map2.equals(map1)); + } + + /** + * containsKey returns true for contained key + */ + public void testContainsKey() { + ConcurrentNavigableMap map = map5(); + assertTrue(map.containsKey(one)); + assertFalse(map.containsKey(zero)); + } + + /** + * containsValue returns true for held values + */ + public void testContainsValue() { + ConcurrentNavigableMap map = map5(); + assertTrue(map.containsValue("A")); + assertFalse(map.containsValue("Z")); + } + + /** + * get returns the correct element at the given key, + * or null if not present + */ + public void testGet() { + ConcurrentNavigableMap map = map5(); + assertEquals("A", (String)map.get(one)); + ConcurrentNavigableMap empty = map0(); + assertNull(empty.get(one)); + } + + /** + * isEmpty is true of empty map and false for non-empty + */ + public void testIsEmpty() { + ConcurrentNavigableMap empty = map0(); + ConcurrentNavigableMap map = map5(); + assertTrue(empty.isEmpty()); + assertFalse(map.isEmpty()); + } + + /** + * firstKey returns first key + */ + public void testFirstKey() { + ConcurrentNavigableMap map = map5(); + assertEquals(one, map.firstKey()); + } + + /** + * lastKey returns last key + */ + public void testLastKey() { + ConcurrentNavigableMap map = map5(); + assertEquals(five, map.lastKey()); + } + + + /** + * keySet returns a Set containing all the keys + */ + public void testKeySet() { + ConcurrentNavigableMap map = map5(); + Set s = map.keySet(); + assertEquals(5, s.size()); + assertTrue(s.contains(one)); + assertTrue(s.contains(two)); + assertTrue(s.contains(three)); + assertTrue(s.contains(four)); + assertTrue(s.contains(five)); + } + + /** + * keySet is ordered + */ + public void testKeySetOrder() { + ConcurrentNavigableMap map = map5(); + Set s = map.keySet(); + Iterator i = s.iterator(); + Integer last = (Integer)i.next(); + assertEquals(last, one); + while (i.hasNext()) { + Integer k = (Integer)i.next(); + assertTrue(last.compareTo(k) < 0); + last = k; + } + } + + /** + * values collection contains all values + */ + public void testValues() { + ConcurrentNavigableMap map = map5(); + Collection s = map.values(); + assertEquals(5, s.size()); + assertTrue(s.contains("A")); + assertTrue(s.contains("B")); + assertTrue(s.contains("C")); + assertTrue(s.contains("D")); + assertTrue(s.contains("E")); + } + + /** + * keySet.toArray returns contains all keys + */ + public void testKeySetToArray() { + ConcurrentNavigableMap map = map5(); + Set s = map.keySet(); + Object[] ar = s.toArray(); + assertTrue(s.containsAll(Arrays.asList(ar))); + assertEquals(5, ar.length); + ar[0] = m10; + assertFalse(s.containsAll(Arrays.asList(ar))); + } + + /** + * descendingkeySet.toArray returns contains all keys + */ + public void testDescendingKeySetToArray() { + ConcurrentNavigableMap map = map5(); + Set s = map.descendingKeySet(); + Object[] ar = s.toArray(); + assertEquals(5, ar.length); + assertTrue(s.containsAll(Arrays.asList(ar))); + ar[0] = m10; + assertFalse(s.containsAll(Arrays.asList(ar))); + } + + /** + * Values.toArray contains all values + */ + public void testValuesToArray() { + ConcurrentNavigableMap map = map5(); + Collection v = map.values(); + Object[] ar = v.toArray(); + ArrayList s = new ArrayList(Arrays.asList(ar)); + assertEquals(5, ar.length); + assertTrue(s.contains("A")); + assertTrue(s.contains("B")); + assertTrue(s.contains("C")); + assertTrue(s.contains("D")); + assertTrue(s.contains("E")); + } + + + /** + * entrySet contains all pairs + */ + public void testEntrySet() { + ConcurrentNavigableMap map = map5(); + Set s = map.entrySet(); + assertEquals(5, s.size()); + Iterator it = s.iterator(); + while (it.hasNext()) { + Map.Entry e = (Map.Entry) it.next(); + assertTrue( + (e.getKey().equals(one) && e.getValue().equals("A")) || + (e.getKey().equals(two) && e.getValue().equals("B")) || + (e.getKey().equals(three) && e.getValue().equals("C")) || + (e.getKey().equals(four) && e.getValue().equals("D")) || + (e.getKey().equals(five) && e.getValue().equals("E"))); + } + } + + /** + * putAll adds all key-value pairs from the given map + */ + public void testPutAll() { + ConcurrentNavigableMap empty = map0(); + ConcurrentNavigableMap map = map5(); + empty.putAll(map); + assertEquals(5, empty.size()); + assertTrue(empty.containsKey(one)); + assertTrue(empty.containsKey(two)); + assertTrue(empty.containsKey(three)); + assertTrue(empty.containsKey(four)); + assertTrue(empty.containsKey(five)); + } + + /** + * putIfAbsent works when the given key is not present + */ + public void testPutIfAbsent() { + ConcurrentNavigableMap map = map5(); + map.putIfAbsent(six, "Z"); + assertTrue(map.containsKey(six)); + } + + /** + * putIfAbsent does not add the pair if the key is already present + */ + public void testPutIfAbsent2() { + ConcurrentNavigableMap map = map5(); + assertEquals("A", map.putIfAbsent(one, "Z")); + } + + /** + * replace fails when the given key is not present + */ + public void testReplace() { + ConcurrentNavigableMap map = map5(); + assertNull(map.replace(six, "Z")); + assertFalse(map.containsKey(six)); + } + + /** + * replace succeeds if the key is already present + */ + public void testReplace2() { + ConcurrentNavigableMap map = map5(); + assertNotNull(map.replace(one, "Z")); + assertEquals("Z", map.get(one)); + } + + + /** + * replace value fails when the given key not mapped to expected value + */ + public void testReplaceValue() { + ConcurrentNavigableMap map = map5(); + assertEquals("A", map.get(one)); + assertFalse(map.replace(one, "Z", "Z")); + assertEquals("A", map.get(one)); + } + + /** + * replace value succeeds when the given key mapped to expected value + */ + public void testReplaceValue2() { + ConcurrentNavigableMap map = map5(); + assertEquals("A", map.get(one)); + assertTrue(map.replace(one, "A", "Z")); + assertEquals("Z", map.get(one)); + } + + + /** + * remove removes the correct key-value pair from the map + */ + public void testRemove() { + ConcurrentNavigableMap map = map5(); + map.remove(five); + assertEquals(4, map.size()); + assertFalse(map.containsKey(five)); + } + + /** + * remove(key,value) removes only if pair present + */ + public void testRemove2() { + ConcurrentNavigableMap map = map5(); + assertTrue(map.containsKey(five)); + assertEquals("E", map.get(five)); + map.remove(five, "E"); + assertEquals(4, map.size()); + assertFalse(map.containsKey(five)); + map.remove(four, "A"); + assertEquals(4, map.size()); + assertTrue(map.containsKey(four)); + } + + /** + * lowerEntry returns preceding entry. + */ + public void testLowerEntry() { + ConcurrentNavigableMap map = map5(); + Map.Entry e1 = map.lowerEntry(three); + assertEquals(two, e1.getKey()); + + Map.Entry e2 = map.lowerEntry(six); + assertEquals(five, e2.getKey()); + + Map.Entry e3 = map.lowerEntry(one); + assertNull(e3); + + Map.Entry e4 = map.lowerEntry(zero); + assertNull(e4); + } + + /** + * higherEntry returns next entry. + */ + public void testHigherEntry() { + ConcurrentNavigableMap map = map5(); + Map.Entry e1 = map.higherEntry(three); + assertEquals(four, e1.getKey()); + + Map.Entry e2 = map.higherEntry(zero); + assertEquals(one, e2.getKey()); + + Map.Entry e3 = map.higherEntry(five); + assertNull(e3); + + Map.Entry e4 = map.higherEntry(six); + assertNull(e4); + } + + /** + * floorEntry returns preceding entry. + */ + public void testFloorEntry() { + ConcurrentNavigableMap map = map5(); + Map.Entry e1 = map.floorEntry(three); + assertEquals(three, e1.getKey()); + + Map.Entry e2 = map.floorEntry(six); + assertEquals(five, e2.getKey()); + + Map.Entry e3 = map.floorEntry(one); + assertEquals(one, e3.getKey()); + + Map.Entry e4 = map.floorEntry(zero); + assertNull(e4); + } + + /** + * ceilingEntry returns next entry. + */ + public void testCeilingEntry() { + ConcurrentNavigableMap map = map5(); + Map.Entry e1 = map.ceilingEntry(three); + assertEquals(three, e1.getKey()); + + Map.Entry e2 = map.ceilingEntry(zero); + assertEquals(one, e2.getKey()); + + Map.Entry e3 = map.ceilingEntry(five); + assertEquals(five, e3.getKey()); + + Map.Entry e4 = map.ceilingEntry(six); + assertNull(e4); + } + + /** + * pollFirstEntry returns entries in order + */ + public void testPollFirstEntry() { + ConcurrentNavigableMap map = map5(); + Map.Entry e = map.pollFirstEntry(); + assertEquals(one, e.getKey()); + assertEquals("A", e.getValue()); + e = map.pollFirstEntry(); + assertEquals(two, e.getKey()); + map.put(one, "A"); + e = map.pollFirstEntry(); + assertEquals(one, e.getKey()); + assertEquals("A", e.getValue()); + e = map.pollFirstEntry(); + assertEquals(three, e.getKey()); + map.remove(four); + e = map.pollFirstEntry(); + assertEquals(five, e.getKey()); + try { + e.setValue("A"); + shouldThrow(); + } catch (UnsupportedOperationException success) {} + e = map.pollFirstEntry(); + assertNull(e); + } + + /** + * pollLastEntry returns entries in order + */ + public void testPollLastEntry() { + ConcurrentNavigableMap map = map5(); + Map.Entry e = map.pollLastEntry(); + assertEquals(five, e.getKey()); + assertEquals("E", e.getValue()); + e = map.pollLastEntry(); + assertEquals(four, e.getKey()); + map.put(five, "E"); + e = map.pollLastEntry(); + assertEquals(five, e.getKey()); + assertEquals("E", e.getValue()); + e = map.pollLastEntry(); + assertEquals(three, e.getKey()); + map.remove(two); + e = map.pollLastEntry(); + assertEquals(one, e.getKey()); + try { + e.setValue("E"); + shouldThrow(); + } catch (UnsupportedOperationException success) {} + e = map.pollLastEntry(); + assertNull(e); + } + + /** + * size returns the correct values + */ + public void testSize() { + ConcurrentNavigableMap map = map5(); + ConcurrentNavigableMap empty = map0(); + assertEquals(0, empty.size()); + assertEquals(5, map.size()); + } + + /** + * toString contains toString of elements + */ + public void testToString() { + ConcurrentNavigableMap map = map5(); + String s = map.toString(); + for (int i = 1; i <= 5; ++i) { + assertTrue(s.indexOf(String.valueOf(i)) >= 0); + } + } + + // Exception tests + + /** + * get(null) of nonempty map throws NPE + */ + public void testGet_NullPointerException() { + try { + ConcurrentNavigableMap c = map5(); + c.get(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * containsKey(null) of nonempty map throws NPE + */ + public void testContainsKey_NullPointerException() { + try { + ConcurrentNavigableMap c = map5(); + c.containsKey(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * containsValue(null) throws NPE + */ + public void testContainsValue_NullPointerException() { + try { + ConcurrentNavigableMap c = map0(); + c.containsValue(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + + /** + * put(null,x) throws NPE + */ + public void testPut1_NullPointerException() { + try { + ConcurrentNavigableMap c = map5(); + c.put(null, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * putIfAbsent(null, x) throws NPE + */ + public void testPutIfAbsent1_NullPointerException() { + try { + ConcurrentNavigableMap c = map5(); + c.putIfAbsent(null, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * replace(null, x) throws NPE + */ + public void testReplace_NullPointerException() { + try { + ConcurrentNavigableMap c = map5(); + c.replace(null, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * replace(null, x, y) throws NPE + */ + public void testReplaceValue_NullPointerException() { + try { + ConcurrentNavigableMap c = map5(); + c.replace(null, one, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * remove(null) throws NPE + */ + public void testRemove1_NullPointerException() { + try { + ConcurrentNavigableMap c = map5(); + c.remove(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * remove(null, x) throws NPE + */ + public void testRemove2_NullPointerException() { + try { + ConcurrentNavigableMap c = map5(); + c.remove(null, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * A deserialized map equals original + */ + public void testSerialization() throws Exception { + ConcurrentNavigableMap q = map5(); + + ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); + ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); + out.writeObject(q); + out.close(); + + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); + ConcurrentNavigableMap r = (ConcurrentNavigableMap)in.readObject(); + assertEquals(q.size(), r.size()); + assertTrue(q.equals(r)); + assertTrue(r.equals(q)); + } + + + + /** + * subMap returns map with keys in requested range + */ + public void testSubMapContents() { + ConcurrentNavigableMap map = map5(); + SortedMap sm = map.subMap(two, four); + assertEquals(two, sm.firstKey()); + assertEquals(three, sm.lastKey()); + assertEquals(2, sm.size()); + assertFalse(sm.containsKey(one)); + assertTrue(sm.containsKey(two)); + assertTrue(sm.containsKey(three)); + assertFalse(sm.containsKey(four)); + assertFalse(sm.containsKey(five)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + assertFalse(i.hasNext()); + Iterator j = sm.keySet().iterator(); + j.next(); + j.remove(); + assertFalse(map.containsKey(two)); + assertEquals(4, map.size()); + assertEquals(1, sm.size()); + assertEquals(three, sm.firstKey()); + assertEquals(three, sm.lastKey()); + assertEquals("C", sm.remove(three)); + assertTrue(sm.isEmpty()); + assertEquals(3, map.size()); + } + + public void testSubMapContents2() { + ConcurrentNavigableMap map = map5(); + SortedMap sm = map.subMap(two, three); + assertEquals(1, sm.size()); + assertEquals(two, sm.firstKey()); + assertEquals(two, sm.lastKey()); + assertFalse(sm.containsKey(one)); + assertTrue(sm.containsKey(two)); + assertFalse(sm.containsKey(three)); + assertFalse(sm.containsKey(four)); + assertFalse(sm.containsKey(five)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + assertFalse(i.hasNext()); + Iterator j = sm.keySet().iterator(); + j.next(); + j.remove(); + assertFalse(map.containsKey(two)); + assertEquals(4, map.size()); + assertEquals(0, sm.size()); + assertTrue(sm.isEmpty()); + assertSame(sm.remove(three), null); + assertEquals(4, map.size()); + } + + /** + * headMap returns map with keys in requested range + */ + public void testHeadMapContents() { + ConcurrentNavigableMap map = map5(); + SortedMap sm = map.headMap(four); + assertTrue(sm.containsKey(one)); + assertTrue(sm.containsKey(two)); + assertTrue(sm.containsKey(three)); + assertFalse(sm.containsKey(four)); + assertFalse(sm.containsKey(five)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(one, k); + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + assertFalse(i.hasNext()); + sm.clear(); + assertTrue(sm.isEmpty()); + assertEquals(2, map.size()); + assertEquals(four, map.firstKey()); + } + + /** + * headMap returns map with keys in requested range + */ + public void testTailMapContents() { + ConcurrentNavigableMap map = map5(); + SortedMap sm = map.tailMap(two); + assertFalse(sm.containsKey(one)); + assertTrue(sm.containsKey(two)); + assertTrue(sm.containsKey(three)); + assertTrue(sm.containsKey(four)); + assertTrue(sm.containsKey(five)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + k = (Integer)(i.next()); + assertEquals(four, k); + k = (Integer)(i.next()); + assertEquals(five, k); + assertFalse(i.hasNext()); + + Iterator ei = sm.entrySet().iterator(); + Map.Entry e; + e = (Map.Entry)(ei.next()); + assertEquals(two, e.getKey()); + assertEquals("B", e.getValue()); + e = (Map.Entry)(ei.next()); + assertEquals(three, e.getKey()); + assertEquals("C", e.getValue()); + e = (Map.Entry)(ei.next()); + assertEquals(four, e.getKey()); + assertEquals("D", e.getValue()); + e = (Map.Entry)(ei.next()); + assertEquals(five, e.getKey()); + assertEquals("E", e.getValue()); + assertFalse(i.hasNext()); + + SortedMap ssm = sm.tailMap(four); + assertEquals(four, ssm.firstKey()); + assertEquals(five, ssm.lastKey()); + assertEquals("D", ssm.remove(four)); + assertEquals(1, ssm.size()); + assertEquals(3, sm.size()); + assertEquals(4, map.size()); + } + + /** + * clear removes all pairs + */ + public void testDescendingClear() { + ConcurrentNavigableMap map = dmap5(); + map.clear(); + assertEquals(map.size(), 0); + } + + + /** + * Maps with same contents are equal + */ + public void testDescendingEquals() { + ConcurrentNavigableMap map1 = dmap5(); + ConcurrentNavigableMap map2 = dmap5(); + assertEquals(map1, map2); + assertEquals(map2, map1); + map1.clear(); + assertFalse(map1.equals(map2)); + assertFalse(map2.equals(map1)); + } + + /** + * containsKey returns true for contained key + */ + public void testDescendingContainsKey() { + ConcurrentNavigableMap map = dmap5(); + assertTrue(map.containsKey(m1)); + assertFalse(map.containsKey(zero)); + } + + /** + * containsValue returns true for held values + */ + public void testDescendingContainsValue() { + ConcurrentNavigableMap map = dmap5(); + assertTrue(map.containsValue("A")); + assertFalse(map.containsValue("Z")); + } + + /** + * get returns the correct element at the given key, + * or null if not present + */ + public void testDescendingGet() { + ConcurrentNavigableMap map = dmap5(); + assertEquals("A", (String)map.get(m1)); + ConcurrentNavigableMap empty = dmap0(); + assertNull(empty.get(m1)); + } + + /** + * isEmpty is true of empty map and false for non-empty + */ + public void testDescendingIsEmpty() { + ConcurrentNavigableMap empty = dmap0(); + ConcurrentNavigableMap map = dmap5(); + assertTrue(empty.isEmpty()); + assertFalse(map.isEmpty()); + } + + /** + * firstKey returns first key + */ + public void testDescendingFirstKey() { + ConcurrentNavigableMap map = dmap5(); + assertEquals(m1, map.firstKey()); + } + + /** + * lastKey returns last key + */ + public void testDescendingLastKey() { + ConcurrentNavigableMap map = dmap5(); + assertEquals(m5, map.lastKey()); + } + + + /** + * keySet returns a Set containing all the keys + */ + public void testDescendingKeySet() { + ConcurrentNavigableMap map = dmap5(); + Set s = map.keySet(); + assertEquals(5, s.size()); + assertTrue(s.contains(m1)); + assertTrue(s.contains(m2)); + assertTrue(s.contains(m3)); + assertTrue(s.contains(m4)); + assertTrue(s.contains(m5)); + } + + /** + * keySet is ordered + */ + public void testDescendingKeySetOrder() { + ConcurrentNavigableMap map = dmap5(); + Set s = map.keySet(); + Iterator i = s.iterator(); + Integer last = (Integer)i.next(); + assertEquals(last, m1); + while (i.hasNext()) { + Integer k = (Integer)i.next(); + assertTrue(last.compareTo(k) > 0); + last = k; + } + } + + /** + * values collection contains all values + */ + public void testDescendingValues() { + ConcurrentNavigableMap map = dmap5(); + Collection s = map.values(); + assertEquals(5, s.size()); + assertTrue(s.contains("A")); + assertTrue(s.contains("B")); + assertTrue(s.contains("C")); + assertTrue(s.contains("D")); + assertTrue(s.contains("E")); + } + + /** + * keySet.toArray returns contains all keys + */ + public void testDescendingAscendingKeySetToArray() { + ConcurrentNavigableMap map = dmap5(); + Set s = map.keySet(); + Object[] ar = s.toArray(); + assertTrue(s.containsAll(Arrays.asList(ar))); + assertEquals(5, ar.length); + ar[0] = m10; + assertFalse(s.containsAll(Arrays.asList(ar))); + } + + /** + * descendingkeySet.toArray returns contains all keys + */ + public void testDescendingDescendingKeySetToArray() { + ConcurrentNavigableMap map = dmap5(); + Set s = map.descendingKeySet(); + Object[] ar = s.toArray(); + assertEquals(5, ar.length); + assertTrue(s.containsAll(Arrays.asList(ar))); + ar[0] = m10; + assertFalse(s.containsAll(Arrays.asList(ar))); + } + + /** + * Values.toArray contains all values + */ + public void testDescendingValuesToArray() { + ConcurrentNavigableMap map = dmap5(); + Collection v = map.values(); + Object[] ar = v.toArray(); + ArrayList s = new ArrayList(Arrays.asList(ar)); + assertEquals(5, ar.length); + assertTrue(s.contains("A")); + assertTrue(s.contains("B")); + assertTrue(s.contains("C")); + assertTrue(s.contains("D")); + assertTrue(s.contains("E")); + } + + + /** + * entrySet contains all pairs + */ + public void testDescendingEntrySet() { + ConcurrentNavigableMap map = dmap5(); + Set s = map.entrySet(); + assertEquals(5, s.size()); + Iterator it = s.iterator(); + while (it.hasNext()) { + Map.Entry e = (Map.Entry) it.next(); + assertTrue( + (e.getKey().equals(m1) && e.getValue().equals("A")) || + (e.getKey().equals(m2) && e.getValue().equals("B")) || + (e.getKey().equals(m3) && e.getValue().equals("C")) || + (e.getKey().equals(m4) && e.getValue().equals("D")) || + (e.getKey().equals(m5) && e.getValue().equals("E"))); + } + } + + /** + * putAll adds all key-value pairs from the given map + */ + public void testDescendingPutAll() { + ConcurrentNavigableMap empty = dmap0(); + ConcurrentNavigableMap map = dmap5(); + empty.putAll(map); + assertEquals(5, empty.size()); + assertTrue(empty.containsKey(m1)); + assertTrue(empty.containsKey(m2)); + assertTrue(empty.containsKey(m3)); + assertTrue(empty.containsKey(m4)); + assertTrue(empty.containsKey(m5)); + } + + /** + * putIfAbsent works when the given key is not present + */ + public void testDescendingPutIfAbsent() { + ConcurrentNavigableMap map = dmap5(); + map.putIfAbsent(six, "Z"); + assertTrue(map.containsKey(six)); + } + + /** + * putIfAbsent does not add the pair if the key is already present + */ + public void testDescendingPutIfAbsent2() { + ConcurrentNavigableMap map = dmap5(); + assertEquals("A", map.putIfAbsent(m1, "Z")); + } + + /** + * replace fails when the given key is not present + */ + public void testDescendingReplace() { + ConcurrentNavigableMap map = dmap5(); + assertNull(map.replace(six, "Z")); + assertFalse(map.containsKey(six)); + } + + /** + * replace succeeds if the key is already present + */ + public void testDescendingReplace2() { + ConcurrentNavigableMap map = dmap5(); + assertNotNull(map.replace(m1, "Z")); + assertEquals("Z", map.get(m1)); + } + + + /** + * replace value fails when the given key not mapped to expected value + */ + public void testDescendingReplaceValue() { + ConcurrentNavigableMap map = dmap5(); + assertEquals("A", map.get(m1)); + assertFalse(map.replace(m1, "Z", "Z")); + assertEquals("A", map.get(m1)); + } + + /** + * replace value succeeds when the given key mapped to expected value + */ + public void testDescendingReplaceValue2() { + ConcurrentNavigableMap map = dmap5(); + assertEquals("A", map.get(m1)); + assertTrue(map.replace(m1, "A", "Z")); + assertEquals("Z", map.get(m1)); + } + + + /** + * remove removes the correct key-value pair from the map + */ + public void testDescendingRemove() { + ConcurrentNavigableMap map = dmap5(); + map.remove(m5); + assertEquals(4, map.size()); + assertFalse(map.containsKey(m5)); + } + + /** + * remove(key,value) removes only if pair present + */ + public void testDescendingRemove2() { + ConcurrentNavigableMap map = dmap5(); + assertTrue(map.containsKey(m5)); + assertEquals("E", map.get(m5)); + map.remove(m5, "E"); + assertEquals(4, map.size()); + assertFalse(map.containsKey(m5)); + map.remove(m4, "A"); + assertEquals(4, map.size()); + assertTrue(map.containsKey(m4)); + } + + /** + * lowerEntry returns preceding entry. + */ + public void testDescendingLowerEntry() { + ConcurrentNavigableMap map = dmap5(); + Map.Entry e1 = map.lowerEntry(m3); + assertEquals(m2, e1.getKey()); + + Map.Entry e2 = map.lowerEntry(m6); + assertEquals(m5, e2.getKey()); + + Map.Entry e3 = map.lowerEntry(m1); + assertNull(e3); + + Map.Entry e4 = map.lowerEntry(zero); + assertNull(e4); + } + + /** + * higherEntry returns next entry. + */ + public void testDescendingHigherEntry() { + ConcurrentNavigableMap map = dmap5(); + Map.Entry e1 = map.higherEntry(m3); + assertEquals(m4, e1.getKey()); + + Map.Entry e2 = map.higherEntry(zero); + assertEquals(m1, e2.getKey()); + + Map.Entry e3 = map.higherEntry(m5); + assertNull(e3); + + Map.Entry e4 = map.higherEntry(m6); + assertNull(e4); + } + + /** + * floorEntry returns preceding entry. + */ + public void testDescendingFloorEntry() { + ConcurrentNavigableMap map = dmap5(); + Map.Entry e1 = map.floorEntry(m3); + assertEquals(m3, e1.getKey()); + + Map.Entry e2 = map.floorEntry(m6); + assertEquals(m5, e2.getKey()); + + Map.Entry e3 = map.floorEntry(m1); + assertEquals(m1, e3.getKey()); + + Map.Entry e4 = map.floorEntry(zero); + assertNull(e4); + } + + /** + * ceilingEntry returns next entry. + */ + public void testDescendingCeilingEntry() { + ConcurrentNavigableMap map = dmap5(); + Map.Entry e1 = map.ceilingEntry(m3); + assertEquals(m3, e1.getKey()); + + Map.Entry e2 = map.ceilingEntry(zero); + assertEquals(m1, e2.getKey()); + + Map.Entry e3 = map.ceilingEntry(m5); + assertEquals(m5, e3.getKey()); + + Map.Entry e4 = map.ceilingEntry(m6); + assertNull(e4); + } + + /** + * pollFirstEntry returns entries in order + */ + public void testDescendingPollFirstEntry() { + ConcurrentNavigableMap map = dmap5(); + Map.Entry e = map.pollFirstEntry(); + assertEquals(m1, e.getKey()); + assertEquals("A", e.getValue()); + e = map.pollFirstEntry(); + assertEquals(m2, e.getKey()); + map.put(m1, "A"); + e = map.pollFirstEntry(); + assertEquals(m1, e.getKey()); + assertEquals("A", e.getValue()); + e = map.pollFirstEntry(); + assertEquals(m3, e.getKey()); + map.remove(m4); + e = map.pollFirstEntry(); + assertEquals(m5, e.getKey()); + try { + e.setValue("A"); + shouldThrow(); + } catch (UnsupportedOperationException success) {} + e = map.pollFirstEntry(); + assertNull(e); + } + + /** + * pollLastEntry returns entries in order + */ + public void testDescendingPollLastEntry() { + ConcurrentNavigableMap map = dmap5(); + Map.Entry e = map.pollLastEntry(); + assertEquals(m5, e.getKey()); + assertEquals("E", e.getValue()); + e = map.pollLastEntry(); + assertEquals(m4, e.getKey()); + map.put(m5, "E"); + e = map.pollLastEntry(); + assertEquals(m5, e.getKey()); + assertEquals("E", e.getValue()); + e = map.pollLastEntry(); + assertEquals(m3, e.getKey()); + map.remove(m2); + e = map.pollLastEntry(); + assertEquals(m1, e.getKey()); + try { + e.setValue("E"); + shouldThrow(); + } catch (UnsupportedOperationException success) {} + e = map.pollLastEntry(); + assertNull(e); + } + + /** + * size returns the correct values + */ + public void testDescendingSize() { + ConcurrentNavigableMap map = dmap5(); + ConcurrentNavigableMap empty = dmap0(); + assertEquals(0, empty.size()); + assertEquals(5, map.size()); + } + + /** + * toString contains toString of elements + */ + public void testDescendingToString() { + ConcurrentNavigableMap map = dmap5(); + String s = map.toString(); + for (int i = 1; i <= 5; ++i) { + assertTrue(s.indexOf(String.valueOf(i)) >= 0); + } + } + + // Exception testDescendings + + /** + * get(null) of empty map throws NPE + */ + public void testDescendingGet_NullPointerException() { + try { + ConcurrentNavigableMap c = dmap5(); + c.get(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * containsKey(null) of empty map throws NPE + */ + public void testDescendingContainsKey_NullPointerException() { + try { + ConcurrentNavigableMap c = dmap5(); + c.containsKey(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * containsValue(null) throws NPE + */ + public void testDescendingContainsValue_NullPointerException() { + try { + ConcurrentNavigableMap c = dmap0(); + c.containsValue(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + + /** + * put(null,x) throws NPE + */ + public void testDescendingPut1_NullPointerException() { + try { + ConcurrentNavigableMap c = dmap5(); + c.put(null, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * putIfAbsent(null, x) throws NPE + */ + public void testDescendingPutIfAbsent1_NullPointerException() { + try { + ConcurrentNavigableMap c = dmap5(); + c.putIfAbsent(null, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * replace(null, x) throws NPE + */ + public void testDescendingReplace_NullPointerException() { + try { + ConcurrentNavigableMap c = dmap5(); + c.replace(null, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * replace(null, x, y) throws NPE + */ + public void testDescendingReplaceValue_NullPointerException() { + try { + ConcurrentNavigableMap c = dmap5(); + c.replace(null, m1, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * remove(null) throws NPE + */ + public void testDescendingRemove1_NullPointerException() { + try { + ConcurrentNavigableMap c = dmap5(); + c.remove(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * remove(null, x) throws NPE + */ + public void testDescendingRemove2_NullPointerException() { + try { + ConcurrentNavigableMap c = dmap5(); + c.remove(null, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * A deserialized map equals original + */ + public void testDescendingSerialization() throws Exception { + ConcurrentNavigableMap q = dmap5(); + + ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); + ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); + out.writeObject(q); + out.close(); + + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); + ConcurrentNavigableMap r = (ConcurrentNavigableMap)in.readObject(); + assertEquals(q.size(), r.size()); + assertTrue(q.equals(r)); + assertTrue(r.equals(q)); + } + + + /** + * subMap returns map with keys in requested range + */ + public void testDescendingSubMapContents() { + ConcurrentNavigableMap map = dmap5(); + SortedMap sm = map.subMap(m2, m4); + assertEquals(m2, sm.firstKey()); + assertEquals(m3, sm.lastKey()); + assertEquals(2, sm.size()); + assertFalse(sm.containsKey(m1)); + assertTrue(sm.containsKey(m2)); + assertTrue(sm.containsKey(m3)); + assertFalse(sm.containsKey(m4)); + assertFalse(sm.containsKey(m5)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(m2, k); + k = (Integer)(i.next()); + assertEquals(m3, k); + assertFalse(i.hasNext()); + Iterator j = sm.keySet().iterator(); + j.next(); + j.remove(); + assertFalse(map.containsKey(m2)); + assertEquals(4, map.size()); + assertEquals(1, sm.size()); + assertEquals(m3, sm.firstKey()); + assertEquals(m3, sm.lastKey()); + assertEquals("C", sm.remove(m3)); + assertTrue(sm.isEmpty()); + assertEquals(3, map.size()); + } + + public void testDescendingSubMapContents2() { + ConcurrentNavigableMap map = dmap5(); + SortedMap sm = map.subMap(m2, m3); + assertEquals(1, sm.size()); + assertEquals(m2, sm.firstKey()); + assertEquals(m2, sm.lastKey()); + assertFalse(sm.containsKey(m1)); + assertTrue(sm.containsKey(m2)); + assertFalse(sm.containsKey(m3)); + assertFalse(sm.containsKey(m4)); + assertFalse(sm.containsKey(m5)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(m2, k); + assertFalse(i.hasNext()); + Iterator j = sm.keySet().iterator(); + j.next(); + j.remove(); + assertFalse(map.containsKey(m2)); + assertEquals(4, map.size()); + assertEquals(0, sm.size()); + assertTrue(sm.isEmpty()); + assertSame(sm.remove(m3), null); + assertEquals(4, map.size()); + } + + /** + * headMap returns map with keys in requested range + */ + public void testDescendingHeadMapContents() { + ConcurrentNavigableMap map = dmap5(); + SortedMap sm = map.headMap(m4); + assertTrue(sm.containsKey(m1)); + assertTrue(sm.containsKey(m2)); + assertTrue(sm.containsKey(m3)); + assertFalse(sm.containsKey(m4)); + assertFalse(sm.containsKey(m5)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(m1, k); + k = (Integer)(i.next()); + assertEquals(m2, k); + k = (Integer)(i.next()); + assertEquals(m3, k); + assertFalse(i.hasNext()); + sm.clear(); + assertTrue(sm.isEmpty()); + assertEquals(2, map.size()); + assertEquals(m4, map.firstKey()); + } + + /** + * headMap returns map with keys in requested range + */ + public void testDescendingTailMapContents() { + ConcurrentNavigableMap map = dmap5(); + SortedMap sm = map.tailMap(m2); + assertFalse(sm.containsKey(m1)); + assertTrue(sm.containsKey(m2)); + assertTrue(sm.containsKey(m3)); + assertTrue(sm.containsKey(m4)); + assertTrue(sm.containsKey(m5)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(m2, k); + k = (Integer)(i.next()); + assertEquals(m3, k); + k = (Integer)(i.next()); + assertEquals(m4, k); + k = (Integer)(i.next()); + assertEquals(m5, k); + assertFalse(i.hasNext()); + + Iterator ei = sm.entrySet().iterator(); + Map.Entry e; + e = (Map.Entry)(ei.next()); + assertEquals(m2, e.getKey()); + assertEquals("B", e.getValue()); + e = (Map.Entry)(ei.next()); + assertEquals(m3, e.getKey()); + assertEquals("C", e.getValue()); + e = (Map.Entry)(ei.next()); + assertEquals(m4, e.getKey()); + assertEquals("D", e.getValue()); + e = (Map.Entry)(ei.next()); + assertEquals(m5, e.getKey()); + assertEquals("E", e.getValue()); + assertFalse(i.hasNext()); + + SortedMap ssm = sm.tailMap(m4); + assertEquals(m4, ssm.firstKey()); + assertEquals(m5, ssm.lastKey()); + assertEquals("D", ssm.remove(m4)); + assertEquals(1, ssm.size()); + assertEquals(3, sm.size()); + assertEquals(4, map.size()); + } + +} diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/ConcurrentSkipListSubSetTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/ConcurrentSkipListSubSetTest.java new file mode 100644 index 0000000..9f0a496 --- /dev/null +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/ConcurrentSkipListSubSetTest.java @@ -0,0 +1,1117 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package tests.api.java.util.concurrent; // android-added + +import junit.framework.*; +import java.util.*; +import java.util.concurrent.*; +import java.io.*; + +public class ConcurrentSkipListSubSetTest extends JSR166TestCase { + public static Test suite() { + return new TestSuite(ConcurrentSkipListSubSetTest.class); + } + + static class MyReverseComparator implements Comparator { + public int compare(Object x, Object y) { + return ((Comparable)y).compareTo(x); + } + } + + /** + * Create a set of given size containing consecutive + * Integers 0 ... n. + */ + private NavigableSet populatedSet(int n) { + ConcurrentSkipListSet q = new ConcurrentSkipListSet(); + assertTrue(q.isEmpty()); + + for (int i = n-1; i >= 0; i-=2) + assertTrue(q.add(new Integer(i))); + for (int i = (n & 1); i < n; i+=2) + assertTrue(q.add(new Integer(i))); + assertTrue(q.add(new Integer(-n))); + assertTrue(q.add(new Integer(n))); + NavigableSet s = q.subSet(new Integer(0), true, new Integer(n), false); + assertFalse(s.isEmpty()); + assertEquals(n, s.size()); + return s; + } + + /** + * Create set of first 5 ints + */ + private NavigableSet set5() { + ConcurrentSkipListSet q = new ConcurrentSkipListSet(); + assertTrue(q.isEmpty()); + q.add(one); + q.add(two); + q.add(three); + q.add(four); + q.add(five); + q.add(zero); + q.add(seven); + NavigableSet s = q.subSet(one, true, seven, false); + assertEquals(5, s.size()); + return s; + } + + /** + * Create set of first 5 negative ints + */ + private NavigableSet dset5() { + ConcurrentSkipListSet q = new ConcurrentSkipListSet(); + assertTrue(q.isEmpty()); + q.add(m1); + q.add(m2); + q.add(m3); + q.add(m4); + q.add(m5); + NavigableSet s = q.descendingSet(); + assertEquals(5, s.size()); + return s; + } + + private static NavigableSet set0() { + ConcurrentSkipListSet set = new ConcurrentSkipListSet(); + assertTrue(set.isEmpty()); + return set.tailSet(m1, true); + } + + private static NavigableSet dset0() { + ConcurrentSkipListSet set = new ConcurrentSkipListSet(); + assertTrue(set.isEmpty()); + return set; + } + + /** + * A new set has unbounded capacity + */ + public void testConstructor1() { + assertEquals(0, set0().size()); + } + + + /** + * isEmpty is true before add, false after + */ + public void testEmpty() { + NavigableSet q = set0(); + assertTrue(q.isEmpty()); + q.add(new Integer(1)); + assertFalse(q.isEmpty()); + q.add(new Integer(2)); + q.pollFirst(); + q.pollFirst(); + assertTrue(q.isEmpty()); + } + + /** + * size changes when elements added and removed + */ + public void testSize() { + NavigableSet q = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(SIZE-i, q.size()); + q.pollFirst(); + } + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.size()); + q.add(new Integer(i)); + } + } + + /** + * add(null) throws NPE + */ + public void testAddNull() { + try { + NavigableSet q = set0(); + q.add(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Add of comparable element succeeds + */ + public void testAdd() { + NavigableSet q = set0(); + assertTrue(q.add(six)); + } + + /** + * Add of duplicate element fails + */ + public void testAddDup() { + NavigableSet q = set0(); + assertTrue(q.add(six)); + assertFalse(q.add(six)); + } + + /** + * Add of non-Comparable throws CCE + */ + public void testAddNonComparable() { + try { + NavigableSet q = set0(); + q.add(new Object()); + q.add(new Object()); + q.add(new Object()); + shouldThrow(); + } catch (ClassCastException success) {} + } + + + /** + * addAll(null) throws NPE + */ + public void testAddAll1() { + try { + NavigableSet q = set0(); + q.addAll(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + /** + * addAll of a collection with null elements throws NPE + */ + public void testAddAll2() { + try { + NavigableSet q = set0(); + Integer[] ints = new Integer[SIZE]; + q.addAll(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + /** + * addAll of a collection with any null elements throws NPE after + * possibly adding some elements + */ + public void testAddAll3() { + try { + NavigableSet q = set0(); + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE-1; ++i) + ints[i] = new Integer(i+SIZE); + q.addAll(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Set contains all elements of successful addAll + */ + public void testAddAll5() { + Integer[] empty = new Integer[0]; + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(SIZE-1- i); + NavigableSet q = set0(); + assertFalse(q.addAll(Arrays.asList(empty))); + assertTrue(q.addAll(Arrays.asList(ints))); + for (int i = 0; i < SIZE; ++i) + assertEquals(new Integer(i), q.pollFirst()); + } + + /** + * poll succeeds unless empty + */ + public void testPoll() { + NavigableSet q = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.pollFirst()); + } + assertNull(q.pollFirst()); + } + + /** + * remove(x) removes x and returns true if present + */ + public void testRemoveElement() { + NavigableSet q = populatedSet(SIZE); + for (int i = 1; i < SIZE; i+=2) { + assertTrue(q.remove(new Integer(i))); + } + for (int i = 0; i < SIZE; i+=2) { + assertTrue(q.remove(new Integer(i))); + assertFalse(q.remove(new Integer(i+1))); + } + assertTrue(q.isEmpty()); + } + + /** + * contains(x) reports true when elements added but not yet removed + */ + public void testContains() { + NavigableSet q = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.contains(new Integer(i))); + q.pollFirst(); + assertFalse(q.contains(new Integer(i))); + } + } + + /** + * clear removes all elements + */ + public void testClear() { + NavigableSet q = populatedSet(SIZE); + q.clear(); + assertTrue(q.isEmpty()); + assertEquals(0, q.size()); + q.add(new Integer(1)); + assertFalse(q.isEmpty()); + q.clear(); + assertTrue(q.isEmpty()); + } + + /** + * containsAll(c) is true when c contains a subset of elements + */ + public void testContainsAll() { + NavigableSet q = populatedSet(SIZE); + NavigableSet p = set0(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.containsAll(p)); + assertFalse(p.containsAll(q)); + p.add(new Integer(i)); + } + assertTrue(p.containsAll(q)); + } + + /** + * retainAll(c) retains only those elements of c and reports true if changed + */ + public void testRetainAll() { + NavigableSet q = populatedSet(SIZE); + NavigableSet p = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + boolean changed = q.retainAll(p); + if (i == 0) + assertFalse(changed); + else + assertTrue(changed); + + assertTrue(q.containsAll(p)); + assertEquals(SIZE-i, q.size()); + p.pollFirst(); + } + } + + /** + * removeAll(c) removes only those elements of c and reports true if changed + */ + public void testRemoveAll() { + for (int i = 1; i < SIZE; ++i) { + NavigableSet q = populatedSet(SIZE); + NavigableSet p = populatedSet(i); + assertTrue(q.removeAll(p)); + assertEquals(SIZE-i, q.size()); + for (int j = 0; j < i; ++j) { + Integer I = (Integer)(p.pollFirst()); + assertFalse(q.contains(I)); + } + } + } + + + + /** + * lower returns preceding element + */ + public void testLower() { + NavigableSet q = set5(); + Object e1 = q.lower(three); + assertEquals(two, e1); + + Object e2 = q.lower(six); + assertEquals(five, e2); + + Object e3 = q.lower(one); + assertNull(e3); + + Object e4 = q.lower(zero); + assertNull(e4); + } + + /** + * higher returns next element + */ + public void testHigher() { + NavigableSet q = set5(); + Object e1 = q.higher(three); + assertEquals(four, e1); + + Object e2 = q.higher(zero); + assertEquals(one, e2); + + Object e3 = q.higher(five); + assertNull(e3); + + Object e4 = q.higher(six); + assertNull(e4); + } + + /** + * floor returns preceding element + */ + public void testFloor() { + NavigableSet q = set5(); + Object e1 = q.floor(three); + assertEquals(three, e1); + + Object e2 = q.floor(six); + assertEquals(five, e2); + + Object e3 = q.floor(one); + assertEquals(one, e3); + + Object e4 = q.floor(zero); + assertNull(e4); + } + + /** + * ceiling returns next element + */ + public void testCeiling() { + NavigableSet q = set5(); + Object e1 = q.ceiling(three); + assertEquals(three, e1); + + Object e2 = q.ceiling(zero); + assertEquals(one, e2); + + Object e3 = q.ceiling(five); + assertEquals(five, e3); + + Object e4 = q.ceiling(six); + assertNull(e4); + } + + /** + * toArray contains all elements + */ + public void testToArray() { + NavigableSet q = populatedSet(SIZE); + Object[] o = q.toArray(); + Arrays.sort(o); + for (int i = 0; i < o.length; i++) + assertEquals(o[i], q.pollFirst()); + } + + /** + * toArray(a) contains all elements + */ + public void testToArray2() { + NavigableSet q = populatedSet(SIZE); + Integer[] ints = new Integer[SIZE]; + ints = (Integer[])q.toArray(ints); + Arrays.sort(ints); + for (int i = 0; i < ints.length; i++) + assertEquals(ints[i], q.pollFirst()); + } + + /** + * iterator iterates through all elements + */ + public void testIterator() { + NavigableSet q = populatedSet(SIZE); + int i = 0; + Iterator it = q.iterator(); + while (it.hasNext()) { + assertTrue(q.contains(it.next())); + ++i; + } + assertEquals(i, SIZE); + } + + /** + * iterator of empty set has no elements + */ + public void testEmptyIterator() { + NavigableSet q = set0(); + int i = 0; + Iterator it = q.iterator(); + while (it.hasNext()) { + assertTrue(q.contains(it.next())); + ++i; + } + assertEquals(i, 0); + } + + /** + * iterator.remove removes current element + */ + public void testIteratorRemove () { + final NavigableSet q = set0(); + q.add(new Integer(2)); + q.add(new Integer(1)); + q.add(new Integer(3)); + + Iterator it = q.iterator(); + it.next(); + it.remove(); + + it = q.iterator(); + assertEquals(it.next(), new Integer(2)); + assertEquals(it.next(), new Integer(3)); + assertFalse(it.hasNext()); + } + + + /** + * toString contains toStrings of elements + */ + public void testToString() { + NavigableSet q = populatedSet(SIZE); + String s = q.toString(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(s.indexOf(String.valueOf(i)) >= 0); + } + } + + /** + * A deserialized serialized set has same elements + */ + public void testSerialization() throws Exception { + NavigableSet q = populatedSet(SIZE); + ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); + ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); + out.writeObject(q); + out.close(); + + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); + NavigableSet r = (NavigableSet)in.readObject(); + assertEquals(q.size(), r.size()); + while (!q.isEmpty()) + assertEquals(q.pollFirst(), r.pollFirst()); + } + + /** + * subSet returns set with keys in requested range + */ + public void testSubSetContents() { + NavigableSet set = set5(); + SortedSet sm = set.subSet(two, four); + assertEquals(two, sm.first()); + assertEquals(three, sm.last()); + assertEquals(2, sm.size()); + assertFalse(sm.contains(one)); + assertTrue(sm.contains(two)); + assertTrue(sm.contains(three)); + assertFalse(sm.contains(four)); + assertFalse(sm.contains(five)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + assertFalse(i.hasNext()); + Iterator j = sm.iterator(); + j.next(); + j.remove(); + assertFalse(set.contains(two)); + assertEquals(4, set.size()); + assertEquals(1, sm.size()); + assertEquals(three, sm.first()); + assertEquals(three, sm.last()); + assertTrue(sm.remove(three)); + assertTrue(sm.isEmpty()); + assertEquals(3, set.size()); + } + + public void testSubSetContents2() { + NavigableSet set = set5(); + SortedSet sm = set.subSet(two, three); + assertEquals(1, sm.size()); + assertEquals(two, sm.first()); + assertEquals(two, sm.last()); + assertFalse(sm.contains(one)); + assertTrue(sm.contains(two)); + assertFalse(sm.contains(three)); + assertFalse(sm.contains(four)); + assertFalse(sm.contains(five)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + assertFalse(i.hasNext()); + Iterator j = sm.iterator(); + j.next(); + j.remove(); + assertFalse(set.contains(two)); + assertEquals(4, set.size()); + assertEquals(0, sm.size()); + assertTrue(sm.isEmpty()); + assertFalse(sm.remove(three)); + assertEquals(4, set.size()); + } + + /** + * headSet returns set with keys in requested range + */ + public void testHeadSetContents() { + NavigableSet set = set5(); + SortedSet sm = set.headSet(four); + assertTrue(sm.contains(one)); + assertTrue(sm.contains(two)); + assertTrue(sm.contains(three)); + assertFalse(sm.contains(four)); + assertFalse(sm.contains(five)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(one, k); + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + assertFalse(i.hasNext()); + sm.clear(); + assertTrue(sm.isEmpty()); + assertEquals(2, set.size()); + assertEquals(four, set.first()); + } + + /** + * tailSet returns set with keys in requested range + */ + public void testTailSetContents() { + NavigableSet set = set5(); + SortedSet sm = set.tailSet(two); + assertFalse(sm.contains(one)); + assertTrue(sm.contains(two)); + assertTrue(sm.contains(three)); + assertTrue(sm.contains(four)); + assertTrue(sm.contains(five)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + k = (Integer)(i.next()); + assertEquals(four, k); + k = (Integer)(i.next()); + assertEquals(five, k); + assertFalse(i.hasNext()); + + SortedSet ssm = sm.tailSet(four); + assertEquals(four, ssm.first()); + assertEquals(five, ssm.last()); + assertTrue(ssm.remove(four)); + assertEquals(1, ssm.size()); + assertEquals(3, sm.size()); + assertEquals(4, set.size()); + } + + /** + * size changes when elements added and removed + */ + public void testDescendingSize() { + NavigableSet q = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(SIZE-i, q.size()); + q.pollFirst(); + } + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.size()); + q.add(new Integer(i)); + } + } + + /** + * add(null) throws NPE + */ + public void testDescendingAddNull() { + try { + NavigableSet q = dset0(); + q.add(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Add of comparable element succeeds + */ + public void testDescendingAdd() { + NavigableSet q = dset0(); + assertTrue(q.add(m6)); + } + + /** + * Add of duplicate element fails + */ + public void testDescendingAddDup() { + NavigableSet q = dset0(); + assertTrue(q.add(m6)); + assertFalse(q.add(m6)); + } + + /** + * Add of non-Comparable throws CCE + */ + public void testDescendingAddNonComparable() { + try { + NavigableSet q = dset0(); + q.add(new Object()); + q.add(new Object()); + q.add(new Object()); + shouldThrow(); + } catch (ClassCastException success) {} + } + + + /** + * addAll(null) throws NPE + */ + public void testDescendingAddAll1() { + try { + NavigableSet q = dset0(); + q.addAll(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + /** + * addAll of a collection with null elements throws NPE + */ + public void testDescendingAddAll2() { + try { + NavigableSet q = dset0(); + Integer[] ints = new Integer[SIZE]; + q.addAll(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + /** + * addAll of a collection with any null elements throws NPE after + * possibly adding some elements + */ + public void testDescendingAddAll3() { + try { + NavigableSet q = dset0(); + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE-1; ++i) + ints[i] = new Integer(i+SIZE); + q.addAll(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Set contains all elements of successful addAll + */ + public void testDescendingAddAll5() { + Integer[] empty = new Integer[0]; + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(SIZE-1- i); + NavigableSet q = dset0(); + assertFalse(q.addAll(Arrays.asList(empty))); + assertTrue(q.addAll(Arrays.asList(ints))); + for (int i = 0; i < SIZE; ++i) + assertEquals(new Integer(i), q.pollFirst()); + } + + /** + * poll succeeds unless empty + */ + public void testDescendingPoll() { + NavigableSet q = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.pollFirst()); + } + assertNull(q.pollFirst()); + } + + /** + * remove(x) removes x and returns true if present + */ + public void testDescendingRemoveElement() { + NavigableSet q = populatedSet(SIZE); + for (int i = 1; i < SIZE; i+=2) { + assertTrue(q.remove(new Integer(i))); + } + for (int i = 0; i < SIZE; i+=2) { + assertTrue(q.remove(new Integer(i))); + assertFalse(q.remove(new Integer(i+1))); + } + assertTrue(q.isEmpty()); + } + + /** + * contains(x) reports true when elements added but not yet removed + */ + public void testDescendingContains() { + NavigableSet q = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.contains(new Integer(i))); + q.pollFirst(); + assertFalse(q.contains(new Integer(i))); + } + } + + /** + * clear removes all elements + */ + public void testDescendingClear() { + NavigableSet q = populatedSet(SIZE); + q.clear(); + assertTrue(q.isEmpty()); + assertEquals(0, q.size()); + q.add(new Integer(1)); + assertFalse(q.isEmpty()); + q.clear(); + assertTrue(q.isEmpty()); + } + + /** + * containsAll(c) is true when c contains a subset of elements + */ + public void testDescendingContainsAll() { + NavigableSet q = populatedSet(SIZE); + NavigableSet p = dset0(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.containsAll(p)); + assertFalse(p.containsAll(q)); + p.add(new Integer(i)); + } + assertTrue(p.containsAll(q)); + } + + /** + * retainAll(c) retains only those elements of c and reports true if changed + */ + public void testDescendingRetainAll() { + NavigableSet q = populatedSet(SIZE); + NavigableSet p = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + boolean changed = q.retainAll(p); + if (i == 0) + assertFalse(changed); + else + assertTrue(changed); + + assertTrue(q.containsAll(p)); + assertEquals(SIZE-i, q.size()); + p.pollFirst(); + } + } + + /** + * removeAll(c) removes only those elements of c and reports true if changed + */ + public void testDescendingRemoveAll() { + for (int i = 1; i < SIZE; ++i) { + NavigableSet q = populatedSet(SIZE); + NavigableSet p = populatedSet(i); + assertTrue(q.removeAll(p)); + assertEquals(SIZE-i, q.size()); + for (int j = 0; j < i; ++j) { + Integer I = (Integer)(p.pollFirst()); + assertFalse(q.contains(I)); + } + } + } + + + + /** + * lower returns preceding element + */ + public void testDescendingLower() { + NavigableSet q = dset5(); + Object e1 = q.lower(m3); + assertEquals(m2, e1); + + Object e2 = q.lower(m6); + assertEquals(m5, e2); + + Object e3 = q.lower(m1); + assertNull(e3); + + Object e4 = q.lower(zero); + assertNull(e4); + } + + /** + * higher returns next element + */ + public void testDescendingHigher() { + NavigableSet q = dset5(); + Object e1 = q.higher(m3); + assertEquals(m4, e1); + + Object e2 = q.higher(zero); + assertEquals(m1, e2); + + Object e3 = q.higher(m5); + assertNull(e3); + + Object e4 = q.higher(m6); + assertNull(e4); + } + + /** + * floor returns preceding element + */ + public void testDescendingFloor() { + NavigableSet q = dset5(); + Object e1 = q.floor(m3); + assertEquals(m3, e1); + + Object e2 = q.floor(m6); + assertEquals(m5, e2); + + Object e3 = q.floor(m1); + assertEquals(m1, e3); + + Object e4 = q.floor(zero); + assertNull(e4); + } + + /** + * ceiling returns next element + */ + public void testDescendingCeiling() { + NavigableSet q = dset5(); + Object e1 = q.ceiling(m3); + assertEquals(m3, e1); + + Object e2 = q.ceiling(zero); + assertEquals(m1, e2); + + Object e3 = q.ceiling(m5); + assertEquals(m5, e3); + + Object e4 = q.ceiling(m6); + assertNull(e4); + } + + /** + * toArray contains all elements + */ + public void testDescendingToArray() { + NavigableSet q = populatedSet(SIZE); + Object[] o = q.toArray(); + Arrays.sort(o); + for (int i = 0; i < o.length; i++) + assertEquals(o[i], q.pollFirst()); + } + + /** + * toArray(a) contains all elements + */ + public void testDescendingToArray2() { + NavigableSet q = populatedSet(SIZE); + Integer[] ints = new Integer[SIZE]; + ints = (Integer[])q.toArray(ints); + Arrays.sort(ints); + for (int i = 0; i < ints.length; i++) + assertEquals(ints[i], q.pollFirst()); + } + + /** + * iterator iterates through all elements + */ + public void testDescendingIterator() { + NavigableSet q = populatedSet(SIZE); + int i = 0; + Iterator it = q.iterator(); + while (it.hasNext()) { + assertTrue(q.contains(it.next())); + ++i; + } + assertEquals(i, SIZE); + } + + /** + * iterator of empty set has no elements + */ + public void testDescendingEmptyIterator() { + NavigableSet q = dset0(); + int i = 0; + Iterator it = q.iterator(); + while (it.hasNext()) { + assertTrue(q.contains(it.next())); + ++i; + } + assertEquals(i, 0); + } + + /** + * iterator.remove removes current element + */ + public void testDescendingIteratorRemove () { + final NavigableSet q = dset0(); + q.add(new Integer(2)); + q.add(new Integer(1)); + q.add(new Integer(3)); + + Iterator it = q.iterator(); + it.next(); + it.remove(); + + it = q.iterator(); + assertEquals(it.next(), new Integer(2)); + assertEquals(it.next(), new Integer(3)); + assertFalse(it.hasNext()); + } + + + /** + * toString contains toStrings of elements + */ + public void testDescendingToString() { + NavigableSet q = populatedSet(SIZE); + String s = q.toString(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(s.indexOf(String.valueOf(i)) >= 0); + } + } + + /** + * A deserialized serialized set has same elements + */ + public void testDescendingSerialization() throws Exception { + NavigableSet q = populatedSet(SIZE); + ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); + ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); + out.writeObject(q); + out.close(); + + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); + NavigableSet r = (NavigableSet)in.readObject(); + assertEquals(q.size(), r.size()); + while (!q.isEmpty()) + assertEquals(q.pollFirst(), r.pollFirst()); + } + + /** + * subSet returns set with keys in requested range + */ + public void testDescendingSubSetContents() { + NavigableSet set = dset5(); + SortedSet sm = set.subSet(m2, m4); + assertEquals(m2, sm.first()); + assertEquals(m3, sm.last()); + assertEquals(2, sm.size()); + assertFalse(sm.contains(m1)); + assertTrue(sm.contains(m2)); + assertTrue(sm.contains(m3)); + assertFalse(sm.contains(m4)); + assertFalse(sm.contains(m5)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(m2, k); + k = (Integer)(i.next()); + assertEquals(m3, k); + assertFalse(i.hasNext()); + Iterator j = sm.iterator(); + j.next(); + j.remove(); + assertFalse(set.contains(m2)); + assertEquals(4, set.size()); + assertEquals(1, sm.size()); + assertEquals(m3, sm.first()); + assertEquals(m3, sm.last()); + assertTrue(sm.remove(m3)); + assertTrue(sm.isEmpty()); + assertEquals(3, set.size()); + } + + public void testDescendingSubSetContents2() { + NavigableSet set = dset5(); + SortedSet sm = set.subSet(m2, m3); + assertEquals(1, sm.size()); + assertEquals(m2, sm.first()); + assertEquals(m2, sm.last()); + assertFalse(sm.contains(m1)); + assertTrue(sm.contains(m2)); + assertFalse(sm.contains(m3)); + assertFalse(sm.contains(m4)); + assertFalse(sm.contains(m5)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(m2, k); + assertFalse(i.hasNext()); + Iterator j = sm.iterator(); + j.next(); + j.remove(); + assertFalse(set.contains(m2)); + assertEquals(4, set.size()); + assertEquals(0, sm.size()); + assertTrue(sm.isEmpty()); + assertFalse(sm.remove(m3)); + assertEquals(4, set.size()); + } + + /** + * headSet returns set with keys in requested range + */ + public void testDescendingHeadSetContents() { + NavigableSet set = dset5(); + SortedSet sm = set.headSet(m4); + assertTrue(sm.contains(m1)); + assertTrue(sm.contains(m2)); + assertTrue(sm.contains(m3)); + assertFalse(sm.contains(m4)); + assertFalse(sm.contains(m5)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(m1, k); + k = (Integer)(i.next()); + assertEquals(m2, k); + k = (Integer)(i.next()); + assertEquals(m3, k); + assertFalse(i.hasNext()); + sm.clear(); + assertTrue(sm.isEmpty()); + assertEquals(2, set.size()); + assertEquals(m4, set.first()); + } + + /** + * tailSet returns set with keys in requested range + */ + public void testDescendingTailSetContents() { + NavigableSet set = dset5(); + SortedSet sm = set.tailSet(m2); + assertFalse(sm.contains(m1)); + assertTrue(sm.contains(m2)); + assertTrue(sm.contains(m3)); + assertTrue(sm.contains(m4)); + assertTrue(sm.contains(m5)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(m2, k); + k = (Integer)(i.next()); + assertEquals(m3, k); + k = (Integer)(i.next()); + assertEquals(m4, k); + k = (Integer)(i.next()); + assertEquals(m5, k); + assertFalse(i.hasNext()); + + SortedSet ssm = sm.tailSet(m4); + assertEquals(m4, ssm.first()); + assertEquals(m5, ssm.last()); + assertTrue(ssm.remove(m4)); + assertEquals(1, ssm.size()); + assertEquals(3, sm.size()); + assertEquals(4, set.size()); + } + +} diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/CopyOnWriteArrayListTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/CopyOnWriteArrayListTest.java index 53a1f70..90d708a 100755 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/CopyOnWriteArrayListTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/CopyOnWriteArrayListTest.java @@ -2,26 +2,26 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.*; import java.util.concurrent.*; import java.io.*; -public class CopyOnWriteArrayListTest extends JSR166TestCase{ +public class CopyOnWriteArrayListTest extends JSR166TestCase { public static Test suite() { return new TestSuite(CopyOnWriteArrayListTest.class); } - static CopyOnWriteArrayList populatedArray(int n){ + static CopyOnWriteArrayList populatedArray(int n) { CopyOnWriteArrayList a = new CopyOnWriteArrayList(); assertTrue(a.isEmpty()); - for (int i = 0; i < n; ++i) + for (int i = 0; i < n; ++i) a.add(new Integer(i)); assertFalse(a.isEmpty()); assertEquals(n, a.size()); @@ -45,7 +45,7 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase{ for (int i = 0; i < SIZE-1; ++i) ints[i] = new Integer(i); CopyOnWriteArrayList a = new CopyOnWriteArrayList(ints); - for (int i = 0; i < SIZE; ++i) + for (int i = 0; i < SIZE; ++i) assertEquals(ints[i], a.get(i)); } @@ -57,10 +57,10 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase{ for (int i = 0; i < SIZE-1; ++i) ints[i] = new Integer(i); CopyOnWriteArrayList a = new CopyOnWriteArrayList(Arrays.asList(ints)); - for (int i = 0; i < SIZE; ++i) + for (int i = 0; i < SIZE; ++i) assertEquals(ints[i], a.get(i)); } - + /** * addAll adds each element from the given collection @@ -171,7 +171,7 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase{ assertEquals(a.hashCode(), b.hashCode()); } - + /** * containsAll returns true for collection with subset of elements */ @@ -186,11 +186,11 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase{ } /** - * get returns the value at the given index + * get returns the value at the given index */ public void testGet() { CopyOnWriteArrayList full = populatedArray(3); - assertEquals(0, ((Integer)full.get(0)).intValue()); + assertEquals(0, full.get(0)); } /** @@ -223,14 +223,14 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase{ } /** - * iterator() returns an iterator containing the elements of the list + * iterator() returns an iterator containing the elements of the list */ public void testIterator() { CopyOnWriteArrayList full = populatedArray(SIZE); Iterator i = full.iterator(); int j; - for(j = 0; i.hasNext(); j++) - assertEquals(j, ((Integer)i.next()).intValue()); + for (j = 0; i.hasNext(); j++) + assertEquals(j, i.next()); assertEquals(SIZE, j); } @@ -244,8 +244,7 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase{ try { it.remove(); shouldThrow(); - } - catch (UnsupportedOperationException success) {} + } catch (UnsupportedOperationException success) {} } /** @@ -257,7 +256,7 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase{ for (int i = 0; i < 3; ++i) { assertTrue(s.indexOf(String.valueOf(i)) >= 0); } - } + } /** * lastIndexOf returns the index for the given object @@ -288,8 +287,8 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase{ CopyOnWriteArrayList full = populatedArray(SIZE); ListIterator i = full.listIterator(); int j; - for(j = 0; i.hasNext(); j++) - assertEquals(j, ((Integer)i.next()).intValue()); + for (j = 0; i.hasNext(); j++) + assertEquals(j, i.next()); assertEquals(SIZE, j); } @@ -300,8 +299,8 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase{ CopyOnWriteArrayList full = populatedArray(3); ListIterator i = full.listIterator(1); int j; - for(j = 0; i.hasNext(); j++) - assertEquals(j+1, ((Integer)i.next()).intValue()); + for (j = 0; i.hasNext(); j++) + assertEquals(j+1, i.next()); assertEquals(2, j); } @@ -310,7 +309,7 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase{ */ public void testRemove() { CopyOnWriteArrayList full = populatedArray(3); - assertEquals(two, full.remove(2)); + assertEquals(2, full.remove(2)); assertEquals(2, full.size()); } @@ -331,8 +330,8 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase{ */ public void testSet() { CopyOnWriteArrayList full = populatedArray(3); - assertEquals(two, full.set(2, four)); - assertEquals(4, ((Integer)full.get(2)).intValue()); + assertEquals(2, full.set(2, four)); + assertEquals(4, full.get(2)); } /** @@ -352,9 +351,9 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase{ CopyOnWriteArrayList full = populatedArray(3); Object[] o = full.toArray(); assertEquals(3, o.length); - assertEquals(0, ((Integer)o[0]).intValue()); - assertEquals(1, ((Integer)o[1]).intValue()); - assertEquals(2, ((Integer)o[2]).intValue()); + assertEquals(0, o[0]); + assertEquals(1, o[1]); + assertEquals(2, o[2]); } /** @@ -378,10 +377,10 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase{ public void testSubList() { CopyOnWriteArrayList a = populatedArray(10); assertTrue(a.subList(1,1).isEmpty()); - for(int j = 0; j < 9; ++j) { - for(int i = j ; i < 10; ++i) { + for (int j = 0; j < 9; ++j) { + for (int i = j ; i < 10; ++i) { List b = a.subList(j,i); - for(int k = j; k < i; ++k) { + for (int k = j; k < i; ++k) { assertEquals(new Integer(k), b.get(k-j)); } } @@ -408,7 +407,7 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase{ c.add("asdadasd"); c.toArray(new Long[5]); shouldThrow(); - } catch(ArrayStoreException e){} + } catch (ArrayStoreException success) {} } /** @@ -419,9 +418,9 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase{ CopyOnWriteArrayList c = new CopyOnWriteArrayList(); c.get(-1); shouldThrow(); - } catch(IndexOutOfBoundsException e){} + } catch (IndexOutOfBoundsException success) {} } - + /** * get throws an IndexOutOfBoundsException on a too high index */ @@ -432,7 +431,7 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase{ c.add("asdad"); c.get(100); shouldThrow(); - } catch(IndexOutOfBoundsException e){} + } catch (IndexOutOfBoundsException success) {} } /** @@ -443,9 +442,9 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase{ CopyOnWriteArrayList c = new CopyOnWriteArrayList(); c.set(-1,"qwerty"); shouldThrow(); - } catch(IndexOutOfBoundsException e){} + } catch (IndexOutOfBoundsException success) {} } - + /** * set throws an IndexOutOfBoundsException on a too high index */ @@ -456,7 +455,7 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase{ c.add("asdad"); c.set(100, "qwerty"); shouldThrow(); - } catch(IndexOutOfBoundsException e){} + } catch (IndexOutOfBoundsException success) {} } /** @@ -467,9 +466,9 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase{ CopyOnWriteArrayList c = new CopyOnWriteArrayList(); c.add(-1,"qwerty"); shouldThrow(); - } catch(IndexOutOfBoundsException e){} + } catch (IndexOutOfBoundsException success) {} } - + /** * add throws an IndexOutOfBoundsException on a too high index */ @@ -480,7 +479,7 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase{ c.add("asdasdasd"); c.add(100, "qwerty"); shouldThrow(); - } catch(IndexOutOfBoundsException e){} + } catch (IndexOutOfBoundsException success) {} } /** @@ -491,7 +490,7 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase{ CopyOnWriteArrayList c = new CopyOnWriteArrayList(); c.remove(-1); shouldThrow(); - } catch(IndexOutOfBoundsException e){} + } catch (IndexOutOfBoundsException success) {} } /** @@ -504,9 +503,9 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase{ c.add("adasdasd"); c.remove(100); shouldThrow(); - } catch(IndexOutOfBoundsException e){} + } catch (IndexOutOfBoundsException success) {} } - + /** * addAll throws an IndexOutOfBoundsException on a negative index */ @@ -515,9 +514,9 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase{ CopyOnWriteArrayList c = new CopyOnWriteArrayList(); c.addAll(-1,new LinkedList()); shouldThrow(); - } catch(IndexOutOfBoundsException e){} + } catch (IndexOutOfBoundsException success) {} } - + /** * addAll throws an IndexOutOfBoundsException on a too high index */ @@ -528,7 +527,7 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase{ c.add("asdasdasd"); c.addAll(100, new LinkedList()); shouldThrow(); - } catch(IndexOutOfBoundsException e){} + } catch (IndexOutOfBoundsException success) {} } /** @@ -539,7 +538,7 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase{ CopyOnWriteArrayList c = new CopyOnWriteArrayList(); c.listIterator(-1); shouldThrow(); - } catch(IndexOutOfBoundsException e){} + } catch (IndexOutOfBoundsException success) {} } /** @@ -552,7 +551,7 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase{ c.add("asdasdas"); c.listIterator(100); shouldThrow(); - } catch(IndexOutOfBoundsException e){} + } catch (IndexOutOfBoundsException success) {} } /** @@ -562,9 +561,8 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase{ try { CopyOnWriteArrayList c = new CopyOnWriteArrayList(); c.subList(-1,100); - shouldThrow(); - } catch(IndexOutOfBoundsException e){} + } catch (IndexOutOfBoundsException success) {} } /** @@ -576,43 +574,38 @@ public class CopyOnWriteArrayListTest extends JSR166TestCase{ c.add("asdasd"); c.subList(1,100); shouldThrow(); - } catch(IndexOutOfBoundsException e){} + } catch (IndexOutOfBoundsException success) {} } /** * subList throws IndexOutOfBoundsException when the second index - * is lower then the first + * is lower then the first */ public void testSubList3_IndexOutOfBoundsException() { try { CopyOnWriteArrayList c = new CopyOnWriteArrayList(); c.subList(3,1); - shouldThrow(); - } catch(IndexOutOfBoundsException e){} + } catch (IndexOutOfBoundsException success) {} } /** - * a deserialized serialiszed list is equal + * a deserialized serialized list is equal */ - public void testSerialization() { + public void testSerialization() throws Exception { CopyOnWriteArrayList q = populatedArray(SIZE); - try { - ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); - ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); - out.writeObject(q); - out.close(); - - ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); - ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); - CopyOnWriteArrayList r = (CopyOnWriteArrayList)in.readObject(); - assertEquals(q.size(), r.size()); - assertTrue(q.equals(r)); - assertTrue(r.equals(q)); - } catch(Exception e){ - unexpectedException(); - } + ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); + ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); + out.writeObject(q); + out.close(); + + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); + CopyOnWriteArrayList r = (CopyOnWriteArrayList)in.readObject(); + assertEquals(q.size(), r.size()); + assertTrue(q.equals(r)); + assertTrue(r.equals(q)); } - + } diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/CopyOnWriteArraySetTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/CopyOnWriteArraySetTest.java index abb33fa..c78ac50 100755 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/CopyOnWriteArraySetTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/CopyOnWriteArraySetTest.java @@ -2,11 +2,11 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.*; @@ -18,10 +18,10 @@ public class CopyOnWriteArraySetTest extends JSR166TestCase { return new TestSuite(CopyOnWriteArraySetTest.class); } - static CopyOnWriteArraySet populatedSet(int n){ + static CopyOnWriteArraySet populatedSet(int n) { CopyOnWriteArraySet a = new CopyOnWriteArraySet(); assertTrue(a.isEmpty()); - for (int i = 0; i < n; ++i) + for (int i = 0; i < n; ++i) a.add(new Integer(i)); assertFalse(a.isEmpty()); assertEquals(n, a.size()); @@ -44,13 +44,13 @@ public class CopyOnWriteArraySetTest extends JSR166TestCase { for (int i = 0; i < SIZE-1; ++i) ints[i] = new Integer(i); CopyOnWriteArraySet a = new CopyOnWriteArraySet(Arrays.asList(ints)); - for (int i = 0; i < SIZE; ++i) + for (int i = 0; i < SIZE; ++i) assertTrue(a.contains(ints[i])); } - + /** - * addAll adds each element from the given collection + * addAll adds each element from the given collection */ public void testAddAll() { CopyOnWriteArraySet full = populatedSet(3); @@ -63,7 +63,7 @@ public class CopyOnWriteArraySetTest extends JSR166TestCase { } /** - * addAll adds each element from the given collection that did not + * addAll adds each element from the given collection that did not * already exist in the set */ public void testAddAll2() { @@ -77,7 +77,7 @@ public class CopyOnWriteArraySetTest extends JSR166TestCase { } /** - * add will not add the element if it already exists in the set + * add will not add the element if it already exists in the set */ public void testAdd2() { CopyOnWriteArraySet full = populatedSet(3); @@ -86,8 +86,8 @@ public class CopyOnWriteArraySetTest extends JSR166TestCase { } /** - * add adds the element when it does not exist - * in the set + * add adds the element when it does not exist + * in the set */ public void testAdd3() { CopyOnWriteArraySet full = populatedSet(3); @@ -96,7 +96,7 @@ public class CopyOnWriteArraySetTest extends JSR166TestCase { } /** - * clear removes all elements from the set + * clear removes all elements from the set */ public void testClear() { CopyOnWriteArraySet full = populatedSet(3); @@ -131,9 +131,9 @@ public class CopyOnWriteArraySetTest extends JSR166TestCase { assertEquals(a.hashCode(), b.hashCode()); } - + /** - * containsAll returns true for collections with subset of elements + * containsAll returns true for collections with subset of elements */ public void testContainsAll() { CopyOnWriteArraySet full = populatedSet(3); @@ -146,7 +146,7 @@ public class CopyOnWriteArraySetTest extends JSR166TestCase { } /** - * isEmpty is true when empty, else false + * isEmpty is true when empty, else false */ public void testIsEmpty() { CopyOnWriteArraySet empty = new CopyOnWriteArraySet(); @@ -156,14 +156,14 @@ public class CopyOnWriteArraySetTest extends JSR166TestCase { } /** - * iterator() returns an iterator containing the elements of the set + * iterator() returns an iterator containing the elements of the set */ public void testIterator() { CopyOnWriteArraySet full = populatedSet(3); Iterator i = full.iterator(); int j; - for(j = 0; i.hasNext(); j++) - assertEquals(j, ((Integer)i.next()).intValue()); + for (j = 0; i.hasNext(); j++) + assertEquals(j, i.next()); assertEquals(3, j); } @@ -177,8 +177,7 @@ public class CopyOnWriteArraySetTest extends JSR166TestCase { try { it.remove(); shouldThrow(); - } - catch (UnsupportedOperationException success) {} + } catch (UnsupportedOperationException success) {} } /** @@ -190,11 +189,11 @@ public class CopyOnWriteArraySetTest extends JSR166TestCase { for (int i = 0; i < 3; ++i) { assertTrue(s.indexOf(String.valueOf(i)) >= 0); } - } + } /** - * removeAll removes all elements from the given collection + * removeAll removes all elements from the given collection */ public void testRemoveAll() { CopyOnWriteArraySet full = populatedSet(3); @@ -217,7 +216,7 @@ public class CopyOnWriteArraySetTest extends JSR166TestCase { } /** - * size returns the number of elements + * size returns the number of elements */ public void testSize() { CopyOnWriteArraySet empty = new CopyOnWriteArraySet(); @@ -227,29 +226,29 @@ public class CopyOnWriteArraySetTest extends JSR166TestCase { } /** - * toArray returns an Object array containing all elements from the set + * toArray returns an Object array containing all elements from the set */ public void testToArray() { CopyOnWriteArraySet full = populatedSet(3); Object[] o = full.toArray(); assertEquals(3, o.length); - assertEquals(0, ((Integer)o[0]).intValue()); - assertEquals(1, ((Integer)o[1]).intValue()); - assertEquals(2, ((Integer)o[2]).intValue()); + assertEquals(0, o[0]); + assertEquals(1, o[1]); + assertEquals(2, o[2]); } /** - * toArray returns an Integer array containing all elements from - * the set + * toArray returns an Integer array containing all elements from + * the set */ public void testToArray2() { CopyOnWriteArraySet full = populatedSet(3); Integer[] i = new Integer[3]; i = (Integer[])full.toArray(i); assertEquals(3, i.length); - assertEquals(0, i[0].intValue()); - assertEquals(1, i[1].intValue()); - assertEquals(2, i[2].intValue()); + assertEquals(0, (int) i[0]); + assertEquals(1, (int) i[1]); + assertEquals(2, (int) i[2]); } @@ -264,30 +263,26 @@ public class CopyOnWriteArraySetTest extends JSR166TestCase { c.add("asdadasd"); c.toArray(new Long[5]); shouldThrow(); - } catch(ArrayStoreException e){} + } catch (ArrayStoreException success) {} } /** * A deserialized serialized set is equal */ - public void testSerialization() { + public void testSerialization() throws Exception { CopyOnWriteArraySet q = populatedSet(SIZE); - try { - ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); - ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); - out.writeObject(q); - out.close(); - - ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); - ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); - CopyOnWriteArraySet r = (CopyOnWriteArraySet)in.readObject(); - assertEquals(q.size(), r.size()); - assertTrue(q.equals(r)); - assertTrue(r.equals(q)); - } catch(Exception e){ - unexpectedException(); - } + ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); + ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); + out.writeObject(q); + out.close(); + + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); + CopyOnWriteArraySet r = (CopyOnWriteArraySet)in.readObject(); + assertEquals(q.size(), r.size()); + assertTrue(q.equals(r)); + assertTrue(r.equals(q)); } } diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/CountDownLatchTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/CountDownLatchTest.java index 179c81e..b06004e 100755 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/CountDownLatchTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/CountDownLatchTest.java @@ -2,15 +2,16 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.*; import java.util.concurrent.*; +import static java.util.concurrent.TimeUnit.MILLISECONDS; public class CountDownLatchTest extends JSR166TestCase { public static Test suite() { @@ -24,7 +25,7 @@ public class CountDownLatchTest extends JSR166TestCase { try { new CountDownLatch(-1); shouldThrow(); - } catch(IllegalArgumentException success){} + } catch (IllegalArgumentException success) {} } /** @@ -52,137 +53,99 @@ public class CountDownLatchTest extends JSR166TestCase { /** * await returns after countDown to zero, but not before */ - public void testAwait() { + public void testAwait() throws InterruptedException { final CountDownLatch l = new CountDownLatch(2); - Thread t = new Thread(new Runnable() { - public void run() { - try { - threadAssertTrue(l.getCount() > 0); - l.await(); - threadAssertTrue(l.getCount() == 0); - } catch(InterruptedException e){ - threadUnexpectedException(); - } - } - }); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadAssertTrue(l.getCount() > 0); + l.await(); + threadAssertTrue(l.getCount() == 0); + }}); + t.start(); - try { - assertEquals(l.getCount(), 2); - Thread.sleep(SHORT_DELAY_MS); - l.countDown(); - assertEquals(l.getCount(), 1); - l.countDown(); - assertEquals(l.getCount(), 0); - t.join(); - } catch (InterruptedException e){ - unexpectedException(); - } + assertEquals(l.getCount(), 2); + Thread.sleep(SHORT_DELAY_MS); + l.countDown(); + assertEquals(l.getCount(), 1); + l.countDown(); + assertEquals(l.getCount(), 0); + t.join(); } - + /** * timed await returns after countDown to zero */ - public void testTimedAwait() { + public void testTimedAwait() throws InterruptedException { final CountDownLatch l = new CountDownLatch(2); - Thread t = new Thread(new Runnable() { - public void run() { - try { - threadAssertTrue(l.getCount() > 0); - threadAssertTrue(l.await(SMALL_DELAY_MS, TimeUnit.MILLISECONDS)); - } catch(InterruptedException e){ - threadUnexpectedException(); - } - } - }); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadAssertTrue(l.getCount() > 0); + threadAssertTrue(l.await(SMALL_DELAY_MS, MILLISECONDS)); + }}); + t.start(); - try { - assertEquals(l.getCount(), 2); - Thread.sleep(SHORT_DELAY_MS); - l.countDown(); - assertEquals(l.getCount(), 1); - l.countDown(); - assertEquals(l.getCount(), 0); - t.join(); - } catch (InterruptedException e){ - unexpectedException(); - } + assertEquals(l.getCount(), 2); + Thread.sleep(SHORT_DELAY_MS); + l.countDown(); + assertEquals(l.getCount(), 1); + l.countDown(); + assertEquals(l.getCount(), 0); + t.join(); } - + /** * await throws IE if interrupted before counted down */ - public void testAwait_InterruptedException() { + public void testAwait_InterruptedException() throws InterruptedException { final CountDownLatch l = new CountDownLatch(1); - Thread t = new Thread(new Runnable() { - public void run() { - try { - threadAssertTrue(l.getCount() > 0); - l.await(); - threadShouldThrow(); - } catch(InterruptedException success){} - } - }); + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + threadAssertTrue(l.getCount() > 0); + l.await(); + }}); + t.start(); - try { - assertEquals(l.getCount(), 1); - t.interrupt(); - t.join(); - } catch (InterruptedException e){ - unexpectedException(); - } + assertEquals(l.getCount(), 1); + t.interrupt(); + t.join(); } /** * timed await throws IE if interrupted before counted down */ - public void testTimedAwait_InterruptedException() { + public void testTimedAwait_InterruptedException() throws InterruptedException { final CountDownLatch l = new CountDownLatch(1); - Thread t = new Thread(new Runnable() { - public void run() { - try { - threadAssertTrue(l.getCount() > 0); - l.await(MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); - threadShouldThrow(); - } catch(InterruptedException success){} - } - }); + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + threadAssertTrue(l.getCount() > 0); + l.await(MEDIUM_DELAY_MS, MILLISECONDS); + }}); + t.start(); - try { - Thread.sleep(SHORT_DELAY_MS); - assertEquals(l.getCount(), 1); - t.interrupt(); - t.join(); - } catch (InterruptedException e){ - unexpectedException(); - } + Thread.sleep(SHORT_DELAY_MS); + assertEquals(l.getCount(), 1); + t.interrupt(); + t.join(); } /** * timed await times out if not counted down before timeout */ - public void testAwaitTimeout() { + public void testAwaitTimeout() throws InterruptedException { final CountDownLatch l = new CountDownLatch(1); - Thread t = new Thread(new Runnable() { - public void run() { - try { - threadAssertTrue(l.getCount() > 0); - threadAssertFalse(l.await(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - threadAssertTrue(l.getCount() > 0); - } catch(InterruptedException ie){ - threadUnexpectedException(); - } - } - }); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadAssertTrue(l.getCount() > 0); + threadAssertFalse(l.await(SHORT_DELAY_MS, MILLISECONDS)); + threadAssertTrue(l.getCount() > 0); + }}); + t.start(); - try { - assertEquals(l.getCount(), 1); - t.join(); - } catch (InterruptedException e){ - unexpectedException(); - } + assertEquals(l.getCount(), 1); + t.join(); } /** diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/CyclicBarrierTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/CyclicBarrierTest.java index 3b99ef8..b8f8b24 100755 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/CyclicBarrierTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/CyclicBarrierTest.java @@ -2,19 +2,20 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.locks.*; import java.util.concurrent.atomic.*; +import static java.util.concurrent.TimeUnit.MILLISECONDS; -public class CyclicBarrierTest extends JSR166TestCase{ +public class CyclicBarrierTest extends JSR166TestCase { public static Test suite() { return new TestSuite(CyclicBarrierTest.class); } @@ -23,7 +24,7 @@ public class CyclicBarrierTest extends JSR166TestCase{ private class MyAction implements Runnable { public void run() { ++countAction; } } - + /** * Creating with negative parties throws IAE */ @@ -31,7 +32,7 @@ public class CyclicBarrierTest extends JSR166TestCase{ try { new CyclicBarrier(-1, (Runnable)null); shouldThrow(); - } catch(IllegalArgumentException e){} + } catch (IllegalArgumentException success) {} } /** @@ -41,7 +42,7 @@ public class CyclicBarrierTest extends JSR166TestCase{ try { new CyclicBarrier(-1); shouldThrow(); - } catch(IllegalArgumentException e){} + } catch (IllegalArgumentException success) {} } /** @@ -56,65 +57,48 @@ public class CyclicBarrierTest extends JSR166TestCase{ /** * A 1-party barrier triggers after single await */ - public void testSingleParty() { - try { - CyclicBarrier b = new CyclicBarrier(1); - assertEquals(1, b.getParties()); - assertEquals(0, b.getNumberWaiting()); - b.await(); - b.await(); - assertEquals(0, b.getNumberWaiting()); - } - catch(Exception e) { - unexpectedException(); - } + public void testSingleParty() throws Exception { + CyclicBarrier b = new CyclicBarrier(1); + assertEquals(1, b.getParties()); + assertEquals(0, b.getNumberWaiting()); + b.await(); + b.await(); + assertEquals(0, b.getNumberWaiting()); } - + /** * The supplied barrier action is run at barrier */ - public void testBarrierAction() { - try { - countAction = 0; - CyclicBarrier b = new CyclicBarrier(1, new MyAction()); - assertEquals(1, b.getParties()); - assertEquals(0, b.getNumberWaiting()); - b.await(); - b.await(); - assertEquals(0, b.getNumberWaiting()); - assertEquals(countAction, 2); - } - catch(Exception e) { - unexpectedException(); - } + public void testBarrierAction() throws Exception { + countAction = 0; + CyclicBarrier b = new CyclicBarrier(1, new MyAction()); + assertEquals(1, b.getParties()); + assertEquals(0, b.getNumberWaiting()); + b.await(); + b.await(); + assertEquals(0, b.getNumberWaiting()); + assertEquals(countAction, 2); } /** * A 2-party/thread barrier triggers after both threads invoke await */ - public void testTwoParties() { + public void testTwoParties() throws Exception { final CyclicBarrier b = new CyclicBarrier(2); - Thread t = new Thread(new Runnable() { - public void run() { - try { - b.await(); - b.await(); - b.await(); - b.await(); - } catch(Exception e){ - threadUnexpectedException(); - }}}); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws Exception { + b.await(); + b.await(); + b.await(); + b.await(); + }}); - try { - t.start(); - b.await(); - b.await(); - b.await(); - b.await(); - t.join(); - } catch(Exception e){ - unexpectedException(); - } + t.start(); + b.await(); + b.await(); + b.await(); + b.await(); + t.join(); } @@ -122,502 +106,320 @@ public class CyclicBarrierTest extends JSR166TestCase{ * An interruption in one party causes others waiting in await to * throw BrokenBarrierException */ - public void testAwait1_Interrupted_BrokenBarrier() { + public void testAwait1_Interrupted_BrokenBarrier() throws Exception { final CyclicBarrier c = new CyclicBarrier(3); - Thread t1 = new Thread(new Runnable() { - public void run() { - try { - c.await(); - threadShouldThrow(); - } catch(InterruptedException success){} - catch(Exception b){ - threadUnexpectedException(); - } - } - }); - Thread t2 = new Thread(new Runnable() { - public void run() { - try { - c.await(); - threadShouldThrow(); - } catch(BrokenBarrierException success){ - } catch(Exception i){ - threadUnexpectedException(); - } - } - }); - try { - t1.start(); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - t1.interrupt(); - t1.join(); - t2.join(); - } catch(InterruptedException e){ - unexpectedException(); - } + Thread t1 = new ThreadShouldThrow(InterruptedException.class) { + public void realRun() throws Exception { + c.await(); + }}; + Thread t2 = new ThreadShouldThrow(BrokenBarrierException.class) { + public void realRun() throws Exception { + c.await(); + }}; + + t1.start(); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + t1.interrupt(); + t1.join(); + t2.join(); } /** * An interruption in one party causes others waiting in timed await to * throw BrokenBarrierException */ - public void testAwait2_Interrupted_BrokenBarrier() { + public void testAwait2_Interrupted_BrokenBarrier() throws Exception { final CyclicBarrier c = new CyclicBarrier(3); - Thread t1 = new Thread(new Runnable() { - public void run() { - try { - c.await(LONG_DELAY_MS, TimeUnit.MILLISECONDS); - threadShouldThrow(); - } catch(InterruptedException success){ - } catch(Exception b){ - threadUnexpectedException(); - } - } - }); - Thread t2 = new Thread(new Runnable() { - public void run() { - try { - c.await(LONG_DELAY_MS, TimeUnit.MILLISECONDS); - threadShouldThrow(); - } catch(BrokenBarrierException success){ - } catch(Exception i){ - threadUnexpectedException(); - } - } - }); - try { - t1.start(); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - t1.interrupt(); - t1.join(); - t2.join(); - } catch(InterruptedException e){ - unexpectedException(); - } + Thread t1 = new ThreadShouldThrow(InterruptedException.class) { + public void realRun() throws Exception { + c.await(LONG_DELAY_MS, MILLISECONDS); + }}; + Thread t2 = new ThreadShouldThrow(BrokenBarrierException.class) { + public void realRun() throws Exception { + c.await(LONG_DELAY_MS, MILLISECONDS); + }}; + + t1.start(); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + t1.interrupt(); + t1.join(); + t2.join(); } - + /** * A timeout in timed await throws TimeoutException */ - public void testAwait3_TimeOutException() { + public void testAwait3_TimeOutException() throws InterruptedException { final CyclicBarrier c = new CyclicBarrier(2); - Thread t = new Thread(new Runnable() { - public void run() { - try { - c.await(SHORT_DELAY_MS, TimeUnit.MILLISECONDS); - threadShouldThrow(); - } catch(TimeoutException success){ - } catch(Exception b){ - threadUnexpectedException(); - - } - } - }); - try { - t.start(); - t.join(); - } catch(InterruptedException e){ - unexpectedException(); - } + Thread t = new ThreadShouldThrow(TimeoutException.class) { + public void realRun() throws Exception { + c.await(SHORT_DELAY_MS, MILLISECONDS); + }}; + + t.start(); + t.join(); } /** * A timeout in one party causes others waiting in timed await to * throw BrokenBarrierException */ - public void testAwait4_Timeout_BrokenBarrier() { + public void testAwait4_Timeout_BrokenBarrier() throws InterruptedException { final CyclicBarrier c = new CyclicBarrier(3); - Thread t1 = new Thread(new Runnable() { - public void run() { - try { - c.await(SHORT_DELAY_MS, TimeUnit.MILLISECONDS); - threadShouldThrow(); - } catch(TimeoutException success){ - } catch(Exception b){ - threadUnexpectedException(); - } - } - }); - Thread t2 = new Thread(new Runnable() { - public void run() { - try { - c.await(MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); - threadShouldThrow(); - } catch(BrokenBarrierException success){ - } catch(Exception i){ - threadUnexpectedException(); - } - } - }); - try { - t1.start(); - t2.start(); - t1.join(); - t2.join(); - } catch(InterruptedException e){ - unexpectedException(); - } + Thread t1 = new ThreadShouldThrow(TimeoutException.class) { + public void realRun() throws Exception { + c.await(SHORT_DELAY_MS, MILLISECONDS); + }}; + Thread t2 = new ThreadShouldThrow(BrokenBarrierException.class) { + public void realRun() throws Exception { + c.await(MEDIUM_DELAY_MS, MILLISECONDS); + }}; + + t1.start(); + t2.start(); + t1.join(); + t2.join(); } /** * A timeout in one party causes others waiting in await to * throw BrokenBarrierException */ - public void testAwait5_Timeout_BrokenBarrier() { + public void testAwait5_Timeout_BrokenBarrier() throws InterruptedException { final CyclicBarrier c = new CyclicBarrier(3); - Thread t1 = new Thread(new Runnable() { - public void run() { - try { - c.await(SHORT_DELAY_MS, TimeUnit.MILLISECONDS); - threadShouldThrow(); - } catch(TimeoutException success){ - } catch(Exception b){ - threadUnexpectedException(); - } - } - }); - Thread t2 = new Thread(new Runnable() { - public void run() { - try { - c.await(); - threadShouldThrow(); - } catch(BrokenBarrierException success){ - } catch(Exception i){ - threadUnexpectedException(); - } - } - }); - try { - t1.start(); - t2.start(); - t1.join(); - t2.join(); - } catch(InterruptedException e){ - unexpectedException(); - } + Thread t1 = new ThreadShouldThrow(TimeoutException.class) { + public void realRun() throws Exception { + c.await(SHORT_DELAY_MS, MILLISECONDS); + }}; + Thread t2 = new ThreadShouldThrow(BrokenBarrierException.class) { + public void realRun() throws Exception { + c.await(); + }}; + + t1.start(); + t2.start(); + t1.join(); + t2.join(); } - + /** * A reset of an active barrier causes waiting threads to throw * BrokenBarrierException */ - public void testReset_BrokenBarrier() { + public void testReset_BrokenBarrier() throws InterruptedException { final CyclicBarrier c = new CyclicBarrier(3); - Thread t1 = new Thread(new Runnable() { - public void run() { - try { - c.await(); - threadShouldThrow(); - } catch(BrokenBarrierException success){} - catch(Exception b){ - threadUnexpectedException(); - } - } - }); - Thread t2 = new Thread(new Runnable() { - public void run() { - try { - c.await(); - threadShouldThrow(); - } catch(BrokenBarrierException success){ - } catch(Exception i){ - threadUnexpectedException(); - } - } - }); - try { - t1.start(); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - c.reset(); - t1.join(); - t2.join(); - } catch(InterruptedException e){ - unexpectedException(); - } + Thread t1 = new ThreadShouldThrow(BrokenBarrierException.class) { + public void realRun() throws Exception { + c.await(); + }}; + Thread t2 = new ThreadShouldThrow(BrokenBarrierException.class) { + public void realRun() throws Exception { + c.await(); + }}; + + t1.start(); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + c.reset(); + t1.join(); + t2.join(); } /** * A reset before threads enter barrier does not throw * BrokenBarrierException */ - public void testReset_NoBrokenBarrier() { + public void testReset_NoBrokenBarrier() throws Exception { final CyclicBarrier c = new CyclicBarrier(3); - Thread t1 = new Thread(new Runnable() { - public void run() { - try { - c.await(); - } catch(Exception b){ - threadUnexpectedException(); - } - } - }); - Thread t2 = new Thread(new Runnable() { - public void run() { - try { - c.await(); - } catch(Exception i){ - threadUnexpectedException(); - } - } - }); - try { - c.reset(); - t1.start(); - t2.start(); - c.await(); - t1.join(); - t2.join(); - } catch(Exception e){ - unexpectedException(); - } + Thread t1 = new Thread(new CheckedRunnable() { + public void realRun() throws Exception { + c.await(); + }}); + Thread t2 = new Thread(new CheckedRunnable() { + public void realRun() throws Exception { + c.await(); + }}); + + c.reset(); + t1.start(); + t2.start(); + c.await(); + t1.join(); + t2.join(); } /** * All threads block while a barrier is broken. */ - public void testReset_Leakage() { - try { - final CyclicBarrier c = new CyclicBarrier(2); - final AtomicBoolean done = new AtomicBoolean(); - Thread t = new Thread() { - public void run() { - while (!done.get()) { - try { - while (c.isBroken()) - c.reset(); - - c.await(); - threadFail("await should not return"); - } - catch (BrokenBarrierException e) { - } - catch (InterruptedException ie) { - } + public void testReset_Leakage() throws InterruptedException { + final CyclicBarrier c = new CyclicBarrier(2); + final AtomicBoolean done = new AtomicBoolean(); + Thread t = new Thread() { + public void run() { + while (!done.get()) { + try { + while (c.isBroken()) + c.reset(); + + c.await(); + threadFail("await should not return"); + } + catch (BrokenBarrierException e) { + } + catch (InterruptedException ie) { } } - }; - - t.start(); - for( int i = 0; i < 4; i++) { - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - } - done.set(true); + } + }; + + t.start(); + for (int i = 0; i < 4; i++) { + Thread.sleep(SHORT_DELAY_MS); t.interrupt(); } - catch (Exception ex) { - unexpectedException(); - } + done.set(true); + t.interrupt(); + t.join(); } /** * Reset of a non-broken barrier does not break barrier */ - public void testResetWithoutBreakage() { - try { - final CyclicBarrier start = new CyclicBarrier(3); - final CyclicBarrier barrier = new CyclicBarrier(3); - for (int i = 0; i < 3; i++) { - Thread t1 = new Thread(new Runnable() { - public void run() { - try { start.await(); } - catch (Exception ie) { - threadFail("start barrier"); - } - try { barrier.await(); } - catch (Throwable thrown) { - unexpectedException(); - }}}); - - Thread t2 = new Thread(new Runnable() { - public void run() { - try { start.await(); } - catch (Exception ie) { - threadFail("start barrier"); - } - try { barrier.await(); } - catch (Throwable thrown) { - unexpectedException(); - }}}); - - - t1.start(); - t2.start(); - try { start.await(); } - catch (Exception ie) { threadFail("start barrier"); } - barrier.await(); - t1.join(); - t2.join(); - assertFalse(barrier.isBroken()); - assertEquals(0, barrier.getNumberWaiting()); - if (i == 1) barrier.reset(); - assertFalse(barrier.isBroken()); - assertEquals(0, barrier.getNumberWaiting()); - } - } - catch (Exception ex) { - unexpectedException(); + public void testResetWithoutBreakage() throws Exception { + final CyclicBarrier start = new CyclicBarrier(3); + final CyclicBarrier barrier = new CyclicBarrier(3); + for (int i = 0; i < 3; i++) { + Thread t1 = new Thread(new CheckedRunnable() { + public void realRun() throws Exception { + start.await(); + barrier.await(); + }}); + + Thread t2 = new Thread(new CheckedRunnable() { + public void realRun() throws Exception { + start.await(); + barrier.await(); + }}); + + t1.start(); + t2.start(); + start.await(); + barrier.await(); + t1.join(); + t2.join(); + assertFalse(barrier.isBroken()); + assertEquals(0, barrier.getNumberWaiting()); + if (i == 1) barrier.reset(); + assertFalse(barrier.isBroken()); + assertEquals(0, barrier.getNumberWaiting()); } } - + /** * Reset of a barrier after interruption reinitializes it. */ - public void testResetAfterInterrupt() { - try { - final CyclicBarrier start = new CyclicBarrier(3); - final CyclicBarrier barrier = new CyclicBarrier(3); - for (int i = 0; i < 2; i++) { - Thread t1 = new Thread(new Runnable() { - public void run() { - try { start.await(); } - catch (Exception ie) { - threadFail("start barrier"); - } - try { barrier.await(); } - catch(InterruptedException ok) {} - catch (Throwable thrown) { - unexpectedException(); - }}}); - - Thread t2 = new Thread(new Runnable() { - public void run() { - try { start.await(); } - catch (Exception ie) { - threadFail("start barrier"); - } - try { barrier.await(); } - catch(BrokenBarrierException ok) {} - catch (Throwable thrown) { - unexpectedException(); - }}}); - - t1.start(); - t2.start(); - try { start.await(); } - catch (Exception ie) { threadFail("start barrier"); } - t1.interrupt(); - t1.join(); - t2.join(); - assertTrue(barrier.isBroken()); - assertEquals(0, barrier.getNumberWaiting()); - barrier.reset(); - assertFalse(barrier.isBroken()); - assertEquals(0, barrier.getNumberWaiting()); - } - } - catch (Exception ex) { - unexpectedException(); + public void testResetAfterInterrupt() throws Exception { + final CyclicBarrier start = new CyclicBarrier(3); + final CyclicBarrier barrier = new CyclicBarrier(3); + for (int i = 0; i < 2; i++) { + Thread t1 = new ThreadShouldThrow(InterruptedException.class) { + public void realRun() throws Exception { + start.await(); + barrier.await(); + }}; + + Thread t2 = new ThreadShouldThrow(BrokenBarrierException.class) { + public void realRun() throws Exception { + start.await(); + barrier.await(); + }}; + + t1.start(); + t2.start(); + start.await(); + t1.interrupt(); + t1.join(); + t2.join(); + assertTrue(barrier.isBroken()); + assertEquals(0, barrier.getNumberWaiting()); + barrier.reset(); + assertFalse(barrier.isBroken()); + assertEquals(0, barrier.getNumberWaiting()); } } - + /** * Reset of a barrier after timeout reinitializes it. */ - public void testResetAfterTimeout() { - try { - final CyclicBarrier start = new CyclicBarrier(3); - final CyclicBarrier barrier = new CyclicBarrier(3); - for (int i = 0; i < 2; i++) { - Thread t1 = new Thread(new Runnable() { - public void run() { - try { start.await(); } - catch (Exception ie) { - threadFail("start barrier"); - } - try { barrier.await(MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); } - catch(TimeoutException ok) {} - catch (Throwable thrown) { - unexpectedException(); - }}}); - - Thread t2 = new Thread(new Runnable() { - public void run() { - try { start.await(); } - catch (Exception ie) { - threadFail("start barrier"); - } - try { barrier.await(); } - catch(BrokenBarrierException ok) {} - catch (Throwable thrown) { - unexpectedException(); - }}}); - - t1.start(); - t2.start(); - try { start.await(); } - catch (Exception ie) { threadFail("start barrier"); } - t1.join(); - t2.join(); - assertTrue(barrier.isBroken()); - assertEquals(0, barrier.getNumberWaiting()); - barrier.reset(); - assertFalse(barrier.isBroken()); - assertEquals(0, barrier.getNumberWaiting()); - } - } - catch (Exception ex) { - unexpectedException(); + public void testResetAfterTimeout() throws Exception { + final CyclicBarrier start = new CyclicBarrier(3); + final CyclicBarrier barrier = new CyclicBarrier(3); + for (int i = 0; i < 2; i++) { + Thread t1 = new ThreadShouldThrow(TimeoutException.class) { + public void realRun() throws Exception { + start.await(); + barrier.await(MEDIUM_DELAY_MS, MILLISECONDS); + }}; + + Thread t2 = new ThreadShouldThrow(BrokenBarrierException.class) { + public void realRun() throws Exception { + start.await(); + barrier.await(); + }}; + + t1.start(); + t2.start(); + start.await(); + t1.join(); + t2.join(); + assertTrue(barrier.isBroken()); + assertEquals(0, barrier.getNumberWaiting()); + barrier.reset(); + assertFalse(barrier.isBroken()); + assertEquals(0, barrier.getNumberWaiting()); } } - + /** * Reset of a barrier after a failed command reinitializes it. */ - public void testResetAfterCommandException() { - try { - final CyclicBarrier start = new CyclicBarrier(3); - final CyclicBarrier barrier = - new CyclicBarrier(3, new Runnable() { - public void run() { - throw new NullPointerException(); }}); - for (int i = 0; i < 2; i++) { - Thread t1 = new Thread(new Runnable() { - public void run() { - try { start.await(); } - catch (Exception ie) { - threadFail("start barrier"); - } - try { barrier.await(); } - catch(BrokenBarrierException ok) {} - catch (Throwable thrown) { - unexpectedException(); - }}}); - - Thread t2 = new Thread(new Runnable() { - public void run() { - try { start.await(); } - catch (Exception ie) { - threadFail("start barrier"); - } - try { barrier.await(); } - catch(BrokenBarrierException ok) {} - catch (Throwable thrown) { - unexpectedException(); - }}}); - - t1.start(); - t2.start(); - try { start.await(); } - catch (Exception ie) { threadFail("start barrier"); } - while (barrier.getNumberWaiting() < 2) { Thread.yield(); } - try { barrier.await(); } - catch (Exception ok) { } - t1.join(); - t2.join(); - assertTrue(barrier.isBroken()); - assertEquals(0, barrier.getNumberWaiting()); - barrier.reset(); - assertFalse(barrier.isBroken()); - assertEquals(0, barrier.getNumberWaiting()); - } - } - catch (Exception ex) { - unexpectedException(); + public void testResetAfterCommandException() throws Exception { + final CyclicBarrier start = new CyclicBarrier(3); + final CyclicBarrier barrier = + new CyclicBarrier(3, new Runnable() { + public void run() { + throw new NullPointerException(); }}); + for (int i = 0; i < 2; i++) { + Thread t1 = new ThreadShouldThrow(BrokenBarrierException.class) { + public void realRun() throws Exception { + start.await(); + barrier.await(); + }}; + + Thread t2 = new ThreadShouldThrow(BrokenBarrierException.class) { + public void realRun() throws Exception { + start.await(); + barrier.await(); + }}; + + t1.start(); + t2.start(); + start.await(); + while (barrier.getNumberWaiting() < 2) { Thread.yield(); } + try { + barrier.await(); + shouldThrow(); + } catch (NullPointerException success) {} + t1.join(); + t2.join(); + assertTrue(barrier.isBroken()); + assertEquals(0, barrier.getNumberWaiting()); + barrier.reset(); + assertFalse(barrier.isBroken()); + assertEquals(0, barrier.getNumberWaiting()); } } } diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/DelayQueueTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/DelayQueueTest.java index 3d851e8..7aeceda 100755 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/DelayQueueTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/DelayQueueTest.java @@ -2,26 +2,27 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.*; +import static java.util.concurrent.TimeUnit.MILLISECONDS; import java.util.concurrent.*; public class DelayQueueTest extends JSR166TestCase { public static Test suite() { - return new TestSuite(DelayQueueTest.class); + return new TestSuite(DelayQueueTest.class); } private static final int NOCAP = Integer.MAX_VALUE; /** * A delayed implementation for testing. - * Most tests use Pseudodelays, where delays are all elapsed + * Most tests use Pseudodelays, where delays are all elapsed * (so, no blocking solely for delays) but are still ordered */ static class PDelay implements Delayed { @@ -29,25 +30,21 @@ public class DelayQueueTest extends JSR166TestCase { PDelay(int i) { pseudodelay = Integer.MIN_VALUE + i; } public int compareTo(PDelay y) { int i = pseudodelay; - int j = ((PDelay)y).pseudodelay; + int j = y.pseudodelay; if (i < j) return -1; if (i > j) return 1; return 0; } public int compareTo(Delayed y) { - int i = pseudodelay; - int j = ((PDelay)y).pseudodelay; - if (i < j) return -1; - if (i > j) return 1; - return 0; + return compareTo((PDelay)y); } public boolean equals(Object other) { - return ((PDelay)other).pseudodelay == pseudodelay; + return equals((PDelay)other); } public boolean equals(PDelay other) { - return ((PDelay)other).pseudodelay == pseudodelay; + return other.pseudodelay == pseudodelay; } @@ -74,25 +71,21 @@ public class DelayQueueTest extends JSR166TestCase { } public int compareTo(NanoDelay y) { long i = trigger; - long j = ((NanoDelay)y).trigger; + long j = y.trigger; if (i < j) return -1; if (i > j) return 1; return 0; } public int compareTo(Delayed y) { - long i = trigger; - long j = ((NanoDelay)y).trigger; - if (i < j) return -1; - if (i > j) return 1; - return 0; + return compareTo((NanoDelay)y); } public boolean equals(Object other) { - return ((NanoDelay)other).trigger == trigger; + return equals((NanoDelay)other); } public boolean equals(NanoDelay other) { - return ((NanoDelay)other).trigger == trigger; + return other.trigger == trigger; } public long getDelay(TimeUnit unit) { @@ -117,13 +110,13 @@ public class DelayQueueTest extends JSR166TestCase { private DelayQueue populatedQueue(int n) { DelayQueue q = new DelayQueue(); assertTrue(q.isEmpty()); - for(int i = n-1; i >= 0; i-=2) - assertTrue(q.offer(new PDelay(i))); - for(int i = (n & 1); i < n; i+=2) - assertTrue(q.offer(new PDelay(i))); + for (int i = n-1; i >= 0; i-=2) + assertTrue(q.offer(new PDelay(i))); + for (int i = (n & 1); i < n; i+=2) + assertTrue(q.offer(new PDelay(i))); assertFalse(q.isEmpty()); assertEquals(NOCAP, q.remainingCapacity()); - assertEquals(n, q.size()); + assertEquals(n, q.size()); return q; } @@ -141,8 +134,7 @@ public class DelayQueueTest extends JSR166TestCase { try { DelayQueue q = new DelayQueue(null); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** @@ -153,8 +145,7 @@ public class DelayQueueTest extends JSR166TestCase { PDelay[] ints = new PDelay[SIZE]; DelayQueue q = new DelayQueue(Arrays.asList(ints)); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** @@ -167,23 +158,19 @@ public class DelayQueueTest extends JSR166TestCase { ints[i] = new PDelay(i); DelayQueue q = new DelayQueue(Arrays.asList(ints)); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** * Queue contains all elements of collection used to initialize */ public void testConstructor6() { - try { - PDelay[] ints = new PDelay[SIZE]; - for (int i = 0; i < SIZE; ++i) - ints[i] = new PDelay(i); - DelayQueue q = new DelayQueue(Arrays.asList(ints)); - for (int i = 0; i < SIZE; ++i) - assertEquals(ints[i], q.poll()); - } - finally {} + PDelay[] ints = new PDelay[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new PDelay(i); + DelayQueue q = new DelayQueue(Arrays.asList(ints)); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.poll()); } /** @@ -202,7 +189,7 @@ public class DelayQueueTest extends JSR166TestCase { } /** - * remainingCapacity does not change when elementa added or removed, + * remainingCapacity does not change when elements added or removed, * but size does */ public void testRemainingCapacity() { @@ -223,22 +210,22 @@ public class DelayQueueTest extends JSR166TestCase { * offer(null) throws NPE */ public void testOfferNull() { - try { + try { DelayQueue q = new DelayQueue(); q.offer(null); shouldThrow(); - } catch (NullPointerException success) { } + } catch (NullPointerException success) {} } /** * add(null) throws NPE */ public void testAddNull() { - try { + try { DelayQueue q = new DelayQueue(); q.add(null); shouldThrow(); - } catch (NullPointerException success) { } + } catch (NullPointerException success) {} } /** @@ -269,8 +256,7 @@ public class DelayQueueTest extends JSR166TestCase { DelayQueue q = new DelayQueue(); q.addAll(null); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } @@ -282,8 +268,7 @@ public class DelayQueueTest extends JSR166TestCase { DelayQueue q = populatedQueue(SIZE); q.addAll(q); shouldThrow(); - } - catch (IllegalArgumentException success) {} + } catch (IllegalArgumentException success) {} } /** @@ -295,8 +280,7 @@ public class DelayQueueTest extends JSR166TestCase { PDelay[] ints = new PDelay[SIZE]; q.addAll(Arrays.asList(ints)); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** * addAll of a collection with any null elements throws NPE after @@ -310,179 +294,133 @@ public class DelayQueueTest extends JSR166TestCase { ints[i] = new PDelay(i); q.addAll(Arrays.asList(ints)); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** * Queue contains all elements of successful addAll */ public void testAddAll5() { - try { - PDelay[] empty = new PDelay[0]; - PDelay[] ints = new PDelay[SIZE]; - for (int i = SIZE-1; i >= 0; --i) - ints[i] = new PDelay(i); - DelayQueue q = new DelayQueue(); - assertFalse(q.addAll(Arrays.asList(empty))); - assertTrue(q.addAll(Arrays.asList(ints))); - for (int i = 0; i < SIZE; ++i) - assertEquals(ints[i], q.poll()); - } - finally {} + PDelay[] empty = new PDelay[0]; + PDelay[] ints = new PDelay[SIZE]; + for (int i = SIZE-1; i >= 0; --i) + ints[i] = new PDelay(i); + DelayQueue q = new DelayQueue(); + assertFalse(q.addAll(Arrays.asList(empty))); + assertTrue(q.addAll(Arrays.asList(ints))); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.poll()); } /** * put(null) throws NPE */ public void testPutNull() { - try { + try { DelayQueue q = new DelayQueue(); q.put(null); shouldThrow(); - } - catch (NullPointerException success){ - } + } catch (NullPointerException success) {} } /** * all elements successfully put are contained */ public void testPut() { - try { - DelayQueue q = new DelayQueue(); - for (int i = 0; i < SIZE; ++i) { - PDelay I = new PDelay(i); - q.put(I); - assertTrue(q.contains(I)); - } - assertEquals(SIZE, q.size()); + DelayQueue q = new DelayQueue(); + for (int i = 0; i < SIZE; ++i) { + PDelay I = new PDelay(i); + q.put(I); + assertTrue(q.contains(I)); } - finally { - } + assertEquals(SIZE, q.size()); } /** * put doesn't block waiting for take */ - public void testPutWithTake() { + public void testPutWithTake() throws InterruptedException { final DelayQueue q = new DelayQueue(); - Thread t = new Thread(new Runnable() { - public void run() { - int added = 0; - try { - q.put(new PDelay(0)); - ++added; - q.put(new PDelay(0)); - ++added; - q.put(new PDelay(0)); - ++added; - q.put(new PDelay(0)); - ++added; - threadAssertTrue(added == 4); - } finally { - } - } - }); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - q.take(); - t.interrupt(); - t.join(); - } catch (Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + q.put(new PDelay(0)); + q.put(new PDelay(0)); + q.put(new PDelay(0)); + q.put(new PDelay(0)); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + q.take(); + t.interrupt(); + t.join(); } /** * timed offer does not time out */ - public void testTimedOffer() { + public void testTimedOffer() throws InterruptedException { final DelayQueue q = new DelayQueue(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - q.put(new PDelay(0)); - q.put(new PDelay(0)); - threadAssertTrue(q.offer(new PDelay(0), SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - threadAssertTrue(q.offer(new PDelay(0), LONG_DELAY_MS, TimeUnit.MILLISECONDS)); - } finally { } - } - }); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + q.put(new PDelay(0)); + q.put(new PDelay(0)); + assertTrue(q.offer(new PDelay(0), SHORT_DELAY_MS, MILLISECONDS)); + assertTrue(q.offer(new PDelay(0), LONG_DELAY_MS, MILLISECONDS)); + }}); - try { - t.start(); - Thread.sleep(SMALL_DELAY_MS); - t.interrupt(); - t.join(); - } catch (Exception e){ - unexpectedException(); - } + t.start(); + Thread.sleep(SMALL_DELAY_MS); + t.interrupt(); + t.join(); } /** * take retrieves elements in priority order */ - public void testTake() { - try { - DelayQueue q = populatedQueue(SIZE); - for (int i = 0; i < SIZE; ++i) { - assertEquals(new PDelay(i), ((PDelay)q.take())); - } - } catch (InterruptedException e){ - unexpectedException(); - } + public void testTake() throws InterruptedException { + DelayQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(new PDelay(i), ((PDelay)q.take())); + } } /** * take blocks interruptibly when empty */ - public void testTakeFromEmpty() { + public void testTakeFromEmpty() throws InterruptedException { final DelayQueue q = new DelayQueue(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - q.take(); - threadShouldThrow(); - } catch (InterruptedException success){ } - } - }); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } catch (Exception e){ - unexpectedException(); - } + Thread t = new ThreadShouldThrow(InterruptedException.class) { + public void realRun() throws InterruptedException { + q.take(); + }}; + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } /** * Take removes existing elements until empty, then blocks interruptibly */ - public void testBlockingTake() { - Thread t = new Thread(new Runnable() { - public void run() { - try { - DelayQueue q = populatedQueue(SIZE); - for (int i = 0; i < SIZE; ++i) { - threadAssertEquals(new PDelay(i), ((PDelay)q.take())); - } - q.take(); - threadShouldThrow(); - } catch (InterruptedException success){ - } - }}); + public void testBlockingTake() throws InterruptedException { + final DelayQueue q = populatedQueue(SIZE); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < SIZE; ++i) { + assertEquals(new PDelay(i), ((PDelay)q.take())); + } + try { + q.take(); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + t.start(); - try { - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } - catch (InterruptedException ie) { - unexpectedException(); - } + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } @@ -494,91 +432,76 @@ public class DelayQueueTest extends JSR166TestCase { for (int i = 0; i < SIZE; ++i) { assertEquals(new PDelay(i), ((PDelay)q.poll())); } - assertNull(q.poll()); + assertNull(q.poll()); } /** * timed pool with zero timeout succeeds when non-empty, else times out */ - public void testTimedPoll0() { - try { - DelayQueue q = populatedQueue(SIZE); - for (int i = 0; i < SIZE; ++i) { - assertEquals(new PDelay(i), ((PDelay)q.poll(0, TimeUnit.MILLISECONDS))); - } - assertNull(q.poll(0, TimeUnit.MILLISECONDS)); - } catch (InterruptedException e){ - unexpectedException(); - } + public void testTimedPoll0() throws InterruptedException { + DelayQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(new PDelay(i), ((PDelay)q.poll(0, MILLISECONDS))); + } + assertNull(q.poll(0, MILLISECONDS)); } /** * timed pool with nonzero timeout succeeds when non-empty, else times out */ - public void testTimedPoll() { - try { - DelayQueue q = populatedQueue(SIZE); - for (int i = 0; i < SIZE; ++i) { - assertEquals(new PDelay(i), ((PDelay)q.poll(SHORT_DELAY_MS, TimeUnit.MILLISECONDS))); - } - assertNull(q.poll(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - } catch (InterruptedException e){ - unexpectedException(); - } + public void testTimedPoll() throws InterruptedException { + DelayQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(new PDelay(i), ((PDelay)q.poll(SHORT_DELAY_MS, MILLISECONDS))); + } + assertNull(q.poll(SHORT_DELAY_MS, MILLISECONDS)); } /** * Interrupted timed poll throws InterruptedException instead of * returning timeout status */ - public void testInterruptedTimedPoll() { - Thread t = new Thread(new Runnable() { - public void run() { - try { - DelayQueue q = populatedQueue(SIZE); - for (int i = 0; i < SIZE; ++i) { - threadAssertEquals(new PDelay(i), ((PDelay)q.poll(SHORT_DELAY_MS, TimeUnit.MILLISECONDS))); - } - threadAssertNull(q.poll(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - } catch (InterruptedException success){ - } - }}); + public void testInterruptedTimedPoll() throws InterruptedException { + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + DelayQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(new PDelay(i), ((PDelay)q.poll(SHORT_DELAY_MS, MILLISECONDS))); + } + try { + q.poll(SMALL_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + t.start(); - try { - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } - catch (InterruptedException ie) { - unexpectedException(); - } + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } /** * timed poll before a delayed offer fails; after offer succeeds; * on interruption throws */ - public void testTimedPollWithOffer() { + public void testTimedPollWithOffer() throws InterruptedException { final DelayQueue q = new DelayQueue(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - threadAssertNull(q.poll(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - q.poll(LONG_DELAY_MS, TimeUnit.MILLISECONDS); - q.poll(LONG_DELAY_MS, TimeUnit.MILLISECONDS); - threadFail("Should block"); - } catch (InterruptedException success) { } - } - }); - try { - t.start(); - Thread.sleep(SMALL_DELAY_MS); - assertTrue(q.offer(new PDelay(0), SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - t.interrupt(); - t.join(); - } catch (Exception e){ - unexpectedException(); - } + final PDelay pdelay = new PDelay(0); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertNull(q.poll(SHORT_DELAY_MS, MILLISECONDS)); + assertSame(pdelay, q.poll(LONG_DELAY_MS, MILLISECONDS)); + try { + q.poll(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + t.start(); + Thread.sleep(SMALL_DELAY_MS); + assertTrue(q.offer(pdelay, SHORT_DELAY_MS, MILLISECONDS)); + t.interrupt(); + t.join(); } @@ -589,13 +512,13 @@ public class DelayQueueTest extends JSR166TestCase { DelayQueue q = populatedQueue(SIZE); for (int i = 0; i < SIZE; ++i) { assertEquals(new PDelay(i), ((PDelay)q.peek())); - q.poll(); + assertEquals(new PDelay(i), ((PDelay)q.poll())); if (q.isEmpty()) assertNull(q.peek()); else - assertTrue(i != ((PDelay)q.peek()).intValue()); + assertFalse(new PDelay(i).equals(q.peek())); } - assertNull(q.peek()); + assertNull(q.peek()); } /** @@ -610,8 +533,7 @@ public class DelayQueueTest extends JSR166TestCase { try { q.element(); shouldThrow(); - } - catch (NoSuchElementException success) {} + } catch (NoSuchElementException success) {} } /** @@ -625,8 +547,7 @@ public class DelayQueueTest extends JSR166TestCase { try { q.remove(); shouldThrow(); - } catch (NoSuchElementException success){ - } + } catch (NoSuchElementException success) {} } /** @@ -725,32 +646,24 @@ public class DelayQueueTest extends JSR166TestCase { /** * toArray contains all elements */ - public void testToArray() { + public void testToArray() throws InterruptedException { DelayQueue q = populatedQueue(SIZE); - Object[] o = q.toArray(); + Object[] o = q.toArray(); Arrays.sort(o); - try { - for(int i = 0; i < o.length; i++) - assertEquals(o[i], q.take()); - } catch (InterruptedException e){ - unexpectedException(); - } + for (int i = 0; i < o.length; i++) + assertEquals(o[i], q.take()); } /** * toArray(a) contains all elements */ - public void testToArray2() { + public void testToArray2() throws InterruptedException { DelayQueue q = populatedQueue(SIZE); - PDelay[] ints = new PDelay[SIZE]; - ints = (PDelay[])q.toArray(ints); + PDelay[] ints = new PDelay[SIZE]; + ints = (PDelay[])q.toArray(ints); Arrays.sort(ints); - try { - for(int i = 0; i < ints.length; i++) - assertEquals(ints[i], q.take()); - } catch (InterruptedException e){ - unexpectedException(); - } + for (int i = 0; i < ints.length; i++) + assertEquals(ints[i], q.take()); } @@ -758,22 +671,22 @@ public class DelayQueueTest extends JSR166TestCase { * toArray(null) throws NPE */ public void testToArray_BadArg() { - try { - DelayQueue q = populatedQueue(SIZE); - Object o[] = q.toArray(null); - shouldThrow(); - } catch(NullPointerException success){} + DelayQueue q = populatedQueue(SIZE); + try { + Object o[] = q.toArray(null); + shouldThrow(); + } catch (NullPointerException success) {} } /** * toArray with incompatible array type throws CCE */ public void testToArray1_BadArg() { - try { - DelayQueue q = populatedQueue(SIZE); - Object o[] = q.toArray(new String[10] ); - shouldThrow(); - } catch(ArrayStoreException success){} + DelayQueue q = populatedQueue(SIZE); + try { + Object o[] = q.toArray(new String[10]); + shouldThrow(); + } catch (ArrayStoreException success) {} } /** @@ -782,8 +695,8 @@ public class DelayQueueTest extends JSR166TestCase { public void testIterator() { DelayQueue q = populatedQueue(SIZE); int i = 0; - Iterator it = q.iterator(); - while(it.hasNext()) { + Iterator it = q.iterator(); + while (it.hasNext()) { assertTrue(q.contains(it.next())); ++i; } @@ -825,39 +738,27 @@ public class DelayQueueTest extends JSR166TestCase { public void testPollInExecutor() { final DelayQueue q = new DelayQueue(); ExecutorService executor = Executors.newFixedThreadPool(2); - executor.execute(new Runnable() { - public void run() { - threadAssertNull(q.poll()); - try { - threadAssertTrue(null != q.poll(MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS)); - threadAssertTrue(q.isEmpty()); - } - catch (InterruptedException e) { - threadUnexpectedException(); - } - } - }); + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertNull(q.poll()); + assertTrue(null != q.poll(MEDIUM_DELAY_MS, MILLISECONDS)); + assertTrue(q.isEmpty()); + }}); + + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + Thread.sleep(SHORT_DELAY_MS); + q.put(new PDelay(1)); + }}); - executor.execute(new Runnable() { - public void run() { - try { - Thread.sleep(SHORT_DELAY_MS); - q.put(new PDelay(1)); - } - catch (InterruptedException e) { - threadUnexpectedException(); - } - } - }); joinPool(executor); - } /** * Delayed actions do not occur until their delay elapses */ - public void testDelay() { + public void testDelay() throws InterruptedException { DelayQueue q = new DelayQueue(); NanoDelay[] elements = new NanoDelay[SIZE]; for (int i = 0; i < SIZE; ++i) { @@ -867,19 +768,14 @@ public class DelayQueueTest extends JSR166TestCase { q.add(elements[i]); } - try { - long last = 0; - for (int i = 0; i < SIZE; ++i) { - NanoDelay e = (NanoDelay)(q.take()); - long tt = e.getTriggerTime(); - assertTrue(tt <= System.nanoTime()); - if (i != 0) - assertTrue(tt >= last); - last = tt; - } - } - catch(InterruptedException ie) { - unexpectedException(); + long last = 0; + for (int i = 0; i < SIZE; ++i) { + NanoDelay e = (NanoDelay)(q.take()); + long tt = e.getTriggerTime(); + assertTrue(tt <= System.nanoTime()); + if (i != 0) + assertTrue(tt >= last); + last = tt; } } @@ -905,14 +801,10 @@ public class DelayQueueTest extends JSR166TestCase { /** * timed poll of a non-empty queue returns null if no expired elements. */ - public void testTimedPollDelayed() { + public void testTimedPollDelayed() throws InterruptedException { DelayQueue q = new DelayQueue(); q.add(new NanoDelay(LONG_DELAY_MS * 1000000L)); - try { - assertNull(q.poll(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - } catch (Exception ex) { - unexpectedException(); - } + assertNull(q.poll(SHORT_DELAY_MS, MILLISECONDS)); } /** @@ -923,8 +815,7 @@ public class DelayQueueTest extends JSR166TestCase { try { q.drainTo(null); shouldThrow(); - } catch(NullPointerException success) { - } + } catch (NullPointerException success) {} } /** @@ -935,8 +826,7 @@ public class DelayQueueTest extends JSR166TestCase { try { q.drainTo(q); shouldThrow(); - } catch(IllegalArgumentException success) { - } + } catch (IllegalArgumentException success) {} } /** @@ -969,53 +859,47 @@ public class DelayQueueTest extends JSR166TestCase { /** * drainTo empties queue - */ - public void testDrainToWithActivePut() { + */ + public void testDrainToWithActivePut() throws InterruptedException { final DelayQueue q = populatedQueue(SIZE); - Thread t = new Thread(new Runnable() { - public void run() { - q.put(new PDelay(SIZE+1)); - } - }); - try { - t.start(); - ArrayList l = new ArrayList(); - q.drainTo(l); - assertTrue(l.size() >= SIZE); - t.join(); - assertTrue(q.size() + l.size() >= SIZE); - } catch(Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + q.put(new PDelay(SIZE+1)); + }}); + + t.start(); + ArrayList l = new ArrayList(); + q.drainTo(l); + assertTrue(l.size() >= SIZE); + t.join(); + assertTrue(q.size() + l.size() >= SIZE); } /** * drainTo(null, n) throws NPE - */ + */ public void testDrainToNullN() { DelayQueue q = populatedQueue(SIZE); try { q.drainTo(null, 0); shouldThrow(); - } catch(NullPointerException success) { - } + } catch (NullPointerException success) {} } /** * drainTo(this, n) throws IAE - */ + */ public void testDrainToSelfN() { DelayQueue q = populatedQueue(SIZE); try { q.drainTo(q, 0); shouldThrow(); - } catch(IllegalArgumentException success) { - } + } catch (IllegalArgumentException success) {} } /** * drainTo(c, n) empties first max {n, size} elements of queue into c - */ + */ public void testDrainToN() { for (int i = 0; i < SIZE + 2; ++i) { DelayQueue q = populatedQueue(SIZE); diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/EntryTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/EntryTest.java new file mode 100644 index 0000000..893fd48 --- /dev/null +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/EntryTest.java @@ -0,0 +1,131 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package tests.api.java.util.concurrent; // android-added + +import junit.framework.*; +import java.util.*; +import java.util.concurrent.*; +import java.io.*; + +public class EntryTest extends JSR166TestCase { + public static Test suite() { + return new TestSuite(EntryTest.class); + } + + static final String k1 = "1"; + static final String v1 = "a"; + static final String k2 = "2"; + static final String v2 = "b"; + + + /** + * A new SimpleEntry(k, v) holds k, v. + */ + public void testConstructor1() { + Map.Entry e = new AbstractMap.SimpleEntry(k1, v1); + assertEquals(k1, e.getKey()); + assertEquals(v1, e.getValue()); + } + + /** + * A new SimpleImmutableEntry(k, v) holds k, v. + */ + public void testConstructor2() { + Map.Entry s = new AbstractMap.SimpleImmutableEntry(k1, v1); + assertEquals(k1, s.getKey()); + assertEquals(v1, s.getValue()); + } + + + /** + * A new SimpleEntry(entry(k, v)) holds k, v. + */ + public void testConstructor3() { + Map.Entry e2 = new AbstractMap.SimpleEntry(k1, v1); + Map.Entry e = new AbstractMap.SimpleEntry(e2); + assertEquals(k1, e.getKey()); + assertEquals(v1, e.getValue()); + } + + /** + * A new SimpleImmutableEntry(entry(k, v)) holds k, v. + */ + public void testConstructor4() { + Map.Entry s2 = new AbstractMap.SimpleImmutableEntry(k1, v1); + Map.Entry s = new AbstractMap.SimpleImmutableEntry(s2); + assertEquals(k1, s.getKey()); + assertEquals(v1, s.getValue()); + } + + /** + * Entries with same key-value pairs are equal and have same + * hashcodes + */ + public void testEquals() { + Map.Entry e2 = new AbstractMap.SimpleEntry(k1, v1); + Map.Entry e = new AbstractMap.SimpleEntry(e2); + Map.Entry s2 = new AbstractMap.SimpleImmutableEntry(k1, v1); + Map.Entry s = new AbstractMap.SimpleImmutableEntry(s2); + assertEquals(e2, e); + assertEquals(e2.hashCode(), e.hashCode()); + assertEquals(s2, s); + assertEquals(s2.hashCode(), s.hashCode()); + assertEquals(e2, s2); + assertEquals(e2.hashCode(), s2.hashCode()); + assertEquals(e, s); + assertEquals(e.hashCode(), s.hashCode()); + } + + /** + * Entries with different key-value pairs are not equal + */ + public void testNotEquals() { + Map.Entry e2 = new AbstractMap.SimpleEntry(k1, v1); + Map.Entry e = new AbstractMap.SimpleEntry(k2, v1); + assertFalse(e2.equals( e)); + e = new AbstractMap.SimpleEntry(k1, v2); + assertFalse(e2.equals( e)); + e = new AbstractMap.SimpleEntry(k2, v2); + assertFalse(e2.equals( e)); + + Map.Entry s2 = new AbstractMap.SimpleImmutableEntry(k1, v1); + Map.Entry s = new AbstractMap.SimpleImmutableEntry(k2, v1); + assertFalse(s2.equals( s)); + s = new AbstractMap.SimpleImmutableEntry(k1, v2); + assertFalse(s2.equals( s)); + s = new AbstractMap.SimpleImmutableEntry(k2, v2); + assertFalse(s2.equals( s)); + } + + + /** + * getValue returns last setValue for SimpleEntry + */ + public void testSetValue1() { + Map.Entry e2 = new AbstractMap.SimpleEntry(k1, v1); + Map.Entry e = new AbstractMap.SimpleEntry(e2); + assertEquals(k1, e.getKey()); + assertEquals(v1, e.getValue()); + e.setValue(k2); + assertEquals(k2, e.getValue()); + assertFalse(e2.equals( e)); + } + + /** + * setValue for SimpleImmutableEntry throws UnsupportedOperationException + */ + public void testsetValue2() { + Map.Entry s2 = new AbstractMap.SimpleImmutableEntry(k1, v1); + Map.Entry s = new AbstractMap.SimpleImmutableEntry(s2); + assertEquals(k1, s.getKey()); + assertEquals(v1, s.getValue()); + try { + s.setValue(k2); + shouldThrow(); + } catch (UnsupportedOperationException success) {} + } +} diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/ExchangerTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/ExchangerTest.java index bc0df85..be1eaa3 100755 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/ExchangerTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/ExchangerTest.java @@ -2,15 +2,16 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.*; import java.util.concurrent.*; +import static java.util.concurrent.TimeUnit.MILLISECONDS; public class ExchangerTest extends JSR166TestCase { public static Test suite() { @@ -20,211 +21,123 @@ public class ExchangerTest extends JSR166TestCase { /** * exchange exchanges objects across two threads */ - public void testExchange() { + public void testExchange() throws InterruptedException { final Exchanger e = new Exchanger(); - Thread t1 = new Thread(new Runnable(){ - public void run(){ - try { - Object v = e.exchange(one); - threadAssertEquals(v, two); - Object w = e.exchange(v); - threadAssertEquals(w, one); - } catch(InterruptedException e){ - threadUnexpectedException(); - } - } - }); - Thread t2 = new Thread(new Runnable(){ - public void run(){ - try { - Object v = e.exchange(two); - threadAssertEquals(v, one); - Object w = e.exchange(v); - threadAssertEquals(w, two); - } catch(InterruptedException e){ - threadUnexpectedException(); - } - } - }); - try { - t1.start(); - t2.start(); - t1.join(); - t2.join(); - } catch(InterruptedException ex) { - unexpectedException(); - } + Thread t1 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertSame(one, e.exchange(two)); + assertSame(two, e.exchange(one)); + }}); + Thread t2 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertSame(two, e.exchange(one)); + assertSame(one, e.exchange(two)); + }}); + + t1.start(); + t2.start(); + t1.join(); + t2.join(); } /** * timed exchange exchanges objects across two threads */ - public void testTimedExchange() { + public void testTimedExchange() throws InterruptedException { final Exchanger e = new Exchanger(); - Thread t1 = new Thread(new Runnable(){ - public void run(){ - try { - Object v = e.exchange(one, SHORT_DELAY_MS, TimeUnit.MILLISECONDS); - threadAssertEquals(v, two); - Object w = e.exchange(v, SHORT_DELAY_MS, TimeUnit.MILLISECONDS); - threadAssertEquals(w, one); - } catch(InterruptedException e){ - threadUnexpectedException(); - } catch(TimeoutException toe) { - threadUnexpectedException(); - } - } - }); - Thread t2 = new Thread(new Runnable(){ - public void run(){ - try { - Object v = e.exchange(two, SHORT_DELAY_MS, TimeUnit.MILLISECONDS); - threadAssertEquals(v, one); - Object w = e.exchange(v, SHORT_DELAY_MS, TimeUnit.MILLISECONDS); - threadAssertEquals(w, two); - } catch(InterruptedException e){ - threadUnexpectedException(); - } catch(TimeoutException toe) { - threadUnexpectedException(); - } - } - }); - try { - t1.start(); - t2.start(); - t1.join(); - t2.join(); - } catch(InterruptedException ex) { - unexpectedException(); - } + Thread t1 = new Thread(new CheckedRunnable() { + public void realRun() throws Exception { + assertSame(one, e.exchange(two, SHORT_DELAY_MS, MILLISECONDS)); + assertSame(two, e.exchange(one, SHORT_DELAY_MS, MILLISECONDS)); + }}); + Thread t2 = new Thread(new CheckedRunnable() { + public void realRun() throws Exception { + assertSame(two, e.exchange(one, SHORT_DELAY_MS, MILLISECONDS)); + assertSame(one, e.exchange(two, SHORT_DELAY_MS, MILLISECONDS)); + }}); + + t1.start(); + t2.start(); + t1.join(); + t2.join(); } /** * interrupt during wait for exchange throws IE */ - public void testExchange_InterruptedException(){ + public void testExchange_InterruptedException() throws InterruptedException { final Exchanger e = new Exchanger(); - Thread t = new Thread(new Runnable() { - public void run(){ - try { - e.exchange(one); - threadShouldThrow(); - } catch(InterruptedException success){ - } - } - }); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } catch(InterruptedException ex) { - unexpectedException(); - } + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + e.exchange(one); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } /** * interrupt during wait for timed exchange throws IE */ - public void testTimedExchange_InterruptedException(){ + public void testTimedExchange_InterruptedException() throws InterruptedException { final Exchanger e = new Exchanger(); - Thread t = new Thread(new Runnable() { - public void run(){ - try { - e.exchange(null, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); - threadShouldThrow(); - } catch(InterruptedException success){ - } catch(Exception e2){ - threadFail("should throw IE"); - } - } - }); - try { - t.start(); - t.interrupt(); - t.join(); - } catch(InterruptedException ex){ - unexpectedException(); - } + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws Exception { + e.exchange(null, SMALL_DELAY_MS, MILLISECONDS); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } /** * timeout during wait for timed exchange throws TOE */ - public void testExchange_TimeOutException(){ + public void testExchange_TimeOutException() throws InterruptedException { final Exchanger e = new Exchanger(); - Thread t = new Thread(new Runnable() { - public void run(){ - try { - e.exchange(null, SHORT_DELAY_MS, TimeUnit.MILLISECONDS); - threadShouldThrow(); - } catch(TimeoutException success){ - } catch(InterruptedException e2){ - threadFail("should throw TOE"); - } - } - }); - try { - t.start(); - t.join(); - } catch(InterruptedException ex){ - unexpectedException(); - } + Thread t = new ThreadShouldThrow(TimeoutException.class) { + public void realRun() throws Exception { + e.exchange(null, SHORT_DELAY_MS, MILLISECONDS); + }}; + + t.start(); + t.join(); } /** * If one exchanging thread is interrupted, another succeeds. */ - public void testReplacementAfterExchange() { + public void testReplacementAfterExchange() throws InterruptedException { final Exchanger e = new Exchanger(); - Thread t1 = new Thread(new Runnable(){ - public void run(){ - try { - Object v = e.exchange(one); - threadAssertEquals(v, two); - Object w = e.exchange(v); - threadShouldThrow(); - } catch(InterruptedException success){ - } - } - }); - Thread t2 = new Thread(new Runnable(){ - public void run(){ - try { - Object v = e.exchange(two); - threadAssertEquals(v, one); - Thread.sleep(SMALL_DELAY_MS); - Object w = e.exchange(v); - threadAssertEquals(w, three); - } catch(InterruptedException e){ - threadUnexpectedException(); - } - } - }); - Thread t3 = new Thread(new Runnable(){ - public void run(){ - try { - Thread.sleep(SMALL_DELAY_MS); - Object w = e.exchange(three); - threadAssertEquals(w, one); - } catch(InterruptedException e){ - threadUnexpectedException(); - } - } - }); - - try { - t1.start(); - t2.start(); - t3.start(); - Thread.sleep(SHORT_DELAY_MS); - t1.interrupt(); - t1.join(); - t2.join(); - t3.join(); - } catch(InterruptedException ex) { - unexpectedException(); - } + Thread t1 = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + assertSame(two, e.exchange(one)); + e.exchange(two); + }}); + Thread t2 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertSame(one, e.exchange(two)); + Thread.sleep(SMALL_DELAY_MS); + assertSame(three, e.exchange(one)); + }}); + Thread t3 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + Thread.sleep(SMALL_DELAY_MS); + assertSame(one, e.exchange(three)); + }}); + + t1.start(); + t2.start(); + t3.start(); + Thread.sleep(SHORT_DELAY_MS); + t1.interrupt(); + t1.join(); + t2.join(); + t3.join(); } } diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/ExecutorCompletionServiceTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/ExecutorCompletionServiceTest.java index 91bedf9..dfa8f7d 100644 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/ExecutorCompletionServiceTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/ExecutorCompletionServiceTest.java @@ -2,20 +2,21 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.*; import java.util.concurrent.*; +import static java.util.concurrent.TimeUnit.MILLISECONDS; import java.util.concurrent.atomic.*; import java.math.BigInteger; import java.security.*; -public class ExecutorCompletionServiceTest extends JSR166TestCase{ +public class ExecutorCompletionServiceTest extends JSR166TestCase { public static Test suite() { return new TestSuite(ExecutorCompletionServiceTest.class); } @@ -23,30 +24,28 @@ public class ExecutorCompletionServiceTest extends JSR166TestCase{ /** * Creating a new ECS with null Executor throw NPE - */ + */ public void testConstructorNPE() { try { ExecutorCompletionService ecs = new ExecutorCompletionService(null); shouldThrow(); - } catch (NullPointerException success) { - } + } catch (NullPointerException success) {} } /** * Creating a new ECS with null queue throw NPE - */ + */ public void testConstructorNPE2() { try { ExecutorService e = Executors.newCachedThreadPool(); ExecutorCompletionService ecs = new ExecutorCompletionService(e, null); shouldThrow(); - } catch (NullPointerException success) { - } + } catch (NullPointerException success) {} } /** * Submitting a null callable throws NPE - */ + */ public void testSubmitNPE() { ExecutorService e = Executors.newCachedThreadPool(); ExecutorCompletionService ecs = new ExecutorCompletionService(e); @@ -62,7 +61,7 @@ public class ExecutorCompletionServiceTest extends JSR166TestCase{ /** * Submitting a null runnable throws NPE - */ + */ public void testSubmitNPE2() { ExecutorService e = Executors.newCachedThreadPool(); ExecutorCompletionService ecs = new ExecutorCompletionService(e); @@ -78,8 +77,8 @@ public class ExecutorCompletionServiceTest extends JSR166TestCase{ /** * A taken submitted task is completed - */ - public void testTake() { + */ + public void testTake() throws InterruptedException { ExecutorService e = Executors.newCachedThreadPool(); ExecutorCompletionService ecs = new ExecutorCompletionService(e); try { @@ -87,8 +86,6 @@ public class ExecutorCompletionServiceTest extends JSR166TestCase{ ecs.submit(c); Future f = ecs.take(); assertTrue(f.isDone()); - } catch (Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -96,8 +93,8 @@ public class ExecutorCompletionServiceTest extends JSR166TestCase{ /** * Take returns the same future object returned by submit - */ - public void testTake2() { + */ + public void testTake2() throws InterruptedException { ExecutorService e = Executors.newCachedThreadPool(); ExecutorCompletionService ecs = new ExecutorCompletionService(e); try { @@ -105,8 +102,6 @@ public class ExecutorCompletionServiceTest extends JSR166TestCase{ Future f1 = ecs.submit(c); Future f2 = ecs.take(); assertSame(f1, f2); - } catch (Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -114,8 +109,8 @@ public class ExecutorCompletionServiceTest extends JSR166TestCase{ /** * If poll returns non-null, the returned task is completed - */ - public void testPoll1() { + */ + public void testPoll1() throws InterruptedException { ExecutorService e = Executors.newCachedThreadPool(); ExecutorCompletionService ecs = new ExecutorCompletionService(e); try { @@ -130,8 +125,6 @@ public class ExecutorCompletionServiceTest extends JSR166TestCase{ break; } } - } catch (Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -139,21 +132,85 @@ public class ExecutorCompletionServiceTest extends JSR166TestCase{ /** * If timed poll returns non-null, the returned task is completed - */ - public void testPoll2() { + */ + public void testPoll2() throws InterruptedException { ExecutorService e = Executors.newCachedThreadPool(); ExecutorCompletionService ecs = new ExecutorCompletionService(e); try { assertNull(ecs.poll()); Callable c = new StringTask(); ecs.submit(c); - Future f = ecs.poll(SHORT_DELAY_MS, TimeUnit.MILLISECONDS); - if (f != null) + Future f = ecs.poll(SHORT_DELAY_MS, MILLISECONDS); + if (f != null) assertTrue(f.isDone()); - } catch (Exception ex) { - unexpectedException(); } finally { joinPool(e); } } + /** + * Submitting to underlying AES that overrides newTaskFor(Callable) + * returns and eventually runs Future returned by newTaskFor. + */ + public void testNewTaskForCallable() throws InterruptedException { + final AtomicBoolean done = new AtomicBoolean(false); + class MyCallableFuture<V> extends FutureTask<V> { + MyCallableFuture(Callable<V> c) { super(c); } + protected void done() { done.set(true); } + } + ExecutorService e = new ThreadPoolExecutor( + 1, 1, 30L, TimeUnit.SECONDS, + new ArrayBlockingQueue<Runnable>(1)) { + protected <T> RunnableFuture<T> newTaskFor(Callable<T> c) { + return new MyCallableFuture<T>(c); + } + }; + ExecutorCompletionService<String> ecs = + new ExecutorCompletionService<String>(e); + try { + assertNull(ecs.poll()); + Callable<String> c = new StringTask(); + Future f1 = ecs.submit(c); + assertTrue("submit must return MyCallableFuture", + f1 instanceof MyCallableFuture); + Future f2 = ecs.take(); + assertSame("submit and take must return same objects", f1, f2); + assertTrue("completed task must have set done", done.get()); + } finally { + joinPool(e); + } + } + + /** + * Submitting to underlying AES that overrides newTaskFor(Runnable,T) + * returns and eventually runs Future returned by newTaskFor. + */ + public void testNewTaskForRunnable() throws InterruptedException { + final AtomicBoolean done = new AtomicBoolean(false); + class MyRunnableFuture<V> extends FutureTask<V> { + MyRunnableFuture(Runnable t, V r) { super(t, r); } + protected void done() { done.set(true); } + } + ExecutorService e = new ThreadPoolExecutor( + 1, 1, 30L, TimeUnit.SECONDS, + new ArrayBlockingQueue<Runnable>(1)) { + protected <T> RunnableFuture<T> newTaskFor(Runnable t, T r) { + return new MyRunnableFuture<T>(t, r); + } + }; + ExecutorCompletionService<String> ecs = + new ExecutorCompletionService<String>(e); + try { + assertNull(ecs.poll()); + Runnable r = new NoOpRunnable(); + Future f1 = ecs.submit(r, null); + assertTrue("submit must return MyRunnableFuture", + f1 instanceof MyRunnableFuture); + Future f2 = ecs.take(); + assertSame("submit and take must return same objects", f1, f2); + assertTrue("completed task must have set done", done.get()); + } finally { + joinPool(e); + } + } + } diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/ExecutorsTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/ExecutorsTest.java index b0a2ccd..f29a712 100755 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/ExecutorsTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/ExecutorsTest.java @@ -2,63 +2,24 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.*; import java.util.concurrent.*; +import static java.util.concurrent.TimeUnit.MILLISECONDS; import java.math.BigInteger; import java.security.*; -public class ExecutorsTest extends JSR166TestCase{ +public class ExecutorsTest extends JSR166TestCase { public static Test suite() { return new TestSuite(ExecutorsTest.class); } - static class TimedCallable<T> implements Callable<T> { - private final ExecutorService exec; - private final Callable<T> func; - private final long msecs; - - TimedCallable(ExecutorService exec, Callable<T> func, long msecs) { - this.exec = exec; - this.func = func; - this.msecs = msecs; - } - - public T call() throws Exception { - Future<T> ftask = exec.submit(func); - try { - return ftask.get(msecs, TimeUnit.MILLISECONDS); - } finally { - ftask.cancel(true); - } - } - } - - - private static class Fib implements Callable<BigInteger> { - private final BigInteger n; - Fib(long n) { - if (n < 0) throw new IllegalArgumentException("need non-negative arg, but got " + n); - this.n = BigInteger.valueOf(n); - } - public BigInteger call() { - BigInteger f1 = BigInteger.ONE; - BigInteger f2 = f1; - for (BigInteger i = BigInteger.ZERO; i.compareTo(n) < 0; i = i.add(BigInteger.ONE)) { - BigInteger t = f1.add(f2); - f1 = f2; - f2 = t; - } - return f1; - } - }; - /** * A newCachedThreadPool can execute runnables */ @@ -88,9 +49,7 @@ public class ExecutorsTest extends JSR166TestCase{ try { ExecutorService e = Executors.newCachedThreadPool(null); shouldThrow(); - } - catch(NullPointerException success) { - } + } catch (NullPointerException success) {} } @@ -123,9 +82,7 @@ public class ExecutorsTest extends JSR166TestCase{ try { ExecutorService e = Executors.newSingleThreadExecutor(null); shouldThrow(); - } - catch(NullPointerException success) { - } + } catch (NullPointerException success) {} } /** @@ -135,6 +92,7 @@ public class ExecutorsTest extends JSR166TestCase{ ExecutorService e = Executors.newSingleThreadExecutor(); try { ThreadPoolExecutor tpe = (ThreadPoolExecutor)e; + shouldThrow(); } catch (ClassCastException success) { } finally { joinPool(e); @@ -171,9 +129,7 @@ public class ExecutorsTest extends JSR166TestCase{ try { ExecutorService e = Executors.newFixedThreadPool(2, null); shouldThrow(); - } - catch(NullPointerException success) { - } + } catch (NullPointerException success) {} } /** @@ -183,9 +139,7 @@ public class ExecutorsTest extends JSR166TestCase{ try { ExecutorService e = Executors.newFixedThreadPool(0); shouldThrow(); - } - catch(IllegalArgumentException success) { - } + } catch (IllegalArgumentException success) {} } @@ -206,9 +160,8 @@ public class ExecutorsTest extends JSR166TestCase{ public void testunconfigurableExecutorServiceNPE() { try { ExecutorService e = Executors.unconfigurableExecutorService(null); - } - catch (NullPointerException success) { - } + shouldThrow(); + } catch (NullPointerException success) {} } /** @@ -217,109 +170,82 @@ public class ExecutorsTest extends JSR166TestCase{ public void testunconfigurableScheduledExecutorServiceNPE() { try { ExecutorService e = Executors.unconfigurableScheduledExecutorService(null); - } - catch (NullPointerException success) { - } + shouldThrow(); + } catch (NullPointerException success) {} } /** * a newSingleThreadScheduledExecutor successfully runs delayed task */ - public void testNewSingleThreadScheduledExecutor() { - try { - TrackedCallable callable = new TrackedCallable(); - ScheduledExecutorService p1 = Executors.newSingleThreadScheduledExecutor(); - Future f = p1.schedule(callable, SHORT_DELAY_MS, TimeUnit.MILLISECONDS); - assertFalse(callable.done); - Thread.sleep(MEDIUM_DELAY_MS); - assertTrue(callable.done); - assertEquals(Boolean.TRUE, f.get()); - joinPool(p1); - } catch(RejectedExecutionException e){} - catch(Exception e){ - e.printStackTrace(); - unexpectedException(); - } + public void testNewSingleThreadScheduledExecutor() throws Exception { + TrackedCallable callable = new TrackedCallable(); + ScheduledExecutorService p1 = Executors.newSingleThreadScheduledExecutor(); + Future f = p1.schedule(callable, SHORT_DELAY_MS, MILLISECONDS); + assertFalse(callable.done); + Thread.sleep(MEDIUM_DELAY_MS); + assertTrue(callable.done); + assertEquals(Boolean.TRUE, f.get()); + joinPool(p1); } /** * a newScheduledThreadPool successfully runs delayed task */ - public void testnewScheduledThreadPool() { - try { - TrackedCallable callable = new TrackedCallable(); - ScheduledExecutorService p1 = Executors.newScheduledThreadPool(2); - Future f = p1.schedule(callable, SHORT_DELAY_MS, TimeUnit.MILLISECONDS); - assertFalse(callable.done); - Thread.sleep(MEDIUM_DELAY_MS); - assertTrue(callable.done); - assertEquals(Boolean.TRUE, f.get()); - joinPool(p1); - } catch(RejectedExecutionException e){} - catch(Exception e){ - e.printStackTrace(); - unexpectedException(); - } + public void testnewScheduledThreadPool() throws Exception { + TrackedCallable callable = new TrackedCallable(); + ScheduledExecutorService p1 = Executors.newScheduledThreadPool(2); + Future f = p1.schedule(callable, SHORT_DELAY_MS, MILLISECONDS); + assertFalse(callable.done); + Thread.sleep(MEDIUM_DELAY_MS); + assertTrue(callable.done); + assertEquals(Boolean.TRUE, f.get()); + joinPool(p1); } /** - * an unconfigurable newScheduledThreadPool successfully runs delayed task + * an unconfigurable newScheduledThreadPool successfully runs delayed task */ - public void testunconfigurableScheduledExecutorService() { - try { - TrackedCallable callable = new TrackedCallable(); - ScheduledExecutorService p1 = Executors.unconfigurableScheduledExecutorService(Executors.newScheduledThreadPool(2)); - Future f = p1.schedule(callable, SHORT_DELAY_MS, TimeUnit.MILLISECONDS); - assertFalse(callable.done); - Thread.sleep(MEDIUM_DELAY_MS); - assertTrue(callable.done); - assertEquals(Boolean.TRUE, f.get()); - joinPool(p1); - } catch(RejectedExecutionException e){} - catch(Exception e){ - e.printStackTrace(); - unexpectedException(); - } + public void testunconfigurableScheduledExecutorService() throws Exception { + TrackedCallable callable = new TrackedCallable(); + ScheduledExecutorService p1 = Executors.unconfigurableScheduledExecutorService(Executors.newScheduledThreadPool(2)); + Future f = p1.schedule(callable, SHORT_DELAY_MS, MILLISECONDS); + assertFalse(callable.done); + Thread.sleep(MEDIUM_DELAY_MS); + assertTrue(callable.done); + assertEquals(Boolean.TRUE, f.get()); + joinPool(p1); } /** - * timeouts from execute will time out if they compute too long. + * Future.get on submitted tasks will time out if they compute too long. */ - public void testTimedCallable() { - int N = 10000; - ExecutorService executor = Executors.newSingleThreadExecutor(); - List<Callable<BigInteger>> tasks = new ArrayList<Callable<BigInteger>>(N); - try { - long startTime = System.currentTimeMillis(); - - long i = 0; - while (tasks.size() < N) { - tasks.add(new TimedCallable<BigInteger>(executor, new Fib(i), 1)); - i += 10; - } - - int iters = 0; - BigInteger sum = BigInteger.ZERO; - for (Iterator<Callable<BigInteger>> it = tasks.iterator(); it.hasNext();) { + public void testTimedCallable() throws Exception { + final Runnable sleeper = + new RunnableShouldThrow(InterruptedException.class) { + public void realRun() throws InterruptedException { + Thread.sleep(LONG_DELAY_MS); + }}; + for (ExecutorService executor : + new ExecutorService[] { + Executors.newSingleThreadExecutor(), + Executors.newCachedThreadPool(), + Executors.newFixedThreadPool(2), + Executors.newScheduledThreadPool(2), + }) { + try { + Future future = executor.submit(sleeper); try { - ++iters; - sum = sum.add(it.next().call()); - } - catch (TimeoutException success) { - assertTrue(iters > 0); - return; - } - catch (Exception e) { - unexpectedException(); + future.get(SHORT_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (TimeoutException success) { + } finally { + future.cancel(true); } } - // if by chance we didn't ever time out, total time must be small - long elapsed = System.currentTimeMillis() - startTime; - assertTrue(elapsed < N); - } - finally { - joinPool(executor); + finally { + joinPool(executor); + } } } @@ -328,25 +254,25 @@ public class ExecutorsTest extends JSR166TestCase{ * ThreadPoolExecutor using defaultThreadFactory has * specified group, priority, daemon status, and name */ - public void testDefaultThreadFactory() { + public void testDefaultThreadFactory() throws Exception { final ThreadGroup egroup = Thread.currentThread().getThreadGroup(); Runnable r = new Runnable() { public void run() { - try { - Thread current = Thread.currentThread(); - threadAssertTrue(!current.isDaemon()); - threadAssertTrue(current.getPriority() <= Thread.NORM_PRIORITY); - ThreadGroup g = current.getThreadGroup(); - SecurityManager s = System.getSecurityManager(); - if (s != null) - threadAssertTrue(g == s.getThreadGroup()); - else - threadAssertTrue(g == egroup); - String name = current.getName(); - threadAssertTrue(name.endsWith("thread-1")); - } catch (SecurityException ok) { - // Also pass if not allowed to change setting - } + try { + Thread current = Thread.currentThread(); + threadAssertTrue(!current.isDaemon()); + threadAssertTrue(current.getPriority() <= Thread.NORM_PRIORITY); + ThreadGroup g = current.getThreadGroup(); + SecurityManager s = System.getSecurityManager(); + if (s != null) + threadAssertTrue(g == s.getThreadGroup()); + else + threadAssertTrue(g == egroup); + String name = current.getName(); + threadAssertTrue(name.endsWith("thread-1")); + } catch (SecurityException ok) { + // Also pass if not allowed to change setting + } } }; ExecutorService e = Executors.newSingleThreadExecutor(Executors.defaultThreadFactory()); @@ -354,13 +280,11 @@ public class ExecutorsTest extends JSR166TestCase{ e.execute(r); try { e.shutdown(); - } catch(SecurityException ok) { + } catch (SecurityException ok) { } try { Thread.sleep(SHORT_DELAY_MS); - } catch (Exception eX) { - unexpectedException(); } finally { joinPool(e); } @@ -371,61 +295,60 @@ public class ExecutorsTest extends JSR166TestCase{ * specified group, priority, daemon status, name, * access control context and context class loader */ - public void testPrivilegedThreadFactory() { - Policy savedPolicy = null; - try { - savedPolicy = Policy.getPolicy(); - AdjustablePolicy policy = new AdjustablePolicy(); - policy.addPermission(new RuntimePermission("getContextClassLoader")); - policy.addPermission(new RuntimePermission("setContextClassLoader")); - Policy.setPolicy(policy); - } catch (AccessControlException ok) { - return; - } - final ThreadGroup egroup = Thread.currentThread().getThreadGroup(); - final ClassLoader thisccl = Thread.currentThread().getContextClassLoader(); - final AccessControlContext thisacc = AccessController.getContext(); - Runnable r = new Runnable() { - public void run() { - try { - Thread current = Thread.currentThread(); - threadAssertTrue(!current.isDaemon()); - threadAssertTrue(current.getPriority() <= Thread.NORM_PRIORITY); - ThreadGroup g = current.getThreadGroup(); - SecurityManager s = System.getSecurityManager(); - if (s != null) - threadAssertTrue(g == s.getThreadGroup()); - else - threadAssertTrue(g == egroup); - String name = current.getName(); - threadAssertTrue(name.endsWith("thread-1")); - threadAssertTrue(thisccl == current.getContextClassLoader()); - threadAssertTrue(thisacc.equals(AccessController.getContext())); - } catch(SecurityException ok) { - // Also pass if not allowed to change settings - } - } - }; - ExecutorService e = Executors.newSingleThreadExecutor(Executors.privilegedThreadFactory()); - - Policy.setPolicy(savedPolicy); - e.execute(r); - try { - e.shutdown(); - } catch(SecurityException ok) { - } - try { - Thread.sleep(SHORT_DELAY_MS); - } catch (Exception ex) { - unexpectedException(); - } finally { - joinPool(e); + public void testPrivilegedThreadFactory() throws Exception { + Runnable r = new CheckedRunnable() { + public void realRun() throws Exception { + final ThreadGroup egroup = Thread.currentThread().getThreadGroup(); + final ClassLoader thisccl = Thread.currentThread().getContextClassLoader(); + final AccessControlContext thisacc = AccessController.getContext(); + Runnable r = new CheckedRunnable() { + public void realRun() { + Thread current = Thread.currentThread(); + assertTrue(!current.isDaemon()); + assertTrue(current.getPriority() <= Thread.NORM_PRIORITY); + ThreadGroup g = current.getThreadGroup(); + SecurityManager s = System.getSecurityManager(); + if (s != null) + assertTrue(g == s.getThreadGroup()); + else + assertTrue(g == egroup); + String name = current.getName(); + assertTrue(name.endsWith("thread-1")); + assertTrue(thisccl == current.getContextClassLoader()); + assertTrue(thisacc.equals(AccessController.getContext())); + }}; + ExecutorService e = Executors.newSingleThreadExecutor(Executors.privilegedThreadFactory()); + e.execute(r); + e.shutdown(); + Thread.sleep(SHORT_DELAY_MS); + joinPool(e); + }}; + + runWithPermissions(r, + new RuntimePermission("getClassLoader"), + new RuntimePermission("setContextClassLoader"), + new RuntimePermission("modifyThread")); + } + + boolean haveCCLPermissions() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + try { + sm.checkPermission(new RuntimePermission("setContextClassLoader")); + sm.checkPermission(new RuntimePermission("getClassLoader")); + } catch (AccessControlException e) { + return false; + } } - + return true; } void checkCCL() { - AccessController.getContext().checkPermission(new RuntimePermission("getContextClassLoader")); + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new RuntimePermission("setContextClassLoader")); + sm.checkPermission(new RuntimePermission("getClassLoader")); + } } class CheckCCL implements Callable<Object> { @@ -441,222 +364,192 @@ public class ExecutorsTest extends JSR166TestCase{ * privilegedCallableUsingCurrentClassLoader throws ACE */ public void testCreatePrivilegedCallableUsingCCLWithNoPrivs() { - Policy savedPolicy = null; - try { - savedPolicy = Policy.getPolicy(); - AdjustablePolicy policy = new AdjustablePolicy(); - Policy.setPolicy(policy); - } catch (AccessControlException ok) { - return; - } - - // Check if program still has too many permissions to run test - try { - checkCCL(); - // too many privileges to test; so return - Policy.setPolicy(savedPolicy); - return; - } catch(AccessControlException ok) { - } + Runnable r = new CheckedRunnable() { + public void realRun() throws Exception { + if (System.getSecurityManager() == null) + return; + try { + Executors.privilegedCallableUsingCurrentClassLoader(new NoOpCallable()); + shouldThrow(); + } catch (AccessControlException success) {} + }}; - try { - Callable task = Executors.privilegedCallableUsingCurrentClassLoader(new NoOpCallable()); - shouldThrow(); - } catch(AccessControlException success) { - } catch(Exception ex) { - unexpectedException(); - } - finally { - Policy.setPolicy(savedPolicy); - } + runWithoutPermissions(r); } /** * With class loader permissions, calling * privilegedCallableUsingCurrentClassLoader does not throw ACE */ - public void testprivilegedCallableUsingCCLWithPrivs() { - Policy savedPolicy = null; - try { - savedPolicy = Policy.getPolicy(); - AdjustablePolicy policy = new AdjustablePolicy(); - policy.addPermission(new RuntimePermission("getContextClassLoader")); - policy.addPermission(new RuntimePermission("setContextClassLoader")); - Policy.setPolicy(policy); - } catch (AccessControlException ok) { - return; - } + public void testprivilegedCallableUsingCCLWithPrivs() throws Exception { + Runnable r = new CheckedRunnable() { + public void realRun() throws Exception { + Executors.privilegedCallableUsingCurrentClassLoader + (new NoOpCallable()) + .call(); + }}; - try { - Callable task = Executors.privilegedCallableUsingCurrentClassLoader(new NoOpCallable()); - task.call(); - } catch(Exception ex) { - unexpectedException(); - } - finally { - Policy.setPolicy(savedPolicy); - } + runWithPermissions(r, + new RuntimePermission("getClassLoader"), + new RuntimePermission("setContextClassLoader")); } /** * Without permissions, calling privilegedCallable throws ACE */ - public void testprivilegedCallableWithNoPrivs() { - Callable task; - Policy savedPolicy = null; - AdjustablePolicy policy = null; - AccessControlContext noprivAcc = null; - try { - savedPolicy = Policy.getPolicy(); - policy = new AdjustablePolicy(); - Policy.setPolicy(policy); - noprivAcc = AccessController.getContext(); - task = Executors.privilegedCallable(new CheckCCL()); - Policy.setPolicy(savedPolicy); - } catch (AccessControlException ok) { - return; // program has too few permissions to set up test - } - - // Make sure that program doesn't have too many permissions - try { - AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - checkCCL(); - return null; - }}, noprivAcc); - // too many permssions; skip test - return; - } catch(AccessControlException ok) { - } - - try { - task.call(); - shouldThrow(); - } catch(AccessControlException success) { - } catch(Exception ex) { - unexpectedException(); - } + public void testprivilegedCallableWithNoPrivs() throws Exception { + Runnable r = new CheckedRunnable() { + public void realRun() throws Exception { + if (System.getSecurityManager() == null) + return; + Callable task = Executors.privilegedCallable(new CheckCCL()); + try { + task.call(); + shouldThrow(); + } catch (AccessControlException success) {} + }}; + + runWithoutPermissions(r); + + // It seems rather difficult to test that the + // AccessControlContext of the privilegedCallable is used + // instead of its caller. Below is a failed attempt to do + // that, which does not work because the AccessController + // cannot capture the internal state of the current Policy. + // It would be much more work to differentiate based on, + // e.g. CodeSource. + +// final AccessControlContext[] noprivAcc = new AccessControlContext[1]; +// final Callable[] task = new Callable[1]; + +// runWithPermissions +// (new CheckedRunnable() { +// public void realRun() { +// if (System.getSecurityManager() == null) +// return; +// noprivAcc[0] = AccessController.getContext(); +// task[0] = Executors.privilegedCallable(new CheckCCL()); +// try { +// AccessController.doPrivileged(new PrivilegedAction<Void>() { +// public Void run() { +// checkCCL(); +// return null; +// }}, noprivAcc[0]); +// shouldThrow(); +// } catch (AccessControlException success) {} +// }}); + +// runWithPermissions +// (new CheckedRunnable() { +// public void realRun() throws Exception { +// if (System.getSecurityManager() == null) +// return; +// // Verify that we have an underprivileged ACC +// try { +// AccessController.doPrivileged(new PrivilegedAction<Void>() { +// public Void run() { +// checkCCL(); +// return null; +// }}, noprivAcc[0]); +// shouldThrow(); +// } catch (AccessControlException success) {} + +// try { +// task[0].call(); +// shouldThrow(); +// } catch (AccessControlException success) {} +// }}, +// new RuntimePermission("getClassLoader"), +// new RuntimePermission("setContextClassLoader")); } /** * With permissions, calling privilegedCallable succeeds */ - public void testprivilegedCallableWithPrivs() { - Policy savedPolicy = null; - try { - savedPolicy = Policy.getPolicy(); - AdjustablePolicy policy = new AdjustablePolicy(); - policy.addPermission(new RuntimePermission("getContextClassLoader")); - policy.addPermission(new RuntimePermission("setContextClassLoader")); - Policy.setPolicy(policy); - } catch (AccessControlException ok) { - return; - } - - Callable task = Executors.privilegedCallable(new CheckCCL()); - try { - task.call(); - } catch(Exception ex) { - unexpectedException(); - } finally { - Policy.setPolicy(savedPolicy); - } + public void testprivilegedCallableWithPrivs() throws Exception { + Runnable r = new CheckedRunnable() { + public void realRun() throws Exception { + Executors.privilegedCallable(new CheckCCL()).call(); + }}; + + runWithPermissions(r, + new RuntimePermission("getClassLoader"), + new RuntimePermission("setContextClassLoader")); } /** * callable(Runnable) returns null when called - */ - public void testCallable1() { - try { - Callable c = Executors.callable(new NoOpRunnable()); - assertNull(c.call()); - } catch(Exception ex) { - unexpectedException(); - } - + */ + public void testCallable1() throws Exception { + Callable c = Executors.callable(new NoOpRunnable()); + assertNull(c.call()); } /** * callable(Runnable, result) returns result when called - */ - public void testCallable2() { - try { - Callable c = Executors.callable(new NoOpRunnable(), one); - assertEquals(one, c.call()); - } catch(Exception ex) { - unexpectedException(); - } + */ + public void testCallable2() throws Exception { + Callable c = Executors.callable(new NoOpRunnable(), one); + assertSame(one, c.call()); } /** * callable(PrivilegedAction) returns its result when called - */ - public void testCallable3() { - try { - Callable c = Executors.callable(new PrivilegedAction() { - public Object run() { return one; }}); - assertEquals(one, c.call()); - } catch(Exception ex) { - unexpectedException(); - } + */ + public void testCallable3() throws Exception { + Callable c = Executors.callable(new PrivilegedAction() { + public Object run() { return one; }}); + assertSame(one, c.call()); } /** * callable(PrivilegedExceptionAction) returns its result when called - */ - public void testCallable4() { - try { - Callable c = Executors.callable(new PrivilegedExceptionAction() { - public Object run() { return one; }}); - assertEquals(one, c.call()); - } catch(Exception ex) { - unexpectedException(); - } + */ + public void testCallable4() throws Exception { + Callable c = Executors.callable(new PrivilegedExceptionAction() { + public Object run() { return one; }}); + assertSame(one, c.call()); } /** * callable(null Runnable) throws NPE - */ + */ public void testCallableNPE1() { try { - Runnable r = null; - Callable c = Executors.callable(r); - } catch (NullPointerException success) { - } + Callable c = Executors.callable((Runnable) null); + shouldThrow(); + } catch (NullPointerException success) {} } /** * callable(null, result) throws NPE - */ + */ public void testCallableNPE2() { try { - Runnable r = null; - Callable c = Executors.callable(r, one); - } catch (NullPointerException success) { - } + Callable c = Executors.callable((Runnable) null, one); + shouldThrow(); + } catch (NullPointerException success) {} } /** * callable(null PrivilegedAction) throws NPE - */ + */ public void testCallableNPE3() { try { - PrivilegedAction r = null; - Callable c = Executors.callable(r); - } catch (NullPointerException success) { - } + Callable c = Executors.callable((PrivilegedAction) null); + shouldThrow(); + } catch (NullPointerException success) {} } /** * callable(null PrivilegedExceptionAction) throws NPE - */ + */ public void testCallableNPE4() { try { - PrivilegedExceptionAction r = null; - Callable c = Executors.callable(r); - } catch (NullPointerException success) { - } + Callable c = Executors.callable((PrivilegedExceptionAction) null); + shouldThrow(); + } catch (NullPointerException success) {} } diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/FutureTaskTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/FutureTaskTest.java index 2635054..b1f9f40 100755 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/FutureTaskTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/FutureTaskTest.java @@ -2,14 +2,15 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.concurrent.*; +import static java.util.concurrent.TimeUnit.MILLISECONDS; import java.util.*; public class FutureTaskTest extends JSR166TestCase { @@ -34,9 +35,7 @@ public class FutureTaskTest extends JSR166TestCase { try { FutureTask task = new FutureTask(null); shouldThrow(); - } - catch(NullPointerException success) { - } + } catch (NullPointerException success) {} } /** @@ -46,16 +45,14 @@ public class FutureTaskTest extends JSR166TestCase { try { FutureTask task = new FutureTask(null, Boolean.TRUE); shouldThrow(); - } - catch(NullPointerException success) { - } + } catch (NullPointerException success) {} } /** * isDone is true when a task completes */ public void testIsDone() { - FutureTask task = new FutureTask( new NoOpCallable()); + FutureTask task = new FutureTask(new NoOpCallable()); task.run(); assertTrue(task.isDone()); assertFalse(task.isCancelled()); @@ -86,34 +83,24 @@ public class FutureTaskTest extends JSR166TestCase { /** * setting value causes get to return it */ - public void testSet() { + public void testSet() throws Exception { PublicFutureTask task = new PublicFutureTask(new NoOpCallable()); task.set(one); - try { - assertEquals(task.get(), one); - } - catch(Exception e) { - unexpectedException(); - } + assertSame(task.get(), one); } /** * setException causes get to throw ExecutionException */ - public void testSetException() { + public void testSetException() throws Exception { Exception nse = new NoSuchElementException(); PublicFutureTask task = new PublicFutureTask(new NoOpCallable()); task.setException(nse); try { Object x = task.get(); shouldThrow(); - } - catch(ExecutionException ee) { - Throwable cause = ee.getCause(); - assertEquals(cause, nse); - } - catch(Exception e) { - unexpectedException(); + } catch (ExecutionException success) { + assertSame(success.getCause(), nse); } } @@ -121,7 +108,7 @@ public class FutureTaskTest extends JSR166TestCase { * Cancelling before running succeeds */ public void testCancelBeforeRun() { - FutureTask task = new FutureTask( new NoOpCallable()); + FutureTask task = new FutureTask(new NoOpCallable()); assertTrue(task.cancel(false)); task.run(); assertTrue(task.isDone()); @@ -132,7 +119,7 @@ public class FutureTaskTest extends JSR166TestCase { * Cancel(true) before run succeeds */ public void testCancelBeforeRun2() { - FutureTask task = new FutureTask( new NoOpCallable()); + FutureTask task = new FutureTask(new NoOpCallable()); assertTrue(task.cancel(true)); task.run(); assertTrue(task.isDone()); @@ -143,7 +130,7 @@ public class FutureTaskTest extends JSR166TestCase { * cancel of a completed task fails */ public void testCancelAfterRun() { - FutureTask task = new FutureTask( new NoOpCallable()); + FutureTask task = new FutureTask(new NoOpCallable()); task.run(); assertFalse(task.cancel(false)); assertTrue(task.isDone()); @@ -153,320 +140,219 @@ public class FutureTaskTest extends JSR166TestCase { /** * cancel(true) interrupts a running task */ - public void testCancelInterrupt() { - FutureTask task = new FutureTask( new Callable() { - public Object call() { - try { - Thread.sleep(MEDIUM_DELAY_MS); - threadShouldThrow(); - } - catch (InterruptedException success) {} + public void testCancelInterrupt() throws InterruptedException { + final FutureTask task = + new FutureTask(new CheckedInterruptedCallable<Object>() { + public Object realCall() throws InterruptedException { + Thread.sleep(SMALL_DELAY_MS); return Boolean.TRUE; - } }); - Thread t = new Thread(task); + }}); + + Thread t = new Thread(task); t.start(); - - try { - Thread.sleep(SHORT_DELAY_MS); - assertTrue(task.cancel(true)); - t.join(); - assertTrue(task.isDone()); - assertTrue(task.isCancelled()); - } catch(InterruptedException e){ - unexpectedException(); - } + Thread.sleep(SHORT_DELAY_MS); + assertTrue(task.cancel(true)); + t.join(); + assertTrue(task.isDone()); + assertTrue(task.isCancelled()); } /** * cancel(false) does not interrupt a running task */ - public void testCancelNoInterrupt() { - FutureTask task = new FutureTask( new Callable() { - public Object call() { - try { - Thread.sleep(MEDIUM_DELAY_MS); - } - catch (InterruptedException success) { - threadFail("should not interrupt"); - } + public void testCancelNoInterrupt() throws InterruptedException { + final FutureTask task = + new FutureTask(new CheckedCallable<Object>() { + public Object realCall() throws InterruptedException { + Thread.sleep(MEDIUM_DELAY_MS); return Boolean.TRUE; - } }); - Thread t = new Thread(task); + }}); + + Thread t = new Thread(task); t.start(); - - try { - Thread.sleep(SHORT_DELAY_MS); - assertTrue(task.cancel(false)); - t.join(); - assertTrue(task.isDone()); - assertTrue(task.isCancelled()); - } catch(InterruptedException e){ - unexpectedException(); - } + Thread.sleep(SHORT_DELAY_MS); + assertTrue(task.cancel(false)); + t.join(); + assertTrue(task.isDone()); + assertTrue(task.isCancelled()); } /** * set in one thread causes get in another thread to retrieve value */ - public void testGet1() { - final FutureTask ft = new FutureTask(new Callable() { - public Object call() { - try { - Thread.sleep(MEDIUM_DELAY_MS); - } catch(InterruptedException e){ - threadUnexpectedException(); - } + public void testGet1() throws InterruptedException { + final FutureTask ft = + new FutureTask(new CheckedCallable<Object>() { + public Object realCall() throws InterruptedException { return Boolean.TRUE; - } - }); - Thread t = new Thread(new Runnable() { - public void run() { - try { - ft.get(); - } catch(Exception e){ - threadUnexpectedException(); - } - } - }); - try { - assertFalse(ft.isDone()); - assertFalse(ft.isCancelled()); - t.start(); - Thread.sleep(SHORT_DELAY_MS); - ft.run(); - t.join(); - assertTrue(ft.isDone()); - assertFalse(ft.isCancelled()); - } catch(InterruptedException e){ - unexpectedException(); - - } + }}); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws Exception { + assertSame(Boolean.TRUE, ft.get()); + }}); + + assertFalse(ft.isDone()); + assertFalse(ft.isCancelled()); + t.start(); + Thread.sleep(SHORT_DELAY_MS); + ft.run(); + t.join(); + assertTrue(ft.isDone()); + assertFalse(ft.isCancelled()); } /** * set in one thread causes timed get in another thread to retrieve value */ - public void testTimedGet1() { - final FutureTask ft = new FutureTask(new Callable() { - public Object call() { - try { - Thread.sleep(MEDIUM_DELAY_MS); - } catch(InterruptedException e){ - threadUnexpectedException(); - } + public void testTimedGet1() throws InterruptedException { + final FutureTask ft = + new FutureTask(new CheckedCallable<Object>() { + public Object realCall() throws InterruptedException { return Boolean.TRUE; - } - }); - Thread t = new Thread(new Runnable() { - public void run() { - try { - ft.get(SHORT_DELAY_MS, TimeUnit.MILLISECONDS); - } catch(TimeoutException success) { - } catch(Exception e){ - threadUnexpectedException(); - } - } - }); - try { - assertFalse(ft.isDone()); - assertFalse(ft.isCancelled()); - t.start(); - ft.run(); - t.join(); - assertTrue(ft.isDone()); - assertFalse(ft.isCancelled()); - } catch(InterruptedException e){ - unexpectedException(); - - } + }}); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws Exception { + assertSame(Boolean.TRUE, ft.get(SMALL_DELAY_MS, MILLISECONDS)); + }}); + + assertFalse(ft.isDone()); + assertFalse(ft.isCancelled()); + t.start(); + Thread.sleep(SHORT_DELAY_MS); + ft.run(); + t.join(); + assertTrue(ft.isDone()); + assertFalse(ft.isCancelled()); } /** * Cancelling a task causes timed get in another thread to throw CancellationException */ - public void testTimedGet_Cancellation() { - final FutureTask ft = new FutureTask(new Callable() { - public Object call() { - try { - Thread.sleep(SMALL_DELAY_MS); - threadShouldThrow(); - } catch(InterruptedException e) { - } + public void testTimedGet_Cancellation() throws InterruptedException { + final FutureTask ft = + new FutureTask(new CheckedInterruptedCallable<Object>() { + public Object realCall() throws InterruptedException { + Thread.sleep(SMALL_DELAY_MS); return Boolean.TRUE; - } - }); - try { - Thread t1 = new Thread(new Runnable() { - public void run() { - try { - ft.get(MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); - threadShouldThrow(); - } catch(CancellationException success) {} - catch(Exception e){ - threadUnexpectedException(); - } - } - }); - Thread t2 = new Thread(ft); - t1.start(); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - ft.cancel(true); - t1.join(); - t2.join(); - } catch(InterruptedException ie){ - unexpectedException(); - } + }}); + + Thread t1 = new ThreadShouldThrow(CancellationException.class) { + public void realRun() throws Exception { + ft.get(MEDIUM_DELAY_MS, MILLISECONDS); + }}; + Thread t2 = new Thread(ft); + t1.start(); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + ft.cancel(true); + t1.join(); + t2.join(); } /** * Cancelling a task causes get in another thread to throw CancellationException */ - public void testGet_Cancellation() { - final FutureTask ft = new FutureTask(new Callable() { - public Object call() { - try { - Thread.sleep(MEDIUM_DELAY_MS); - threadShouldThrow(); - } catch(InterruptedException e){ - } + public void testGet_Cancellation() throws InterruptedException { + final FutureTask ft = + new FutureTask(new CheckedInterruptedCallable<Object>() { + public Object realCall() throws InterruptedException { + Thread.sleep(SMALL_DELAY_MS); return Boolean.TRUE; - } - }); - try { - Thread t1 = new Thread(new Runnable() { - public void run() { - try { - ft.get(); - threadShouldThrow(); - } catch(CancellationException success){ - } - catch(Exception e){ - threadUnexpectedException(); - } - } - }); - Thread t2 = new Thread(ft); - t1.start(); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - ft.cancel(true); - t1.join(); - t2.join(); - } catch(InterruptedException success){ - unexpectedException(); - } + }}); + Thread t1 = new ThreadShouldThrow(CancellationException.class) { + public void realRun() throws Exception { + ft.get(); + }}; + + Thread t2 = new Thread(ft); + t1.start(); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + ft.cancel(true); + t1.join(); + t2.join(); } - + /** * A runtime exception in task causes get to throw ExecutionException */ - public void testGet_ExecutionException() { + public void testGet_ExecutionException() throws InterruptedException { final FutureTask ft = new FutureTask(new Callable() { - public Object call() { - int i = 5/0; - return Boolean.TRUE; - } - }); + public Object call() { + return 5/0; + }}); + + ft.run(); try { - ft.run(); ft.get(); shouldThrow(); - } catch(ExecutionException success){ - } - catch(Exception e){ - unexpectedException(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof ArithmeticException); } } - + /** * A runtime exception in task causes timed get to throw ExecutionException */ - public void testTimedGet_ExecutionException2() { + public void testTimedGet_ExecutionException2() throws Exception { final FutureTask ft = new FutureTask(new Callable() { - public Object call() { - int i = 5/0; - return Boolean.TRUE; - } - }); + public Object call() { + return 5/0; + }}); + + ft.run(); try { - ft.run(); - ft.get(SHORT_DELAY_MS, TimeUnit.MILLISECONDS); + ft.get(SHORT_DELAY_MS, MILLISECONDS); shouldThrow(); - } catch(ExecutionException success) { - } catch(TimeoutException success) { } // unlikely but OK - catch(Exception e){ - unexpectedException(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof ArithmeticException); } } - + /** * Interrupting a waiting get causes it to throw InterruptedException */ - public void testGet_InterruptedException() { + public void testGet_InterruptedException() throws InterruptedException { final FutureTask ft = new FutureTask(new NoOpCallable()); - Thread t = new Thread(new Runnable() { - public void run() { - try { - ft.get(); - threadShouldThrow(); - } catch(InterruptedException success){ - } catch(Exception e){ - threadUnexpectedException(); - } - } - }); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } catch(Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws Exception { + ft.get(); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } /** * Interrupting a waiting timed get causes it to throw InterruptedException */ - public void testTimedGet_InterruptedException2() { + public void testTimedGet_InterruptedException2() throws InterruptedException { final FutureTask ft = new FutureTask(new NoOpCallable()); - Thread t = new Thread(new Runnable() { - public void run() { - try { - ft.get(LONG_DELAY_MS,TimeUnit.MILLISECONDS); - threadShouldThrow(); - } catch(InterruptedException success){} - catch(Exception e){ - threadUnexpectedException(); - } - } - }); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } catch(Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws Exception { + ft.get(LONG_DELAY_MS,MILLISECONDS); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } - + /** * A timed out timed get throws TimeoutException */ - public void testGet_TimeoutException() { + public void testGet_TimeoutException() throws Exception { try { FutureTask ft = new FutureTask(new NoOpCallable()); - ft.get(1,TimeUnit.MILLISECONDS); + ft.get(1,MILLISECONDS); shouldThrow(); - } catch(TimeoutException success){} - catch(Exception success){ - unexpectedException(); - } + } catch (TimeoutException success) {} } - + } diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/JSR166TestCase.java b/concurrent/src/test/java/tests/api/java/util/concurrent/JSR166TestCase.java index 6acd363..b764855 100644 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/JSR166TestCase.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/JSR166TestCase.java @@ -6,11 +6,12 @@ * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.*; import java.util.concurrent.*; +import static java.util.concurrent.TimeUnit.MILLISECONDS; import java.io.*; import java.security.*; @@ -88,71 +89,91 @@ import java.security.*; * </ul> */ public class JSR166TestCase extends TestCase { - /** - * Runs all JSR166 unit tests using junit.textui.TestRunner - */ - public static void main (String[] args) { - int iters = 1; - if (args.length > 0) - iters = Integer.parseInt(args[0]); - Test s = suite(); - for (int i = 0; i < iters; ++i) { - // junit.textui.TestRunner.run (s); android-changed - System.gc(); - System.runFinalization(); - } - System.exit(0); - } + private static final boolean useSecurityManager = + Boolean.getBoolean("jsr166.useSecurityManager"); + + // BEGIN android-removed + // /** + // * Runs all JSR166 unit tests using junit.textui.TestRunner + // */ + // public static void main(String[] args) { + // if (useSecurityManager) { + // System.err.println("Setting a permissive security manager"); + // Policy.setPolicy(permissivePolicy()); + // System.setSecurityManager(new SecurityManager()); + // } + // int iters = 1; + // if (args.length > 0) + // iters = Integer.parseInt(args[0]); + // Test s = suite(); + // for (int i = 0; i < iters; ++i) { + // junit.textui.TestRunner.run(s); + // System.gc(); + // System.runFinalization(); + // } + // System.exit(0); + // } + // END android-removed /** * Collects all JSR166 unit tests as one suite */ - public static Test suite ( ) { - // BEGIN android-changed + public static Test suite() { TestSuite suite = new TestSuite("JSR166 Unit Tests"); - suite.addTest(AbstractExecutorServiceTest.suite()); - suite.addTest(AbstractQueueTest.suite()); - suite.addTest(AbstractQueuedSynchronizerTest.suite()); - suite.addTest(ArrayBlockingQueueTest.suite()); - suite.addTest(AtomicBooleanTest.suite()); - suite.addTest(AtomicIntegerArrayTest.suite()); - suite.addTest(AtomicIntegerFieldUpdaterTest.suite()); - suite.addTest(AtomicIntegerTest.suite()); - suite.addTest(AtomicLongArrayTest.suite()); - suite.addTest(AtomicLongFieldUpdaterTest.suite()); - suite.addTest(AtomicLongTest.suite()); - suite.addTest(AtomicMarkableReferenceTest.suite()); - suite.addTest(AtomicReferenceArrayTest.suite()); - suite.addTest(AtomicReferenceFieldUpdaterTest.suite()); - suite.addTest(AtomicReferenceTest.suite()); - suite.addTest(AtomicStampedReferenceTest.suite()); - suite.addTest(ConcurrentHashMapTest.suite()); - suite.addTest(ConcurrentLinkedQueueTest.suite()); - suite.addTest(CopyOnWriteArrayListTest.suite()); - suite.addTest(CopyOnWriteArraySetTest.suite()); - suite.addTest(CountDownLatchTest.suite()); - suite.addTest(CyclicBarrierTest.suite()); - suite.addTest(DelayQueueTest.suite()); - suite.addTest(ExchangerTest.suite()); - suite.addTest(ExecutorsTest.suite()); - suite.addTest(ExecutorCompletionServiceTest.suite()); - suite.addTest(FutureTaskTest.suite()); - suite.addTest(LinkedBlockingQueueTest.suite()); - suite.addTest(LinkedListTest.suite()); - suite.addTest(LockSupportTest.suite()); - suite.addTest(PriorityBlockingQueueTest.suite()); - suite.addTest(PriorityQueueTest.suite()); - suite.addTest(ReentrantLockTest.suite()); - suite.addTest(ReentrantReadWriteLockTest.suite()); - suite.addTest(ScheduledExecutorTest.suite()); - suite.addTest(SemaphoreTest.suite()); - suite.addTest(SynchronousQueueTest.suite()); - suite.addTest(SystemTest.suite()); - suite.addTest(ThreadLocalTest.suite()); - suite.addTest(ThreadPoolExecutorTest.suite()); - suite.addTest(ThreadTest.suite()); - suite.addTest(TimeUnitTest.suite()); - // END android-changed + + suite.addTest(new TestSuite(AbstractExecutorServiceTest.class)); + suite.addTest(new TestSuite(AbstractQueueTest.class)); + suite.addTest(new TestSuite(AbstractQueuedSynchronizerTest.class)); + suite.addTest(new TestSuite(AbstractQueuedLongSynchronizerTest.class)); + suite.addTest(new TestSuite(ArrayBlockingQueueTest.class)); + suite.addTest(new TestSuite(ArrayDequeTest.class)); + suite.addTest(new TestSuite(AtomicBooleanTest.class)); + suite.addTest(new TestSuite(AtomicIntegerArrayTest.class)); + suite.addTest(new TestSuite(AtomicIntegerFieldUpdaterTest.class)); + suite.addTest(new TestSuite(AtomicIntegerTest.class)); + suite.addTest(new TestSuite(AtomicLongArrayTest.class)); + suite.addTest(new TestSuite(AtomicLongFieldUpdaterTest.class)); + suite.addTest(new TestSuite(AtomicLongTest.class)); + suite.addTest(new TestSuite(AtomicMarkableReferenceTest.class)); + suite.addTest(new TestSuite(AtomicReferenceArrayTest.class)); + suite.addTest(new TestSuite(AtomicReferenceFieldUpdaterTest.class)); + suite.addTest(new TestSuite(AtomicReferenceTest.class)); + suite.addTest(new TestSuite(AtomicStampedReferenceTest.class)); + suite.addTest(new TestSuite(ConcurrentHashMapTest.class)); + suite.addTest(new TestSuite(ConcurrentLinkedQueueTest.class)); + suite.addTest(new TestSuite(ConcurrentSkipListMapTest.class)); + suite.addTest(new TestSuite(ConcurrentSkipListSubMapTest.class)); + suite.addTest(new TestSuite(ConcurrentSkipListSetTest.class)); + suite.addTest(new TestSuite(ConcurrentSkipListSubSetTest.class)); + suite.addTest(new TestSuite(CopyOnWriteArrayListTest.class)); + suite.addTest(new TestSuite(CopyOnWriteArraySetTest.class)); + suite.addTest(new TestSuite(CountDownLatchTest.class)); + suite.addTest(new TestSuite(CyclicBarrierTest.class)); + suite.addTest(new TestSuite(DelayQueueTest.class)); + suite.addTest(new TestSuite(EntryTest.class)); + suite.addTest(new TestSuite(ExchangerTest.class)); + suite.addTest(new TestSuite(ExecutorsTest.class)); + suite.addTest(new TestSuite(ExecutorCompletionServiceTest.class)); + suite.addTest(new TestSuite(FutureTaskTest.class)); + suite.addTest(new TestSuite(LinkedBlockingDequeTest.class)); + suite.addTest(new TestSuite(LinkedBlockingQueueTest.class)); + suite.addTest(new TestSuite(LinkedListTest.class)); + suite.addTest(new TestSuite(LockSupportTest.class)); + suite.addTest(new TestSuite(PriorityBlockingQueueTest.class)); + suite.addTest(new TestSuite(PriorityQueueTest.class)); + suite.addTest(new TestSuite(ReentrantLockTest.class)); + suite.addTest(new TestSuite(ReentrantReadWriteLockTest.class)); + suite.addTest(new TestSuite(ScheduledExecutorTest.class)); + suite.addTest(new TestSuite(ScheduledExecutorSubclassTest.class)); + suite.addTest(new TestSuite(SemaphoreTest.class)); + suite.addTest(new TestSuite(SynchronousQueueTest.class)); + suite.addTest(new TestSuite(SystemTest.class)); + suite.addTest(new TestSuite(ThreadLocalTest.class)); + suite.addTest(new TestSuite(ThreadPoolExecutorTest.class)); + suite.addTest(new TestSuite(ThreadPoolExecutorSubclassTest.class)); + suite.addTest(new TestSuite(ThreadTest.class)); + suite.addTest(new TestSuite(TimeUnitTest.class)); + return suite; } @@ -178,7 +199,7 @@ public class JSR166TestCase extends TestCase { /** * Sets delays as multiples of SHORT_DELAY. */ - protected void setDelays() { + protected void setDelays() { SHORT_DELAY_MS = getShortDelay(); SMALL_DELAY_MS = SHORT_DELAY_MS * 5; MEDIUM_DELAY_MS = SHORT_DELAY_MS * 10; @@ -272,13 +293,16 @@ public class JSR166TestCase extends TestCase { * threadFail with message "should throw exception" */ public void threadShouldThrow() { - try { - threadFailed = true; - fail("should throw exception"); - } catch (AssertionFailedError e) { - e.printStackTrace(); - throw e; - } + threadFailed = true; + fail("should throw exception"); + } + + /** + * threadFail with message "should throw" + exceptionName + */ + public void threadShouldThrow(String exceptionName) { + threadFailed = true; + fail("should throw " + exceptionName); } /** @@ -304,11 +328,11 @@ public class JSR166TestCase extends TestCase { public void joinPool(ExecutorService exec) { try { exec.shutdown(); - assertTrue(exec.awaitTermination(LONG_DELAY_MS, TimeUnit.MILLISECONDS)); - } catch(SecurityException ok) { + assertTrue(exec.awaitTermination(LONG_DELAY_MS, MILLISECONDS)); + } catch (SecurityException ok) { // Allowed in case test doesn't have privs - } catch(InterruptedException ie) { - fail("Unexpected exception"); + } catch (InterruptedException ie) { + fail("Unexpected InterruptedException"); } } @@ -321,46 +345,105 @@ public class JSR166TestCase extends TestCase { } /** + * fail with message "should throw " + exceptionName + */ + public void shouldThrow(String exceptionName) { + fail("Should throw " + exceptionName); + } + + /** * fail with message "Unexpected exception" */ public void unexpectedException() { fail("Unexpected exception"); } + /** + * fail with message "Unexpected exception", with argument + */ + public void unexpectedException(Throwable ex) { + ex.printStackTrace(); + fail("Unexpected exception: " + ex); + } + /** * The number of elements to place in collections, arrays, etc. */ - static final int SIZE = 20; + public static final int SIZE = 20; // Some convenient Integer constants - static final Integer zero = new Integer(0); - static final Integer one = new Integer(1); - static final Integer two = new Integer(2); - static final Integer three = new Integer(3); - static final Integer four = new Integer(4); - static final Integer five = new Integer(5); - static final Integer six = new Integer(6); - static final Integer seven = new Integer(7); - static final Integer eight = new Integer(8); - static final Integer nine = new Integer(9); - static final Integer m1 = new Integer(-1); - static final Integer m2 = new Integer(-2); - static final Integer m3 = new Integer(-3); - static final Integer m4 = new Integer(-4); - static final Integer m5 = new Integer(-5); - static final Integer m6 = new Integer(-6); - static final Integer m10 = new Integer(-10); + public static final Integer zero = new Integer(0); + public static final Integer one = new Integer(1); + public static final Integer two = new Integer(2); + public static final Integer three = new Integer(3); + public static final Integer four = new Integer(4); + public static final Integer five = new Integer(5); + public static final Integer six = new Integer(6); + public static final Integer seven = new Integer(7); + public static final Integer eight = new Integer(8); + public static final Integer nine = new Integer(9); + public static final Integer m1 = new Integer(-1); + public static final Integer m2 = new Integer(-2); + public static final Integer m3 = new Integer(-3); + public static final Integer m4 = new Integer(-4); + public static final Integer m5 = new Integer(-5); + public static final Integer m6 = new Integer(-6); + public static final Integer m10 = new Integer(-10); + + + /** + * Runs Runnable r with a security policy that permits precisely + * the specified permissions. If there is no current security + * manager, the runnable is run twice, both with and without a + * security manager. We require that any security manager permit + * getPolicy/setPolicy. + */ + public void runWithPermissions(Runnable r, Permission... permissions) { + SecurityManager sm = System.getSecurityManager(); + if (sm == null) { + r.run(); + Policy savedPolicy = Policy.getPolicy(); + try { + Policy.setPolicy(permissivePolicy()); + System.setSecurityManager(new SecurityManager()); + runWithPermissions(r, permissions); + } finally { + System.setSecurityManager(null); + Policy.setPolicy(savedPolicy); + } + } else { + Policy savedPolicy = Policy.getPolicy(); + AdjustablePolicy policy = new AdjustablePolicy(permissions); + Policy.setPolicy(policy); + try { + r.run(); + } finally { + policy.addPermission(new SecurityPermission("setPolicy")); + Policy.setPolicy(savedPolicy); + } + } + } + + /** + * Runs a runnable without any permissions. + */ + public void runWithoutPermissions(Runnable r) { + runWithPermissions(r); + } /** * A security policy where new permissions can be dynamically added * or all cleared. */ - static class AdjustablePolicy extends java.security.Policy { + public static class AdjustablePolicy extends java.security.Policy { Permissions perms = new Permissions(); - AdjustablePolicy() { } + AdjustablePolicy(Permission... permissions) { + for (Permission permission : permissions) + perms.add(permission); + } void addPermission(Permission perm) { perms.add(perm); } void clearPermissions() { perms = new Permissions(); } public PermissionCollection getPermissions(CodeSource cs) { @@ -375,197 +458,293 @@ public class JSR166TestCase extends TestCase { public void refresh() {} } + /** + * Returns a policy containing all the permissions we ever need. + */ + public static Policy permissivePolicy() { + return new AdjustablePolicy + // Permissions j.u.c. needs directly + (new RuntimePermission("modifyThread"), + new RuntimePermission("getClassLoader"), + new RuntimePermission("setContextClassLoader"), + // Permissions needed to change permissions! + new SecurityPermission("getPolicy"), + new SecurityPermission("setPolicy"), + new RuntimePermission("setSecurityManager"), + // Permissions needed by the junit test harness + new RuntimePermission("accessDeclaredMembers"), + new PropertyPermission("*", "read"), + new java.io.FilePermission("<<ALL FILES>>", "read")); + } - // Some convenient Runnable classes - - static class NoOpRunnable implements Runnable { - public void run() {} + /** + * Sleep until the timeout has elapsed, or interrupted. + * Does <em>NOT</em> throw InterruptedException. + */ + void sleepTillInterrupted(long timeoutMillis) { + try { + Thread.sleep(timeoutMillis); + } catch (InterruptedException wakeup) {} } - static class NoOpCallable implements Callable { - public Object call() { return Boolean.TRUE; } + /** + * Returns a new started Thread running the given runnable. + */ + Thread newStartedThread(Runnable runnable) { + Thread t = new Thread(runnable); + t.start(); + return t; } - static final String TEST_STRING = "a test string"; + // Some convenient Runnable classes - static class StringTask implements Callable<String> { - public String call() { return TEST_STRING; } - } + public abstract class CheckedRunnable implements Runnable { + protected abstract void realRun() throws Throwable; - static class NPETask implements Callable<String> { - public String call() { throw new NullPointerException(); } + public final void run() { + try { + realRun(); + } catch (Throwable t) { + threadUnexpectedException(t); + } + } } - static class CallableOne implements Callable<Integer> { - public Integer call() { return one; } - } + public abstract class RunnableShouldThrow implements Runnable { + protected abstract void realRun() throws Throwable; - class ShortRunnable implements Runnable { - public void run() { + final Class<?> exceptionClass; + + <T extends Throwable> RunnableShouldThrow(Class<T> exceptionClass) { + this.exceptionClass = exceptionClass; + } + + public final void run() { try { - Thread.sleep(SHORT_DELAY_MS); - } - catch(Exception e) { - threadUnexpectedException(e); + realRun(); + threadShouldThrow(exceptionClass.getSimpleName()); + } catch (Throwable t) { + if (! exceptionClass.isInstance(t)) + threadUnexpectedException(t); } } } - class ShortInterruptedRunnable implements Runnable { - public void run() { + public abstract class ThreadShouldThrow extends Thread { + protected abstract void realRun() throws Throwable; + + final Class<?> exceptionClass; + + <T extends Throwable> ThreadShouldThrow(Class<T> exceptionClass) { + this.exceptionClass = exceptionClass; + } + + public final void run() { try { - Thread.sleep(SHORT_DELAY_MS); - threadShouldThrow(); - } - catch(InterruptedException success) { + realRun(); + threadShouldThrow(exceptionClass.getSimpleName()); + } catch (Throwable t) { + if (! exceptionClass.isInstance(t)) + threadUnexpectedException(t); } } } - class SmallRunnable implements Runnable { - public void run() { + public abstract class CheckedInterruptedRunnable implements Runnable { + protected abstract void realRun() throws Throwable; + + public final void run() { try { - Thread.sleep(SMALL_DELAY_MS); - } - catch(Exception e) { - threadUnexpectedException(e); + realRun(); + threadShouldThrow("InterruptedException"); + } catch (InterruptedException success) { + } catch (Throwable t) { + threadUnexpectedException(t); } } } - class SmallPossiblyInterruptedRunnable implements Runnable { - public void run() { + public abstract class CheckedCallable<T> implements Callable<T> { + protected abstract T realCall() throws Throwable; + + public final T call() { try { - Thread.sleep(SMALL_DELAY_MS); - } - catch(Exception e) { + return realCall(); + } catch (Throwable t) { + threadUnexpectedException(t); } + return null; } } - class SmallCallable implements Callable { - public Object call() { + public abstract class CheckedInterruptedCallable<T> implements Callable<T> { + protected abstract T realCall() throws Throwable; + + public final T call() { try { - Thread.sleep(SMALL_DELAY_MS); - } - catch(Exception e) { - threadUnexpectedException(e); + T result = realCall(); + threadShouldThrow("InterruptedException"); + return result; + } catch (InterruptedException success) { + } catch (Throwable t) { + threadUnexpectedException(t); } - return Boolean.TRUE; + return null; } } - class SmallInterruptedRunnable implements Runnable { - public void run() { + public static class NoOpRunnable implements Runnable { + public void run() {} + } + + public static class NoOpCallable implements Callable { + public Object call() { return Boolean.TRUE; } + } + + public static final String TEST_STRING = "a test string"; + + public static class StringTask implements Callable<String> { + public String call() { return TEST_STRING; } + } + + public Callable<String> latchAwaitingStringTask(final CountDownLatch latch) { + return new CheckedCallable<String>() { + public String realCall() { + try { + latch.await(); + } catch (InterruptedException quittingTime) {} + return TEST_STRING; + }}; + } + + public static class NPETask implements Callable<String> { + public String call() { throw new NullPointerException(); } + } + + public static class CallableOne implements Callable<Integer> { + public Integer call() { return one; } + } + + public class ShortRunnable extends CheckedRunnable { + protected void realRun() throws Throwable { + Thread.sleep(SHORT_DELAY_MS); + } + } + + public class ShortInterruptedRunnable extends CheckedInterruptedRunnable { + protected void realRun() throws InterruptedException { + Thread.sleep(SHORT_DELAY_MS); + } + } + + public class SmallRunnable extends CheckedRunnable { + protected void realRun() throws Throwable { + Thread.sleep(SMALL_DELAY_MS); + } + } + + public class SmallPossiblyInterruptedRunnable extends CheckedRunnable { + protected void realRun() { try { Thread.sleep(SMALL_DELAY_MS); - threadShouldThrow(); - } - catch(InterruptedException success) { - } + } catch (InterruptedException ok) {} } } + public class SmallCallable extends CheckedCallable { + protected Object realCall() throws InterruptedException { + Thread.sleep(SMALL_DELAY_MS); + return Boolean.TRUE; + } + } - class MediumRunnable implements Runnable { - public void run() { - try { - Thread.sleep(MEDIUM_DELAY_MS); - } - catch(Exception e) { - threadUnexpectedException(e); - } + public class SmallInterruptedRunnable extends CheckedInterruptedRunnable { + protected void realRun() throws InterruptedException { + Thread.sleep(SMALL_DELAY_MS); } } - class MediumInterruptedRunnable implements Runnable { - public void run() { - try { - Thread.sleep(MEDIUM_DELAY_MS); - threadShouldThrow(); - } - catch(InterruptedException success) { - } + public class MediumRunnable extends CheckedRunnable { + protected void realRun() throws Throwable { + Thread.sleep(MEDIUM_DELAY_MS); } } - class MediumPossiblyInterruptedRunnable implements Runnable { - public void run() { + public class MediumInterruptedRunnable extends CheckedInterruptedRunnable { + protected void realRun() throws InterruptedException { + Thread.sleep(MEDIUM_DELAY_MS); + } + } + + public class MediumPossiblyInterruptedRunnable extends CheckedRunnable { + protected void realRun() { try { Thread.sleep(MEDIUM_DELAY_MS); - } - catch(InterruptedException success) { - } + } catch (InterruptedException ok) {} } } - class LongPossiblyInterruptedRunnable implements Runnable { - public void run() { + public class LongPossiblyInterruptedRunnable extends CheckedRunnable { + protected void realRun() { try { Thread.sleep(LONG_DELAY_MS); - } - catch(InterruptedException success) { - } + } catch (InterruptedException ok) {} } } /** * For use as ThreadFactory in constructors */ - static class SimpleThreadFactory implements ThreadFactory{ - public Thread newThread(Runnable r){ + public static class SimpleThreadFactory implements ThreadFactory { + public Thread newThread(Runnable r) { return new Thread(r); } } - static class TrackedShortRunnable implements Runnable { - volatile boolean done = false; + public static class TrackedShortRunnable implements Runnable { + public volatile boolean done = false; public void run() { try { Thread.sleep(SMALL_DELAY_MS); done = true; - } catch(Exception e){ - } + } catch (InterruptedException ok) {} } } - static class TrackedMediumRunnable implements Runnable { - volatile boolean done = false; + public static class TrackedMediumRunnable implements Runnable { + public volatile boolean done = false; public void run() { try { Thread.sleep(MEDIUM_DELAY_MS); done = true; - } catch(Exception e){ - } + } catch (InterruptedException ok) {} } } - static class TrackedLongRunnable implements Runnable { - volatile boolean done = false; + public static class TrackedLongRunnable implements Runnable { + public volatile boolean done = false; public void run() { try { Thread.sleep(LONG_DELAY_MS); done = true; - } catch(Exception e){ - } + } catch (InterruptedException ok) {} } } - static class TrackedNoOpRunnable implements Runnable { - volatile boolean done = false; + public static class TrackedNoOpRunnable implements Runnable { + public volatile boolean done = false; public void run() { done = true; } } - static class TrackedCallable implements Callable { - volatile boolean done = false; + public static class TrackedCallable implements Callable { + public volatile boolean done = false; public Object call() { try { Thread.sleep(SMALL_DELAY_MS); done = true; - } catch(Exception e){ - } + } catch (InterruptedException ok) {} return Boolean.TRUE; } } @@ -574,9 +753,9 @@ public class JSR166TestCase extends TestCase { /** * For use as RejectedExecutionHandler in constructors */ - static class NoOpREHandler implements RejectedExecutionHandler{ - public void rejectedExecution(Runnable r, ThreadPoolExecutor executor){} + public static class NoOpREHandler implements RejectedExecutionHandler { + public void rejectedExecution(Runnable r, + ThreadPoolExecutor executor) {} } - } diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/LinkedBlockingDequeTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/LinkedBlockingDequeTest.java new file mode 100644 index 0000000..a858bb9 --- /dev/null +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/LinkedBlockingDequeTest.java @@ -0,0 +1,1671 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package tests.api.java.util.concurrent; // android-added + +import junit.framework.*; +import java.util.*; +import java.util.concurrent.*; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import java.io.*; + +public class LinkedBlockingDequeTest extends JSR166TestCase { + public static Test suite() { + return new TestSuite(LinkedBlockingDequeTest.class); + } + + /** + * Create a deque of given size containing consecutive + * Integers 0 ... n. + */ + private LinkedBlockingDeque populatedDeque(int n) { + LinkedBlockingDeque q = new LinkedBlockingDeque(n); + assertTrue(q.isEmpty()); + for (int i = 0; i < n; i++) + assertTrue(q.offer(new Integer(i))); + assertFalse(q.isEmpty()); + assertEquals(0, q.remainingCapacity()); + assertEquals(n, q.size()); + return q; + } + + /** + * isEmpty is true before add, false after + */ + public void testEmpty() { + LinkedBlockingDeque q = new LinkedBlockingDeque(); + assertTrue(q.isEmpty()); + q.add(new Integer(1)); + assertFalse(q.isEmpty()); + q.add(new Integer(2)); + q.removeFirst(); + q.removeFirst(); + assertTrue(q.isEmpty()); + } + + /** + * size changes when elements added and removed + */ + public void testSize() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(SIZE-i, q.size()); + q.removeFirst(); + } + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.size()); + q.add(new Integer(i)); + } + } + + /** + * offer(null) throws NPE + */ + public void testOfferFirstNull() { + try { + LinkedBlockingDeque q = new LinkedBlockingDeque(); + q.offerFirst(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * OfferFirst succeeds + */ + public void testOfferFirst() { + LinkedBlockingDeque q = new LinkedBlockingDeque(); + assertTrue(q.offerFirst(new Integer(0))); + assertTrue(q.offerFirst(new Integer(1))); + } + + /** + * OfferLast succeeds + */ + public void testOfferLast() { + LinkedBlockingDeque q = new LinkedBlockingDeque(); + assertTrue(q.offerLast(new Integer(0))); + assertTrue(q.offerLast(new Integer(1))); + } + + /** + * pollFirst succeeds unless empty + */ + public void testPollFirst() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.pollFirst()); + } + assertNull(q.pollFirst()); + } + + /** + * pollLast succeeds unless empty + */ + public void testPollLast() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = SIZE-1; i >= 0; --i) { + assertEquals(i, q.pollLast()); + } + assertNull(q.pollLast()); + } + + /** + * peekFirst returns next element, or null if empty + */ + public void testPeekFirst() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.peekFirst()); + assertEquals(i, q.pollFirst()); + assertTrue(q.peekFirst() == null || + !q.peekFirst().equals(i)); + } + assertNull(q.peekFirst()); + } + + /** + * peek returns next element, or null if empty + */ + public void testPeek() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.peek()); + assertEquals(i, q.pollFirst()); + assertTrue(q.peek() == null || + !q.peek().equals(i)); + } + assertNull(q.peek()); + } + + /** + * peekLast returns next element, or null if empty + */ + public void testPeekLast() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = SIZE-1; i >= 0; --i) { + assertEquals(i, q.peekLast()); + assertEquals(i, q.pollLast()); + assertTrue(q.peekLast() == null || + !q.peekLast().equals(i)); + } + assertNull(q.peekLast()); + } + + /** + * getFirst returns next getFirst, or throws NSEE if empty + */ + public void testFirstElement() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.getFirst()); + assertEquals(i, q.pollFirst()); + } + try { + q.getFirst(); + shouldThrow(); + } catch (NoSuchElementException success) {} + assertNull(q.peekFirst()); + } + + /** + * getLast returns next element, or throws NSEE if empty + */ + public void testLastElement() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = SIZE-1; i >= 0; --i) { + assertEquals(i, q.getLast()); + assertEquals(i, q.pollLast()); + } + try { + q.getLast(); + shouldThrow(); + } catch (NoSuchElementException success) {} + assertNull(q.peekLast()); + } + + /** + * removeFirst removes next element, or throws NSEE if empty + */ + public void testRemoveFirst() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.removeFirst()); + } + try { + q.removeFirst(); + shouldThrow(); + } catch (NoSuchElementException success) {} + assertNull(q.peekFirst()); + } + + /** + * removeLast removes last element, or throws NSEE if empty + */ + public void testRemoveLast() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = SIZE - 1; i >= 0; --i) { + assertEquals(i, q.removeLast()); + } + try { + q.removeLast(); + shouldThrow(); + } catch (NoSuchElementException success) {} + assertNull(q.peekLast()); + } + + /** + * remove removes next element, or throws NSEE if empty + */ + public void testRemove() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.remove()); + } + try { + q.remove(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * removeFirstOccurrence(x) removes x and returns true if present + */ + public void testRemoveFirstOccurrence() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 1; i < SIZE; i+=2) { + assertTrue(q.removeFirstOccurrence(new Integer(i))); + } + for (int i = 0; i < SIZE; i+=2) { + assertTrue(q.removeFirstOccurrence(new Integer(i))); + assertFalse(q.removeFirstOccurrence(new Integer(i+1))); + } + assertTrue(q.isEmpty()); + } + + /** + * removeLastOccurrence(x) removes x and returns true if present + */ + public void testRemoveLastOccurrence() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 1; i < SIZE; i+=2) { + assertTrue(q.removeLastOccurrence(new Integer(i))); + } + for (int i = 0; i < SIZE; i+=2) { + assertTrue(q.removeLastOccurrence(new Integer(i))); + assertFalse(q.removeLastOccurrence(new Integer(i+1))); + } + assertTrue(q.isEmpty()); + } + + /** + * peekFirst returns element inserted with addFirst + */ + public void testAddFirst() { + LinkedBlockingDeque q = populatedDeque(3); + q.pollLast(); + q.addFirst(four); + assertSame(four, q.peekFirst()); + } + + /** + * peekLast returns element inserted with addLast + */ + public void testAddLast() { + LinkedBlockingDeque q = populatedDeque(3); + q.pollLast(); + q.addLast(four); + assertSame(four, q.peekLast()); + } + + + /** + * A new deque has the indicated capacity, or Integer.MAX_VALUE if + * none given + */ + public void testConstructor1() { + assertEquals(SIZE, new LinkedBlockingDeque(SIZE).remainingCapacity()); + assertEquals(Integer.MAX_VALUE, new LinkedBlockingDeque().remainingCapacity()); + } + + /** + * Constructor throws IAE if capacity argument nonpositive + */ + public void testConstructor2() { + try { + LinkedBlockingDeque q = new LinkedBlockingDeque(0); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Initializing from null Collection throws NPE + */ + public void testConstructor3() { + try { + LinkedBlockingDeque q = new LinkedBlockingDeque(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Initializing from Collection of null elements throws NPE + */ + public void testConstructor4() { + try { + Integer[] ints = new Integer[SIZE]; + LinkedBlockingDeque q = new LinkedBlockingDeque(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Initializing from Collection with some null elements throws NPE + */ + public void testConstructor5() { + try { + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE-1; ++i) + ints[i] = new Integer(i); + LinkedBlockingDeque q = new LinkedBlockingDeque(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Deque contains all elements of collection used to initialize + */ + public void testConstructor6() { + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + LinkedBlockingDeque q = new LinkedBlockingDeque(Arrays.asList(ints)); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.poll()); + } + + /** + * Deque transitions from empty to full when elements added + */ + public void testEmptyFull() { + LinkedBlockingDeque q = new LinkedBlockingDeque(2); + assertTrue(q.isEmpty()); + assertEquals("should have room for 2", 2, q.remainingCapacity()); + q.add(one); + assertFalse(q.isEmpty()); + q.add(two); + assertFalse(q.isEmpty()); + assertEquals(0, q.remainingCapacity()); + assertFalse(q.offer(three)); + } + + /** + * remainingCapacity decreases on add, increases on remove + */ + public void testRemainingCapacity() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.remainingCapacity()); + assertEquals(SIZE-i, q.size()); + q.remove(); + } + for (int i = 0; i < SIZE; ++i) { + assertEquals(SIZE-i, q.remainingCapacity()); + assertEquals(i, q.size()); + q.add(new Integer(i)); + } + } + + /** + * offer(null) throws NPE + */ + public void testOfferNull() { + try { + LinkedBlockingDeque q = new LinkedBlockingDeque(1); + q.offer(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * add(null) throws NPE + */ + public void testAddNull() { + try { + LinkedBlockingDeque q = new LinkedBlockingDeque(1); + q.add(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * push(null) throws NPE + */ + public void testPushNull() { + try { + LinkedBlockingDeque q = new LinkedBlockingDeque(1); + q.push(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * push succeeds if not full; throws ISE if full + */ + public void testPush() { + try { + LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + Integer I = new Integer(i); + q.push(I); + assertEquals(I, q.peek()); + } + assertEquals(0, q.remainingCapacity()); + q.push(new Integer(SIZE)); + shouldThrow(); + } catch (IllegalStateException success) {} + } + + /** + * peekFirst returns element inserted with push + */ + public void testPushWithPeek() { + LinkedBlockingDeque q = populatedDeque(3); + q.pollLast(); + q.push(four); + assertSame(four, q.peekFirst()); + } + + + /** + * pop removes next element, or throws NSEE if empty + */ + public void testPop() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.pop()); + } + try { + q.pop(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + + /** + * Offer succeeds if not full; fails if full + */ + public void testOffer() { + LinkedBlockingDeque q = new LinkedBlockingDeque(1); + assertTrue(q.offer(zero)); + assertFalse(q.offer(one)); + } + + /** + * add succeeds if not full; throws ISE if full + */ + public void testAdd() { + try { + LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.add(new Integer(i))); + } + assertEquals(0, q.remainingCapacity()); + q.add(new Integer(SIZE)); + shouldThrow(); + } catch (IllegalStateException success) {} + } + + /** + * addAll(null) throws NPE + */ + public void testAddAll1() { + try { + LinkedBlockingDeque q = new LinkedBlockingDeque(1); + q.addAll(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * addAll(this) throws IAE + */ + public void testAddAllSelf() { + try { + LinkedBlockingDeque q = populatedDeque(SIZE); + q.addAll(q); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * addAll of a collection with null elements throws NPE + */ + public void testAddAll2() { + try { + LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE); + Integer[] ints = new Integer[SIZE]; + q.addAll(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + /** + * addAll of a collection with any null elements throws NPE after + * possibly adding some elements + */ + public void testAddAll3() { + try { + LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE); + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE-1; ++i) + ints[i] = new Integer(i); + q.addAll(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + /** + * addAll throws ISE if not enough room + */ + public void testAddAll4() { + try { + LinkedBlockingDeque q = new LinkedBlockingDeque(1); + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + q.addAll(Arrays.asList(ints)); + shouldThrow(); + } catch (IllegalStateException success) {} + } + + /** + * Deque contains all elements, in traversal order, of successful addAll + */ + public void testAddAll5() { + Integer[] empty = new Integer[0]; + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE); + assertFalse(q.addAll(Arrays.asList(empty))); + assertTrue(q.addAll(Arrays.asList(ints))); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.poll()); + } + + + /** + * put(null) throws NPE + */ + public void testPutNull() throws InterruptedException { + try { + LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE); + q.put(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * all elements successfully put are contained + */ + public void testPut() throws InterruptedException { + LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + Integer I = new Integer(i); + q.put(I); + assertTrue(q.contains(I)); + } + assertEquals(0, q.remainingCapacity()); + } + + /** + * put blocks interruptibly if full + */ + public void testBlockingPut() throws InterruptedException { + final LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < SIZE; ++i) + q.put(i); + assertEquals(SIZE, q.size()); + assertEquals(0, q.remainingCapacity()); + try { + q.put(99); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); + assertEquals(SIZE, q.size()); + assertEquals(0, q.remainingCapacity()); + } + + /** + * put blocks waiting for take when full + */ + public void testPutWithTake() throws InterruptedException { + final int capacity = 2; + final LinkedBlockingDeque q = new LinkedBlockingDeque(capacity); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < capacity + 1; i++) + q.put(i); + try { + q.put(99); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(q.remainingCapacity(), 0); + assertEquals(0, q.take()); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); + assertEquals(q.remainingCapacity(), 0); + } + + /** + * timed offer times out if full and elements not taken + */ + public void testTimedOffer() throws InterruptedException { + final LinkedBlockingDeque q = new LinkedBlockingDeque(2); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + q.put(new Object()); + q.put(new Object()); + assertFalse(q.offer(new Object(), SHORT_DELAY_MS, MILLISECONDS)); + try { + q.offer(new Object(), LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + t.start(); + Thread.sleep(SMALL_DELAY_MS); + t.interrupt(); + t.join(); + } + + /** + * take retrieves elements in FIFO order + */ + public void testTake() throws InterruptedException { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.take()); + } + } + + /** + * take blocks interruptibly when empty + */ + public void testTakeFromEmpty() throws InterruptedException { + final LinkedBlockingDeque q = new LinkedBlockingDeque(2); + Thread t = new ThreadShouldThrow(InterruptedException.class) { + public void realRun() throws InterruptedException { + q.take(); + }}; + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); + } + + /** + * Take removes existing elements until empty, then blocks interruptibly + */ + public void testBlockingTake() throws InterruptedException { + final LinkedBlockingDeque q = populatedDeque(SIZE); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.take()); + } + try { + q.take(); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); + } + + + /** + * poll succeeds unless empty + */ + public void testPoll() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.poll()); + } + assertNull(q.poll()); + } + + /** + * timed poll with zero timeout succeeds when non-empty, else times out + */ + public void testTimedPoll0() throws InterruptedException { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.poll(0, MILLISECONDS)); + } + assertNull(q.poll(0, MILLISECONDS)); + } + + /** + * timed poll with nonzero timeout succeeds when non-empty, else times out + */ + public void testTimedPoll() throws InterruptedException { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.poll(SHORT_DELAY_MS, MILLISECONDS)); + } + assertNull(q.poll(SHORT_DELAY_MS, MILLISECONDS)); + } + + /** + * Interrupted timed poll throws InterruptedException instead of + * returning timeout status + */ + public void testInterruptedTimedPoll() throws InterruptedException { + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.poll(SHORT_DELAY_MS, MILLISECONDS)); + } + try { + q.poll(SMALL_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); + } + + /** + * timed poll before a delayed offer fails; after offer succeeds; + * on interruption throws + */ + public void testTimedPollWithOffer() throws InterruptedException { + final LinkedBlockingDeque q = new LinkedBlockingDeque(2); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertNull(q.poll(SHORT_DELAY_MS, MILLISECONDS)); + assertSame(zero, q.poll(LONG_DELAY_MS, MILLISECONDS)); + try { + q.poll(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + t.start(); + Thread.sleep(SMALL_DELAY_MS); + assertTrue(q.offer(zero, SHORT_DELAY_MS, MILLISECONDS)); + t.interrupt(); + t.join(); + } + + + /** + * putFirst(null) throws NPE + */ + public void testPutFirstNull() throws InterruptedException { + try { + LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE); + q.putFirst(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * all elements successfully putFirst are contained + */ + public void testPutFirst() throws InterruptedException { + LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + Integer I = new Integer(i); + q.putFirst(I); + assertTrue(q.contains(I)); + } + assertEquals(0, q.remainingCapacity()); + } + + /** + * putFirst blocks interruptibly if full + */ + public void testBlockingPutFirst() throws InterruptedException { + final LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < SIZE; ++i) + q.putFirst(i); + assertEquals(SIZE, q.size()); + assertEquals(0, q.remainingCapacity()); + try { + q.putFirst(99); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); + assertEquals(SIZE, q.size()); + assertEquals(0, q.remainingCapacity()); + } + + /** + * putFirst blocks waiting for take when full + */ + public void testPutFirstWithTake() throws InterruptedException { + final int capacity = 2; + final LinkedBlockingDeque q = new LinkedBlockingDeque(capacity); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < capacity + 1; i++) + q.putFirst(i); + try { + q.putFirst(99); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(q.remainingCapacity(), 0); + assertEquals(capacity - 1, q.take()); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); + assertEquals(q.remainingCapacity(), 0); + } + + /** + * timed offerFirst times out if full and elements not taken + */ + public void testTimedOfferFirst() throws InterruptedException { + final LinkedBlockingDeque q = new LinkedBlockingDeque(2); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + q.putFirst(new Object()); + q.putFirst(new Object()); + assertFalse(q.offerFirst(new Object(), SHORT_DELAY_MS, MILLISECONDS)); + try { + q.offerFirst(new Object(), LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + t.start(); + Thread.sleep(SMALL_DELAY_MS); + t.interrupt(); + t.join(); + } + + /** + * take retrieves elements in FIFO order + */ + public void testTakeFirst() throws InterruptedException { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.takeFirst()); + } + } + + /** + * takeFirst blocks interruptibly when empty + */ + public void testTakeFirstFromEmpty() throws InterruptedException { + final LinkedBlockingDeque q = new LinkedBlockingDeque(2); + Thread t = new ThreadShouldThrow(InterruptedException.class) { + public void realRun() throws InterruptedException { + q.takeFirst(); + }}; + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); + } + + /** + * TakeFirst removes existing elements until empty, then blocks interruptibly + */ + public void testBlockingTakeFirst() throws InterruptedException { + final LinkedBlockingDeque q = populatedDeque(SIZE); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < SIZE; ++i) + assertEquals(i, q.takeFirst()); + try { + q.takeFirst(); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); + } + + + /** + * timed pollFirst with zero timeout succeeds when non-empty, else times out + */ + public void testTimedPollFirst0() throws InterruptedException { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.pollFirst(0, MILLISECONDS)); + } + assertNull(q.pollFirst(0, MILLISECONDS)); + } + + /** + * timed pollFirst with nonzero timeout succeeds when non-empty, else times out + */ + public void testTimedPollFirst() throws InterruptedException { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.pollFirst(SHORT_DELAY_MS, MILLISECONDS)); + } + assertNull(q.pollFirst(SHORT_DELAY_MS, MILLISECONDS)); + } + + /** + * Interrupted timed pollFirst throws InterruptedException instead of + * returning timeout status + */ + public void testInterruptedTimedPollFirst() throws InterruptedException { + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.pollFirst(SHORT_DELAY_MS, MILLISECONDS)); + } + try { + q.pollFirst(SMALL_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); + } + + /** + * timed pollFirst before a delayed offerFirst fails; after offerFirst succeeds; + * on interruption throws + */ + public void testTimedPollFirstWithOfferFirst() throws InterruptedException { + final LinkedBlockingDeque q = new LinkedBlockingDeque(2); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertNull(q.pollFirst(SHORT_DELAY_MS, MILLISECONDS)); + assertSame(zero, q.pollFirst(LONG_DELAY_MS, MILLISECONDS)); + try { + q.pollFirst(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + t.start(); + Thread.sleep(SMALL_DELAY_MS); + assertTrue(q.offerFirst(zero, SHORT_DELAY_MS, MILLISECONDS)); + t.interrupt(); + t.join(); + } + + /** + * putLast(null) throws NPE + */ + public void testPutLastNull() throws InterruptedException { + try { + LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE); + q.putLast(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * all elements successfully putLast are contained + */ + public void testPutLast() throws InterruptedException { + LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + Integer I = new Integer(i); + q.putLast(I); + assertTrue(q.contains(I)); + } + assertEquals(0, q.remainingCapacity()); + } + + /** + * putLast blocks interruptibly if full + */ + public void testBlockingPutLast() throws InterruptedException { + final LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < SIZE; ++i) + q.putLast(i); + assertEquals(SIZE, q.size()); + assertEquals(0, q.remainingCapacity()); + try { + q.putLast(99); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); + assertEquals(SIZE, q.size()); + assertEquals(0, q.remainingCapacity()); + } + + /** + * putLast blocks waiting for take when full + */ + public void testPutLastWithTake() throws InterruptedException { + final int capacity = 2; + final LinkedBlockingDeque q = new LinkedBlockingDeque(capacity); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < capacity + 1; i++) + q.putLast(i); + try { + q.putLast(99); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(q.remainingCapacity(), 0); + assertEquals(0, q.take()); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); + assertEquals(q.remainingCapacity(), 0); + } + + /** + * timed offerLast times out if full and elements not taken + */ + public void testTimedOfferLast() throws InterruptedException { + final LinkedBlockingDeque q = new LinkedBlockingDeque(2); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + q.putLast(new Object()); + q.putLast(new Object()); + assertFalse(q.offerLast(new Object(), SHORT_DELAY_MS, MILLISECONDS)); + try { + q.offerLast(new Object(), LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + t.start(); + Thread.sleep(SMALL_DELAY_MS); + t.interrupt(); + t.join(); + } + + /** + * takeLast retrieves elements in FIFO order + */ + public void testTakeLast() throws InterruptedException { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(SIZE-i-1, q.takeLast()); + } + } + + /** + * takeLast blocks interruptibly when empty + */ + public void testTakeLastFromEmpty() throws InterruptedException { + final LinkedBlockingDeque q = new LinkedBlockingDeque(2); + Thread t = new ThreadShouldThrow(InterruptedException.class) { + public void realRun() throws InterruptedException { + q.takeLast(); + }}; + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); + } + + /** + * TakeLast removes existing elements until empty, then blocks interruptibly + */ + public void testBlockingTakeLast() throws InterruptedException { + final LinkedBlockingDeque q = populatedDeque(SIZE); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < SIZE; ++i) + assertEquals(SIZE - 1 - i, q.takeLast()); + try { + q.takeLast(); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); + } + + /** + * timed pollLast with zero timeout succeeds when non-empty, else times out + */ + public void testTimedPollLast0() throws InterruptedException { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(SIZE-i-1, q.pollLast(0, MILLISECONDS)); + } + assertNull(q.pollLast(0, MILLISECONDS)); + } + + /** + * timed pollLast with nonzero timeout succeeds when non-empty, else times out + */ + public void testTimedPollLast() throws InterruptedException { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(SIZE-i-1, q.pollLast(SHORT_DELAY_MS, MILLISECONDS)); + } + assertNull(q.pollLast(SHORT_DELAY_MS, MILLISECONDS)); + } + + /** + * Interrupted timed pollLast throws InterruptedException instead of + * returning timeout status + */ + public void testInterruptedTimedPollLast() throws InterruptedException { + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(SIZE-i-1, q.pollLast(SHORT_DELAY_MS, MILLISECONDS)); + } + try { + q.pollLast(SMALL_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); + } + + /** + * timed poll before a delayed offerLast fails; after offerLast succeeds; + * on interruption throws + */ + public void testTimedPollWithOfferLast() throws InterruptedException { + final LinkedBlockingDeque q = new LinkedBlockingDeque(2); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertNull(q.poll(SHORT_DELAY_MS, MILLISECONDS)); + assertSame(zero, q.poll(LONG_DELAY_MS, MILLISECONDS)); + try { + q.poll(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + t.start(); + Thread.sleep(SMALL_DELAY_MS); + assertTrue(q.offerLast(zero, SHORT_DELAY_MS, MILLISECONDS)); + t.interrupt(); + t.join(); + } + + + /** + * element returns next element, or throws NSEE if empty + */ + public void testElement() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.element()); + q.poll(); + } + try { + q.element(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * remove(x) removes x and returns true if present + */ + public void testRemoveElement() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 1; i < SIZE; i+=2) { + assertTrue(q.remove(new Integer(i))); + } + for (int i = 0; i < SIZE; i+=2) { + assertTrue(q.remove(new Integer(i))); + assertFalse(q.remove(new Integer(i+1))); + } + assertTrue(q.isEmpty()); + } + + /** + * contains(x) reports true when elements added but not yet removed + */ + public void testContains() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.contains(new Integer(i))); + q.poll(); + assertFalse(q.contains(new Integer(i))); + } + } + + /** + * clear removes all elements + */ + public void testClear() { + LinkedBlockingDeque q = populatedDeque(SIZE); + q.clear(); + assertTrue(q.isEmpty()); + assertEquals(0, q.size()); + assertEquals(SIZE, q.remainingCapacity()); + q.add(one); + assertFalse(q.isEmpty()); + assertTrue(q.contains(one)); + q.clear(); + assertTrue(q.isEmpty()); + } + + /** + * containsAll(c) is true when c contains a subset of elements + */ + public void testContainsAll() { + LinkedBlockingDeque q = populatedDeque(SIZE); + LinkedBlockingDeque p = new LinkedBlockingDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.containsAll(p)); + assertFalse(p.containsAll(q)); + p.add(new Integer(i)); + } + assertTrue(p.containsAll(q)); + } + + /** + * retainAll(c) retains only those elements of c and reports true if changed + */ + public void testRetainAll() { + LinkedBlockingDeque q = populatedDeque(SIZE); + LinkedBlockingDeque p = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + boolean changed = q.retainAll(p); + if (i == 0) + assertFalse(changed); + else + assertTrue(changed); + + assertTrue(q.containsAll(p)); + assertEquals(SIZE-i, q.size()); + p.remove(); + } + } + + /** + * removeAll(c) removes only those elements of c and reports true if changed + */ + public void testRemoveAll() { + for (int i = 1; i < SIZE; ++i) { + LinkedBlockingDeque q = populatedDeque(SIZE); + LinkedBlockingDeque p = populatedDeque(i); + assertTrue(q.removeAll(p)); + assertEquals(SIZE-i, q.size()); + for (int j = 0; j < i; ++j) { + Integer I = (Integer)(p.remove()); + assertFalse(q.contains(I)); + } + } + } + + /** + * toArray contains all elements + */ + public void testToArray() throws InterruptedException{ + LinkedBlockingDeque q = populatedDeque(SIZE); + Object[] o = q.toArray(); + for (int i = 0; i < o.length; i++) + assertEquals(o[i], q.take()); + } + + /** + * toArray(a) contains all elements + */ + public void testToArray2() throws InterruptedException { + LinkedBlockingDeque q = populatedDeque(SIZE); + Integer[] ints = new Integer[SIZE]; + ints = (Integer[])q.toArray(ints); + for (int i = 0; i < ints.length; i++) + assertEquals(ints[i], q.take()); + } + + /** + * toArray(null) throws NPE + */ + public void testToArray_BadArg() { + LinkedBlockingDeque q = populatedDeque(SIZE); + try { + Object o[] = q.toArray(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * toArray with incompatible array type throws CCE + */ + public void testToArray1_BadArg() { + LinkedBlockingDeque q = populatedDeque(SIZE); + try { + Object o[] = q.toArray(new String[10]); + shouldThrow(); + } catch (ArrayStoreException success) {} + } + + + /** + * iterator iterates through all elements + */ + public void testIterator() throws InterruptedException { + LinkedBlockingDeque q = populatedDeque(SIZE); + Iterator it = q.iterator(); + while (it.hasNext()) { + assertEquals(it.next(), q.take()); + } + } + + /** + * iterator.remove removes current element + */ + public void testIteratorRemove () { + final LinkedBlockingDeque q = new LinkedBlockingDeque(3); + q.add(two); + q.add(one); + q.add(three); + + Iterator it = q.iterator(); + it.next(); + it.remove(); + + it = q.iterator(); + assertSame(it.next(), one); + assertSame(it.next(), three); + assertFalse(it.hasNext()); + } + + + /** + * iterator ordering is FIFO + */ + public void testIteratorOrdering() { + final LinkedBlockingDeque q = new LinkedBlockingDeque(3); + q.add(one); + q.add(two); + q.add(three); + assertEquals(0, q.remainingCapacity()); + int k = 0; + for (Iterator it = q.iterator(); it.hasNext();) { + assertEquals(++k, it.next()); + } + assertEquals(3, k); + } + + /** + * Modifications do not cause iterators to fail + */ + public void testWeaklyConsistentIteration () { + final LinkedBlockingDeque q = new LinkedBlockingDeque(3); + q.add(one); + q.add(two); + q.add(three); + for (Iterator it = q.iterator(); it.hasNext();) { + q.remove(); + it.next(); + } + assertEquals(0, q.size()); + } + + + /** + * Descending iterator iterates through all elements + */ + public void testDescendingIterator() { + LinkedBlockingDeque q = populatedDeque(SIZE); + int i = 0; + Iterator it = q.descendingIterator(); + while (it.hasNext()) { + assertTrue(q.contains(it.next())); + ++i; + } + assertEquals(i, SIZE); + assertFalse(it.hasNext()); + try { + it.next(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * Descending iterator ordering is reverse FIFO + */ + public void testDescendingIteratorOrdering() { + final LinkedBlockingDeque q = new LinkedBlockingDeque(); + for (int iters = 0; iters < 100; ++iters) { + q.add(new Integer(3)); + q.add(new Integer(2)); + q.add(new Integer(1)); + int k = 0; + for (Iterator it = q.descendingIterator(); it.hasNext();) { + assertEquals(++k, it.next()); + } + + assertEquals(3, k); + q.remove(); + q.remove(); + q.remove(); + } + } + + /** + * descendingIterator.remove removes current element + */ + public void testDescendingIteratorRemove () { + final LinkedBlockingDeque q = new LinkedBlockingDeque(); + for (int iters = 0; iters < 100; ++iters) { + q.add(new Integer(3)); + q.add(new Integer(2)); + q.add(new Integer(1)); + Iterator it = q.descendingIterator(); + assertEquals(it.next(), new Integer(1)); + it.remove(); + assertEquals(it.next(), new Integer(2)); + it = q.descendingIterator(); + assertEquals(it.next(), new Integer(2)); + assertEquals(it.next(), new Integer(3)); + it.remove(); + assertFalse(it.hasNext()); + q.remove(); + } + } + + + /** + * toString contains toStrings of elements + */ + public void testToString() { + LinkedBlockingDeque q = populatedDeque(SIZE); + String s = q.toString(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(s.indexOf(String.valueOf(i)) >= 0); + } + } + + + /** + * offer transfers elements across Executor tasks + */ + public void testOfferInExecutor() { + final LinkedBlockingDeque q = new LinkedBlockingDeque(2); + q.add(one); + q.add(two); + ExecutorService executor = Executors.newFixedThreadPool(2); + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(q.offer(three)); + assertTrue(q.offer(three, MEDIUM_DELAY_MS, MILLISECONDS)); + assertEquals(0, q.remainingCapacity()); + }}); + + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + Thread.sleep(SMALL_DELAY_MS); + assertSame(one, q.take()); + }}); + + joinPool(executor); + } + + /** + * poll retrieves elements across Executor threads + */ + public void testPollInExecutor() { + final LinkedBlockingDeque q = new LinkedBlockingDeque(2); + ExecutorService executor = Executors.newFixedThreadPool(2); + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertNull(q.poll()); + assertSame(one, q.poll(MEDIUM_DELAY_MS, MILLISECONDS)); + assertTrue(q.isEmpty()); + }}); + + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + Thread.sleep(SMALL_DELAY_MS); + q.put(one); + }}); + + joinPool(executor); + } + + /** + * A deserialized serialized deque has same elements in same order + */ + public void testSerialization() throws Exception { + LinkedBlockingDeque q = populatedDeque(SIZE); + + ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); + ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); + out.writeObject(q); + out.close(); + + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); + LinkedBlockingDeque r = (LinkedBlockingDeque)in.readObject(); + assertEquals(q.size(), r.size()); + while (!q.isEmpty()) + assertEquals(q.remove(), r.remove()); + } + + /** + * drainTo(null) throws NPE + */ + public void testDrainToNull() { + LinkedBlockingDeque q = populatedDeque(SIZE); + try { + q.drainTo(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * drainTo(this) throws IAE + */ + public void testDrainToSelf() { + LinkedBlockingDeque q = populatedDeque(SIZE); + try { + q.drainTo(q); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * drainTo(c) empties deque into another collection c + */ + public void testDrainTo() { + LinkedBlockingDeque q = populatedDeque(SIZE); + ArrayList l = new ArrayList(); + q.drainTo(l); + assertEquals(q.size(), 0); + assertEquals(l.size(), SIZE); + for (int i = 0; i < SIZE; ++i) + assertEquals(l.get(i), new Integer(i)); + q.add(zero); + q.add(one); + assertFalse(q.isEmpty()); + assertTrue(q.contains(zero)); + assertTrue(q.contains(one)); + l.clear(); + q.drainTo(l); + assertEquals(q.size(), 0); + assertEquals(l.size(), 2); + for (int i = 0; i < 2; ++i) + assertEquals(l.get(i), new Integer(i)); + } + + /** + * drainTo empties full deque, unblocking a waiting put. + */ + public void testDrainToWithActivePut() throws InterruptedException { + final LinkedBlockingDeque q = populatedDeque(SIZE); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + q.put(new Integer(SIZE+1)); + }}); + + t.start(); + ArrayList l = new ArrayList(); + q.drainTo(l); + assertTrue(l.size() >= SIZE); + for (int i = 0; i < SIZE; ++i) + assertEquals(l.get(i), new Integer(i)); + t.join(); + assertTrue(q.size() + l.size() >= SIZE); + } + + /** + * drainTo(null, n) throws NPE + */ + public void testDrainToNullN() { + LinkedBlockingDeque q = populatedDeque(SIZE); + try { + q.drainTo(null, 0); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * drainTo(this, n) throws IAE + */ + public void testDrainToSelfN() { + LinkedBlockingDeque q = populatedDeque(SIZE); + try { + q.drainTo(q, 0); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * drainTo(c, n) empties first max {n, size} elements of deque into c + */ + public void testDrainToN() { + LinkedBlockingDeque q = new LinkedBlockingDeque(); + for (int i = 0; i < SIZE + 2; ++i) { + for (int j = 0; j < SIZE; j++) + assertTrue(q.offer(new Integer(j))); + ArrayList l = new ArrayList(); + q.drainTo(l, i); + int k = (i < SIZE)? i : SIZE; + assertEquals(l.size(), k); + assertEquals(q.size(), SIZE-k); + for (int j = 0; j < k; ++j) + assertEquals(l.get(j), new Integer(j)); + while (q.poll() != null) ; + } + } + +} diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/LinkedBlockingQueueTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/LinkedBlockingQueueTest.java index dd6be9a..a98dc21 100755 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/LinkedBlockingQueueTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/LinkedBlockingQueueTest.java @@ -2,15 +2,16 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.*; import java.util.concurrent.*; +import static java.util.concurrent.TimeUnit.MILLISECONDS; import java.io.*; public class LinkedBlockingQueueTest extends JSR166TestCase { @@ -26,7 +27,7 @@ public class LinkedBlockingQueueTest extends JSR166TestCase { private LinkedBlockingQueue populatedQueue(int n) { LinkedBlockingQueue q = new LinkedBlockingQueue(n); assertTrue(q.isEmpty()); - for(int i = 0; i < n; i++) + for (int i = 0; i < n; i++) assertTrue(q.offer(new Integer(i))); assertFalse(q.isEmpty()); assertEquals(0, q.remainingCapacity()); @@ -44,14 +45,13 @@ public class LinkedBlockingQueueTest extends JSR166TestCase { } /** - * Constructor throws IAE if capacity argument nonpositive + * Constructor throws IAE if capacity argument nonpositive */ public void testConstructor2() { try { LinkedBlockingQueue q = new LinkedBlockingQueue(0); shouldThrow(); - } - catch (IllegalArgumentException success) {} + } catch (IllegalArgumentException success) {} } /** @@ -61,8 +61,7 @@ public class LinkedBlockingQueueTest extends JSR166TestCase { try { LinkedBlockingQueue q = new LinkedBlockingQueue(null); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** @@ -73,8 +72,7 @@ public class LinkedBlockingQueueTest extends JSR166TestCase { Integer[] ints = new Integer[SIZE]; LinkedBlockingQueue q = new LinkedBlockingQueue(Arrays.asList(ints)); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** @@ -87,23 +85,19 @@ public class LinkedBlockingQueueTest extends JSR166TestCase { ints[i] = new Integer(i); LinkedBlockingQueue q = new LinkedBlockingQueue(Arrays.asList(ints)); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** * Queue contains all elements of collection used to initialize */ public void testConstructor6() { - try { - Integer[] ints = new Integer[SIZE]; - for (int i = 0; i < SIZE; ++i) - ints[i] = new Integer(i); - LinkedBlockingQueue q = new LinkedBlockingQueue(Arrays.asList(ints)); - for (int i = 0; i < SIZE; ++i) - assertEquals(ints[i], q.poll()); - } - finally {} + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + LinkedBlockingQueue q = new LinkedBlockingQueue(Arrays.asList(ints)); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.poll()); } /** @@ -146,7 +140,7 @@ public class LinkedBlockingQueueTest extends JSR166TestCase { LinkedBlockingQueue q = new LinkedBlockingQueue(1); q.offer(null); shouldThrow(); - } catch (NullPointerException success) { } + } catch (NullPointerException success) {} } /** @@ -157,7 +151,7 @@ public class LinkedBlockingQueueTest extends JSR166TestCase { LinkedBlockingQueue q = new LinkedBlockingQueue(1); q.add(null); shouldThrow(); - } catch (NullPointerException success) { } + } catch (NullPointerException success) {} } /** @@ -180,8 +174,8 @@ public class LinkedBlockingQueueTest extends JSR166TestCase { } assertEquals(0, q.remainingCapacity()); q.add(new Integer(SIZE)); - } catch (IllegalStateException success){ - } + shouldThrow(); + } catch (IllegalStateException success) {} } /** @@ -192,8 +186,7 @@ public class LinkedBlockingQueueTest extends JSR166TestCase { LinkedBlockingQueue q = new LinkedBlockingQueue(1); q.addAll(null); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** @@ -204,8 +197,7 @@ public class LinkedBlockingQueueTest extends JSR166TestCase { LinkedBlockingQueue q = populatedQueue(SIZE); q.addAll(q); shouldThrow(); - } - catch (IllegalArgumentException success) {} + } catch (IllegalArgumentException success) {} } /** @@ -217,8 +209,7 @@ public class LinkedBlockingQueueTest extends JSR166TestCase { Integer[] ints = new Integer[SIZE]; q.addAll(Arrays.asList(ints)); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** * addAll of a collection with any null elements throws NPE after @@ -232,8 +223,7 @@ public class LinkedBlockingQueueTest extends JSR166TestCase { ints[i] = new Integer(i); q.addAll(Arrays.asList(ints)); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** * addAll throws ISE if not enough room @@ -246,224 +236,175 @@ public class LinkedBlockingQueueTest extends JSR166TestCase { ints[i] = new Integer(i); q.addAll(Arrays.asList(ints)); shouldThrow(); - } - catch (IllegalStateException success) {} + } catch (IllegalStateException success) {} } /** * Queue contains all elements, in traversal order, of successful addAll */ public void testAddAll5() { - try { - Integer[] empty = new Integer[0]; - Integer[] ints = new Integer[SIZE]; - for (int i = 0; i < SIZE; ++i) - ints[i] = new Integer(i); - LinkedBlockingQueue q = new LinkedBlockingQueue(SIZE); - assertFalse(q.addAll(Arrays.asList(empty))); - assertTrue(q.addAll(Arrays.asList(ints))); - for (int i = 0; i < SIZE; ++i) - assertEquals(ints[i], q.poll()); - } - finally {} + Integer[] empty = new Integer[0]; + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + LinkedBlockingQueue q = new LinkedBlockingQueue(SIZE); + assertFalse(q.addAll(Arrays.asList(empty))); + assertTrue(q.addAll(Arrays.asList(ints))); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.poll()); } /** * put(null) throws NPE */ - public void testPutNull() { + public void testPutNull() throws InterruptedException { try { LinkedBlockingQueue q = new LinkedBlockingQueue(SIZE); q.put(null); shouldThrow(); - } - catch (NullPointerException success){ - } - catch (InterruptedException ie) { - unexpectedException(); - } + } catch (NullPointerException success) {} } /** * all elements successfully put are contained */ - public void testPut() { - try { - LinkedBlockingQueue q = new LinkedBlockingQueue(SIZE); - for (int i = 0; i < SIZE; ++i) { - Integer I = new Integer(i); - q.put(I); - assertTrue(q.contains(I)); - } - assertEquals(0, q.remainingCapacity()); - } - catch (InterruptedException ie) { - unexpectedException(); + public void testPut() throws InterruptedException { + LinkedBlockingQueue q = new LinkedBlockingQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + Integer I = new Integer(i); + q.put(I); + assertTrue(q.contains(I)); } + assertEquals(0, q.remainingCapacity()); } /** * put blocks interruptibly if full */ - public void testBlockingPut() { - Thread t = new Thread(new Runnable() { - public void run() { - int added = 0; - try { - LinkedBlockingQueue q = new LinkedBlockingQueue(SIZE); - for (int i = 0; i < SIZE; ++i) { - q.put(new Integer(i)); - ++added; - } - q.put(new Integer(SIZE)); - threadShouldThrow(); - } catch (InterruptedException ie){ - threadAssertEquals(added, SIZE); - } - }}); + public void testBlockingPut() throws InterruptedException { + final LinkedBlockingQueue q = new LinkedBlockingQueue(SIZE); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < SIZE; ++i) + q.put(i); + assertEquals(SIZE, q.size()); + assertEquals(0, q.remainingCapacity()); + try { + q.put(99); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + t.start(); - try { - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } - catch (InterruptedException ie) { - unexpectedException(); - } + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); + assertEquals(SIZE, q.size()); + assertEquals(0, q.remainingCapacity()); } /** * put blocks waiting for take when full */ - public void testPutWithTake() { + public void testPutWithTake() throws InterruptedException { + final int capacity = 2; final LinkedBlockingQueue q = new LinkedBlockingQueue(2); - Thread t = new Thread(new Runnable() { - public void run() { - int added = 0; - try { - q.put(new Object()); - ++added; - q.put(new Object()); - ++added; - q.put(new Object()); - ++added; - q.put(new Object()); - ++added; - threadShouldThrow(); - } catch (InterruptedException e){ - threadAssertTrue(added >= 2); - } - } - }); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - q.take(); - t.interrupt(); - t.join(); - } catch (Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < capacity + 1; i++) + q.put(i); + try { + q.put(99); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(q.remainingCapacity(), 0); + assertEquals(0, q.take()); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); + assertEquals(q.remainingCapacity(), 0); } /** * timed offer times out if full and elements not taken */ - public void testTimedOffer() { + public void testTimedOffer() throws InterruptedException { final LinkedBlockingQueue q = new LinkedBlockingQueue(2); - Thread t = new Thread(new Runnable() { - public void run() { - try { - q.put(new Object()); - q.put(new Object()); - threadAssertFalse(q.offer(new Object(), SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - q.offer(new Object(), LONG_DELAY_MS, TimeUnit.MILLISECONDS); - threadShouldThrow(); - } catch (InterruptedException success){} - } - }); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + q.put(new Object()); + q.put(new Object()); + assertFalse(q.offer(new Object(), SHORT_DELAY_MS, MILLISECONDS)); + try { + q.offer(new Object(), LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + }}); - try { - t.start(); - Thread.sleep(SMALL_DELAY_MS); - t.interrupt(); - t.join(); - } catch (Exception e){ - unexpectedException(); - } + t.start(); + Thread.sleep(SMALL_DELAY_MS); + t.interrupt(); + t.join(); } /** * take retrieves elements in FIFO order */ - public void testTake() { - try { - LinkedBlockingQueue q = populatedQueue(SIZE); - for (int i = 0; i < SIZE; ++i) { - assertEquals(i, ((Integer)q.take()).intValue()); - } - } catch (InterruptedException e){ - unexpectedException(); + public void testTake() throws InterruptedException { + LinkedBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.take()); } } /** * take blocks interruptibly when empty */ - public void testTakeFromEmpty() { + public void testTakeFromEmpty() throws InterruptedException { final LinkedBlockingQueue q = new LinkedBlockingQueue(2); - Thread t = new Thread(new Runnable() { - public void run() { - try { - q.take(); - threadShouldThrow(); - } catch (InterruptedException success){ } - } - }); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } catch (Exception e){ - unexpectedException(); - } + Thread t = new ThreadShouldThrow(InterruptedException.class) { + public void realRun() throws InterruptedException { + q.take(); + }}; + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } /** * Take removes existing elements until empty, then blocks interruptibly */ - public void testBlockingTake() { - Thread t = new Thread(new Runnable() { - public void run() { - try { - LinkedBlockingQueue q = populatedQueue(SIZE); - for (int i = 0; i < SIZE; ++i) { - assertEquals(i, ((Integer)q.take()).intValue()); - } - q.take(); - threadShouldThrow(); - } catch (InterruptedException success){ - } - }}); + public void testBlockingTake() throws InterruptedException { + final LinkedBlockingQueue q = populatedQueue(SIZE); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.take()); + } + try { + q.take(); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + t.start(); - try { - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } - catch (InterruptedException ie) { - unexpectedException(); - } + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } - /** * poll succeeds unless empty */ public void testPoll() { LinkedBlockingQueue q = populatedQueue(SIZE); for (int i = 0; i < SIZE; ++i) { - assertEquals(i, ((Integer)q.poll()).intValue()); + assertEquals(i, q.poll()); } assertNull(q.poll()); } @@ -471,85 +412,69 @@ public class LinkedBlockingQueueTest extends JSR166TestCase { /** * timed pool with zero timeout succeeds when non-empty, else times out */ - public void testTimedPoll0() { - try { - LinkedBlockingQueue q = populatedQueue(SIZE); - for (int i = 0; i < SIZE; ++i) { - assertEquals(i, ((Integer)q.poll(0, TimeUnit.MILLISECONDS)).intValue()); - } - assertNull(q.poll(0, TimeUnit.MILLISECONDS)); - } catch (InterruptedException e){ - unexpectedException(); + public void testTimedPoll0() throws InterruptedException { + LinkedBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.poll(0, MILLISECONDS)); } + assertNull(q.poll(0, MILLISECONDS)); } /** * timed pool with nonzero timeout succeeds when non-empty, else times out */ - public void testTimedPoll() { - try { - LinkedBlockingQueue q = populatedQueue(SIZE); - for (int i = 0; i < SIZE; ++i) { - assertEquals(i, ((Integer)q.poll(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)).intValue()); - } - assertNull(q.poll(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - } catch (InterruptedException e){ - unexpectedException(); + public void testTimedPoll() throws InterruptedException { + LinkedBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.poll(SHORT_DELAY_MS, MILLISECONDS)); } + assertNull(q.poll(SHORT_DELAY_MS, MILLISECONDS)); } /** * Interrupted timed poll throws InterruptedException instead of * returning timeout status */ - public void testInterruptedTimedPoll() { - Thread t = new Thread(new Runnable() { - public void run() { - try { - LinkedBlockingQueue q = populatedQueue(SIZE); - for (int i = 0; i < SIZE; ++i) { - threadAssertEquals(i, ((Integer)q.poll(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)).intValue()); - } - threadAssertNull(q.poll(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - } catch (InterruptedException success){ - } - }}); + public void testInterruptedTimedPoll() throws InterruptedException { + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + LinkedBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.poll(SHORT_DELAY_MS, MILLISECONDS)); + } + try { + q.poll(SMALL_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + t.start(); - try { - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } - catch (InterruptedException ie) { - unexpectedException(); - } + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } /** * timed poll before a delayed offer fails; after offer succeeds; * on interruption throws */ - public void testTimedPollWithOffer() { + public void testTimedPollWithOffer() throws InterruptedException { final LinkedBlockingQueue q = new LinkedBlockingQueue(2); - Thread t = new Thread(new Runnable() { - public void run() { - try { - threadAssertNull(q.poll(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - q.poll(LONG_DELAY_MS, TimeUnit.MILLISECONDS); - q.poll(LONG_DELAY_MS, TimeUnit.MILLISECONDS); - threadShouldThrow(); - } catch (InterruptedException success) { } - } - }); - try { - t.start(); - Thread.sleep(SMALL_DELAY_MS); - assertTrue(q.offer(zero, SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - t.interrupt(); - t.join(); - } catch (Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertNull(q.poll(SHORT_DELAY_MS, MILLISECONDS)); + assertSame(zero, q.poll(LONG_DELAY_MS, MILLISECONDS)); + try { + q.poll(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + t.start(); + Thread.sleep(SMALL_DELAY_MS); + assertTrue(q.offer(zero, SHORT_DELAY_MS, MILLISECONDS)); + t.interrupt(); + t.join(); } /** @@ -558,10 +483,10 @@ public class LinkedBlockingQueueTest extends JSR166TestCase { public void testPeek() { LinkedBlockingQueue q = populatedQueue(SIZE); for (int i = 0; i < SIZE; ++i) { - assertEquals(i, ((Integer)q.peek()).intValue()); - q.poll(); + assertEquals(i, q.peek()); + assertEquals(i, q.poll()); assertTrue(q.peek() == null || - i != ((Integer)q.peek()).intValue()); + !q.peek().equals(i)); } assertNull(q.peek()); } @@ -572,14 +497,13 @@ public class LinkedBlockingQueueTest extends JSR166TestCase { public void testElement() { LinkedBlockingQueue q = populatedQueue(SIZE); for (int i = 0; i < SIZE; ++i) { - assertEquals(i, ((Integer)q.element()).intValue()); - q.poll(); + assertEquals(i, q.element()); + assertEquals(i, q.poll()); } try { q.element(); shouldThrow(); - } - catch (NoSuchElementException success) {} + } catch (NoSuchElementException success) {} } /** @@ -588,13 +512,12 @@ public class LinkedBlockingQueueTest extends JSR166TestCase { public void testRemove() { LinkedBlockingQueue q = populatedQueue(SIZE); for (int i = 0; i < SIZE; ++i) { - assertEquals(i, ((Integer)q.remove()).intValue()); + assertEquals(i, q.remove()); } try { q.remove(); shouldThrow(); - } catch (NoSuchElementException success){ - } + } catch (NoSuchElementException success) {} } /** @@ -615,18 +538,14 @@ public class LinkedBlockingQueueTest extends JSR166TestCase { /** * An add following remove(x) succeeds */ - public void testRemoveElementAndAdd() { - try { - LinkedBlockingQueue q = new LinkedBlockingQueue(); - assertTrue(q.add(new Integer(1))); - assertTrue(q.add(new Integer(2))); - assertTrue(q.remove(new Integer(1))); - assertTrue(q.remove(new Integer(2))); - assertTrue(q.add(new Integer(3))); - assertTrue(q.take() != null); - } catch (Exception e){ - unexpectedException(); - } + public void testRemoveElementAndAdd() throws InterruptedException { + LinkedBlockingQueue q = new LinkedBlockingQueue(); + assertTrue(q.add(new Integer(1))); + assertTrue(q.add(new Integer(2))); + assertTrue(q.remove(new Integer(1))); + assertTrue(q.remove(new Integer(2))); + assertTrue(q.add(new Integer(3))); + assertTrue(q.take() != null); } /** @@ -709,67 +628,55 @@ public class LinkedBlockingQueueTest extends JSR166TestCase { /** * toArray contains all elements */ - public void testToArray() { + public void testToArray() throws InterruptedException { LinkedBlockingQueue q = populatedQueue(SIZE); Object[] o = q.toArray(); - try { - for(int i = 0; i < o.length; i++) + for (int i = 0; i < o.length; i++) assertEquals(o[i], q.take()); - } catch (InterruptedException e){ - unexpectedException(); - } } /** * toArray(a) contains all elements */ - public void testToArray2() { + public void testToArray2() throws InterruptedException { LinkedBlockingQueue q = populatedQueue(SIZE); Integer[] ints = new Integer[SIZE]; ints = (Integer[])q.toArray(ints); - try { - for(int i = 0; i < ints.length; i++) - assertEquals(ints[i], q.take()); - } catch (InterruptedException e){ - unexpectedException(); - } + for (int i = 0; i < ints.length; i++) + assertEquals(ints[i], q.take()); } /** * toArray(null) throws NPE */ public void testToArray_BadArg() { + LinkedBlockingQueue q = populatedQueue(SIZE); try { - LinkedBlockingQueue q = populatedQueue(SIZE); Object o[] = q.toArray(null); shouldThrow(); - } catch(NullPointerException success){} + } catch (NullPointerException success) {} } /** * toArray with incompatible array type throws CCE */ public void testToArray1_BadArg() { + LinkedBlockingQueue q = populatedQueue(SIZE); try { - LinkedBlockingQueue q = populatedQueue(SIZE); - Object o[] = q.toArray(new String[10] ); + Object o[] = q.toArray(new String[10]); shouldThrow(); - } catch(ArrayStoreException success){} + } catch (ArrayStoreException success) {} } /** * iterator iterates through all elements */ - public void testIterator() { + public void testIterator() throws InterruptedException { LinkedBlockingQueue q = populatedQueue(SIZE); Iterator it = q.iterator(); - try { - while(it.hasNext()){ - assertEquals(it.next(), q.take()); - } - } catch (InterruptedException e){ - unexpectedException(); + while (it.hasNext()) { + assertEquals(it.next(), q.take()); } } @@ -787,8 +694,8 @@ public class LinkedBlockingQueueTest extends JSR166TestCase { it.remove(); it = q.iterator(); - assertEquals(it.next(), one); - assertEquals(it.next(), three); + assertSame(it.next(), one); + assertSame(it.next(), three); assertFalse(it.hasNext()); } @@ -804,8 +711,7 @@ public class LinkedBlockingQueueTest extends JSR166TestCase { assertEquals(0, q.remainingCapacity()); int k = 0; for (Iterator it = q.iterator(); it.hasNext();) { - int i = ((Integer)(it.next())).intValue(); - assertEquals(++k, i); + assertEquals(++k, it.next()); } assertEquals(3, k); } @@ -818,14 +724,9 @@ public class LinkedBlockingQueueTest extends JSR166TestCase { q.add(one); q.add(two); q.add(three); - try { - for (Iterator it = q.iterator(); it.hasNext();) { - q.remove(); - it.next(); - } - } - catch (ConcurrentModificationException e) { - unexpectedException(); + for (Iterator it = q.iterator(); it.hasNext();) { + q.remove(); + it.next(); } assertEquals(0, q.size()); } @@ -851,30 +752,18 @@ public class LinkedBlockingQueueTest extends JSR166TestCase { q.add(one); q.add(two); ExecutorService executor = Executors.newFixedThreadPool(2); - executor.execute(new Runnable() { - public void run() { - threadAssertFalse(q.offer(three)); - try { - threadAssertTrue(q.offer(three, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS)); - threadAssertEquals(0, q.remainingCapacity()); - } - catch (InterruptedException e) { - threadUnexpectedException(); - } - } - }); - - executor.execute(new Runnable() { - public void run() { - try { - Thread.sleep(SMALL_DELAY_MS); - threadAssertEquals(one, q.take()); - } - catch (InterruptedException e) { - threadUnexpectedException(); - } - } - }); + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(q.offer(three)); + assertTrue(q.offer(three, MEDIUM_DELAY_MS, MILLISECONDS)); + assertEquals(0, q.remainingCapacity()); + }}); + + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + Thread.sleep(SMALL_DELAY_MS); + assertSame(one, q.take()); + }}); joinPool(executor); } @@ -885,30 +774,18 @@ public class LinkedBlockingQueueTest extends JSR166TestCase { public void testPollInExecutor() { final LinkedBlockingQueue q = new LinkedBlockingQueue(2); ExecutorService executor = Executors.newFixedThreadPool(2); - executor.execute(new Runnable() { - public void run() { - threadAssertNull(q.poll()); - try { - threadAssertTrue(null != q.poll(MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS)); - threadAssertTrue(q.isEmpty()); - } - catch (InterruptedException e) { - threadUnexpectedException(); - } - } - }); - - executor.execute(new Runnable() { - public void run() { - try { - Thread.sleep(SMALL_DELAY_MS); - q.put(one); - } - catch (InterruptedException e) { - threadUnexpectedException(); - } - } - }); + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertNull(q.poll()); + assertSame(one, q.poll(MEDIUM_DELAY_MS, MILLISECONDS)); + assertTrue(q.isEmpty()); + }}); + + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + Thread.sleep(SMALL_DELAY_MS); + q.put(one); + }}); joinPool(executor); } @@ -916,24 +793,20 @@ public class LinkedBlockingQueueTest extends JSR166TestCase { /** * A deserialized serialized queue has same elements in same order */ - public void testSerialization() { + public void testSerialization() throws Exception { LinkedBlockingQueue q = populatedQueue(SIZE); - try { - ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); - ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); - out.writeObject(q); - out.close(); - - ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); - ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); - LinkedBlockingQueue r = (LinkedBlockingQueue)in.readObject(); - assertEquals(q.size(), r.size()); - while (!q.isEmpty()) - assertEquals(q.remove(), r.remove()); - } catch(Exception e){ - unexpectedException(); - } + ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); + ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); + out.writeObject(q); + out.close(); + + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); + LinkedBlockingQueue r = (LinkedBlockingQueue)in.readObject(); + assertEquals(q.size(), r.size()); + while (!q.isEmpty()) + assertEquals(q.remove(), r.remove()); } /** @@ -944,8 +817,7 @@ public class LinkedBlockingQueueTest extends JSR166TestCase { try { q.drainTo(null); shouldThrow(); - } catch(NullPointerException success) { - } + } catch (NullPointerException success) {} } /** @@ -956,8 +828,7 @@ public class LinkedBlockingQueueTest extends JSR166TestCase { try { q.drainTo(q); shouldThrow(); - } catch(IllegalArgumentException success) { - } + } catch (IllegalArgumentException success) {} } /** @@ -987,29 +858,21 @@ public class LinkedBlockingQueueTest extends JSR166TestCase { /** * drainTo empties full queue, unblocking a waiting put. */ - public void testDrainToWithActivePut() { + public void testDrainToWithActivePut() throws InterruptedException { final LinkedBlockingQueue q = populatedQueue(SIZE); - Thread t = new Thread(new Runnable() { - public void run() { - try { - q.put(new Integer(SIZE+1)); - } catch (InterruptedException ie){ - threadUnexpectedException(); - } - } - }); - try { - t.start(); - ArrayList l = new ArrayList(); - q.drainTo(l); - assertTrue(l.size() >= SIZE); - for (int i = 0; i < SIZE; ++i) - assertEquals(l.get(i), new Integer(i)); - t.join(); - assertTrue(q.size() + l.size() >= SIZE); - } catch(Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + q.put(new Integer(SIZE+1)); + }}); + + t.start(); + ArrayList l = new ArrayList(); + q.drainTo(l); + assertTrue(l.size() >= SIZE); + for (int i = 0; i < SIZE; ++i) + assertEquals(l.get(i), new Integer(i)); + t.join(); + assertTrue(q.size() + l.size() >= SIZE); } /** @@ -1020,8 +883,7 @@ public class LinkedBlockingQueueTest extends JSR166TestCase { try { q.drainTo(null, 0); shouldThrow(); - } catch(NullPointerException success) { - } + } catch (NullPointerException success) {} } /** @@ -1032,8 +894,7 @@ public class LinkedBlockingQueueTest extends JSR166TestCase { try { q.drainTo(q, 0); shouldThrow(); - } catch(IllegalArgumentException success) { - } + } catch (IllegalArgumentException success) {} } /** @@ -1042,7 +903,7 @@ public class LinkedBlockingQueueTest extends JSR166TestCase { public void testDrainToN() { LinkedBlockingQueue q = new LinkedBlockingQueue(); for (int i = 0; i < SIZE + 2; ++i) { - for(int j = 0; j < SIZE; j++) + for (int j = 0; j < SIZE; j++) assertTrue(q.offer(new Integer(j))); ArrayList l = new ArrayList(); q.drainTo(l, i); diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/LockSupportTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/LockSupportTest.java index 0a74f91..1052a24 100755 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/LockSupportTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/LockSupportTest.java @@ -2,18 +2,18 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.locks.*; -public class LockSupportTest extends JSR166TestCase{ +public class LockSupportTest extends JSR166TestCase { public static Test suite() { return new TestSuite(LockSupportTest.class); } @@ -21,145 +21,92 @@ public class LockSupportTest extends JSR166TestCase{ /** * park is released by unpark occurring after park */ - public void testPark() { - Thread t = new Thread(new Runnable() { - public void run() { - try { - LockSupport.park(); - } catch(Exception e){ - threadUnexpectedException(); - } - } - }); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - LockSupport.unpark(t); - t.join(); - } - catch(Exception e) { - unexpectedException(); - } + public void testPark() throws InterruptedException { + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + LockSupport.park(); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + LockSupport.unpark(t); + t.join(); } /** * park is released by unpark occurring before park */ - public void testPark2() { - Thread t = new Thread(new Runnable() { - public void run() { - try { - Thread.sleep(SHORT_DELAY_MS); - LockSupport.park(); - } catch(Exception e){ - threadUnexpectedException(); - } - } - }); - try { - t.start(); - LockSupport.unpark(t); - t.join(); - } - catch(Exception e) { - unexpectedException(); - } + public void testPark2() throws InterruptedException { + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + Thread.sleep(SHORT_DELAY_MS); + LockSupport.park(); + }}); + + t.start(); + LockSupport.unpark(t); + t.join(); } /** * park is released by interrupt */ - public void testPark3() { - Thread t = new Thread(new Runnable() { - public void run() { - try { - LockSupport.park(); - } catch(Exception e){ - threadUnexpectedException(); - } - } - }); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } - catch(Exception e) { - unexpectedException(); - } + public void testPark3() throws InterruptedException { + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + LockSupport.park(); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } /** * park returns if interrupted before park */ - public void testPark4() { + public void testPark4() throws InterruptedException { final ReentrantLock lock = new ReentrantLock(); lock.lock(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - lock.lock(); - LockSupport.park(); - } catch(Exception e){ - threadUnexpectedException(); - } - } - }); - try { - t.start(); - t.interrupt(); - lock.unlock(); - t.join(); - } - catch(Exception e) { - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + lock.lock(); + LockSupport.park(); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + lock.unlock(); + t.join(); } /** * parkNanos times out if not unparked */ - public void testParkNanos() { - Thread t = new Thread(new Runnable() { - public void run() { - try { - LockSupport.parkNanos(1000); - } catch(Exception e){ - threadUnexpectedException(); - } - } - }); - try { - t.start(); - t.join(); - } - catch(Exception e) { - unexpectedException(); - } + public void testParkNanos() throws InterruptedException { + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + LockSupport.parkNanos(1000); + }}); + + t.start(); + t.join(); } /** * parkUntil times out if not unparked */ - public void testParkUntil() { - Thread t = new Thread(new Runnable() { - public void run() { - try { - long d = new Date().getTime() + 100; - LockSupport.parkUntil(d); - } catch(Exception e){ - threadUnexpectedException(); - } - } - }); - try { - t.start(); - t.join(); - } - catch(Exception e) { - unexpectedException(); - } + public void testParkUntil() throws InterruptedException { + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + long d = new Date().getTime() + 100; + LockSupport.parkUntil(d); + }}); + + t.start(); + t.join(); } } diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/PriorityBlockingQueueTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/PriorityBlockingQueueTest.java index a764866..f1dd88d 100755 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/PriorityBlockingQueueTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/PriorityBlockingQueueTest.java @@ -2,15 +2,16 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.*; import java.util.concurrent.*; +import static java.util.concurrent.TimeUnit.MILLISECONDS; import java.io.*; public class PriorityBlockingQueueTest extends JSR166TestCase { @@ -21,13 +22,9 @@ public class PriorityBlockingQueueTest extends JSR166TestCase { private static final int NOCAP = Integer.MAX_VALUE; /** Sample Comparator */ - static class MyReverseComparator implements Comparator { + static class MyReverseComparator implements Comparator { public int compare(Object x, Object y) { - int i = ((Integer)x).intValue(); - int j = ((Integer)y).intValue(); - if (i < j) return 1; - if (i > j) return -1; - return 0; + return ((Comparable)y).compareTo(x); } } @@ -38,16 +35,16 @@ public class PriorityBlockingQueueTest extends JSR166TestCase { private PriorityBlockingQueue populatedQueue(int n) { PriorityBlockingQueue q = new PriorityBlockingQueue(n); assertTrue(q.isEmpty()); - for(int i = n-1; i >= 0; i-=2) + for (int i = n-1; i >= 0; i-=2) assertTrue(q.offer(new Integer(i))); - for(int i = (n & 1); i < n; i+=2) + for (int i = (n & 1); i < n; i+=2) assertTrue(q.offer(new Integer(i))); assertFalse(q.isEmpty()); assertEquals(NOCAP, q.remainingCapacity()); assertEquals(n, q.size()); return q; } - + /** * A new queue has unbounded capacity */ @@ -56,14 +53,13 @@ public class PriorityBlockingQueueTest extends JSR166TestCase { } /** - * Constructor throws IAE if capacity argument nonpositive + * Constructor throws IAE if capacity argument nonpositive */ public void testConstructor2() { try { PriorityBlockingQueue q = new PriorityBlockingQueue(0); shouldThrow(); - } - catch (IllegalArgumentException success) {} + } catch (IllegalArgumentException success) {} } /** @@ -73,8 +69,7 @@ public class PriorityBlockingQueueTest extends JSR166TestCase { try { PriorityBlockingQueue q = new PriorityBlockingQueue(null); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** @@ -85,8 +80,7 @@ public class PriorityBlockingQueueTest extends JSR166TestCase { Integer[] ints = new Integer[SIZE]; PriorityBlockingQueue q = new PriorityBlockingQueue(Arrays.asList(ints)); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** @@ -99,41 +93,34 @@ public class PriorityBlockingQueueTest extends JSR166TestCase { ints[i] = new Integer(i); PriorityBlockingQueue q = new PriorityBlockingQueue(Arrays.asList(ints)); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** * Queue contains all elements of collection used to initialize */ public void testConstructor6() { - try { - Integer[] ints = new Integer[SIZE]; - for (int i = 0; i < SIZE; ++i) - ints[i] = new Integer(i); - PriorityBlockingQueue q = new PriorityBlockingQueue(Arrays.asList(ints)); - for (int i = 0; i < SIZE; ++i) - assertEquals(ints[i], q.poll()); - } - finally {} + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + PriorityBlockingQueue q = new PriorityBlockingQueue(Arrays.asList(ints)); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.poll()); } /** * The comparator used in constructor is used */ public void testConstructor7() { - try { - MyReverseComparator cmp = new MyReverseComparator(); - PriorityBlockingQueue q = new PriorityBlockingQueue(SIZE, cmp); - assertEquals(cmp, q.comparator()); - Integer[] ints = new Integer[SIZE]; - for (int i = 0; i < SIZE; ++i) - ints[i] = new Integer(i); - q.addAll(Arrays.asList(ints)); - for (int i = SIZE-1; i >= 0; --i) - assertEquals(ints[i], q.poll()); - } - finally {} + MyReverseComparator cmp = new MyReverseComparator(); + PriorityBlockingQueue q = new PriorityBlockingQueue(SIZE, cmp); + assertEquals(cmp, q.comparator()); + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + q.addAll(Arrays.asList(ints)); + for (int i = SIZE-1; i >= 0; --i) + assertEquals(ints[i], q.poll()); } /** @@ -177,7 +164,7 @@ public class PriorityBlockingQueueTest extends JSR166TestCase { PriorityBlockingQueue q = new PriorityBlockingQueue(1); q.offer(null); shouldThrow(); - } catch (NullPointerException success) { } + } catch (NullPointerException success) {} } /** @@ -188,7 +175,7 @@ public class PriorityBlockingQueueTest extends JSR166TestCase { PriorityBlockingQueue q = new PriorityBlockingQueue(1); q.add(null); shouldThrow(); - } catch (NullPointerException success) { } + } catch (NullPointerException success) {} } /** @@ -210,8 +197,7 @@ public class PriorityBlockingQueueTest extends JSR166TestCase { q.offer(new Object()); q.offer(new Object()); shouldThrow(); - } - catch(ClassCastException success) {} + } catch (ClassCastException success) {} } /** @@ -233,8 +219,7 @@ public class PriorityBlockingQueueTest extends JSR166TestCase { PriorityBlockingQueue q = new PriorityBlockingQueue(1); q.addAll(null); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** @@ -245,8 +230,7 @@ public class PriorityBlockingQueueTest extends JSR166TestCase { PriorityBlockingQueue q = populatedQueue(SIZE); q.addAll(q); shouldThrow(); - } - catch (IllegalArgumentException success) {} + } catch (IllegalArgumentException success) {} } /** @@ -258,8 +242,7 @@ public class PriorityBlockingQueueTest extends JSR166TestCase { Integer[] ints = new Integer[SIZE]; q.addAll(Arrays.asList(ints)); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** * addAll of a collection with any null elements throws NPE after @@ -273,26 +256,22 @@ public class PriorityBlockingQueueTest extends JSR166TestCase { ints[i] = new Integer(i); q.addAll(Arrays.asList(ints)); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** * Queue contains all elements of successful addAll */ public void testAddAll5() { - try { - Integer[] empty = new Integer[0]; - Integer[] ints = new Integer[SIZE]; - for (int i = SIZE-1; i >= 0; --i) - ints[i] = new Integer(i); - PriorityBlockingQueue q = new PriorityBlockingQueue(SIZE); - assertFalse(q.addAll(Arrays.asList(empty))); - assertTrue(q.addAll(Arrays.asList(ints))); - for (int i = 0; i < SIZE; ++i) - assertEquals(ints[i], q.poll()); - } - finally {} + Integer[] empty = new Integer[0]; + Integer[] ints = new Integer[SIZE]; + for (int i = SIZE-1; i >= 0; --i) + ints[i] = new Integer(i); + PriorityBlockingQueue q = new PriorityBlockingQueue(SIZE); + assertFalse(q.addAll(Arrays.asList(empty))); + assertTrue(q.addAll(Arrays.asList(ints))); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.poll()); } /** @@ -303,149 +282,107 @@ public class PriorityBlockingQueueTest extends JSR166TestCase { PriorityBlockingQueue q = new PriorityBlockingQueue(SIZE); q.put(null); shouldThrow(); - } - catch (NullPointerException success){ - } + } catch (NullPointerException success) {} } /** * all elements successfully put are contained */ public void testPut() { - try { - PriorityBlockingQueue q = new PriorityBlockingQueue(SIZE); - for (int i = 0; i < SIZE; ++i) { - Integer I = new Integer(i); - q.put(I); - assertTrue(q.contains(I)); - } - assertEquals(SIZE, q.size()); + PriorityBlockingQueue q = new PriorityBlockingQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + Integer I = new Integer(i); + q.put(I); + assertTrue(q.contains(I)); } - finally { - } + assertEquals(SIZE, q.size()); } /** * put doesn't block waiting for take */ - public void testPutWithTake() { + public void testPutWithTake() throws InterruptedException { final PriorityBlockingQueue q = new PriorityBlockingQueue(2); - Thread t = new Thread(new Runnable() { - public void run() { - int added = 0; - try { - q.put(new Integer(0)); - ++added; - q.put(new Integer(0)); - ++added; - q.put(new Integer(0)); - ++added; - q.put(new Integer(0)); - ++added; - threadAssertTrue(added == 4); - } finally { - } - } - }); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - q.take(); - t.interrupt(); - t.join(); - } catch (Exception e){ - unexpectedException(); - } + final int size = 4; + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + for (int i = 0; i < size; i++) + q.put(new Integer(0)); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(q.size(), size); + q.take(); + t.interrupt(); + t.join(); } /** * timed offer does not time out */ - public void testTimedOffer() { + public void testTimedOffer() throws InterruptedException { final PriorityBlockingQueue q = new PriorityBlockingQueue(2); - Thread t = new Thread(new Runnable() { - public void run() { - try { - q.put(new Integer(0)); - q.put(new Integer(0)); - threadAssertTrue(q.offer(new Integer(0), SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - threadAssertTrue(q.offer(new Integer(0), LONG_DELAY_MS, TimeUnit.MILLISECONDS)); - } finally { } - } - }); - - try { - t.start(); - Thread.sleep(SMALL_DELAY_MS); - t.interrupt(); - t.join(); - } catch (Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + q.put(new Integer(0)); + q.put(new Integer(0)); + assertTrue(q.offer(new Integer(0), SHORT_DELAY_MS, MILLISECONDS)); + assertTrue(q.offer(new Integer(0), LONG_DELAY_MS, MILLISECONDS)); + }}); + + t.start(); + Thread.sleep(SMALL_DELAY_MS); + t.interrupt(); + t.join(); } /** * take retrieves elements in priority order */ - public void testTake() { - try { - PriorityBlockingQueue q = populatedQueue(SIZE); - for (int i = 0; i < SIZE; ++i) { - assertEquals(i, ((Integer)q.take()).intValue()); - } - } catch (InterruptedException e){ - unexpectedException(); - } + public void testTake() throws InterruptedException { + PriorityBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.take()); + } } /** * take blocks interruptibly when empty */ - public void testTakeFromEmpty() { + public void testTakeFromEmpty() throws InterruptedException { final PriorityBlockingQueue q = new PriorityBlockingQueue(2); - Thread t = new Thread(new Runnable() { - public void run() { - try { - q.take(); - threadShouldThrow(); - } catch (InterruptedException success){ } - } - }); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } catch (Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + q.take(); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } /** * Take removes existing elements until empty, then blocks interruptibly */ - public void testBlockingTake() { - Thread t = new Thread(new Runnable() { - public void run() { - try { - PriorityBlockingQueue q = populatedQueue(SIZE); - for (int i = 0; i < SIZE; ++i) { - threadAssertEquals(i, ((Integer)q.take()).intValue()); - } - q.take(); - threadShouldThrow(); - } catch (InterruptedException success){ - } - }}); + public void testBlockingTake() throws InterruptedException { + final PriorityBlockingQueue q = populatedQueue(SIZE); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.take()); + } + try { + q.take(); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + t.start(); - try { - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } - catch (InterruptedException ie) { - unexpectedException(); - } + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } @@ -455,7 +392,7 @@ public class PriorityBlockingQueueTest extends JSR166TestCase { public void testPoll() { PriorityBlockingQueue q = populatedQueue(SIZE); for (int i = 0; i < SIZE; ++i) { - assertEquals(i, ((Integer)q.poll()).intValue()); + assertEquals(i, q.poll()); } assertNull(q.poll()); } @@ -463,86 +400,70 @@ public class PriorityBlockingQueueTest extends JSR166TestCase { /** * timed pool with zero timeout succeeds when non-empty, else times out */ - public void testTimedPoll0() { - try { - PriorityBlockingQueue q = populatedQueue(SIZE); - for (int i = 0; i < SIZE; ++i) { - assertEquals(i, ((Integer)q.poll(0, TimeUnit.MILLISECONDS)).intValue()); - } - assertNull(q.poll(0, TimeUnit.MILLISECONDS)); - } catch (InterruptedException e){ - unexpectedException(); - } + public void testTimedPoll0() throws InterruptedException { + PriorityBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.poll(0, MILLISECONDS)); + } + assertNull(q.poll(0, MILLISECONDS)); } /** * timed pool with nonzero timeout succeeds when non-empty, else times out */ - public void testTimedPoll() { - try { - PriorityBlockingQueue q = populatedQueue(SIZE); - for (int i = 0; i < SIZE; ++i) { - assertEquals(i, ((Integer)q.poll(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)).intValue()); - } - assertNull(q.poll(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - } catch (InterruptedException e){ - unexpectedException(); - } + public void testTimedPoll() throws InterruptedException { + PriorityBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.poll(SHORT_DELAY_MS, MILLISECONDS)); + } + assertNull(q.poll(SHORT_DELAY_MS, MILLISECONDS)); } /** * Interrupted timed poll throws InterruptedException instead of * returning timeout status */ - public void testInterruptedTimedPoll() { - Thread t = new Thread(new Runnable() { - public void run() { - try { - PriorityBlockingQueue q = populatedQueue(SIZE); - for (int i = 0; i < SIZE; ++i) { - threadAssertEquals(i, ((Integer)q.poll(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)).intValue()); - } - threadAssertNull(q.poll(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - } catch (InterruptedException success){ - } - }}); + public void testInterruptedTimedPoll() throws InterruptedException { + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + PriorityBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.poll(SHORT_DELAY_MS, MILLISECONDS)); + } + try { + q.poll(SMALL_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + t.start(); - try { - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } - catch (InterruptedException ie) { - unexpectedException(); - } + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } /** * timed poll before a delayed offer fails; after offer succeeds; * on interruption throws */ - public void testTimedPollWithOffer() { + public void testTimedPollWithOffer() throws InterruptedException { final PriorityBlockingQueue q = new PriorityBlockingQueue(2); - Thread t = new Thread(new Runnable() { - public void run() { - try { - threadAssertNull(q.poll(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - q.poll(LONG_DELAY_MS, TimeUnit.MILLISECONDS); - q.poll(LONG_DELAY_MS, TimeUnit.MILLISECONDS); - threadShouldThrow(); - } catch (InterruptedException success) { } - } - }); - try { - t.start(); - Thread.sleep(SMALL_DELAY_MS); - assertTrue(q.offer(new Integer(0), SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - t.interrupt(); - t.join(); - } catch (Exception e){ - unexpectedException(); - } - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertNull(q.poll(SHORT_DELAY_MS, MILLISECONDS)); + assertSame(zero, q.poll(MEDIUM_DELAY_MS, MILLISECONDS)); + try { + q.poll(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + t.start(); + Thread.sleep(SMALL_DELAY_MS); + assertTrue(q.offer(zero, SHORT_DELAY_MS, MILLISECONDS)); + t.interrupt(); + t.join(); + } /** @@ -551,10 +472,10 @@ public class PriorityBlockingQueueTest extends JSR166TestCase { public void testPeek() { PriorityBlockingQueue q = populatedQueue(SIZE); for (int i = 0; i < SIZE; ++i) { - assertEquals(i, ((Integer)q.peek()).intValue()); - q.poll(); + assertEquals(i, q.peek()); + assertEquals(i, q.poll()); assertTrue(q.peek() == null || - i != ((Integer)q.peek()).intValue()); + !q.peek().equals(i)); } assertNull(q.peek()); } @@ -565,14 +486,13 @@ public class PriorityBlockingQueueTest extends JSR166TestCase { public void testElement() { PriorityBlockingQueue q = populatedQueue(SIZE); for (int i = 0; i < SIZE; ++i) { - assertEquals(i, ((Integer)q.element()).intValue()); - q.poll(); + assertEquals(i, q.element()); + assertEquals(i, q.poll()); } try { q.element(); shouldThrow(); - } - catch (NoSuchElementException success) {} + } catch (NoSuchElementException success) {} } /** @@ -581,13 +501,12 @@ public class PriorityBlockingQueueTest extends JSR166TestCase { public void testRemove() { PriorityBlockingQueue q = populatedQueue(SIZE); for (int i = 0; i < SIZE; ++i) { - assertEquals(i, ((Integer)q.remove()).intValue()); + assertEquals(i, q.remove()); } try { q.remove(); shouldThrow(); - } catch (NoSuchElementException success){ - } + } catch (NoSuchElementException success) {} } /** @@ -604,7 +523,7 @@ public class PriorityBlockingQueueTest extends JSR166TestCase { } assertTrue(q.isEmpty()); } - + /** * contains(x) reports true when elements added but not yet removed */ @@ -684,56 +603,48 @@ public class PriorityBlockingQueueTest extends JSR166TestCase { /** * toArray contains all elements */ - public void testToArray() { + public void testToArray() throws InterruptedException { PriorityBlockingQueue q = populatedQueue(SIZE); Object[] o = q.toArray(); Arrays.sort(o); - try { - for(int i = 0; i < o.length; i++) + for (int i = 0; i < o.length; i++) assertEquals(o[i], q.take()); - } catch (InterruptedException e){ - unexpectedException(); - } } /** * toArray(a) contains all elements */ - public void testToArray2() { + public void testToArray2() throws InterruptedException { PriorityBlockingQueue q = populatedQueue(SIZE); Integer[] ints = new Integer[SIZE]; ints = (Integer[])q.toArray(ints); Arrays.sort(ints); - try { - for(int i = 0; i < ints.length; i++) - assertEquals(ints[i], q.take()); - } catch (InterruptedException e){ - unexpectedException(); - } + for (int i = 0; i < ints.length; i++) + assertEquals(ints[i], q.take()); } /** * toArray(null) throws NPE */ public void testToArray_BadArg() { + PriorityBlockingQueue q = populatedQueue(SIZE); try { - PriorityBlockingQueue q = populatedQueue(SIZE); Object o[] = q.toArray(null); shouldThrow(); - } catch(NullPointerException success){} + } catch (NullPointerException success) {} } /** * toArray with incompatible array type throws CCE */ public void testToArray1_BadArg() { + PriorityBlockingQueue q = populatedQueue(SIZE); try { - PriorityBlockingQueue q = populatedQueue(SIZE); - Object o[] = q.toArray(new String[10] ); + Object o[] = q.toArray(new String[10]); shouldThrow(); - } catch(ArrayStoreException success){} + } catch (ArrayStoreException success) {} } - + /** * iterator iterates through all elements */ @@ -741,7 +652,7 @@ public class PriorityBlockingQueueTest extends JSR166TestCase { PriorityBlockingQueue q = populatedQueue(SIZE); int i = 0; Iterator it = q.iterator(); - while(it.hasNext()) { + while (it.hasNext()) { assertTrue(q.contains(it.next())); ++i; } @@ -777,7 +688,7 @@ public class PriorityBlockingQueueTest extends JSR166TestCase { for (int i = 0; i < SIZE; ++i) { assertTrue(s.indexOf(String.valueOf(i)) >= 0); } - } + } /** * offer transfers elements across Executor tasks @@ -785,90 +696,72 @@ public class PriorityBlockingQueueTest extends JSR166TestCase { public void testPollInExecutor() { final PriorityBlockingQueue q = new PriorityBlockingQueue(2); ExecutorService executor = Executors.newFixedThreadPool(2); - executor.execute(new Runnable() { - public void run() { - threadAssertNull(q.poll()); - try { - threadAssertTrue(null != q.poll(MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS)); - threadAssertTrue(q.isEmpty()); - } - catch (InterruptedException e) { - threadUnexpectedException(); - } - } - }); + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertNull(q.poll()); + assertSame(one, q.poll(MEDIUM_DELAY_MS, MILLISECONDS)); + assertTrue(q.isEmpty()); + }}); + + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + Thread.sleep(SMALL_DELAY_MS); + q.put(one); + }}); - executor.execute(new Runnable() { - public void run() { - try { - Thread.sleep(SMALL_DELAY_MS); - q.put(new Integer(1)); - } - catch (InterruptedException e) { - threadUnexpectedException(); - } - } - }); - joinPool(executor); } /** - * A deserialized serialized queue has same elements + * A deserialized serialized queue has same elements */ - public void testSerialization() { + public void testSerialization() throws Exception { PriorityBlockingQueue q = populatedQueue(SIZE); - try { - ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); - ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); - out.writeObject(q); - out.close(); - - ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); - ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); - PriorityBlockingQueue r = (PriorityBlockingQueue)in.readObject(); - assertEquals(q.size(), r.size()); - while (!q.isEmpty()) - assertEquals(q.remove(), r.remove()); - } catch(Exception e){ - unexpectedException(); - } + ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); + ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); + out.writeObject(q); + out.close(); + + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); + PriorityBlockingQueue r = (PriorityBlockingQueue)in.readObject(); + assertEquals(q.size(), r.size()); + while (!q.isEmpty()) + assertEquals(q.remove(), r.remove()); } /** * drainTo(null) throws NPE - */ + */ public void testDrainToNull() { PriorityBlockingQueue q = populatedQueue(SIZE); try { q.drainTo(null); shouldThrow(); - } catch(NullPointerException success) { - } + } catch (NullPointerException success) {} } /** * drainTo(this) throws IAE - */ + */ public void testDrainToSelf() { PriorityBlockingQueue q = populatedQueue(SIZE); try { q.drainTo(q); shouldThrow(); - } catch(IllegalArgumentException success) { - } + } catch (IllegalArgumentException success) {} } /** * drainTo(c) empties queue into another collection c - */ + */ public void testDrainTo() { PriorityBlockingQueue q = populatedQueue(SIZE); ArrayList l = new ArrayList(); q.drainTo(l); assertEquals(q.size(), 0); assertEquals(l.size(), SIZE); - for (int i = 0; i < SIZE; ++i) + for (int i = 0; i < SIZE; ++i) assertEquals(l.get(i), new Integer(i)); q.add(zero); q.add(one); @@ -879,76 +772,69 @@ public class PriorityBlockingQueueTest extends JSR166TestCase { q.drainTo(l); assertEquals(q.size(), 0); assertEquals(l.size(), 2); - for (int i = 0; i < 2; ++i) + for (int i = 0; i < 2; ++i) assertEquals(l.get(i), new Integer(i)); } /** * drainTo empties queue - */ - public void testDrainToWithActivePut() { + */ + public void testDrainToWithActivePut() throws InterruptedException { final PriorityBlockingQueue q = populatedQueue(SIZE); - Thread t = new Thread(new Runnable() { - public void run() { - q.put(new Integer(SIZE+1)); - } - }); - try { - t.start(); - ArrayList l = new ArrayList(); - q.drainTo(l); - assertTrue(l.size() >= SIZE); - for (int i = 0; i < SIZE; ++i) - assertEquals(l.get(i), new Integer(i)); - t.join(); - assertTrue(q.size() + l.size() >= SIZE); - } catch(Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + q.put(new Integer(SIZE+1)); + }}); + + t.start(); + ArrayList l = new ArrayList(); + q.drainTo(l); + assertTrue(l.size() >= SIZE); + for (int i = 0; i < SIZE; ++i) + assertEquals(l.get(i), new Integer(i)); + t.join(); + assertTrue(q.size() + l.size() >= SIZE); } /** * drainTo(null, n) throws NPE - */ + */ public void testDrainToNullN() { PriorityBlockingQueue q = populatedQueue(SIZE); try { q.drainTo(null, 0); shouldThrow(); - } catch(NullPointerException success) { - } + } catch (NullPointerException success) {} } /** * drainTo(this, n) throws IAE - */ + */ public void testDrainToSelfN() { PriorityBlockingQueue q = populatedQueue(SIZE); try { q.drainTo(q, 0); shouldThrow(); - } catch(IllegalArgumentException success) { - } + } catch (IllegalArgumentException success) {} } /** * drainTo(c, n) empties first max {n, size} elements of queue into c - */ + */ public void testDrainToN() { PriorityBlockingQueue q = new PriorityBlockingQueue(SIZE*2); for (int i = 0; i < SIZE + 2; ++i) { - for(int j = 0; j < SIZE; j++) + for (int j = 0; j < SIZE; j++) assertTrue(q.offer(new Integer(j))); ArrayList l = new ArrayList(); q.drainTo(l, i); int k = (i < SIZE)? i : SIZE; assertEquals(l.size(), k); assertEquals(q.size(), SIZE-k); - for (int j = 0; j < k; ++j) + for (int j = 0; j < k; ++j) assertEquals(l.get(j), new Integer(j)); while (q.poll() != null) ; } } - } diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/PriorityQueueTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/PriorityQueueTest.java index 3d3c1be..12ddef4 100755 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/PriorityQueueTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/PriorityQueueTest.java @@ -2,11 +2,11 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.*; @@ -18,13 +18,9 @@ public class PriorityQueueTest extends JSR166TestCase { return new TestSuite(PriorityQueueTest.class); } - static class MyReverseComparator implements Comparator { + static class MyReverseComparator implements Comparator { public int compare(Object x, Object y) { - int i = ((Integer)x).intValue(); - int j = ((Integer)y).intValue(); - if (i < j) return 1; - if (i > j) return -1; - return 0; + return ((Comparable)y).compareTo(x); } } @@ -35,15 +31,15 @@ public class PriorityQueueTest extends JSR166TestCase { private PriorityQueue populatedQueue(int n) { PriorityQueue q = new PriorityQueue(n); assertTrue(q.isEmpty()); - for(int i = n-1; i >= 0; i-=2) + for (int i = n-1; i >= 0; i-=2) assertTrue(q.offer(new Integer(i))); - for(int i = (n & 1); i < n; i+=2) + for (int i = (n & 1); i < n; i+=2) assertTrue(q.offer(new Integer(i))); assertFalse(q.isEmpty()); assertEquals(n, q.size()); return q; } - + /** * A new queue has unbounded capacity */ @@ -52,14 +48,13 @@ public class PriorityQueueTest extends JSR166TestCase { } /** - * Constructor throws IAE if capacity argument nonpositive + * Constructor throws IAE if capacity argument nonpositive */ public void testConstructor2() { try { PriorityQueue q = new PriorityQueue(0); shouldThrow(); - } - catch (IllegalArgumentException success) {} + } catch (IllegalArgumentException success) {} } /** @@ -69,8 +64,7 @@ public class PriorityQueueTest extends JSR166TestCase { try { PriorityQueue q = new PriorityQueue((Collection)null); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** @@ -81,8 +75,7 @@ public class PriorityQueueTest extends JSR166TestCase { Integer[] ints = new Integer[SIZE]; PriorityQueue q = new PriorityQueue(Arrays.asList(ints)); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** @@ -95,41 +88,34 @@ public class PriorityQueueTest extends JSR166TestCase { ints[i] = new Integer(i); PriorityQueue q = new PriorityQueue(Arrays.asList(ints)); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** * Queue contains all elements of collection used to initialize */ public void testConstructor6() { - try { - Integer[] ints = new Integer[SIZE]; - for (int i = 0; i < SIZE; ++i) - ints[i] = new Integer(i); - PriorityQueue q = new PriorityQueue(Arrays.asList(ints)); - for (int i = 0; i < SIZE; ++i) - assertEquals(ints[i], q.poll()); - } - finally {} + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + PriorityQueue q = new PriorityQueue(Arrays.asList(ints)); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.poll()); } /** * The comparator used in constructor is used */ public void testConstructor7() { - try { - MyReverseComparator cmp = new MyReverseComparator(); - PriorityQueue q = new PriorityQueue(SIZE, cmp); - assertEquals(cmp, q.comparator()); - Integer[] ints = new Integer[SIZE]; - for (int i = 0; i < SIZE; ++i) - ints[i] = new Integer(i); - q.addAll(Arrays.asList(ints)); - for (int i = SIZE-1; i >= 0; --i) - assertEquals(ints[i], q.poll()); - } - finally {} + MyReverseComparator cmp = new MyReverseComparator(); + PriorityQueue q = new PriorityQueue(SIZE, cmp); + assertEquals(cmp, q.comparator()); + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + q.addAll(Arrays.asList(ints)); + for (int i = SIZE-1; i >= 0; --i) + assertEquals(ints[i], q.poll()); } /** @@ -169,7 +155,7 @@ public class PriorityQueueTest extends JSR166TestCase { PriorityQueue q = new PriorityQueue(1); q.offer(null); shouldThrow(); - } catch (NullPointerException success) { } + } catch (NullPointerException success) {} } /** @@ -180,7 +166,7 @@ public class PriorityQueueTest extends JSR166TestCase { PriorityQueue q = new PriorityQueue(1); q.add(null); shouldThrow(); - } catch (NullPointerException success) { } + } catch (NullPointerException success) {} } /** @@ -202,8 +188,7 @@ public class PriorityQueueTest extends JSR166TestCase { q.offer(new Object()); q.offer(new Object()); shouldThrow(); - } - catch(ClassCastException success) {} + } catch (ClassCastException success) {} } /** @@ -225,8 +210,7 @@ public class PriorityQueueTest extends JSR166TestCase { PriorityQueue q = new PriorityQueue(1); q.addAll(null); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** * addAll of a collection with null elements throws NPE @@ -237,8 +221,7 @@ public class PriorityQueueTest extends JSR166TestCase { Integer[] ints = new Integer[SIZE]; q.addAll(Arrays.asList(ints)); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** * addAll of a collection with any null elements throws NPE after @@ -252,26 +235,22 @@ public class PriorityQueueTest extends JSR166TestCase { ints[i] = new Integer(i); q.addAll(Arrays.asList(ints)); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** * Queue contains all elements of successful addAll */ public void testAddAll5() { - try { - Integer[] empty = new Integer[0]; - Integer[] ints = new Integer[SIZE]; - for (int i = 0; i < SIZE; ++i) - ints[i] = new Integer(SIZE-1-i); - PriorityQueue q = new PriorityQueue(SIZE); - assertFalse(q.addAll(Arrays.asList(empty))); - assertTrue(q.addAll(Arrays.asList(ints))); - for (int i = 0; i < SIZE; ++i) - assertEquals(new Integer(i), q.poll()); - } - finally {} + Integer[] empty = new Integer[0]; + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(SIZE-1-i); + PriorityQueue q = new PriorityQueue(SIZE); + assertFalse(q.addAll(Arrays.asList(empty))); + assertTrue(q.addAll(Arrays.asList(ints))); + for (int i = 0; i < SIZE; ++i) + assertEquals(new Integer(i), q.poll()); } /** @@ -280,7 +259,7 @@ public class PriorityQueueTest extends JSR166TestCase { public void testPoll() { PriorityQueue q = populatedQueue(SIZE); for (int i = 0; i < SIZE; ++i) { - assertEquals(i, ((Integer)q.poll()).intValue()); + assertEquals(i, q.poll()); } assertNull(q.poll()); } @@ -291,10 +270,10 @@ public class PriorityQueueTest extends JSR166TestCase { public void testPeek() { PriorityQueue q = populatedQueue(SIZE); for (int i = 0; i < SIZE; ++i) { - assertEquals(i, ((Integer)q.peek()).intValue()); - q.poll(); + assertEquals(i, q.peek()); + assertEquals(i, q.poll()); assertTrue(q.peek() == null || - i != ((Integer)q.peek()).intValue()); + !q.peek().equals(i)); } assertNull(q.peek()); } @@ -305,14 +284,13 @@ public class PriorityQueueTest extends JSR166TestCase { public void testElement() { PriorityQueue q = populatedQueue(SIZE); for (int i = 0; i < SIZE; ++i) { - assertEquals(i, ((Integer)q.element()).intValue()); - q.poll(); + assertEquals(i, q.element()); + assertEquals(i, q.poll()); } try { q.element(); shouldThrow(); - } - catch (NoSuchElementException success) {} + } catch (NoSuchElementException success) {} } /** @@ -321,13 +299,12 @@ public class PriorityQueueTest extends JSR166TestCase { public void testRemove() { PriorityQueue q = populatedQueue(SIZE); for (int i = 0; i < SIZE; ++i) { - assertEquals(i, ((Integer)q.remove()).intValue()); + assertEquals(i, q.remove()); } try { q.remove(); shouldThrow(); - } catch (NoSuchElementException success){ - } + } catch (NoSuchElementException success) {} } /** @@ -344,7 +321,7 @@ public class PriorityQueueTest extends JSR166TestCase { } assertTrue(q.isEmpty()); } - + /** * contains(x) reports true when elements added but not yet removed */ @@ -427,7 +404,7 @@ public class PriorityQueueTest extends JSR166TestCase { PriorityQueue q = populatedQueue(SIZE); Object[] o = q.toArray(); Arrays.sort(o); - for(int i = 0; i < o.length; i++) + for (int i = 0; i < o.length; i++) assertEquals(o[i], q.poll()); } @@ -439,10 +416,10 @@ public class PriorityQueueTest extends JSR166TestCase { Integer[] ints = new Integer[SIZE]; ints = (Integer[])q.toArray(ints); Arrays.sort(ints); - for(int i = 0; i < ints.length; i++) + for (int i = 0; i < ints.length; i++) assertEquals(ints[i], q.poll()); } - + /** * iterator iterates through all elements */ @@ -450,7 +427,7 @@ public class PriorityQueueTest extends JSR166TestCase { PriorityQueue q = populatedQueue(SIZE); int i = 0; Iterator it = q.iterator(); - while(it.hasNext()) { + while (it.hasNext()) { assertTrue(q.contains(it.next())); ++i; } @@ -486,27 +463,23 @@ public class PriorityQueueTest extends JSR166TestCase { for (int i = 0; i < SIZE; ++i) { assertTrue(s.indexOf(String.valueOf(i)) >= 0); } - } + } /** - * A deserialized serialized queue has same elements + * A deserialized serialized queue has same elements */ - public void testSerialization() { + public void testSerialization() throws Exception { PriorityQueue q = populatedQueue(SIZE); - try { - ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); - ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); - out.writeObject(q); - out.close(); - - ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); - ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); - PriorityQueue r = (PriorityQueue)in.readObject(); - assertEquals(q.size(), r.size()); - while (!q.isEmpty()) - assertEquals(q.remove(), r.remove()); - } catch(Exception e){ - unexpectedException(); - } + ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); + ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); + out.writeObject(q); + out.close(); + + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); + PriorityQueue r = (PriorityQueue)in.readObject(); + assertEquals(q.size(), r.size()); + while (!q.isEmpty()) + assertEquals(q.remove(), r.remove()); } } diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/ReentrantLockTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/ReentrantLockTest.java index 8372251..d6b434e 100755 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/ReentrantLockTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/ReentrantLockTest.java @@ -2,15 +2,16 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.concurrent.locks.*; import java.util.concurrent.*; +import static java.util.concurrent.TimeUnit.MILLISECONDS; import java.util.*; import java.io.*; @@ -22,13 +23,11 @@ public class ReentrantLockTest extends JSR166TestCase { /** * A runnable calling lockInterruptibly */ - class InterruptibleLockRunnable implements Runnable { + class InterruptibleLockRunnable extends CheckedRunnable { final ReentrantLock lock; InterruptibleLockRunnable(ReentrantLock l) { lock = l; } - public void run() { - try { - lock.lockInterruptibly(); - } catch(InterruptedException success){} + public void realRun() throws InterruptedException { + lock.lockInterruptibly(); } } @@ -37,14 +36,11 @@ public class ReentrantLockTest extends JSR166TestCase { * A runnable calling lockInterruptibly that expects to be * interrupted */ - class InterruptedLockRunnable implements Runnable { + class InterruptedLockRunnable extends CheckedInterruptedRunnable { final ReentrantLock lock; InterruptedLockRunnable(ReentrantLock l) { lock = l; } - public void run() { - try { - lock.lockInterruptibly(); - threadShouldThrow(); - } catch(InterruptedException success){} + public void realRun() throws InterruptedException { + lock.lockInterruptibly(); } } @@ -59,18 +55,15 @@ public class ReentrantLockTest extends JSR166TestCase { public Collection<Thread> getWaitingThreads(Condition c) { return super.getWaitingThreads(c); } - - } /** * Constructor sets given fairness */ public void testConstructor() { - ReentrantLock rl = new ReentrantLock(); - assertFalse(rl.isFair()); - ReentrantLock r2 = new ReentrantLock(true); - assertTrue(r2.isFair()); + assertFalse(new ReentrantLock().isFair()); + assertFalse(new ReentrantLock(false).isFair()); + assertTrue(new ReentrantLock(true).isFair()); } /** @@ -81,6 +74,7 @@ public class ReentrantLockTest extends JSR166TestCase { rl.lock(); assertTrue(rl.isLocked()); rl.unlock(); + assertFalse(rl.isLocked()); } /** @@ -101,8 +95,7 @@ public class ReentrantLockTest extends JSR166TestCase { try { rl.unlock(); shouldThrow(); - - } catch(IllegalMonitorStateException success){} + } catch (IllegalMonitorStateException success) {} } /** @@ -119,88 +112,76 @@ public class ReentrantLockTest extends JSR166TestCase { /** * hasQueuedThreads reports whether there are waiting threads */ - public void testhasQueuedThreads() { + public void testhasQueuedThreads() throws InterruptedException { final ReentrantLock lock = new ReentrantLock(); Thread t1 = new Thread(new InterruptedLockRunnable(lock)); Thread t2 = new Thread(new InterruptibleLockRunnable(lock)); - try { - assertFalse(lock.hasQueuedThreads()); - lock.lock(); - t1.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(lock.hasQueuedThreads()); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(lock.hasQueuedThreads()); - t1.interrupt(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(lock.hasQueuedThreads()); - lock.unlock(); - Thread.sleep(SHORT_DELAY_MS); - assertFalse(lock.hasQueuedThreads()); - t1.join(); - t2.join(); - } catch(Exception e){ - unexpectedException(); - } + assertFalse(lock.hasQueuedThreads()); + lock.lock(); + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(lock.hasQueuedThreads()); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(lock.hasQueuedThreads()); + t1.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(lock.hasQueuedThreads()); + lock.unlock(); + Thread.sleep(SHORT_DELAY_MS); + assertFalse(lock.hasQueuedThreads()); + t1.join(); + t2.join(); } /** * getQueueLength reports number of waiting threads */ - public void testGetQueueLength() { + public void testGetQueueLength() throws InterruptedException { final ReentrantLock lock = new ReentrantLock(); Thread t1 = new Thread(new InterruptedLockRunnable(lock)); Thread t2 = new Thread(new InterruptibleLockRunnable(lock)); - try { - assertEquals(0, lock.getQueueLength()); - lock.lock(); - t1.start(); - Thread.sleep(SHORT_DELAY_MS); - assertEquals(1, lock.getQueueLength()); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - assertEquals(2, lock.getQueueLength()); - t1.interrupt(); - Thread.sleep(SHORT_DELAY_MS); - assertEquals(1, lock.getQueueLength()); - lock.unlock(); - Thread.sleep(SHORT_DELAY_MS); - assertEquals(0, lock.getQueueLength()); - t1.join(); - t2.join(); - } catch(Exception e){ - unexpectedException(); - } + assertEquals(0, lock.getQueueLength()); + lock.lock(); + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(1, lock.getQueueLength()); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(2, lock.getQueueLength()); + t1.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(1, lock.getQueueLength()); + lock.unlock(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(0, lock.getQueueLength()); + t1.join(); + t2.join(); } /** * getQueueLength reports number of waiting threads */ - public void testGetQueueLength_fair() { + public void testGetQueueLength_fair() throws InterruptedException { final ReentrantLock lock = new ReentrantLock(true); Thread t1 = new Thread(new InterruptedLockRunnable(lock)); Thread t2 = new Thread(new InterruptibleLockRunnable(lock)); - try { - assertEquals(0, lock.getQueueLength()); - lock.lock(); - t1.start(); - Thread.sleep(SHORT_DELAY_MS); - assertEquals(1, lock.getQueueLength()); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - assertEquals(2, lock.getQueueLength()); - t1.interrupt(); - Thread.sleep(SHORT_DELAY_MS); - assertEquals(1, lock.getQueueLength()); - lock.unlock(); - Thread.sleep(SHORT_DELAY_MS); - assertEquals(0, lock.getQueueLength()); - t1.join(); - t2.join(); - } catch(Exception e){ - unexpectedException(); - } + assertEquals(0, lock.getQueueLength()); + lock.lock(); + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(1, lock.getQueueLength()); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(2, lock.getQueueLength()); + t1.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(1, lock.getQueueLength()); + lock.unlock(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(0, lock.getQueueLength()); + t1.join(); + t2.join(); } /** @@ -211,143 +192,117 @@ public class ReentrantLockTest extends JSR166TestCase { try { sync.hasQueuedThread(null); shouldThrow(); - } catch (NullPointerException success) { - } + } catch (NullPointerException success) {} } /** * hasQueuedThread reports whether a thread is queued. */ - public void testHasQueuedThread() { + public void testHasQueuedThread() throws InterruptedException { final ReentrantLock sync = new ReentrantLock(); Thread t1 = new Thread(new InterruptedLockRunnable(sync)); Thread t2 = new Thread(new InterruptibleLockRunnable(sync)); - try { - assertFalse(sync.hasQueuedThread(t1)); - assertFalse(sync.hasQueuedThread(t2)); - sync.lock(); - t1.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(sync.hasQueuedThread(t1)); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(sync.hasQueuedThread(t1)); - assertTrue(sync.hasQueuedThread(t2)); - t1.interrupt(); - Thread.sleep(SHORT_DELAY_MS); - assertFalse(sync.hasQueuedThread(t1)); - assertTrue(sync.hasQueuedThread(t2)); - sync.unlock(); - Thread.sleep(SHORT_DELAY_MS); - assertFalse(sync.hasQueuedThread(t1)); - Thread.sleep(SHORT_DELAY_MS); - assertFalse(sync.hasQueuedThread(t2)); - t1.join(); - t2.join(); - } catch(Exception e){ - unexpectedException(); - } + assertFalse(sync.hasQueuedThread(t1)); + assertFalse(sync.hasQueuedThread(t2)); + sync.lock(); + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.hasQueuedThread(t1)); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.hasQueuedThread(t1)); + assertTrue(sync.hasQueuedThread(t2)); + t1.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + assertFalse(sync.hasQueuedThread(t1)); + assertTrue(sync.hasQueuedThread(t2)); + sync.unlock(); + Thread.sleep(SHORT_DELAY_MS); + assertFalse(sync.hasQueuedThread(t1)); + Thread.sleep(SHORT_DELAY_MS); + assertFalse(sync.hasQueuedThread(t2)); + t1.join(); + t2.join(); } /** * getQueuedThreads includes waiting threads */ - public void testGetQueuedThreads() { + public void testGetQueuedThreads() throws InterruptedException { final PublicReentrantLock lock = new PublicReentrantLock(); Thread t1 = new Thread(new InterruptedLockRunnable(lock)); Thread t2 = new Thread(new InterruptibleLockRunnable(lock)); - try { - assertTrue(lock.getQueuedThreads().isEmpty()); - lock.lock(); - assertTrue(lock.getQueuedThreads().isEmpty()); - t1.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(lock.getQueuedThreads().contains(t1)); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(lock.getQueuedThreads().contains(t1)); - assertTrue(lock.getQueuedThreads().contains(t2)); - t1.interrupt(); - Thread.sleep(SHORT_DELAY_MS); - assertFalse(lock.getQueuedThreads().contains(t1)); - assertTrue(lock.getQueuedThreads().contains(t2)); - lock.unlock(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(lock.getQueuedThreads().isEmpty()); - t1.join(); - t2.join(); - } catch(Exception e){ - unexpectedException(); - } + assertTrue(lock.getQueuedThreads().isEmpty()); + lock.lock(); + assertTrue(lock.getQueuedThreads().isEmpty()); + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(lock.getQueuedThreads().contains(t1)); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(lock.getQueuedThreads().contains(t1)); + assertTrue(lock.getQueuedThreads().contains(t2)); + t1.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + assertFalse(lock.getQueuedThreads().contains(t1)); + assertTrue(lock.getQueuedThreads().contains(t2)); + lock.unlock(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(lock.getQueuedThreads().isEmpty()); + t1.join(); + t2.join(); } /** * timed tryLock is interruptible. */ - public void testInterruptedException2() { + public void testInterruptedException2() throws InterruptedException { final ReentrantLock lock = new ReentrantLock(); lock.lock(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - lock.tryLock(MEDIUM_DELAY_MS,TimeUnit.MILLISECONDS); - threadShouldThrow(); - } catch(InterruptedException success){} - } - }); - try { - t.start(); - t.interrupt(); - } catch(Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + lock.tryLock(MEDIUM_DELAY_MS,MILLISECONDS); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } /** * TryLock on a locked lock fails */ - public void testTryLockWhenLocked() { + public void testTryLockWhenLocked() throws InterruptedException { final ReentrantLock lock = new ReentrantLock(); lock.lock(); - Thread t = new Thread(new Runnable() { - public void run() { - threadAssertFalse(lock.tryLock()); - } - }); - try { - t.start(); - t.join(); - lock.unlock(); - } catch(Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + threadAssertFalse(lock.tryLock()); + }}); + + t.start(); + t.join(); + lock.unlock(); } /** * Timed tryLock on a locked lock times out */ - public void testTryLock_Timeout() { + public void testTryLock_Timeout() throws InterruptedException { final ReentrantLock lock = new ReentrantLock(); lock.lock(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - threadAssertFalse(lock.tryLock(1, TimeUnit.MILLISECONDS)); - } catch (Exception ex) { - threadUnexpectedException(); - } - } - }); - try { - t.start(); - t.join(); - lock.unlock(); - } catch(Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadAssertFalse(lock.tryLock(1, MILLISECONDS)); + }}); + + t.start(); + t.join(); + lock.unlock(); } /** @@ -355,13 +310,13 @@ public class ReentrantLockTest extends JSR166TestCase { */ public void testGetHoldCount() { ReentrantLock lock = new ReentrantLock(); - for(int i = 1; i <= SIZE; i++) { + for (int i = 1; i <= SIZE; i++) { lock.lock(); - assertEquals(i,lock.getHoldCount()); + assertEquals(i, lock.getHoldCount()); } - for(int i = SIZE; i > 0; i--) { + for (int i = SIZE; i > 0; i--) { lock.unlock(); - assertEquals(i-1,lock.getHoldCount()); + assertEquals(i-1, lock.getHoldCount()); } } @@ -369,92 +324,67 @@ public class ReentrantLockTest extends JSR166TestCase { /** * isLocked is true when locked and false when not */ - public void testIsLocked() { + public void testIsLocked() throws InterruptedException { final ReentrantLock lock = new ReentrantLock(); lock.lock(); assertTrue(lock.isLocked()); lock.unlock(); assertFalse(lock.isLocked()); - Thread t = new Thread(new Runnable() { - public void run() { - lock.lock(); - try { - Thread.sleep(SMALL_DELAY_MS); - } - catch(Exception e) { - threadUnexpectedException(); - } - lock.unlock(); - } - }); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(lock.isLocked()); - t.join(); - assertFalse(lock.isLocked()); - } catch(Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.lock(); + Thread.sleep(SMALL_DELAY_MS); + lock.unlock(); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(lock.isLocked()); + t.join(); + assertFalse(lock.isLocked()); } /** * lockInterruptibly is interruptible. */ - public void testLockInterruptibly1() { + public void testLockInterruptibly1() throws InterruptedException { final ReentrantLock lock = new ReentrantLock(); lock.lock(); Thread t = new Thread(new InterruptedLockRunnable(lock)); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - Thread.sleep(SHORT_DELAY_MS); - lock.unlock(); - t.join(); - } catch(Exception e){ - unexpectedException(); - } + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + lock.unlock(); + t.join(); } /** * lockInterruptibly succeeds when unlocked, else is interruptible */ - public void testLockInterruptibly2() { + public void testLockInterruptibly2() throws InterruptedException { final ReentrantLock lock = new ReentrantLock(); - try { - lock.lockInterruptibly(); - } catch(Exception e) { - unexpectedException(); - } + lock.lockInterruptibly(); Thread t = new Thread(new InterruptedLockRunnable(lock)); - try { - t.start(); - t.interrupt(); - assertTrue(lock.isLocked()); - assertTrue(lock.isHeldByCurrentThread()); - t.join(); - } catch(Exception e){ - unexpectedException(); - } + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + assertTrue(lock.isLocked()); + assertTrue(lock.isHeldByCurrentThread()); + t.join(); } /** * Calling await without holding lock throws IllegalMonitorStateException */ - public void testAwait_IllegalMonitor() { + public void testAwait_IllegalMonitor() throws InterruptedException { final ReentrantLock lock = new ReentrantLock(); final Condition c = lock.newCondition(); try { c.await(); shouldThrow(); - } - catch (IllegalMonitorStateException success) { - } - catch (Exception ex) { - unexpectedException(); - } + } catch (IllegalMonitorStateException success) {} } /** @@ -466,95 +396,64 @@ public class ReentrantLockTest extends JSR166TestCase { try { c.signal(); shouldThrow(); - } - catch (IllegalMonitorStateException success) { - } - catch (Exception ex) { - unexpectedException(); - } + } catch (IllegalMonitorStateException success) {} } /** * awaitNanos without a signal times out */ - public void testAwaitNanos_Timeout() { + public void testAwaitNanos_Timeout() throws InterruptedException { final ReentrantLock lock = new ReentrantLock(); final Condition c = lock.newCondition(); - try { - lock.lock(); - long t = c.awaitNanos(100); - assertTrue(t <= 0); - lock.unlock(); - } - catch (Exception ex) { - unexpectedException(); - } + lock.lock(); + long t = c.awaitNanos(100); + assertTrue(t <= 0); + lock.unlock(); } /** * timed await without a signal times out */ - public void testAwait_Timeout() { + public void testAwait_Timeout() throws InterruptedException { final ReentrantLock lock = new ReentrantLock(); final Condition c = lock.newCondition(); - try { - lock.lock(); - c.await(SHORT_DELAY_MS, TimeUnit.MILLISECONDS); - lock.unlock(); - } - catch (Exception ex) { - unexpectedException(); - } + lock.lock(); + assertFalse(c.await(SHORT_DELAY_MS, MILLISECONDS)); + lock.unlock(); } /** * awaitUntil without a signal times out */ - public void testAwaitUntil_Timeout() { + public void testAwaitUntil_Timeout() throws InterruptedException { final ReentrantLock lock = new ReentrantLock(); final Condition c = lock.newCondition(); - try { - lock.lock(); - java.util.Date d = new java.util.Date(); - c.awaitUntil(new java.util.Date(d.getTime() + 10)); - lock.unlock(); - } - catch (Exception ex) { - unexpectedException(); - } + lock.lock(); + java.util.Date d = new java.util.Date(); + assertFalse(c.awaitUntil(new java.util.Date(d.getTime() + 10))); + lock.unlock(); } /** * await returns when signalled */ - public void testAwait() { + public void testAwait() throws InterruptedException { final ReentrantLock lock = new ReentrantLock(); final Condition c = lock.newCondition(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - lock.lock(); - c.await(); - lock.unlock(); - } - catch(InterruptedException e) { - threadUnexpectedException(); - } - } - }); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.lock(); + c.await(); + lock.unlock(); + }}); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - lock.lock(); - c.signal(); - lock.unlock(); - t.join(SHORT_DELAY_MS); - assertFalse(t.isAlive()); - } - catch (Exception ex) { - unexpectedException(); - } + t.start(); + Thread.sleep(SHORT_DELAY_MS); + lock.lock(); + c.signal(); + lock.unlock(); + t.join(SHORT_DELAY_MS); + assertFalse(t.isAlive()); } /** @@ -565,10 +464,7 @@ public class ReentrantLockTest extends JSR166TestCase { try { lock.hasWaiters(null); shouldThrow(); - } catch (NullPointerException success) { - } catch (Exception ex) { - unexpectedException(); - } + } catch (NullPointerException success) {} } /** @@ -579,10 +475,7 @@ public class ReentrantLockTest extends JSR166TestCase { try { lock.getWaitQueueLength(null); shouldThrow(); - } catch (NullPointerException success) { - } catch (Exception ex) { - unexpectedException(); - } + } catch (NullPointerException success) {} } @@ -594,10 +487,7 @@ public class ReentrantLockTest extends JSR166TestCase { try { lock.getWaitingThreads(null); shouldThrow(); - } catch (NullPointerException success) { - } catch (Exception ex) { - unexpectedException(); - } + } catch (NullPointerException success) {} } @@ -606,15 +496,12 @@ public class ReentrantLockTest extends JSR166TestCase { */ public void testHasWaitersIAE() { final ReentrantLock lock = new ReentrantLock(); - final Condition c = (lock.newCondition()); + final Condition c = lock.newCondition(); final ReentrantLock lock2 = new ReentrantLock(); try { lock2.hasWaiters(c); shouldThrow(); - } catch (IllegalArgumentException success) { - } catch (Exception ex) { - unexpectedException(); - } + } catch (IllegalArgumentException success) {} } /** @@ -622,14 +509,11 @@ public class ReentrantLockTest extends JSR166TestCase { */ public void testHasWaitersIMSE() { final ReentrantLock lock = new ReentrantLock(); - final Condition c = (lock.newCondition()); + final Condition c = lock.newCondition(); try { lock.hasWaiters(c); shouldThrow(); - } catch (IllegalMonitorStateException success) { - } catch (Exception ex) { - unexpectedException(); - } + } catch (IllegalMonitorStateException success) {} } @@ -638,15 +522,12 @@ public class ReentrantLockTest extends JSR166TestCase { */ public void testGetWaitQueueLengthIAE() { final ReentrantLock lock = new ReentrantLock(); - final Condition c = (lock.newCondition()); + final Condition c = lock.newCondition(); final ReentrantLock lock2 = new ReentrantLock(); try { lock2.getWaitQueueLength(c); shouldThrow(); - } catch (IllegalArgumentException success) { - } catch (Exception ex) { - unexpectedException(); - } + } catch (IllegalArgumentException success) {} } /** @@ -654,14 +535,11 @@ public class ReentrantLockTest extends JSR166TestCase { */ public void testGetWaitQueueLengthIMSE() { final ReentrantLock lock = new ReentrantLock(); - final Condition c = (lock.newCondition()); + final Condition c = lock.newCondition(); try { lock.getWaitQueueLength(c); shouldThrow(); - } catch (IllegalMonitorStateException success) { - } catch (Exception ex) { - unexpectedException(); - } + } catch (IllegalMonitorStateException success) {} } @@ -670,15 +548,12 @@ public class ReentrantLockTest extends JSR166TestCase { */ public void testGetWaitingThreadsIAE() { final PublicReentrantLock lock = new PublicReentrantLock(); - final Condition c = (lock.newCondition()); + final Condition c = lock.newCondition(); final PublicReentrantLock lock2 = new PublicReentrantLock(); try { lock2.getWaitingThreads(c); shouldThrow(); - } catch (IllegalArgumentException success) { - } catch (Exception ex) { - unexpectedException(); - } + } catch (IllegalArgumentException success) {} } /** @@ -686,186 +561,137 @@ public class ReentrantLockTest extends JSR166TestCase { */ public void testGetWaitingThreadsIMSE() { final PublicReentrantLock lock = new PublicReentrantLock(); - final Condition c = (lock.newCondition()); + final Condition c = lock.newCondition(); try { lock.getWaitingThreads(c); shouldThrow(); - } catch (IllegalMonitorStateException success) { - } catch (Exception ex) { - unexpectedException(); - } + } catch (IllegalMonitorStateException success) {} } - /** * hasWaiters returns true when a thread is waiting, else false */ - public void testHasWaiters() { + public void testHasWaiters() throws InterruptedException { final ReentrantLock lock = new ReentrantLock(); final Condition c = lock.newCondition(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - lock.lock(); - threadAssertFalse(lock.hasWaiters(c)); - threadAssertEquals(0, lock.getWaitQueueLength(c)); - c.await(); - lock.unlock(); - } - catch(InterruptedException e) { - threadUnexpectedException(); - } - } - }); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.lock(); + threadAssertFalse(lock.hasWaiters(c)); + threadAssertEquals(0, lock.getWaitQueueLength(c)); + c.await(); + lock.unlock(); + }}); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - lock.lock(); - assertTrue(lock.hasWaiters(c)); - assertEquals(1, lock.getWaitQueueLength(c)); - c.signal(); - lock.unlock(); - Thread.sleep(SHORT_DELAY_MS); - lock.lock(); - assertFalse(lock.hasWaiters(c)); - assertEquals(0, lock.getWaitQueueLength(c)); - lock.unlock(); - t.join(SHORT_DELAY_MS); - assertFalse(t.isAlive()); - } - catch (Exception ex) { - unexpectedException(); - } + t.start(); + Thread.sleep(SHORT_DELAY_MS); + lock.lock(); + assertTrue(lock.hasWaiters(c)); + assertEquals(1, lock.getWaitQueueLength(c)); + c.signal(); + lock.unlock(); + Thread.sleep(SHORT_DELAY_MS); + lock.lock(); + assertFalse(lock.hasWaiters(c)); + assertEquals(0, lock.getWaitQueueLength(c)); + lock.unlock(); + t.join(SHORT_DELAY_MS); + assertFalse(t.isAlive()); } /** * getWaitQueueLength returns number of waiting threads */ - public void testGetWaitQueueLength() { + public void testGetWaitQueueLength() throws InterruptedException { final ReentrantLock lock = new ReentrantLock(); final Condition c = lock.newCondition(); - Thread t1 = new Thread(new Runnable() { - public void run() { - try { - lock.lock(); - threadAssertFalse(lock.hasWaiters(c)); - threadAssertEquals(0, lock.getWaitQueueLength(c)); - c.await(); - lock.unlock(); - } - catch(InterruptedException e) { - threadUnexpectedException(); - } - } - }); - - Thread t2 = new Thread(new Runnable() { - public void run() { - try { - lock.lock(); - threadAssertTrue(lock.hasWaiters(c)); - threadAssertEquals(1, lock.getWaitQueueLength(c)); - c.await(); - lock.unlock(); - } - catch(InterruptedException e) { - threadUnexpectedException(); - } - } - }); + Thread t1 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.lock(); + threadAssertFalse(lock.hasWaiters(c)); + threadAssertEquals(0, lock.getWaitQueueLength(c)); + c.await(); + lock.unlock(); + }}); + + Thread t2 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.lock(); + threadAssertTrue(lock.hasWaiters(c)); + threadAssertEquals(1, lock.getWaitQueueLength(c)); + c.await(); + lock.unlock(); + }}); - try { - t1.start(); - Thread.sleep(SHORT_DELAY_MS); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - lock.lock(); - assertTrue(lock.hasWaiters(c)); - assertEquals(2, lock.getWaitQueueLength(c)); - c.signalAll(); - lock.unlock(); - Thread.sleep(SHORT_DELAY_MS); - lock.lock(); - assertFalse(lock.hasWaiters(c)); - assertEquals(0, lock.getWaitQueueLength(c)); - lock.unlock(); - t1.join(SHORT_DELAY_MS); - t2.join(SHORT_DELAY_MS); - assertFalse(t1.isAlive()); - assertFalse(t2.isAlive()); - } - catch (Exception ex) { - unexpectedException(); - } + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + lock.lock(); + assertTrue(lock.hasWaiters(c)); + assertEquals(2, lock.getWaitQueueLength(c)); + c.signalAll(); + lock.unlock(); + Thread.sleep(SHORT_DELAY_MS); + lock.lock(); + assertFalse(lock.hasWaiters(c)); + assertEquals(0, lock.getWaitQueueLength(c)); + lock.unlock(); + t1.join(SHORT_DELAY_MS); + t2.join(SHORT_DELAY_MS); + assertFalse(t1.isAlive()); + assertFalse(t2.isAlive()); } /** * getWaitingThreads returns only and all waiting threads */ - public void testGetWaitingThreads() { + public void testGetWaitingThreads() throws InterruptedException { final PublicReentrantLock lock = new PublicReentrantLock(); final Condition c = lock.newCondition(); - Thread t1 = new Thread(new Runnable() { - public void run() { - try { - lock.lock(); - threadAssertTrue(lock.getWaitingThreads(c).isEmpty()); - c.await(); - lock.unlock(); - } - catch(InterruptedException e) { - threadUnexpectedException(); - } - } - }); - - Thread t2 = new Thread(new Runnable() { - public void run() { - try { - lock.lock(); - threadAssertFalse(lock.getWaitingThreads(c).isEmpty()); - c.await(); - lock.unlock(); - } - catch(InterruptedException e) { - threadUnexpectedException(); - } - } - }); + Thread t1 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.lock(); + threadAssertTrue(lock.getWaitingThreads(c).isEmpty()); + c.await(); + lock.unlock(); + }}); - try { - lock.lock(); - assertTrue(lock.getWaitingThreads(c).isEmpty()); - lock.unlock(); - t1.start(); - Thread.sleep(SHORT_DELAY_MS); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - lock.lock(); - assertTrue(lock.hasWaiters(c)); - assertTrue(lock.getWaitingThreads(c).contains(t1)); - assertTrue(lock.getWaitingThreads(c).contains(t2)); - c.signalAll(); - lock.unlock(); - Thread.sleep(SHORT_DELAY_MS); - lock.lock(); - assertFalse(lock.hasWaiters(c)); - assertTrue(lock.getWaitingThreads(c).isEmpty()); - lock.unlock(); - t1.join(SHORT_DELAY_MS); - t2.join(SHORT_DELAY_MS); - assertFalse(t1.isAlive()); - assertFalse(t2.isAlive()); - } - catch (Exception ex) { - unexpectedException(); - } + Thread t2 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.lock(); + threadAssertFalse(lock.getWaitingThreads(c).isEmpty()); + c.await(); + lock.unlock(); + }}); + + lock.lock(); + assertTrue(lock.getWaitingThreads(c).isEmpty()); + lock.unlock(); + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + lock.lock(); + assertTrue(lock.hasWaiters(c)); + assertTrue(lock.getWaitingThreads(c).contains(t1)); + assertTrue(lock.getWaitingThreads(c).contains(t2)); + c.signalAll(); + lock.unlock(); + Thread.sleep(SHORT_DELAY_MS); + lock.lock(); + assertFalse(lock.hasWaiters(c)); + assertTrue(lock.getWaitingThreads(c).isEmpty()); + lock.unlock(); + t1.join(SHORT_DELAY_MS); + t2.join(SHORT_DELAY_MS); + assertFalse(t1.isAlive()); + assertFalse(t2.isAlive()); } /** A helper class for uninterruptible wait tests */ - class UninterruptableThread extends Thread { + class UninterruptibleThread extends Thread { private ReentrantLock lock; private Condition c; @@ -873,7 +699,7 @@ public class ReentrantLockTest extends JSR166TestCase { public volatile boolean interrupted = false; public volatile boolean lockStarted = false; - public UninterruptableThread(ReentrantLock lock, Condition c) { + public UninterruptibleThread(ReentrantLock lock, Condition c) { this.lock = lock; this.c = c; } @@ -894,256 +720,180 @@ public class ReentrantLockTest extends JSR166TestCase { /** * awaitUninterruptibly doesn't abort on interrupt */ - public void testAwaitUninterruptibly() { + public void testAwaitUninterruptibly() throws InterruptedException { final ReentrantLock lock = new ReentrantLock(); final Condition c = lock.newCondition(); - UninterruptableThread thread = new UninterruptableThread(lock, c); + UninterruptibleThread thread = new UninterruptibleThread(lock, c); - try { - thread.start(); + thread.start(); - while (!thread.lockStarted) { - Thread.sleep(100); - } - - lock.lock(); - try { - thread.interrupt(); - thread.canAwake = true; - c.signal(); - } finally { - lock.unlock(); - } + while (!thread.lockStarted) { + Thread.sleep(100); + } - thread.join(); - assertTrue(thread.interrupted); - assertFalse(thread.isAlive()); - } catch (Exception ex) { - unexpectedException(); + lock.lock(); + try { + thread.interrupt(); + thread.canAwake = true; + c.signal(); + } finally { + lock.unlock(); } + + thread.join(); + assertTrue(thread.interrupted); + assertFalse(thread.isAlive()); } /** * await is interruptible */ - public void testAwait_Interrupt() { + public void testAwait_Interrupt() throws InterruptedException { final ReentrantLock lock = new ReentrantLock(); final Condition c = lock.newCondition(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - lock.lock(); - c.await(); - lock.unlock(); - threadShouldThrow(); - } - catch(InterruptedException success) { - } - } - }); + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + lock.lock(); + c.await(); + }}); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(SHORT_DELAY_MS); - assertFalse(t.isAlive()); - } - catch (Exception ex) { - unexpectedException(); - } + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(SHORT_DELAY_MS); + assertFalse(t.isAlive()); } /** * awaitNanos is interruptible */ - public void testAwaitNanos_Interrupt() { + public void testAwaitNanos_Interrupt() throws InterruptedException { final ReentrantLock lock = new ReentrantLock(); final Condition c = lock.newCondition(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - lock.lock(); - c.awaitNanos(1000 * 1000 * 1000); // 1 sec - lock.unlock(); - threadShouldThrow(); - } - catch(InterruptedException success) { - } - } - }); + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + lock.lock(); + c.awaitNanos(MILLISECONDS.toNanos(LONG_DELAY_MS)); + }}); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(SHORT_DELAY_MS); - assertFalse(t.isAlive()); - } - catch (Exception ex) { - unexpectedException(); - } + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(SHORT_DELAY_MS); + assertFalse(t.isAlive()); } /** * awaitUntil is interruptible */ - public void testAwaitUntil_Interrupt() { + public void testAwaitUntil_Interrupt() throws InterruptedException { final ReentrantLock lock = new ReentrantLock(); final Condition c = lock.newCondition(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - lock.lock(); - java.util.Date d = new java.util.Date(); - c.awaitUntil(new java.util.Date(d.getTime() + 10000)); - lock.unlock(); - threadShouldThrow(); - } - catch(InterruptedException success) { - } - } - }); + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + lock.lock(); + java.util.Date d = new java.util.Date(); + c.awaitUntil(new java.util.Date(d.getTime() + 10000)); + }}); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(SHORT_DELAY_MS); - assertFalse(t.isAlive()); - } - catch (Exception ex) { - unexpectedException(); - } + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(SHORT_DELAY_MS); + assertFalse(t.isAlive()); } /** * signalAll wakes up all threads */ - public void testSignalAll() { + public void testSignalAll() throws InterruptedException { final ReentrantLock lock = new ReentrantLock(); final Condition c = lock.newCondition(); - Thread t1 = new Thread(new Runnable() { - public void run() { - try { - lock.lock(); - c.await(); - lock.unlock(); - } - catch(InterruptedException e) { - threadUnexpectedException(); - } - } - }); - - Thread t2 = new Thread(new Runnable() { - public void run() { - try { - lock.lock(); - c.await(); - lock.unlock(); - } - catch(InterruptedException e) { - threadUnexpectedException(); - } - } - }); + Thread t1 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.lock(); + c.await(); + lock.unlock(); + }}); - try { - t1.start(); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - lock.lock(); - c.signalAll(); - lock.unlock(); - t1.join(SHORT_DELAY_MS); - t2.join(SHORT_DELAY_MS); - assertFalse(t1.isAlive()); - assertFalse(t2.isAlive()); - } - catch (Exception ex) { - unexpectedException(); - } + Thread t2 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.lock(); + c.await(); + lock.unlock(); + }}); + + t1.start(); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + lock.lock(); + c.signalAll(); + lock.unlock(); + t1.join(SHORT_DELAY_MS); + t2.join(SHORT_DELAY_MS); + assertFalse(t1.isAlive()); + assertFalse(t2.isAlive()); } /** * await after multiple reentrant locking preserves lock count */ - public void testAwaitLockCount() { - final ReentrantLock lock = new ReentrantLock(); + public void testAwaitLockCount() throws InterruptedException { + final ReentrantLock lock = new ReentrantLock(); final Condition c = lock.newCondition(); - Thread t1 = new Thread(new Runnable() { - public void run() { - try { - lock.lock(); - threadAssertEquals(1, lock.getHoldCount()); - c.await(); - threadAssertEquals(1, lock.getHoldCount()); - lock.unlock(); - } - catch(InterruptedException e) { - threadUnexpectedException(); - } - } - }); - - Thread t2 = new Thread(new Runnable() { - public void run() { - try { - lock.lock(); - lock.lock(); - threadAssertEquals(2, lock.getHoldCount()); - c.await(); - threadAssertEquals(2, lock.getHoldCount()); - lock.unlock(); - lock.unlock(); - } - catch(InterruptedException e) { - threadUnexpectedException(); - } - } - }); + Thread t1 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.lock(); + threadAssertEquals(1, lock.getHoldCount()); + c.await(); + threadAssertEquals(1, lock.getHoldCount()); + lock.unlock(); + }}); + + Thread t2 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.lock(); + lock.lock(); + threadAssertEquals(2, lock.getHoldCount()); + c.await(); + threadAssertEquals(2, lock.getHoldCount()); + lock.unlock(); + lock.unlock(); + }}); - try { - t1.start(); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - lock.lock(); - c.signalAll(); - lock.unlock(); - t1.join(SHORT_DELAY_MS); - t2.join(SHORT_DELAY_MS); - assertFalse(t1.isAlive()); - assertFalse(t2.isAlive()); - } - catch (Exception ex) { - unexpectedException(); - } + t1.start(); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + lock.lock(); + c.signalAll(); + lock.unlock(); + t1.join(SHORT_DELAY_MS); + t2.join(SHORT_DELAY_MS); + assertFalse(t1.isAlive()); + assertFalse(t2.isAlive()); } /** * A serialized lock deserializes as unlocked */ - public void testSerialization() { + public void testSerialization() throws Exception { ReentrantLock l = new ReentrantLock(); l.lock(); l.unlock(); - try { - ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); - ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); - out.writeObject(l); - out.close(); - - ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); - ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); - ReentrantLock r = (ReentrantLock) in.readObject(); - r.lock(); - r.unlock(); - } catch(Exception e){ - e.printStackTrace(); - unexpectedException(); - } + ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); + ObjectOutputStream out = + new ObjectOutputStream(new BufferedOutputStream(bout)); + out.writeObject(l); + out.close(); + + ByteArrayInputStream bin = + new ByteArrayInputStream(bout.toByteArray()); + ObjectInputStream in = + new ObjectInputStream(new BufferedInputStream(bin)); + ReentrantLock r = (ReentrantLock) in.readObject(); + r.lock(); + r.unlock(); } /** diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/ReentrantReadWriteLockTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/ReentrantReadWriteLockTest.java index 4191a13..eb20255 100644 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/ReentrantReadWriteLockTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/ReentrantReadWriteLockTest.java @@ -2,15 +2,16 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.concurrent.locks.*; import java.util.concurrent.*; +import static java.util.concurrent.TimeUnit.MILLISECONDS; import java.io.*; import java.util.*; @@ -22,13 +23,11 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase { /** * A runnable calling lockInterruptibly */ - class InterruptibleLockRunnable implements Runnable { + class InterruptibleLockRunnable extends CheckedRunnable { final ReentrantReadWriteLock lock; InterruptibleLockRunnable(ReentrantReadWriteLock l) { lock = l; } - public void run() { - try { - lock.writeLock().lockInterruptibly(); - } catch(InterruptedException success){} + public void realRun() throws InterruptedException { + lock.writeLock().lockInterruptibly(); } } @@ -37,14 +36,11 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase { * A runnable calling lockInterruptibly that expects to be * interrupted */ - class InterruptedLockRunnable implements Runnable { + class InterruptedLockRunnable extends CheckedInterruptedRunnable { final ReentrantReadWriteLock lock; InterruptedLockRunnable(ReentrantReadWriteLock l) { lock = l; } - public void run() { - try { - lock.writeLock().lockInterruptibly(); - threadShouldThrow(); - } catch(InterruptedException success){} + public void realRun() throws InterruptedException { + lock.writeLock().lockInterruptibly(); } } @@ -73,6 +69,10 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase { assertTrue(r2.isFair()); assertFalse(r2.isWriteLocked()); assertEquals(0, r2.getReadLockCount()); + ReentrantReadWriteLock r3 = new ReentrantReadWriteLock(false); + assertFalse(r3.isFair()); + assertFalse(r3.isWriteLocked()); + assertEquals(0, r3.getReadLockCount()); } /** @@ -83,10 +83,12 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase { rl.writeLock().lock(); assertTrue(rl.isWriteLocked()); assertTrue(rl.isWriteLockedByCurrentThread()); + assertTrue(rl.writeLock().isHeldByCurrentThread()); assertEquals(0, rl.getReadLockCount()); rl.writeLock().unlock(); assertFalse(rl.isWriteLocked()); assertFalse(rl.isWriteLockedByCurrentThread()); + assertFalse(rl.writeLock().isHeldByCurrentThread()); assertEquals(0, rl.getReadLockCount()); rl.readLock().lock(); assertFalse(rl.isWriteLocked()); @@ -107,10 +109,12 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase { rl.writeLock().lock(); assertTrue(rl.isWriteLocked()); assertTrue(rl.isWriteLockedByCurrentThread()); + assertTrue(rl.writeLock().isHeldByCurrentThread()); assertEquals(0, rl.getReadLockCount()); rl.writeLock().unlock(); assertFalse(rl.isWriteLocked()); assertFalse(rl.isWriteLockedByCurrentThread()); + assertFalse(rl.writeLock().isHeldByCurrentThread()); assertEquals(0, rl.getReadLockCount()); rl.readLock().lock(); assertFalse(rl.isWriteLocked()); @@ -126,15 +130,45 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase { * getWriteHoldCount returns number of recursive holds */ public void testGetWriteHoldCount() { - ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); - for(int i = 1; i <= SIZE; i++) { - lock.writeLock().lock(); - assertEquals(i,lock.getWriteHoldCount()); - } - for(int i = SIZE; i > 0; i--) { - lock.writeLock().unlock(); - assertEquals(i-1,lock.getWriteHoldCount()); - } + ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + for (int i = 1; i <= SIZE; i++) { + lock.writeLock().lock(); + assertEquals(i,lock.getWriteHoldCount()); + } + for (int i = SIZE; i > 0; i--) { + lock.writeLock().unlock(); + assertEquals(i-1,lock.getWriteHoldCount()); + } + } + + /** + * WriteLock.getHoldCount returns number of recursive holds + */ + public void testGetHoldCount() { + ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + for (int i = 1; i <= SIZE; i++) { + lock.writeLock().lock(); + assertEquals(i,lock.writeLock().getHoldCount()); + } + for (int i = SIZE; i > 0; i--) { + lock.writeLock().unlock(); + assertEquals(i-1,lock.writeLock().getHoldCount()); + } + } + + /** + * getReadHoldCount returns number of recursive holds + */ + public void testGetReadHoldCount() { + ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + for (int i = 1; i <= SIZE; i++) { + lock.readLock().lock(); + assertEquals(i,lock.getReadHoldCount()); + } + for (int i = SIZE; i > 0; i--) { + lock.readLock().unlock(); + assertEquals(i-1,lock.getReadHoldCount()); + } } @@ -146,245 +180,196 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase { try { rl.writeLock().unlock(); shouldThrow(); - } catch(IllegalMonitorStateException success){} + } catch (IllegalMonitorStateException success) {} } /** * write-lockInterruptibly is interruptible */ - public void testWriteLockInterruptibly_Interrupted() { + public void testWriteLockInterruptibly_Interrupted() throws Exception { final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - lock.writeLock().lockInterruptibly(); - lock.writeLock().unlock(); - lock.writeLock().lockInterruptibly(); - lock.writeLock().unlock(); - } catch(InterruptedException success){} - } - }); - try { - lock.writeLock().lock(); - t.start(); - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - Thread.sleep(SHORT_DELAY_MS); - lock.writeLock().unlock(); - t.join(); - } catch(Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + lock.writeLock().lockInterruptibly(); + lock.writeLock().unlock(); + lock.writeLock().lockInterruptibly(); + lock.writeLock().unlock(); + }}); + + lock.writeLock().lock(); + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + lock.writeLock().unlock(); + t.join(); } /** * timed write-tryLock is interruptible */ - public void testWriteTryLock_Interrupted() { + public void testWriteTryLock_Interrupted() throws InterruptedException { final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); lock.writeLock().lock(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - lock.writeLock().tryLock(1000,TimeUnit.MILLISECONDS); - } catch(InterruptedException success){} - } - }); - try { - t.start(); - t.interrupt(); - lock.writeLock().unlock(); - t.join(); - } catch(Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + lock.writeLock().tryLock(SMALL_DELAY_MS, MILLISECONDS); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + lock.writeLock().unlock(); + t.join(); } /** * read-lockInterruptibly is interruptible */ - public void testReadLockInterruptibly_Interrupted() { + public void testReadLockInterruptibly_Interrupted() throws InterruptedException { final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); lock.writeLock().lock(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - lock.readLock().lockInterruptibly(); - } catch(InterruptedException success){} - } - }); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - Thread.sleep(SHORT_DELAY_MS); - lock.writeLock().unlock(); - t.join(); - } catch(Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + lock.readLock().lockInterruptibly(); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + lock.writeLock().unlock(); + t.join(); } /** * timed read-tryLock is interruptible */ - public void testReadTryLock_Interrupted() { + public void testReadTryLock_Interrupted() throws InterruptedException { final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); lock.writeLock().lock(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - lock.readLock().tryLock(1000,TimeUnit.MILLISECONDS); - threadShouldThrow(); - } catch(InterruptedException success){} - } - }); - try { - t.start(); - t.interrupt(); - t.join(); - } catch(Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + lock.readLock().tryLock(LONG_DELAY_MS, MILLISECONDS); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } /** * write-tryLock fails if locked */ - public void testWriteTryLockWhenLocked() { + public void testWriteTryLockWhenLocked() throws InterruptedException { final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); lock.writeLock().lock(); - Thread t = new Thread(new Runnable() { - public void run() { - threadAssertFalse(lock.writeLock().tryLock()); - } - }); - try { - t.start(); - t.join(); - lock.writeLock().unlock(); - } catch(Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + threadAssertFalse(lock.writeLock().tryLock()); + }}); + + t.start(); + t.join(); + lock.writeLock().unlock(); } /** * read-tryLock fails if locked */ - public void testReadTryLockWhenLocked() { + public void testReadTryLockWhenLocked() throws InterruptedException { final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); lock.writeLock().lock(); - Thread t = new Thread(new Runnable() { - public void run() { - threadAssertFalse(lock.readLock().tryLock()); - } - }); - try { - t.start(); - t.join(); - lock.writeLock().unlock(); - } catch(Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + threadAssertFalse(lock.readLock().tryLock()); + }}); + + t.start(); + t.join(); + lock.writeLock().unlock(); } /** * Multiple threads can hold a read lock when not write-locked */ - public void testMultipleReadLocks() { + public void testMultipleReadLocks() throws InterruptedException { final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); lock.readLock().lock(); - Thread t = new Thread(new Runnable() { - public void run() { - threadAssertTrue(lock.readLock().tryLock()); - lock.readLock().unlock(); - } - }); - try { - t.start(); - t.join(); - lock.readLock().unlock(); - } catch(Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + threadAssertTrue(lock.readLock().tryLock()); + lock.readLock().unlock(); + }}); + + t.start(); + t.join(); + lock.readLock().unlock(); } /** * A writelock succeeds after reading threads unlock */ - public void testWriteAfterMultipleReadLocks() { + public void testWriteAfterMultipleReadLocks() throws InterruptedException { final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); lock.readLock().lock(); - Thread t1 = new Thread(new Runnable() { - public void run() { - lock.readLock().lock(); - lock.readLock().unlock(); - } - }); - Thread t2 = new Thread(new Runnable() { - public void run() { - lock.writeLock().lock(); - lock.writeLock().unlock(); - } - }); - - try { - t1.start(); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - lock.readLock().unlock(); - t1.join(MEDIUM_DELAY_MS); - t2.join(MEDIUM_DELAY_MS); - assertTrue(!t1.isAlive()); - assertTrue(!t2.isAlive()); + Thread t1 = new Thread(new CheckedRunnable() { + public void realRun() { + lock.readLock().lock(); + lock.readLock().unlock(); + }}); + Thread t2 = new Thread(new CheckedRunnable() { + public void realRun() { + lock.writeLock().lock(); + lock.writeLock().unlock(); + }}); - } catch(Exception e){ - unexpectedException(); - } + t1.start(); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + lock.readLock().unlock(); + t1.join(MEDIUM_DELAY_MS); + t2.join(MEDIUM_DELAY_MS); + assertTrue(!t1.isAlive()); + assertTrue(!t2.isAlive()); } /** * Readlocks succeed after a writing thread unlocks */ - public void testReadAfterWriteLock() { + public void testReadAfterWriteLock() throws InterruptedException { final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); lock.writeLock().lock(); - Thread t1 = new Thread(new Runnable() { - public void run() { - lock.readLock().lock(); - lock.readLock().unlock(); - } - }); - Thread t2 = new Thread(new Runnable() { - public void run() { - lock.readLock().lock(); - lock.readLock().unlock(); - } - }); - - try { - t1.start(); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - lock.writeLock().unlock(); - t1.join(MEDIUM_DELAY_MS); - t2.join(MEDIUM_DELAY_MS); - assertTrue(!t1.isAlive()); - assertTrue(!t2.isAlive()); - - } catch(Exception e){ - unexpectedException(); - } + Thread t1 = new Thread(new CheckedRunnable() { + public void realRun() { + lock.readLock().lock(); + lock.readLock().unlock(); + }}); + Thread t2 = new Thread(new CheckedRunnable() { + public void realRun() { + lock.readLock().lock(); + lock.readLock().unlock(); + }}); + + t1.start(); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + lock.writeLock().unlock(); + t1.join(MEDIUM_DELAY_MS); + t2.join(MEDIUM_DELAY_MS); + assertTrue(!t1.isAlive()); + assertTrue(!t2.isAlive()); } /** * Read trylock succeeds if write locked by current thread */ public void testReadHoldingWriteLock() { - final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); - lock.writeLock().lock(); + final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + lock.writeLock().lock(); assertTrue(lock.readLock().tryLock()); lock.readLock().unlock(); lock.writeLock().unlock(); @@ -394,78 +379,64 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase { * Read lock succeeds if write locked by current thread even if * other threads are waiting for readlock */ - public void testReadHoldingWriteLock2() { - final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); - lock.writeLock().lock(); - Thread t1 = new Thread(new Runnable() { - public void run() { - lock.readLock().lock(); - lock.readLock().unlock(); - } - }); - Thread t2 = new Thread(new Runnable() { - public void run() { - lock.readLock().lock(); - lock.readLock().unlock(); - } - }); - - try { - t1.start(); - t2.start(); - lock.readLock().lock(); - lock.readLock().unlock(); - Thread.sleep(SHORT_DELAY_MS); - lock.readLock().lock(); - lock.readLock().unlock(); - lock.writeLock().unlock(); - t1.join(MEDIUM_DELAY_MS); - t2.join(MEDIUM_DELAY_MS); - assertTrue(!t1.isAlive()); - assertTrue(!t2.isAlive()); - - } catch(Exception e){ - unexpectedException(); - } + public void testReadHoldingWriteLock2() throws InterruptedException { + final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + lock.writeLock().lock(); + Thread t1 = new Thread(new CheckedRunnable() { + public void realRun() { + lock.readLock().lock(); + lock.readLock().unlock(); + }}); + Thread t2 = new Thread(new CheckedRunnable() { + public void realRun() { + lock.readLock().lock(); + lock.readLock().unlock(); + }}); + + t1.start(); + t2.start(); + lock.readLock().lock(); + lock.readLock().unlock(); + Thread.sleep(SHORT_DELAY_MS); + lock.readLock().lock(); + lock.readLock().unlock(); + lock.writeLock().unlock(); + t1.join(MEDIUM_DELAY_MS); + t2.join(MEDIUM_DELAY_MS); + assertTrue(!t1.isAlive()); + assertTrue(!t2.isAlive()); } /** * Read lock succeeds if write locked by current thread even if * other threads are waiting for writelock */ - public void testReadHoldingWriteLock3() { - final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); - lock.writeLock().lock(); - Thread t1 = new Thread(new Runnable() { - public void run() { - lock.writeLock().lock(); - lock.writeLock().unlock(); - } - }); - Thread t2 = new Thread(new Runnable() { - public void run() { - lock.writeLock().lock(); - lock.writeLock().unlock(); - } - }); - - try { - t1.start(); - t2.start(); - lock.readLock().lock(); - lock.readLock().unlock(); - Thread.sleep(SHORT_DELAY_MS); - lock.readLock().lock(); - lock.readLock().unlock(); - lock.writeLock().unlock(); - t1.join(MEDIUM_DELAY_MS); - t2.join(MEDIUM_DELAY_MS); - assertTrue(!t1.isAlive()); - assertTrue(!t2.isAlive()); + public void testReadHoldingWriteLock3() throws InterruptedException { + final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + lock.writeLock().lock(); + Thread t1 = new Thread(new CheckedRunnable() { + public void realRun() { + lock.writeLock().lock(); + lock.writeLock().unlock(); + }}); + Thread t2 = new Thread(new CheckedRunnable() { + public void realRun() { + lock.writeLock().lock(); + lock.writeLock().unlock(); + }}); - } catch(Exception e){ - unexpectedException(); - } + t1.start(); + t2.start(); + lock.readLock().lock(); + lock.readLock().unlock(); + Thread.sleep(SHORT_DELAY_MS); + lock.readLock().lock(); + lock.readLock().unlock(); + lock.writeLock().unlock(); + t1.join(MEDIUM_DELAY_MS); + t2.join(MEDIUM_DELAY_MS); + assertTrue(!t1.isAlive()); + assertTrue(!t2.isAlive()); } @@ -473,39 +444,32 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase { * Write lock succeeds if write locked by current thread even if * other threads are waiting for writelock */ - public void testWriteHoldingWriteLock4() { - final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); - lock.writeLock().lock(); - Thread t1 = new Thread(new Runnable() { - public void run() { - lock.writeLock().lock(); - lock.writeLock().unlock(); - } - }); - Thread t2 = new Thread(new Runnable() { - public void run() { - lock.writeLock().lock(); - lock.writeLock().unlock(); - } - }); - - try { - t1.start(); - t2.start(); - lock.writeLock().lock(); - lock.writeLock().unlock(); - Thread.sleep(SHORT_DELAY_MS); - lock.writeLock().lock(); - lock.writeLock().unlock(); - lock.writeLock().unlock(); - t1.join(MEDIUM_DELAY_MS); - t2.join(MEDIUM_DELAY_MS); - assertTrue(!t1.isAlive()); - assertTrue(!t2.isAlive()); + public void testWriteHoldingWriteLock4() throws InterruptedException { + final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + lock.writeLock().lock(); + Thread t1 = new Thread(new CheckedRunnable() { + public void realRun() { + lock.writeLock().lock(); + lock.writeLock().unlock(); + }}); + Thread t2 = new Thread(new CheckedRunnable() { + public void realRun() { + lock.writeLock().lock(); + lock.writeLock().unlock(); + }}); - } catch(Exception e){ - unexpectedException(); - } + t1.start(); + t2.start(); + lock.writeLock().lock(); + lock.writeLock().unlock(); + Thread.sleep(SHORT_DELAY_MS); + lock.writeLock().lock(); + lock.writeLock().unlock(); + lock.writeLock().unlock(); + t1.join(MEDIUM_DELAY_MS); + t2.join(MEDIUM_DELAY_MS); + assertTrue(!t1.isAlive()); + assertTrue(!t2.isAlive()); } @@ -513,8 +477,8 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase { * Fair Read trylock succeeds if write locked by current thread */ public void testReadHoldingWriteLockFair() { - final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true); - lock.writeLock().lock(); + final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true); + lock.writeLock().lock(); assertTrue(lock.readLock().tryLock()); lock.readLock().unlock(); lock.writeLock().unlock(); @@ -524,39 +488,32 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase { * Fair Read lock succeeds if write locked by current thread even if * other threads are waiting for readlock */ - public void testReadHoldingWriteLockFair2() { - final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true); - lock.writeLock().lock(); - Thread t1 = new Thread(new Runnable() { - public void run() { - lock.readLock().lock(); - lock.readLock().unlock(); - } - }); - Thread t2 = new Thread(new Runnable() { - public void run() { - lock.readLock().lock(); - lock.readLock().unlock(); - } - }); - - try { - t1.start(); - t2.start(); - lock.readLock().lock(); - lock.readLock().unlock(); - Thread.sleep(SHORT_DELAY_MS); - lock.readLock().lock(); - lock.readLock().unlock(); - lock.writeLock().unlock(); - t1.join(MEDIUM_DELAY_MS); - t2.join(MEDIUM_DELAY_MS); - assertTrue(!t1.isAlive()); - assertTrue(!t2.isAlive()); - - } catch(Exception e){ - unexpectedException(); - } + public void testReadHoldingWriteLockFair2() throws InterruptedException { + final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true); + lock.writeLock().lock(); + Thread t1 = new Thread(new CheckedRunnable() { + public void realRun() { + lock.readLock().lock(); + lock.readLock().unlock(); + }}); + Thread t2 = new Thread(new CheckedRunnable() { + public void realRun() { + lock.readLock().lock(); + lock.readLock().unlock(); + }}); + + t1.start(); + t2.start(); + lock.readLock().lock(); + lock.readLock().unlock(); + Thread.sleep(SHORT_DELAY_MS); + lock.readLock().lock(); + lock.readLock().unlock(); + lock.writeLock().unlock(); + t1.join(MEDIUM_DELAY_MS); + t2.join(MEDIUM_DELAY_MS); + assertTrue(!t1.isAlive()); + assertTrue(!t2.isAlive()); } @@ -564,39 +521,32 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase { * Fair Read lock succeeds if write locked by current thread even if * other threads are waiting for writelock */ - public void testReadHoldingWriteLockFair3() { - final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true); - lock.writeLock().lock(); - Thread t1 = new Thread(new Runnable() { - public void run() { - lock.writeLock().lock(); - lock.writeLock().unlock(); - } - }); - Thread t2 = new Thread(new Runnable() { - public void run() { - lock.writeLock().lock(); - lock.writeLock().unlock(); - } - }); - - try { - t1.start(); - t2.start(); - lock.readLock().lock(); - lock.readLock().unlock(); - Thread.sleep(SHORT_DELAY_MS); - lock.readLock().lock(); - lock.readLock().unlock(); - lock.writeLock().unlock(); - t1.join(MEDIUM_DELAY_MS); - t2.join(MEDIUM_DELAY_MS); - assertTrue(!t1.isAlive()); - assertTrue(!t2.isAlive()); + public void testReadHoldingWriteLockFair3() throws InterruptedException { + final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true); + lock.writeLock().lock(); + Thread t1 = new Thread(new CheckedRunnable() { + public void realRun() { + lock.writeLock().lock(); + lock.writeLock().unlock(); + }}); + Thread t2 = new Thread(new CheckedRunnable() { + public void realRun() { + lock.writeLock().lock(); + lock.writeLock().unlock(); + }}); - } catch(Exception e){ - unexpectedException(); - } + t1.start(); + t2.start(); + lock.readLock().lock(); + lock.readLock().unlock(); + Thread.sleep(SHORT_DELAY_MS); + lock.readLock().lock(); + lock.readLock().unlock(); + lock.writeLock().unlock(); + t1.join(MEDIUM_DELAY_MS); + t2.join(MEDIUM_DELAY_MS); + assertTrue(!t1.isAlive()); + assertTrue(!t2.isAlive()); } @@ -604,64 +554,53 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase { * Fair Write lock succeeds if write locked by current thread even if * other threads are waiting for writelock */ - public void testWriteHoldingWriteLockFair4() { - final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true); - lock.writeLock().lock(); - Thread t1 = new Thread(new Runnable() { - public void run() { - lock.writeLock().lock(); - lock.writeLock().unlock(); - } - }); - Thread t2 = new Thread(new Runnable() { - public void run() { - lock.writeLock().lock(); - lock.writeLock().unlock(); - } - }); - - try { - t1.start(); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(lock.isWriteLockedByCurrentThread()); - assertTrue(lock.getWriteHoldCount() == 1); - lock.writeLock().lock(); - assertTrue(lock.getWriteHoldCount() == 2); - lock.writeLock().unlock(); - lock.writeLock().lock(); - lock.writeLock().unlock(); - lock.writeLock().unlock(); - t1.join(MEDIUM_DELAY_MS); - t2.join(MEDIUM_DELAY_MS); - assertTrue(!t1.isAlive()); - assertTrue(!t2.isAlive()); + public void testWriteHoldingWriteLockFair4() throws InterruptedException { + final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true); + lock.writeLock().lock(); + Thread t1 = new Thread(new CheckedRunnable() { + public void realRun() { + lock.writeLock().lock(); + lock.writeLock().unlock(); + }}); + Thread t2 = new Thread(new CheckedRunnable() { + public void realRun() { + lock.writeLock().lock(); + lock.writeLock().unlock(); + }}); - } catch(Exception e){ - unexpectedException(); - } + t1.start(); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(lock.isWriteLockedByCurrentThread()); + assertTrue(lock.getWriteHoldCount() == 1); + lock.writeLock().lock(); + assertTrue(lock.getWriteHoldCount() == 2); + lock.writeLock().unlock(); + lock.writeLock().lock(); + lock.writeLock().unlock(); + lock.writeLock().unlock(); + t1.join(MEDIUM_DELAY_MS); + t2.join(MEDIUM_DELAY_MS); + assertTrue(!t1.isAlive()); + assertTrue(!t2.isAlive()); } /** * Read tryLock succeeds if readlocked but not writelocked */ - public void testTryLockWhenReadLocked() { + public void testTryLockWhenReadLocked() throws InterruptedException { final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); lock.readLock().lock(); - Thread t = new Thread(new Runnable() { - public void run() { - threadAssertTrue(lock.readLock().tryLock()); - lock.readLock().unlock(); - } - }); - try { - t.start(); - t.join(); - lock.readLock().unlock(); - } catch(Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + threadAssertTrue(lock.readLock().tryLock()); + lock.readLock().unlock(); + }}); + + t.start(); + t.join(); + lock.readLock().unlock(); } @@ -669,43 +608,35 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase { /** * write tryLock fails when readlocked */ - public void testWriteTryLockWhenReadLocked() { + public void testWriteTryLockWhenReadLocked() throws InterruptedException { final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); lock.readLock().lock(); - Thread t = new Thread(new Runnable() { - public void run() { - threadAssertFalse(lock.writeLock().tryLock()); - } - }); - try { - t.start(); - t.join(); - lock.readLock().unlock(); - } catch(Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + threadAssertFalse(lock.writeLock().tryLock()); + }}); + + t.start(); + t.join(); + lock.readLock().unlock(); } /** * Fair Read tryLock succeeds if readlocked but not writelocked */ - public void testTryLockWhenReadLockedFair() { - final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true); - lock.readLock().lock(); - Thread t = new Thread(new Runnable() { - public void run() { - threadAssertTrue(lock.readLock().tryLock()); - lock.readLock().unlock(); - } - }); - try { - t.start(); - t.join(); - lock.readLock().unlock(); - } catch(Exception e){ - unexpectedException(); - } + public void testTryLockWhenReadLockedFair() throws InterruptedException { + final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true); + lock.readLock().lock(); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + threadAssertTrue(lock.readLock().tryLock()); + lock.readLock().unlock(); + }}); + + t.start(); + t.join(); + lock.readLock().unlock(); } @@ -713,21 +644,17 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase { /** * Fair write tryLock fails when readlocked */ - public void testWriteTryLockWhenReadLockedFair() { - final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true); - lock.readLock().lock(); - Thread t = new Thread(new Runnable() { - public void run() { - threadAssertFalse(lock.writeLock().tryLock()); - } - }); - try { - t.start(); - t.join(); - lock.readLock().unlock(); - } catch(Exception e){ - unexpectedException(); - } + public void testWriteTryLockWhenReadLockedFair() throws InterruptedException { + final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true); + lock.readLock().lock(); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + threadAssertFalse(lock.writeLock().tryLock()); + }}); + + t.start(); + t.join(); + lock.readLock().unlock(); } @@ -735,130 +662,85 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase { /** * write timed tryLock times out if locked */ - public void testWriteTryLock_Timeout() { + public void testWriteTryLock_Timeout() throws InterruptedException { final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); lock.writeLock().lock(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - threadAssertFalse(lock.writeLock().tryLock(1, TimeUnit.MILLISECONDS)); - } catch (Exception ex) { - threadUnexpectedException(); - } - } - }); - try { - t.start(); - t.join(); - lock.writeLock().unlock(); - } catch(Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadAssertFalse(lock.writeLock().tryLock(1, MILLISECONDS)); + }}); + + t.start(); + t.join(); + assertTrue(lock.writeLock().isHeldByCurrentThread()); + lock.writeLock().unlock(); } /** * read timed tryLock times out if write-locked */ - public void testReadTryLock_Timeout() { + public void testReadTryLock_Timeout() throws InterruptedException { final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); lock.writeLock().lock(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - threadAssertFalse(lock.readLock().tryLock(1, TimeUnit.MILLISECONDS)); - } catch (Exception ex) { - threadUnexpectedException(); - } - } - }); - try { - t.start(); - t.join(); - lock.writeLock().unlock(); - } catch(Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadAssertFalse(lock.readLock().tryLock(1, MILLISECONDS)); + }}); + + t.start(); + t.join(); + assertTrue(lock.writeLock().isHeldByCurrentThread()); + lock.writeLock().unlock(); } /** * write lockInterruptibly succeeds if lock free else is interruptible */ - public void testWriteLockInterruptibly() { + public void testWriteLockInterruptibly() throws InterruptedException { final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); - try { - lock.writeLock().lockInterruptibly(); - } catch(Exception e) { - unexpectedException(); - } - Thread t = new Thread(new Runnable() { - public void run() { - try { - lock.writeLock().lockInterruptibly(); - threadShouldThrow(); - } - catch(InterruptedException success) { - } - } - }); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - Thread.sleep(SHORT_DELAY_MS); - t.join(); - lock.writeLock().unlock(); - } catch(Exception e){ - unexpectedException(); - } + lock.writeLock().lockInterruptibly(); + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + lock.writeLock().lockInterruptibly(); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + t.join(); + lock.writeLock().unlock(); } /** * read lockInterruptibly succeeds if lock free else is interruptible */ - public void testReadLockInterruptibly() { + public void testReadLockInterruptibly() throws InterruptedException { final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); - try { - lock.writeLock().lockInterruptibly(); - } catch(Exception e) { - unexpectedException(); - } - Thread t = new Thread(new Runnable() { - public void run() { - try { - lock.readLock().lockInterruptibly(); - threadShouldThrow(); - } - catch(InterruptedException success) { - } - } - }); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - lock.writeLock().unlock(); - } catch(Exception e){ - unexpectedException(); - } + lock.writeLock().lockInterruptibly(); + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + lock.readLock().lockInterruptibly(); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); + lock.writeLock().unlock(); } /** * Calling await without holding lock throws IllegalMonitorStateException */ - public void testAwait_IllegalMonitor() { + public void testAwait_IllegalMonitor() throws InterruptedException { final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); final Condition c = lock.writeLock().newCondition(); try { c.await(); shouldThrow(); - } - catch (IllegalMonitorStateException success) { - } - catch (Exception ex) { - shouldThrow(); - } + } catch (IllegalMonitorStateException success) {} } /** @@ -870,94 +752,66 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase { try { c.signal(); shouldThrow(); - } - catch (IllegalMonitorStateException success) { - } - catch (Exception ex) { - unexpectedException(); - } + } catch (IllegalMonitorStateException success) {} } /** * awaitNanos without a signal times out */ - public void testAwaitNanos_Timeout() { + public void testAwaitNanos_Timeout() throws InterruptedException { final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); final Condition c = lock.writeLock().newCondition(); - try { - lock.writeLock().lock(); - long t = c.awaitNanos(100); - assertTrue(t <= 0); - lock.writeLock().unlock(); - } - catch (Exception ex) { - unexpectedException(); - } + + lock.writeLock().lock(); + long t = c.awaitNanos(100); + assertTrue(t <= 0); + lock.writeLock().unlock(); } /** * timed await without a signal times out */ - public void testAwait_Timeout() { + public void testAwait_Timeout() throws InterruptedException { final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); final Condition c = lock.writeLock().newCondition(); - try { - lock.writeLock().lock(); - lock.writeLock().unlock(); - } - catch (Exception ex) { - unexpectedException(); - } + lock.writeLock().lock(); + assertFalse(c.await(SHORT_DELAY_MS, MILLISECONDS)); + lock.writeLock().unlock(); } /** * awaitUntil without a signal times out */ - public void testAwaitUntil_Timeout() { + public void testAwaitUntil_Timeout() throws InterruptedException { final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); final Condition c = lock.writeLock().newCondition(); - try { - lock.writeLock().lock(); - java.util.Date d = new java.util.Date(); - lock.writeLock().unlock(); - } - catch (Exception ex) { - unexpectedException(); - } + lock.writeLock().lock(); + java.util.Date d = new java.util.Date(); + assertFalse(c.awaitUntil(new java.util.Date(d.getTime() + 10))); + lock.writeLock().unlock(); } /** * await returns when signalled */ - public void testAwait() { + public void testAwait() throws InterruptedException { final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); final Condition c = lock.writeLock().newCondition(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - lock.writeLock().lock(); - c.await(); - lock.writeLock().unlock(); - } - catch(InterruptedException e) { - threadUnexpectedException(); - } - } - }); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.writeLock().lock(); + c.await(); + lock.writeLock().unlock(); + }}); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - lock.writeLock().lock(); - c.signal(); - lock.writeLock().unlock(); - t.join(SHORT_DELAY_MS); - assertFalse(t.isAlive()); - } - catch (Exception ex) { - unexpectedException(); - } + t.start(); + Thread.sleep(SHORT_DELAY_MS); + lock.writeLock().lock(); + c.signal(); + lock.writeLock().unlock(); + t.join(SHORT_DELAY_MS); + assertFalse(t.isAlive()); } /** A helper class for uninterruptible wait tests */ @@ -990,230 +844,167 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase { /** * awaitUninterruptibly doesn't abort on interrupt */ - public void testAwaitUninterruptibly() { + public void testAwaitUninterruptibly() throws InterruptedException { final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); final Condition c = lock.writeLock().newCondition(); UninterruptableThread thread = new UninterruptableThread(lock.writeLock(), c); - try { - thread.start(); + thread.start(); - while (!thread.lockStarted) { - Thread.sleep(100); - } - - lock.writeLock().lock(); - try { - thread.interrupt(); - thread.canAwake = true; - c.signal(); - } finally { - lock.writeLock().unlock(); - } + while (!thread.lockStarted) { + Thread.sleep(100); + } - thread.join(); - assertTrue(thread.interrupted); - assertFalse(thread.isAlive()); - } catch (Exception ex) { - unexpectedException(); + lock.writeLock().lock(); + try { + thread.interrupt(); + thread.canAwake = true; + c.signal(); + } finally { + lock.writeLock().unlock(); } + + thread.join(); + assertTrue(thread.interrupted); + assertFalse(thread.isAlive()); } /** * await is interruptible */ - public void testAwait_Interrupt() { + public void testAwait_Interrupt() throws InterruptedException { final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); final Condition c = lock.writeLock().newCondition(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - lock.writeLock().lock(); - c.await(); - lock.writeLock().unlock(); - threadShouldThrow(); - } - catch(InterruptedException success) { - } - } - }); + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + lock.writeLock().lock(); + c.await(); + lock.writeLock().unlock(); + }}); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(SHORT_DELAY_MS); - assertFalse(t.isAlive()); - } - catch (Exception ex) { - unexpectedException(); - } + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(SHORT_DELAY_MS); + assertFalse(t.isAlive()); } /** * awaitNanos is interruptible */ - public void testAwaitNanos_Interrupt() { + public void testAwaitNanos_Interrupt() throws InterruptedException { final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); final Condition c = lock.writeLock().newCondition(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - lock.writeLock().lock(); - c.awaitNanos(SHORT_DELAY_MS * 2 * 1000000); - lock.writeLock().unlock(); - threadShouldThrow(); - } - catch(InterruptedException success) { - } - } - }); + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + lock.writeLock().lock(); + c.awaitNanos(MILLISECONDS.toNanos(LONG_DELAY_MS)); + lock.writeLock().unlock(); + }}); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(SHORT_DELAY_MS); - assertFalse(t.isAlive()); - } - catch (Exception ex) { - unexpectedException(); - } + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(SHORT_DELAY_MS); + assertFalse(t.isAlive()); } /** * awaitUntil is interruptible */ - public void testAwaitUntil_Interrupt() { + public void testAwaitUntil_Interrupt() throws InterruptedException { final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); final Condition c = lock.writeLock().newCondition(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - lock.writeLock().lock(); - java.util.Date d = new java.util.Date(); - c.awaitUntil(new java.util.Date(d.getTime() + 10000)); - lock.writeLock().unlock(); - threadShouldThrow(); - } - catch(InterruptedException success) { - } - } - }); + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + lock.writeLock().lock(); + java.util.Date d = new java.util.Date(); + c.awaitUntil(new java.util.Date(d.getTime() + 10000)); + lock.writeLock().unlock(); + }}); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(SHORT_DELAY_MS); - assertFalse(t.isAlive()); - } - catch (Exception ex) { - unexpectedException(); - } + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(SHORT_DELAY_MS); + assertFalse(t.isAlive()); } /** * signalAll wakes up all threads */ - public void testSignalAll() { + public void testSignalAll() throws InterruptedException { final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); final Condition c = lock.writeLock().newCondition(); - Thread t1 = new Thread(new Runnable() { - public void run() { - try { - lock.writeLock().lock(); - c.await(); - lock.writeLock().unlock(); - } - catch(InterruptedException e) { - threadUnexpectedException(); - } - } - }); - - Thread t2 = new Thread(new Runnable() { - public void run() { - try { - lock.writeLock().lock(); - c.await(); - lock.writeLock().unlock(); - } - catch(InterruptedException e) { - threadUnexpectedException(); - } - } - }); + Thread t1 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.writeLock().lock(); + c.await(); + lock.writeLock().unlock(); + }}); - try { - t1.start(); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - lock.writeLock().lock(); - c.signalAll(); - lock.writeLock().unlock(); - t1.join(SHORT_DELAY_MS); - t2.join(SHORT_DELAY_MS); - assertFalse(t1.isAlive()); - assertFalse(t2.isAlive()); - } - catch (Exception ex) { - unexpectedException(); - } + Thread t2 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.writeLock().lock(); + c.await(); + lock.writeLock().unlock(); + }}); + + t1.start(); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + lock.writeLock().lock(); + c.signalAll(); + lock.writeLock().unlock(); + t1.join(SHORT_DELAY_MS); + t2.join(SHORT_DELAY_MS); + assertFalse(t1.isAlive()); + assertFalse(t2.isAlive()); } /** * A serialized lock deserializes as unlocked */ - public void testSerialization() { + public void testSerialization() throws Exception { ReentrantReadWriteLock l = new ReentrantReadWriteLock(); l.readLock().lock(); l.readLock().unlock(); - try { - ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); - ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); - out.writeObject(l); - out.close(); - - ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); - ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); - ReentrantReadWriteLock r = (ReentrantReadWriteLock) in.readObject(); - r.readLock().lock(); - r.readLock().unlock(); - } catch(Exception e){ - e.printStackTrace(); - unexpectedException(); - } + ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); + ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); + out.writeObject(l); + out.close(); + + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); + ReentrantReadWriteLock r = (ReentrantReadWriteLock) in.readObject(); + r.readLock().lock(); + r.readLock().unlock(); } /** * hasQueuedThreads reports whether there are waiting threads */ - public void testhasQueuedThreads() { + public void testhasQueuedThreads() throws InterruptedException { final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); Thread t1 = new Thread(new InterruptedLockRunnable(lock)); Thread t2 = new Thread(new InterruptibleLockRunnable(lock)); - try { - assertFalse(lock.hasQueuedThreads()); - lock.writeLock().lock(); - t1.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(lock.hasQueuedThreads()); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(lock.hasQueuedThreads()); - t1.interrupt(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(lock.hasQueuedThreads()); - lock.writeLock().unlock(); - Thread.sleep(SHORT_DELAY_MS); - assertFalse(lock.hasQueuedThreads()); - t1.join(); - t2.join(); - } catch(Exception e){ - unexpectedException(); - } + assertFalse(lock.hasQueuedThreads()); + lock.writeLock().lock(); + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(lock.hasQueuedThreads()); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(lock.hasQueuedThreads()); + t1.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(lock.hasQueuedThreads()); + lock.writeLock().unlock(); + Thread.sleep(SHORT_DELAY_MS); + assertFalse(lock.hasQueuedThreads()); + t1.join(); + t2.join(); } /** @@ -1224,104 +1015,91 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase { try { sync.hasQueuedThread(null); shouldThrow(); - } catch (NullPointerException success) { - } + } catch (NullPointerException success) {} } /** * hasQueuedThread reports whether a thread is queued. */ - public void testHasQueuedThread() { + public void testHasQueuedThread() throws InterruptedException { final ReentrantReadWriteLock sync = new ReentrantReadWriteLock(); Thread t1 = new Thread(new InterruptedLockRunnable(sync)); Thread t2 = new Thread(new InterruptibleLockRunnable(sync)); - try { - assertFalse(sync.hasQueuedThread(t1)); - assertFalse(sync.hasQueuedThread(t2)); - sync.writeLock().lock(); - t1.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(sync.hasQueuedThread(t1)); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(sync.hasQueuedThread(t1)); - assertTrue(sync.hasQueuedThread(t2)); - t1.interrupt(); - Thread.sleep(SHORT_DELAY_MS); - assertFalse(sync.hasQueuedThread(t1)); - assertTrue(sync.hasQueuedThread(t2)); - sync.writeLock().unlock(); - Thread.sleep(SHORT_DELAY_MS); - assertFalse(sync.hasQueuedThread(t1)); - Thread.sleep(SHORT_DELAY_MS); - assertFalse(sync.hasQueuedThread(t2)); - t1.join(); - t2.join(); - } catch(Exception e){ - unexpectedException(); - } + assertFalse(sync.hasQueuedThread(t1)); + assertFalse(sync.hasQueuedThread(t2)); + sync.writeLock().lock(); + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.hasQueuedThread(t1)); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(sync.hasQueuedThread(t1)); + assertTrue(sync.hasQueuedThread(t2)); + t1.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + assertFalse(sync.hasQueuedThread(t1)); + assertTrue(sync.hasQueuedThread(t2)); + sync.writeLock().unlock(); + Thread.sleep(SHORT_DELAY_MS); + assertFalse(sync.hasQueuedThread(t1)); + Thread.sleep(SHORT_DELAY_MS); + assertFalse(sync.hasQueuedThread(t2)); + t1.join(); + t2.join(); } /** * getQueueLength reports number of waiting threads */ - public void testGetQueueLength() { + public void testGetQueueLength() throws InterruptedException { final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); Thread t1 = new Thread(new InterruptedLockRunnable(lock)); Thread t2 = new Thread(new InterruptibleLockRunnable(lock)); - try { - assertEquals(0, lock.getQueueLength()); - lock.writeLock().lock(); - t1.start(); - Thread.sleep(SHORT_DELAY_MS); - assertEquals(1, lock.getQueueLength()); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - assertEquals(2, lock.getQueueLength()); - t1.interrupt(); - Thread.sleep(SHORT_DELAY_MS); - assertEquals(1, lock.getQueueLength()); - lock.writeLock().unlock(); - Thread.sleep(SHORT_DELAY_MS); - assertEquals(0, lock.getQueueLength()); - t1.join(); - t2.join(); - } catch(Exception e){ - unexpectedException(); - } + assertEquals(0, lock.getQueueLength()); + lock.writeLock().lock(); + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(1, lock.getQueueLength()); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(2, lock.getQueueLength()); + t1.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(1, lock.getQueueLength()); + lock.writeLock().unlock(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(0, lock.getQueueLength()); + t1.join(); + t2.join(); } /** * getQueuedThreads includes waiting threads */ - public void testGetQueuedThreads() { + public void testGetQueuedThreads() throws InterruptedException { final PublicReentrantReadWriteLock lock = new PublicReentrantReadWriteLock(); Thread t1 = new Thread(new InterruptedLockRunnable(lock)); Thread t2 = new Thread(new InterruptibleLockRunnable(lock)); - try { - assertTrue(lock.getQueuedThreads().isEmpty()); - lock.writeLock().lock(); - assertTrue(lock.getQueuedThreads().isEmpty()); - t1.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(lock.getQueuedThreads().contains(t1)); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(lock.getQueuedThreads().contains(t1)); - assertTrue(lock.getQueuedThreads().contains(t2)); - t1.interrupt(); - Thread.sleep(SHORT_DELAY_MS); - assertFalse(lock.getQueuedThreads().contains(t1)); - assertTrue(lock.getQueuedThreads().contains(t2)); - lock.writeLock().unlock(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(lock.getQueuedThreads().isEmpty()); - t1.join(); - t2.join(); - } catch(Exception e){ - unexpectedException(); - } + assertTrue(lock.getQueuedThreads().isEmpty()); + lock.writeLock().lock(); + assertTrue(lock.getQueuedThreads().isEmpty()); + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(lock.getQueuedThreads().contains(t1)); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(lock.getQueuedThreads().contains(t1)); + assertTrue(lock.getQueuedThreads().contains(t2)); + t1.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + assertFalse(lock.getQueuedThreads().contains(t1)); + assertTrue(lock.getQueuedThreads().contains(t2)); + lock.writeLock().unlock(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(lock.getQueuedThreads().isEmpty()); + t1.join(); + t2.join(); } /** @@ -1332,10 +1110,7 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase { try { lock.hasWaiters(null); shouldThrow(); - } catch (NullPointerException success) { - } catch (Exception ex) { - unexpectedException(); - } + } catch (NullPointerException success) {} } /** @@ -1346,10 +1121,7 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase { try { lock.getWaitQueueLength(null); shouldThrow(); - } catch (NullPointerException success) { - } catch (Exception ex) { - unexpectedException(); - } + } catch (NullPointerException success) {} } @@ -1361,10 +1133,7 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase { try { lock.getWaitingThreads(null); shouldThrow(); - } catch (NullPointerException success) { - } catch (Exception ex) { - unexpectedException(); - } + } catch (NullPointerException success) {} } /** @@ -1372,15 +1141,12 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase { */ public void testHasWaitersIAE() { final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); - final Condition c = (lock.writeLock().newCondition()); + final Condition c = lock.writeLock().newCondition(); final ReentrantReadWriteLock lock2 = new ReentrantReadWriteLock(); try { lock2.hasWaiters(c); shouldThrow(); - } catch (IllegalArgumentException success) { - } catch (Exception ex) { - unexpectedException(); - } + } catch (IllegalArgumentException success) {} } /** @@ -1388,14 +1154,11 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase { */ public void testHasWaitersIMSE() { final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); - final Condition c = (lock.writeLock().newCondition()); + final Condition c = lock.writeLock().newCondition(); try { lock.hasWaiters(c); shouldThrow(); - } catch (IllegalMonitorStateException success) { - } catch (Exception ex) { - unexpectedException(); - } + } catch (IllegalMonitorStateException success) {} } @@ -1404,15 +1167,12 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase { */ public void testGetWaitQueueLengthIAE() { final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); - final Condition c = (lock.writeLock().newCondition()); + final Condition c = lock.writeLock().newCondition(); final ReentrantReadWriteLock lock2 = new ReentrantReadWriteLock(); try { lock2.getWaitQueueLength(c); shouldThrow(); - } catch (IllegalArgumentException success) { - } catch (Exception ex) { - unexpectedException(); - } + } catch (IllegalArgumentException success) {} } /** @@ -1420,14 +1180,11 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase { */ public void testGetWaitQueueLengthIMSE() { final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); - final Condition c = (lock.writeLock().newCondition()); + final Condition c = lock.writeLock().newCondition(); try { lock.getWaitQueueLength(c); shouldThrow(); - } catch (IllegalMonitorStateException success) { - } catch (Exception ex) { - unexpectedException(); - } + } catch (IllegalMonitorStateException success) {} } @@ -1436,15 +1193,12 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase { */ public void testGetWaitingThreadsIAE() { final PublicReentrantReadWriteLock lock = new PublicReentrantReadWriteLock(); - final Condition c = (lock.writeLock().newCondition()); + final Condition c = lock.writeLock().newCondition(); final PublicReentrantReadWriteLock lock2 = new PublicReentrantReadWriteLock(); try { lock2.getWaitingThreads(c); shouldThrow(); - } catch (IllegalArgumentException success) { - } catch (Exception ex) { - unexpectedException(); - } + } catch (IllegalArgumentException success) {} } /** @@ -1452,163 +1206,121 @@ public class ReentrantReadWriteLockTest extends JSR166TestCase { */ public void testGetWaitingThreadsIMSE() { final PublicReentrantReadWriteLock lock = new PublicReentrantReadWriteLock(); - final Condition c = (lock.writeLock().newCondition()); + final Condition c = lock.writeLock().newCondition(); try { lock.getWaitingThreads(c); shouldThrow(); - } catch (IllegalMonitorStateException success) { - } catch (Exception ex) { - unexpectedException(); - } + } catch (IllegalMonitorStateException success) {} } /** * hasWaiters returns true when a thread is waiting, else false */ - public void testHasWaiters() { + public void testHasWaiters() throws InterruptedException { final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); - final Condition c = (lock.writeLock().newCondition()); - Thread t = new Thread(new Runnable() { - public void run() { - try { - lock.writeLock().lock(); - threadAssertFalse(lock.hasWaiters(c)); - threadAssertEquals(0, lock.getWaitQueueLength(c)); - c.await(); - lock.writeLock().unlock(); - } - catch(InterruptedException e) { - threadUnexpectedException(); - } - } - }); + final Condition c = lock.writeLock().newCondition(); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.writeLock().lock(); + threadAssertFalse(lock.hasWaiters(c)); + threadAssertEquals(0, lock.getWaitQueueLength(c)); + c.await(); + lock.writeLock().unlock(); + }}); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - lock.writeLock().lock(); - assertTrue(lock.hasWaiters(c)); - assertEquals(1, lock.getWaitQueueLength(c)); - c.signal(); - lock.writeLock().unlock(); - Thread.sleep(SHORT_DELAY_MS); - lock.writeLock().lock(); - assertFalse(lock.hasWaiters(c)); - assertEquals(0, lock.getWaitQueueLength(c)); - lock.writeLock().unlock(); - t.join(SHORT_DELAY_MS); - assertFalse(t.isAlive()); - } - catch (Exception ex) { - unexpectedException(); - } + t.start(); + Thread.sleep(SHORT_DELAY_MS); + lock.writeLock().lock(); + assertTrue(lock.hasWaiters(c)); + assertEquals(1, lock.getWaitQueueLength(c)); + c.signal(); + lock.writeLock().unlock(); + Thread.sleep(SHORT_DELAY_MS); + lock.writeLock().lock(); + assertFalse(lock.hasWaiters(c)); + assertEquals(0, lock.getWaitQueueLength(c)); + lock.writeLock().unlock(); + t.join(SHORT_DELAY_MS); + assertFalse(t.isAlive()); } /** * getWaitQueueLength returns number of waiting threads */ - public void testGetWaitQueueLength() { + public void testGetWaitQueueLength() throws InterruptedException { final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); - final Condition c = (lock.writeLock().newCondition()); - Thread t = new Thread(new Runnable() { - public void run() { - try { - lock.writeLock().lock(); - threadAssertFalse(lock.hasWaiters(c)); - threadAssertEquals(0, lock.getWaitQueueLength(c)); - c.await(); - lock.writeLock().unlock(); - } - catch(InterruptedException e) { - threadUnexpectedException(); - } - } - }); + final Condition c = lock.writeLock().newCondition(); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.writeLock().lock(); + threadAssertFalse(lock.hasWaiters(c)); + threadAssertEquals(0, lock.getWaitQueueLength(c)); + c.await(); + lock.writeLock().unlock(); + }}); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - lock.writeLock().lock(); - assertTrue(lock.hasWaiters(c)); - assertEquals(1, lock.getWaitQueueLength(c)); - c.signal(); - lock.writeLock().unlock(); - Thread.sleep(SHORT_DELAY_MS); - lock.writeLock().lock(); - assertFalse(lock.hasWaiters(c)); - assertEquals(0, lock.getWaitQueueLength(c)); - lock.writeLock().unlock(); - t.join(SHORT_DELAY_MS); - assertFalse(t.isAlive()); - } - catch (Exception ex) { - unexpectedException(); - } + t.start(); + Thread.sleep(SHORT_DELAY_MS); + lock.writeLock().lock(); + assertTrue(lock.hasWaiters(c)); + assertEquals(1, lock.getWaitQueueLength(c)); + c.signal(); + lock.writeLock().unlock(); + Thread.sleep(SHORT_DELAY_MS); + lock.writeLock().lock(); + assertFalse(lock.hasWaiters(c)); + assertEquals(0, lock.getWaitQueueLength(c)); + lock.writeLock().unlock(); + t.join(SHORT_DELAY_MS); + assertFalse(t.isAlive()); } /** * getWaitingThreads returns only and all waiting threads */ - public void testGetWaitingThreads() { + public void testGetWaitingThreads() throws InterruptedException { final PublicReentrantReadWriteLock lock = new PublicReentrantReadWriteLock(); final Condition c = lock.writeLock().newCondition(); - Thread t1 = new Thread(new Runnable() { - public void run() { - try { - lock.writeLock().lock(); - threadAssertTrue(lock.getWaitingThreads(c).isEmpty()); - c.await(); - lock.writeLock().unlock(); - } - catch(InterruptedException e) { - threadUnexpectedException(); - } - } - }); - - Thread t2 = new Thread(new Runnable() { - public void run() { - try { - lock.writeLock().lock(); - threadAssertFalse(lock.getWaitingThreads(c).isEmpty()); - c.await(); - lock.writeLock().unlock(); - } - catch(InterruptedException e) { - threadUnexpectedException(); - } - } - }); + Thread t1 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.writeLock().lock(); + threadAssertTrue(lock.getWaitingThreads(c).isEmpty()); + c.await(); + lock.writeLock().unlock(); + }}); - try { - lock.writeLock().lock(); - assertTrue(lock.getWaitingThreads(c).isEmpty()); - lock.writeLock().unlock(); - t1.start(); - Thread.sleep(SHORT_DELAY_MS); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - lock.writeLock().lock(); - assertTrue(lock.hasWaiters(c)); - assertTrue(lock.getWaitingThreads(c).contains(t1)); - assertTrue(lock.getWaitingThreads(c).contains(t2)); - c.signalAll(); - lock.writeLock().unlock(); - Thread.sleep(SHORT_DELAY_MS); - lock.writeLock().lock(); - assertFalse(lock.hasWaiters(c)); - assertTrue(lock.getWaitingThreads(c).isEmpty()); - lock.writeLock().unlock(); - t1.join(SHORT_DELAY_MS); - t2.join(SHORT_DELAY_MS); - assertFalse(t1.isAlive()); - assertFalse(t2.isAlive()); - } - catch (Exception ex) { - unexpectedException(); - } + Thread t2 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.writeLock().lock(); + threadAssertFalse(lock.getWaitingThreads(c).isEmpty()); + c.await(); + lock.writeLock().unlock(); + }}); + + lock.writeLock().lock(); + assertTrue(lock.getWaitingThreads(c).isEmpty()); + lock.writeLock().unlock(); + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + lock.writeLock().lock(); + assertTrue(lock.hasWaiters(c)); + assertTrue(lock.getWaitingThreads(c).contains(t1)); + assertTrue(lock.getWaitingThreads(c).contains(t2)); + c.signalAll(); + lock.writeLock().unlock(); + Thread.sleep(SHORT_DELAY_MS); + lock.writeLock().lock(); + assertFalse(lock.hasWaiters(c)); + assertTrue(lock.getWaitingThreads(c).isEmpty()); + lock.writeLock().unlock(); + t1.join(SHORT_DELAY_MS); + t2.join(SHORT_DELAY_MS); + assertFalse(t1.isAlive()); + assertFalse(t2.isAlive()); } /** diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/ScheduledExecutorSubclassTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/ScheduledExecutorSubclassTest.java new file mode 100644 index 0000000..21f4ced --- /dev/null +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/ScheduledExecutorSubclassTest.java @@ -0,0 +1,1060 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package tests.api.java.util.concurrent; // android-added + +import junit.framework.*; +import java.util.*; +import java.util.concurrent.*; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import java.util.concurrent.atomic.*; + +public class ScheduledExecutorSubclassTest extends JSR166TestCase { + public static Test suite() { + return new TestSuite(ScheduledExecutorSubclassTest.class); + } + + static class CustomTask<V> implements RunnableScheduledFuture<V> { + RunnableScheduledFuture<V> task; + volatile boolean ran; + CustomTask(RunnableScheduledFuture<V> t) { task = t; } + public boolean isPeriodic() { return task.isPeriodic(); } + public void run() { + ran = true; + task.run(); + } + public long getDelay(TimeUnit unit) { return task.getDelay(unit); } + public int compareTo(Delayed t) { + return task.compareTo(((CustomTask)t).task); + } + public boolean cancel(boolean mayInterruptIfRunning) { + return task.cancel(mayInterruptIfRunning); + } + public boolean isCancelled() { return task.isCancelled(); } + public boolean isDone() { return task.isDone(); } + public V get() throws InterruptedException, ExecutionException { + V v = task.get(); + assertTrue(ran); + return v; + } + public V get(long time, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + V v = task.get(time, unit); + assertTrue(ran); + return v; + } + } + + + public class CustomExecutor extends ScheduledThreadPoolExecutor { + + protected <V> RunnableScheduledFuture<V> decorateTask(Runnable r, RunnableScheduledFuture<V> task) { + return new CustomTask<V>(task); + } + + protected <V> RunnableScheduledFuture<V> decorateTask(Callable<V> c, RunnableScheduledFuture<V> task) { + return new CustomTask<V>(task); + } + CustomExecutor(int corePoolSize) { super(corePoolSize);} + CustomExecutor(int corePoolSize, RejectedExecutionHandler handler) { + super(corePoolSize, handler); + } + + CustomExecutor(int corePoolSize, ThreadFactory threadFactory) { + super(corePoolSize, threadFactory); + } + CustomExecutor(int corePoolSize, ThreadFactory threadFactory, + RejectedExecutionHandler handler) { + super(corePoolSize, threadFactory, handler); + } + + } + + + /** + * execute successfully executes a runnable + */ + public void testExecute() throws InterruptedException { + TrackedShortRunnable runnable =new TrackedShortRunnable(); + CustomExecutor p1 = new CustomExecutor(1); + p1.execute(runnable); + assertFalse(runnable.done); + Thread.sleep(SHORT_DELAY_MS); + try { p1.shutdown(); } catch (SecurityException ok) { return; } + Thread.sleep(MEDIUM_DELAY_MS); + assertTrue(runnable.done); + try { p1.shutdown(); } catch (SecurityException ok) { return; } + joinPool(p1); + } + + + /** + * delayed schedule of callable successfully executes after delay + */ + public void testSchedule1() throws Exception { + TrackedCallable callable = new TrackedCallable(); + CustomExecutor p1 = new CustomExecutor(1); + Future f = p1.schedule(callable, SHORT_DELAY_MS, MILLISECONDS); + assertFalse(callable.done); + Thread.sleep(MEDIUM_DELAY_MS); + assertTrue(callable.done); + assertEquals(Boolean.TRUE, f.get()); + try { p1.shutdown(); } catch (SecurityException ok) { return; } + joinPool(p1); + } + + /** + * delayed schedule of runnable successfully executes after delay + */ + public void testSchedule3() throws InterruptedException { + TrackedShortRunnable runnable = new TrackedShortRunnable(); + CustomExecutor p1 = new CustomExecutor(1); + p1.schedule(runnable, SMALL_DELAY_MS, MILLISECONDS); + Thread.sleep(SHORT_DELAY_MS); + assertFalse(runnable.done); + Thread.sleep(MEDIUM_DELAY_MS); + assertTrue(runnable.done); + try { p1.shutdown(); } catch (SecurityException ok) { return; } + joinPool(p1); + } + + /** + * scheduleAtFixedRate executes runnable after given initial delay + */ + public void testSchedule4() throws InterruptedException { + TrackedShortRunnable runnable = new TrackedShortRunnable(); + CustomExecutor p1 = new CustomExecutor(1); + ScheduledFuture h = p1.scheduleAtFixedRate(runnable, SHORT_DELAY_MS, SHORT_DELAY_MS, MILLISECONDS); + assertFalse(runnable.done); + Thread.sleep(MEDIUM_DELAY_MS); + assertTrue(runnable.done); + h.cancel(true); + joinPool(p1); + } + + static class RunnableCounter implements Runnable { + AtomicInteger count = new AtomicInteger(0); + public void run() { count.getAndIncrement(); } + } + + /** + * scheduleWithFixedDelay executes runnable after given initial delay + */ + public void testSchedule5() throws InterruptedException { + TrackedShortRunnable runnable = new TrackedShortRunnable(); + CustomExecutor p1 = new CustomExecutor(1); + ScheduledFuture h = p1.scheduleWithFixedDelay(runnable, SHORT_DELAY_MS, SHORT_DELAY_MS, MILLISECONDS); + assertFalse(runnable.done); + Thread.sleep(MEDIUM_DELAY_MS); + assertTrue(runnable.done); + h.cancel(true); + joinPool(p1); + } + + /** + * scheduleAtFixedRate executes series of tasks at given rate + */ + public void testFixedRateSequence() throws InterruptedException { + CustomExecutor p1 = new CustomExecutor(1); + RunnableCounter counter = new RunnableCounter(); + ScheduledFuture h = + p1.scheduleAtFixedRate(counter, 0, 1, MILLISECONDS); + Thread.sleep(SMALL_DELAY_MS); + h.cancel(true); + int c = counter.count.get(); + // By time scaling conventions, we must have at least + // an execution per SHORT delay, but no more than one SHORT more + assertTrue(c >= SMALL_DELAY_MS / SHORT_DELAY_MS); + assertTrue(c <= SMALL_DELAY_MS + SHORT_DELAY_MS); + joinPool(p1); + } + + /** + * scheduleWithFixedDelay executes series of tasks with given period + */ + public void testFixedDelaySequence() throws InterruptedException { + CustomExecutor p1 = new CustomExecutor(1); + RunnableCounter counter = new RunnableCounter(); + ScheduledFuture h = + p1.scheduleWithFixedDelay(counter, 0, 1, MILLISECONDS); + Thread.sleep(SMALL_DELAY_MS); + h.cancel(true); + int c = counter.count.get(); + assertTrue(c >= SMALL_DELAY_MS / SHORT_DELAY_MS); + assertTrue(c <= SMALL_DELAY_MS + SHORT_DELAY_MS); + joinPool(p1); + } + + + /** + * execute (null) throws NPE + */ + public void testExecuteNull() throws InterruptedException { + CustomExecutor se = new CustomExecutor(1); + try { + se.execute(null); + shouldThrow(); + } catch (NullPointerException success) {} + joinPool(se); + } + + /** + * schedule (null) throws NPE + */ + public void testScheduleNull() throws InterruptedException { + CustomExecutor se = new CustomExecutor(1); + try { + TrackedCallable callable = null; + Future f = se.schedule(callable, SHORT_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) {} + joinPool(se); + } + + /** + * execute throws RejectedExecutionException if shutdown + */ + public void testSchedule1_RejectedExecutionException() { + CustomExecutor se = new CustomExecutor(1); + try { + se.shutdown(); + se.schedule(new NoOpRunnable(), + MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (RejectedExecutionException success) { + } catch (SecurityException ok) { + } + + joinPool(se); + } + + /** + * schedule throws RejectedExecutionException if shutdown + */ + public void testSchedule2_RejectedExecutionException() { + CustomExecutor se = new CustomExecutor(1); + try { + se.shutdown(); + se.schedule(new NoOpCallable(), + MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (RejectedExecutionException success) { + } catch (SecurityException ok) { + } + joinPool(se); + } + + /** + * schedule callable throws RejectedExecutionException if shutdown + */ + public void testSchedule3_RejectedExecutionException() { + CustomExecutor se = new CustomExecutor(1); + try { + se.shutdown(); + se.schedule(new NoOpCallable(), + MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (RejectedExecutionException success) { + } catch (SecurityException ok) { + } + joinPool(se); + } + + /** + * scheduleAtFixedRate throws RejectedExecutionException if shutdown + */ + public void testScheduleAtFixedRate1_RejectedExecutionException() { + CustomExecutor se = new CustomExecutor(1); + try { + se.shutdown(); + se.scheduleAtFixedRate(new NoOpRunnable(), + MEDIUM_DELAY_MS, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (RejectedExecutionException success) { + } catch (SecurityException ok) { + } + joinPool(se); + } + + /** + * scheduleWithFixedDelay throws RejectedExecutionException if shutdown + */ + public void testScheduleWithFixedDelay1_RejectedExecutionException() { + CustomExecutor se = new CustomExecutor(1); + try { + se.shutdown(); + se.scheduleWithFixedDelay(new NoOpRunnable(), + MEDIUM_DELAY_MS, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (RejectedExecutionException success) { + } catch (SecurityException ok) { + } + joinPool(se); + } + + /** + * getActiveCount increases but doesn't overestimate, when a + * thread becomes active + */ + public void testGetActiveCount() throws InterruptedException { + CustomExecutor p2 = new CustomExecutor(2); + assertEquals(0, p2.getActiveCount()); + p2.execute(new SmallRunnable()); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(1, p2.getActiveCount()); + joinPool(p2); + } + + /** + * getCompletedTaskCount increases, but doesn't overestimate, + * when tasks complete + */ + public void testGetCompletedTaskCount() throws InterruptedException { + CustomExecutor p2 = new CustomExecutor(2); + assertEquals(0, p2.getCompletedTaskCount()); + p2.execute(new SmallRunnable()); + Thread.sleep(MEDIUM_DELAY_MS); + assertEquals(1, p2.getCompletedTaskCount()); + joinPool(p2); + } + + /** + * getCorePoolSize returns size given in constructor if not otherwise set + */ + public void testGetCorePoolSize() { + CustomExecutor p1 = new CustomExecutor(1); + assertEquals(1, p1.getCorePoolSize()); + joinPool(p1); + } + + /** + * getLargestPoolSize increases, but doesn't overestimate, when + * multiple threads active + */ + public void testGetLargestPoolSize() throws InterruptedException { + CustomExecutor p2 = new CustomExecutor(2); + assertEquals(0, p2.getLargestPoolSize()); + p2.execute(new SmallRunnable()); + p2.execute(new SmallRunnable()); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(2, p2.getLargestPoolSize()); + joinPool(p2); + } + + /** + * getPoolSize increases, but doesn't overestimate, when threads + * become active + */ + public void testGetPoolSize() { + CustomExecutor p1 = new CustomExecutor(1); + assertEquals(0, p1.getPoolSize()); + p1.execute(new SmallRunnable()); + assertEquals(1, p1.getPoolSize()); + joinPool(p1); + } + + /** + * getTaskCount increases, but doesn't overestimate, when tasks + * submitted + */ + public void testGetTaskCount() throws InterruptedException { + CustomExecutor p1 = new CustomExecutor(1); + assertEquals(0, p1.getTaskCount()); + for (int i = 0; i < 5; i++) + p1.execute(new SmallRunnable()); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(5, p1.getTaskCount()); + joinPool(p1); + } + + /** + * getThreadFactory returns factory in constructor if not set + */ + public void testGetThreadFactory() { + ThreadFactory tf = new SimpleThreadFactory(); + CustomExecutor p = new CustomExecutor(1, tf); + assertSame(tf, p.getThreadFactory()); + joinPool(p); + } + + /** + * setThreadFactory sets the thread factory returned by getThreadFactory + */ + public void testSetThreadFactory() { + ThreadFactory tf = new SimpleThreadFactory(); + CustomExecutor p = new CustomExecutor(1); + p.setThreadFactory(tf); + assertSame(tf, p.getThreadFactory()); + joinPool(p); + } + + /** + * setThreadFactory(null) throws NPE + */ + public void testSetThreadFactoryNull() { + CustomExecutor p = new CustomExecutor(1); + try { + p.setThreadFactory(null); + shouldThrow(); + } catch (NullPointerException success) { + } finally { + joinPool(p); + } + } + + /** + * is isShutDown is false before shutdown, true after + */ + public void testIsShutdown() { + CustomExecutor p1 = new CustomExecutor(1); + try { + assertFalse(p1.isShutdown()); + } + finally { + try { p1.shutdown(); } catch (SecurityException ok) { return; } + } + assertTrue(p1.isShutdown()); + } + + + /** + * isTerminated is false before termination, true after + */ + public void testIsTerminated() throws InterruptedException { + CustomExecutor p1 = new CustomExecutor(1); + try { + p1.execute(new SmallRunnable()); + } finally { + try { p1.shutdown(); } catch (SecurityException ok) { return; } + } + assertTrue(p1.awaitTermination(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(p1.isTerminated()); + } + + /** + * isTerminating is not true when running or when terminated + */ + public void testIsTerminating() throws InterruptedException { + CustomExecutor p1 = new CustomExecutor(1); + assertFalse(p1.isTerminating()); + try { + p1.execute(new SmallRunnable()); + assertFalse(p1.isTerminating()); + } finally { + try { p1.shutdown(); } catch (SecurityException ok) { return; } + } + assertTrue(p1.awaitTermination(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(p1.isTerminated()); + assertFalse(p1.isTerminating()); + } + + /** + * getQueue returns the work queue, which contains queued tasks + */ + public void testGetQueue() throws InterruptedException { + CustomExecutor p1 = new CustomExecutor(1); + ScheduledFuture[] tasks = new ScheduledFuture[5]; + for (int i = 0; i < 5; i++) { + tasks[i] = p1.schedule(new SmallPossiblyInterruptedRunnable(), 1, MILLISECONDS); + } + try { + Thread.sleep(SHORT_DELAY_MS); + BlockingQueue<Runnable> q = p1.getQueue(); + assertTrue(q.contains(tasks[4])); + assertFalse(q.contains(tasks[0])); + } finally { + joinPool(p1); + } + } + + /** + * remove(task) removes queued task, and fails to remove active task + */ + public void testRemove() throws InterruptedException { + CustomExecutor p1 = new CustomExecutor(1); + ScheduledFuture[] tasks = new ScheduledFuture[5]; + for (int i = 0; i < 5; i++) { + tasks[i] = p1.schedule(new SmallPossiblyInterruptedRunnable(), 1, MILLISECONDS); + } + try { + Thread.sleep(SHORT_DELAY_MS); + BlockingQueue<Runnable> q = p1.getQueue(); + assertFalse(p1.remove((Runnable)tasks[0])); + assertTrue(q.contains((Runnable)tasks[4])); + assertTrue(q.contains((Runnable)tasks[3])); + assertTrue(p1.remove((Runnable)tasks[4])); + assertFalse(p1.remove((Runnable)tasks[4])); + assertFalse(q.contains((Runnable)tasks[4])); + assertTrue(q.contains((Runnable)tasks[3])); + assertTrue(p1.remove((Runnable)tasks[3])); + assertFalse(q.contains((Runnable)tasks[3])); + } finally { + joinPool(p1); + } + } + + /** + * purge removes cancelled tasks from the queue + */ + public void testPurge() throws InterruptedException { + CustomExecutor p1 = new CustomExecutor(1); + ScheduledFuture[] tasks = new ScheduledFuture[5]; + for (int i = 0; i < 5; i++) { + tasks[i] = p1.schedule(new SmallPossiblyInterruptedRunnable(), SHORT_DELAY_MS, MILLISECONDS); + } + try { + int max = 5; + if (tasks[4].cancel(true)) --max; + if (tasks[3].cancel(true)) --max; + // There must eventually be an interference-free point at + // which purge will not fail. (At worst, when queue is empty.) + int k; + for (k = 0; k < SMALL_DELAY_MS; ++k) { + p1.purge(); + long count = p1.getTaskCount(); + if (count >= 0 && count <= max) + break; + Thread.sleep(1); + } + assertTrue(k < SMALL_DELAY_MS); + } finally { + joinPool(p1); + } + } + + /** + * shutDownNow returns a list containing tasks that were not run + */ + public void testShutDownNow() { + CustomExecutor p1 = new CustomExecutor(1); + for (int i = 0; i < 5; i++) + p1.schedule(new SmallPossiblyInterruptedRunnable(), SHORT_DELAY_MS, MILLISECONDS); + List l; + try { + l = p1.shutdownNow(); + } catch (SecurityException ok) { + return; + } + assertTrue(p1.isShutdown()); + assertTrue(l.size() > 0 && l.size() <= 5); + joinPool(p1); + } + + /** + * In default setting, shutdown cancels periodic but not delayed + * tasks at shutdown + */ + public void testShutDown1() throws InterruptedException { + CustomExecutor p1 = new CustomExecutor(1); + assertTrue(p1.getExecuteExistingDelayedTasksAfterShutdownPolicy()); + assertFalse(p1.getContinueExistingPeriodicTasksAfterShutdownPolicy()); + + ScheduledFuture[] tasks = new ScheduledFuture[5]; + for (int i = 0; i < 5; i++) + tasks[i] = p1.schedule(new NoOpRunnable(), SHORT_DELAY_MS, MILLISECONDS); + try { p1.shutdown(); } catch (SecurityException ok) { return; } + BlockingQueue q = p1.getQueue(); + for (Iterator it = q.iterator(); it.hasNext();) { + ScheduledFuture t = (ScheduledFuture)it.next(); + assertFalse(t.isCancelled()); + } + assertTrue(p1.isShutdown()); + Thread.sleep(SMALL_DELAY_MS); + for (int i = 0; i < 5; ++i) { + assertTrue(tasks[i].isDone()); + assertFalse(tasks[i].isCancelled()); + } + } + + + /** + * If setExecuteExistingDelayedTasksAfterShutdownPolicy is false, + * delayed tasks are cancelled at shutdown + */ + public void testShutDown2() throws InterruptedException { + CustomExecutor p1 = new CustomExecutor(1); + p1.setExecuteExistingDelayedTasksAfterShutdownPolicy(false); + ScheduledFuture[] tasks = new ScheduledFuture[5]; + for (int i = 0; i < 5; i++) + tasks[i] = p1.schedule(new NoOpRunnable(), SHORT_DELAY_MS, MILLISECONDS); + try { p1.shutdown(); } catch (SecurityException ok) { return; } + assertTrue(p1.isShutdown()); + BlockingQueue q = p1.getQueue(); + assertTrue(q.isEmpty()); + Thread.sleep(SMALL_DELAY_MS); + assertTrue(p1.isTerminated()); + } + + + /** + * If setContinueExistingPeriodicTasksAfterShutdownPolicy is set false, + * periodic tasks are not cancelled at shutdown + */ + public void testShutDown3() throws InterruptedException { + CustomExecutor p1 = new CustomExecutor(1); + p1.setContinueExistingPeriodicTasksAfterShutdownPolicy(false); + ScheduledFuture task = + p1.scheduleAtFixedRate(new NoOpRunnable(), 5, 5, MILLISECONDS); + try { p1.shutdown(); } catch (SecurityException ok) { return; } + assertTrue(p1.isShutdown()); + BlockingQueue q = p1.getQueue(); + assertTrue(q.isEmpty()); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(p1.isTerminated()); + } + + /** + * if setContinueExistingPeriodicTasksAfterShutdownPolicy is true, + * periodic tasks are cancelled at shutdown + */ + public void testShutDown4() throws InterruptedException { + CustomExecutor p1 = new CustomExecutor(1); + try { + p1.setContinueExistingPeriodicTasksAfterShutdownPolicy(true); + ScheduledFuture task = + p1.scheduleAtFixedRate(new NoOpRunnable(), 1, 1, MILLISECONDS); + assertFalse(task.isCancelled()); + try { p1.shutdown(); } catch (SecurityException ok) { return; } + assertFalse(task.isCancelled()); + assertFalse(p1.isTerminated()); + assertTrue(p1.isShutdown()); + Thread.sleep(SHORT_DELAY_MS); + assertFalse(task.isCancelled()); + assertTrue(task.cancel(true)); + assertTrue(task.isDone()); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(p1.isTerminated()); + } + finally { + joinPool(p1); + } + } + + /** + * completed submit of callable returns result + */ + public void testSubmitCallable() throws Exception { + ExecutorService e = new CustomExecutor(2); + try { + Future<String> future = e.submit(new StringTask()); + String result = future.get(); + assertSame(TEST_STRING, result); + } finally { + joinPool(e); + } + } + + /** + * completed submit of runnable returns successfully + */ + public void testSubmitRunnable() throws Exception { + ExecutorService e = new CustomExecutor(2); + try { + Future<?> future = e.submit(new NoOpRunnable()); + future.get(); + assertTrue(future.isDone()); + } finally { + joinPool(e); + } + } + + /** + * completed submit of (runnable, result) returns result + */ + public void testSubmitRunnable2() throws Exception { + ExecutorService e = new CustomExecutor(2); + try { + Future<String> future = e.submit(new NoOpRunnable(), TEST_STRING); + String result = future.get(); + assertSame(TEST_STRING, result); + } finally { + joinPool(e); + } + } + + /** + * invokeAny(null) throws NPE + */ + public void testInvokeAny1() throws Exception { + ExecutorService e = new CustomExecutor(2); + try { + e.invokeAny(null); + shouldThrow(); + } catch (NullPointerException success) { + } finally { + joinPool(e); + } + } + + /** + * invokeAny(empty collection) throws IAE + */ + public void testInvokeAny2() throws Exception { + ExecutorService e = new CustomExecutor(2); + try { + e.invokeAny(new ArrayList<Callable<String>>()); + shouldThrow(); + } catch (IllegalArgumentException success) { + } finally { + joinPool(e); + } + } + + /** + * invokeAny(c) throws NPE if c has null elements + */ + public void testInvokeAny3() throws Exception { + CountDownLatch latch = new CountDownLatch(1); + ExecutorService e = new CustomExecutor(2); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(latchAwaitingStringTask(latch)); + l.add(null); + try { + e.invokeAny(l); + shouldThrow(); + } catch (NullPointerException success) { + } finally { + latch.countDown(); + joinPool(e); + } + } + + /** + * invokeAny(c) throws ExecutionException if no task completes + */ + public void testInvokeAny4() throws Exception { + ExecutorService e = new CustomExecutor(2); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new NPETask()); + try { + e.invokeAny(l); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } finally { + joinPool(e); + } + } + + /** + * invokeAny(c) returns result of some task + */ + public void testInvokeAny5() throws Exception { + ExecutorService e = new CustomExecutor(2); + try { + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new StringTask()); + l.add(new StringTask()); + String result = e.invokeAny(l); + assertSame(TEST_STRING, result); + } finally { + joinPool(e); + } + } + + /** + * invokeAll(null) throws NPE + */ + public void testInvokeAll1() throws Exception { + ExecutorService e = new CustomExecutor(2); + try { + e.invokeAll(null); + shouldThrow(); + } catch (NullPointerException success) { + } finally { + joinPool(e); + } + } + + /** + * invokeAll(empty collection) returns empty collection + */ + public void testInvokeAll2() throws Exception { + ExecutorService e = new CustomExecutor(2); + try { + List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>()); + assertTrue(r.isEmpty()); + } finally { + joinPool(e); + } + } + + /** + * invokeAll(c) throws NPE if c has null elements + */ + public void testInvokeAll3() throws Exception { + ExecutorService e = new CustomExecutor(2); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new StringTask()); + l.add(null); + try { + e.invokeAll(l); + shouldThrow(); + } catch (NullPointerException success) { + } finally { + joinPool(e); + } + } + + /** + * get of invokeAll(c) throws exception on failed task + */ + public void testInvokeAll4() throws Exception { + ExecutorService e = new CustomExecutor(2); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new NPETask()); + List<Future<String>> futures = e.invokeAll(l); + assertEquals(1, futures.size()); + try { + futures.get(0).get(); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } finally { + joinPool(e); + } + } + + /** + * invokeAll(c) returns results of all completed tasks + */ + public void testInvokeAll5() throws Exception { + ExecutorService e = new CustomExecutor(2); + try { + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new StringTask()); + l.add(new StringTask()); + List<Future<String>> futures = e.invokeAll(l); + assertEquals(2, futures.size()); + for (Future<String> future : futures) + assertSame(TEST_STRING, future.get()); + } finally { + joinPool(e); + } + } + + /** + * timed invokeAny(null) throws NPE + */ + public void testTimedInvokeAny1() throws Exception { + ExecutorService e = new CustomExecutor(2); + try { + e.invokeAny(null, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) { + } finally { + joinPool(e); + } + } + + /** + * timed invokeAny(,,null) throws NPE + */ + public void testTimedInvokeAnyNullTimeUnit() throws Exception { + ExecutorService e = new CustomExecutor(2); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new StringTask()); + try { + e.invokeAny(l, MEDIUM_DELAY_MS, null); + shouldThrow(); + } catch (NullPointerException success) { + } finally { + joinPool(e); + } + } + + /** + * timed invokeAny(empty collection) throws IAE + */ + public void testTimedInvokeAny2() throws Exception { + ExecutorService e = new CustomExecutor(2); + try { + e.invokeAny(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (IllegalArgumentException success) { + } finally { + joinPool(e); + } + } + + /** + * timed invokeAny(c) throws NPE if c has null elements + */ + public void testTimedInvokeAny3() throws Exception { + CountDownLatch latch = new CountDownLatch(1); + ExecutorService e = new CustomExecutor(2); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(latchAwaitingStringTask(latch)); + l.add(null); + try { + e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) { + } finally { + latch.countDown(); + joinPool(e); + } + } + + /** + * timed invokeAny(c) throws ExecutionException if no task completes + */ + public void testTimedInvokeAny4() throws Exception { + ExecutorService e = new CustomExecutor(2); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new NPETask()); + try { + e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } finally { + joinPool(e); + } + } + + /** + * timed invokeAny(c) returns result of some task + */ + public void testTimedInvokeAny5() throws Exception { + ExecutorService e = new CustomExecutor(2); + try { + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new StringTask()); + l.add(new StringTask()); + String result = e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS); + assertSame(TEST_STRING, result); + } finally { + joinPool(e); + } + } + + /** + * timed invokeAll(null) throws NPE + */ + public void testTimedInvokeAll1() throws Exception { + ExecutorService e = new CustomExecutor(2); + try { + e.invokeAll(null, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) { + } finally { + joinPool(e); + } + } + + /** + * timed invokeAll(,,null) throws NPE + */ + public void testTimedInvokeAllNullTimeUnit() throws Exception { + ExecutorService e = new CustomExecutor(2); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new StringTask()); + try { + e.invokeAll(l, MEDIUM_DELAY_MS, null); + shouldThrow(); + } catch (NullPointerException success) { + } finally { + joinPool(e); + } + } + + /** + * timed invokeAll(empty collection) returns empty collection + */ + public void testTimedInvokeAll2() throws Exception { + ExecutorService e = new CustomExecutor(2); + try { + List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS); + assertTrue(r.isEmpty()); + } finally { + joinPool(e); + } + } + + /** + * timed invokeAll(c) throws NPE if c has null elements + */ + public void testTimedInvokeAll3() throws Exception { + ExecutorService e = new CustomExecutor(2); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new StringTask()); + l.add(null); + try { + e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) { + } finally { + joinPool(e); + } + } + + /** + * get of element of invokeAll(c) throws exception on failed task + */ + public void testTimedInvokeAll4() throws Exception { + ExecutorService e = new CustomExecutor(2); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new NPETask()); + List<Future<String>> futures = + e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS); + assertEquals(1, futures.size()); + try { + futures.get(0).get(); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } finally { + joinPool(e); + } + } + + /** + * timed invokeAll(c) returns results of all completed tasks + */ + public void testTimedInvokeAll5() throws Exception { + ExecutorService e = new CustomExecutor(2); + try { + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new StringTask()); + l.add(new StringTask()); + List<Future<String>> futures = + e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS); + assertEquals(2, futures.size()); + for (Future<String> future : futures) + assertSame(TEST_STRING, future.get()); + } finally { + joinPool(e); + } + } + + /** + * timed invokeAll(c) cancels tasks not completed by timeout + */ + public void testTimedInvokeAll6() throws Exception { + ExecutorService e = new CustomExecutor(2); + try { + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new StringTask()); + l.add(Executors.callable(new MediumPossiblyInterruptedRunnable(), TEST_STRING)); + l.add(new StringTask()); + List<Future<String>> futures = + e.invokeAll(l, SHORT_DELAY_MS, MILLISECONDS); + assertEquals(3, futures.size()); + Iterator<Future<String>> it = futures.iterator(); + Future<String> f1 = it.next(); + Future<String> f2 = it.next(); + Future<String> f3 = it.next(); + assertTrue(f1.isDone()); + assertTrue(f2.isDone()); + assertTrue(f3.isDone()); + assertFalse(f1.isCancelled()); + assertTrue(f2.isCancelled()); + } finally { + joinPool(e); + } + } + +} diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/ScheduledExecutorTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/ScheduledExecutorTest.java index 14e98b4..ff1796e 100755 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/ScheduledExecutorTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/ScheduledExecutorTest.java @@ -2,15 +2,16 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.*; import java.util.concurrent.*; +import static java.util.concurrent.TimeUnit.MILLISECONDS; import java.util.concurrent.atomic.*; public class ScheduledExecutorTest extends JSR166TestCase { @@ -22,86 +23,62 @@ public class ScheduledExecutorTest extends JSR166TestCase { /** * execute successfully executes a runnable */ - public void testExecute() { - try { - TrackedShortRunnable runnable =new TrackedShortRunnable(); - ScheduledThreadPoolExecutor p1 = new ScheduledThreadPoolExecutor(1); - p1.execute(runnable); - assertFalse(runnable.done); - Thread.sleep(SHORT_DELAY_MS); - try { p1.shutdown(); } catch(SecurityException ok) { return; } - try { - Thread.sleep(MEDIUM_DELAY_MS); - } catch(InterruptedException e){ - unexpectedException(); - } - assertTrue(runnable.done); - try { p1.shutdown(); } catch(SecurityException ok) { return; } - joinPool(p1); - } - catch(Exception e){ - unexpectedException(); - } - + public void testExecute() throws InterruptedException { + TrackedShortRunnable runnable =new TrackedShortRunnable(); + ScheduledThreadPoolExecutor p1 = new ScheduledThreadPoolExecutor(1); + p1.execute(runnable); + assertFalse(runnable.done); + Thread.sleep(SHORT_DELAY_MS); + try { p1.shutdown(); } catch (SecurityException ok) { return; } + Thread.sleep(MEDIUM_DELAY_MS); + assertTrue(runnable.done); + try { p1.shutdown(); } catch (SecurityException ok) { return; } + joinPool(p1); } /** * delayed schedule of callable successfully executes after delay */ - public void testSchedule1() { - try { - TrackedCallable callable = new TrackedCallable(); - ScheduledThreadPoolExecutor p1 = new ScheduledThreadPoolExecutor(1); - Future f = p1.schedule(callable, SHORT_DELAY_MS, TimeUnit.MILLISECONDS); - assertFalse(callable.done); - Thread.sleep(MEDIUM_DELAY_MS); - assertTrue(callable.done); - assertEquals(Boolean.TRUE, f.get()); - try { p1.shutdown(); } catch(SecurityException ok) { return; } - joinPool(p1); - } catch(RejectedExecutionException e){} - catch(Exception e){ - e.printStackTrace(); - unexpectedException(); - } + public void testSchedule1() throws Exception { + TrackedCallable callable = new TrackedCallable(); + ScheduledThreadPoolExecutor p1 = new ScheduledThreadPoolExecutor(1); + Future f = p1.schedule(callable, SHORT_DELAY_MS, MILLISECONDS); + assertFalse(callable.done); + Thread.sleep(MEDIUM_DELAY_MS); + assertTrue(callable.done); + assertEquals(Boolean.TRUE, f.get()); + try { p1.shutdown(); } catch (SecurityException ok) { return; } + joinPool(p1); } /** * delayed schedule of runnable successfully executes after delay */ - public void testSchedule3() { - try { - TrackedShortRunnable runnable = new TrackedShortRunnable(); - ScheduledThreadPoolExecutor p1 = new ScheduledThreadPoolExecutor(1); - p1.schedule(runnable, SMALL_DELAY_MS, TimeUnit.MILLISECONDS); - Thread.sleep(SHORT_DELAY_MS); - assertFalse(runnable.done); - Thread.sleep(MEDIUM_DELAY_MS); - assertTrue(runnable.done); - try { p1.shutdown(); } catch(SecurityException ok) { return; } - joinPool(p1); - } catch(Exception e){ - unexpectedException(); - } + public void testSchedule3() throws InterruptedException { + TrackedShortRunnable runnable = new TrackedShortRunnable(); + ScheduledThreadPoolExecutor p1 = new ScheduledThreadPoolExecutor(1); + p1.schedule(runnable, SMALL_DELAY_MS, MILLISECONDS); + Thread.sleep(SHORT_DELAY_MS); + assertFalse(runnable.done); + Thread.sleep(MEDIUM_DELAY_MS); + assertTrue(runnable.done); + try { p1.shutdown(); } catch (SecurityException ok) { return; } + joinPool(p1); } - + /** * scheduleAtFixedRate executes runnable after given initial delay */ - public void testSchedule4() { - try { - TrackedShortRunnable runnable = new TrackedShortRunnable(); - ScheduledThreadPoolExecutor p1 = new ScheduledThreadPoolExecutor(1); - ScheduledFuture h = p1.scheduleAtFixedRate(runnable, SHORT_DELAY_MS, SHORT_DELAY_MS, TimeUnit.MILLISECONDS); - assertFalse(runnable.done); - Thread.sleep(MEDIUM_DELAY_MS); - assertTrue(runnable.done); - h.cancel(true); - joinPool(p1); - } catch(Exception e){ - unexpectedException(); - } + public void testSchedule4() throws InterruptedException { + TrackedShortRunnable runnable = new TrackedShortRunnable(); + ScheduledThreadPoolExecutor p1 = new ScheduledThreadPoolExecutor(1); + ScheduledFuture h = p1.scheduleAtFixedRate(runnable, SHORT_DELAY_MS, SHORT_DELAY_MS, MILLISECONDS); + assertFalse(runnable.done); + Thread.sleep(MEDIUM_DELAY_MS); + assertTrue(runnable.done); + h.cancel(true); + joinPool(p1); } static class RunnableCounter implements Runnable { @@ -112,126 +89,107 @@ public class ScheduledExecutorTest extends JSR166TestCase { /** * scheduleWithFixedDelay executes runnable after given initial delay */ - public void testSchedule5() { - try { - TrackedShortRunnable runnable = new TrackedShortRunnable(); - ScheduledThreadPoolExecutor p1 = new ScheduledThreadPoolExecutor(1); - ScheduledFuture h = p1.scheduleWithFixedDelay(runnable, SHORT_DELAY_MS, SHORT_DELAY_MS, TimeUnit.MILLISECONDS); - assertFalse(runnable.done); - Thread.sleep(MEDIUM_DELAY_MS); - assertTrue(runnable.done); - h.cancel(true); - joinPool(p1); - } catch(Exception e){ - unexpectedException(); - } + public void testSchedule5() throws InterruptedException { + TrackedShortRunnable runnable = new TrackedShortRunnable(); + ScheduledThreadPoolExecutor p1 = new ScheduledThreadPoolExecutor(1); + ScheduledFuture h = p1.scheduleWithFixedDelay(runnable, SHORT_DELAY_MS, SHORT_DELAY_MS, MILLISECONDS); + assertFalse(runnable.done); + Thread.sleep(MEDIUM_DELAY_MS); + assertTrue(runnable.done); + h.cancel(true); + joinPool(p1); } - + /** * scheduleAtFixedRate executes series of tasks at given rate */ - public void testFixedRateSequence() { - try { - ScheduledThreadPoolExecutor p1 = new ScheduledThreadPoolExecutor(1); - RunnableCounter counter = new RunnableCounter(); - ScheduledFuture h = - p1.scheduleAtFixedRate(counter, 0, 1, TimeUnit.MILLISECONDS); - Thread.sleep(SMALL_DELAY_MS); - h.cancel(true); - int c = counter.count.get(); - // By time scaling conventions, we must have at least - // an execution per SHORT delay, but no more than one SHORT more - assertTrue(c >= SMALL_DELAY_MS / SHORT_DELAY_MS); - assertTrue(c <= SMALL_DELAY_MS + SHORT_DELAY_MS); - joinPool(p1); - } catch(Exception e){ - unexpectedException(); - } + public void testFixedRateSequence() throws InterruptedException { + ScheduledThreadPoolExecutor p1 = new ScheduledThreadPoolExecutor(1); + RunnableCounter counter = new RunnableCounter(); + ScheduledFuture h = + p1.scheduleAtFixedRate(counter, 0, 1, MILLISECONDS); + Thread.sleep(SMALL_DELAY_MS); + h.cancel(true); + int c = counter.count.get(); + // By time scaling conventions, we must have at least + // an execution per SHORT delay, but no more than one SHORT more + assertTrue(c >= SMALL_DELAY_MS / SHORT_DELAY_MS); + assertTrue(c <= SMALL_DELAY_MS + SHORT_DELAY_MS); + joinPool(p1); } /** * scheduleWithFixedDelay executes series of tasks with given period */ - public void testFixedDelaySequence() { - try { - ScheduledThreadPoolExecutor p1 = new ScheduledThreadPoolExecutor(1); - RunnableCounter counter = new RunnableCounter(); - ScheduledFuture h = - p1.scheduleWithFixedDelay(counter, 0, 1, TimeUnit.MILLISECONDS); - Thread.sleep(SMALL_DELAY_MS); - h.cancel(true); - int c = counter.count.get(); - assertTrue(c >= SMALL_DELAY_MS / SHORT_DELAY_MS); - assertTrue(c <= SMALL_DELAY_MS + SHORT_DELAY_MS); - joinPool(p1); - } catch(Exception e){ - unexpectedException(); - } + public void testFixedDelaySequence() throws InterruptedException { + ScheduledThreadPoolExecutor p1 = new ScheduledThreadPoolExecutor(1); + RunnableCounter counter = new RunnableCounter(); + ScheduledFuture h = + p1.scheduleWithFixedDelay(counter, 0, 1, MILLISECONDS); + Thread.sleep(SMALL_DELAY_MS); + h.cancel(true); + int c = counter.count.get(); + assertTrue(c >= SMALL_DELAY_MS / SHORT_DELAY_MS); + assertTrue(c <= SMALL_DELAY_MS + SHORT_DELAY_MS); + joinPool(p1); } /** * execute (null) throws NPE */ - public void testExecuteNull() { + public void testExecuteNull() throws InterruptedException { ScheduledThreadPoolExecutor se = null; try { se = new ScheduledThreadPoolExecutor(1); se.execute(null); shouldThrow(); - } catch(NullPointerException success){} - catch(Exception e){ - unexpectedException(); - } - + } catch (NullPointerException success) {} + joinPool(se); } /** * schedule (null) throws NPE */ - public void testScheduleNull() { + public void testScheduleNull() throws InterruptedException { ScheduledThreadPoolExecutor se = new ScheduledThreadPoolExecutor(1); try { TrackedCallable callable = null; - Future f = se.schedule(callable, SHORT_DELAY_MS, TimeUnit.MILLISECONDS); + Future f = se.schedule(callable, SHORT_DELAY_MS, MILLISECONDS); shouldThrow(); - } catch(NullPointerException success){} - catch(Exception e){ - unexpectedException(); - } + } catch (NullPointerException success) {} joinPool(se); } - + /** * execute throws RejectedExecutionException if shutdown */ - public void testSchedule1_RejectedExecutionException() { + public void testSchedule1_RejectedExecutionException() throws InterruptedException { ScheduledThreadPoolExecutor se = new ScheduledThreadPoolExecutor(1); try { se.shutdown(); se.schedule(new NoOpRunnable(), - MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); + MEDIUM_DELAY_MS, MILLISECONDS); shouldThrow(); - } catch(RejectedExecutionException success){ + } catch (RejectedExecutionException success) { } catch (SecurityException ok) { } - - joinPool(se); + joinPool(se); } /** * schedule throws RejectedExecutionException if shutdown */ - public void testSchedule2_RejectedExecutionException() { + public void testSchedule2_RejectedExecutionException() throws InterruptedException { ScheduledThreadPoolExecutor se = new ScheduledThreadPoolExecutor(1); try { se.shutdown(); se.schedule(new NoOpCallable(), - MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); + MEDIUM_DELAY_MS, MILLISECONDS); shouldThrow(); - } catch(RejectedExecutionException success){ + } catch (RejectedExecutionException success) { } catch (SecurityException ok) { } joinPool(se); @@ -240,14 +198,14 @@ public class ScheduledExecutorTest extends JSR166TestCase { /** * schedule callable throws RejectedExecutionException if shutdown */ - public void testSchedule3_RejectedExecutionException() { + public void testSchedule3_RejectedExecutionException() throws InterruptedException { ScheduledThreadPoolExecutor se = new ScheduledThreadPoolExecutor(1); try { se.shutdown(); se.schedule(new NoOpCallable(), - MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); + MEDIUM_DELAY_MS, MILLISECONDS); shouldThrow(); - } catch(RejectedExecutionException success){ + } catch (RejectedExecutionException success) { } catch (SecurityException ok) { } joinPool(se); @@ -256,32 +214,32 @@ public class ScheduledExecutorTest extends JSR166TestCase { /** * scheduleAtFixedRate throws RejectedExecutionException if shutdown */ - public void testScheduleAtFixedRate1_RejectedExecutionException() { + public void testScheduleAtFixedRate1_RejectedExecutionException() throws InterruptedException { ScheduledThreadPoolExecutor se = new ScheduledThreadPoolExecutor(1); try { se.shutdown(); se.scheduleAtFixedRate(new NoOpRunnable(), - MEDIUM_DELAY_MS, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); + MEDIUM_DELAY_MS, MEDIUM_DELAY_MS, MILLISECONDS); shouldThrow(); - } catch(RejectedExecutionException success){ + } catch (RejectedExecutionException success) { } catch (SecurityException ok) { - } + } joinPool(se); } - + /** * scheduleWithFixedDelay throws RejectedExecutionException if shutdown */ - public void testScheduleWithFixedDelay1_RejectedExecutionException() { + public void testScheduleWithFixedDelay1_RejectedExecutionException() throws InterruptedException { ScheduledThreadPoolExecutor se = new ScheduledThreadPoolExecutor(1); try { se.shutdown(); se.scheduleWithFixedDelay(new NoOpRunnable(), - MEDIUM_DELAY_MS, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); + MEDIUM_DELAY_MS, MEDIUM_DELAY_MS, MILLISECONDS); shouldThrow(); - } catch(RejectedExecutionException success){ + } catch (RejectedExecutionException success) { } catch (SecurityException ok) { - } + } joinPool(se); } @@ -289,107 +247,91 @@ public class ScheduledExecutorTest extends JSR166TestCase { * getActiveCount increases but doesn't overestimate, when a * thread becomes active */ - public void testGetActiveCount() { + public void testGetActiveCount() throws InterruptedException { ScheduledThreadPoolExecutor p2 = new ScheduledThreadPoolExecutor(2); assertEquals(0, p2.getActiveCount()); p2.execute(new SmallRunnable()); - try { - Thread.sleep(SHORT_DELAY_MS); - } catch(Exception e){ - unexpectedException(); - } + Thread.sleep(SHORT_DELAY_MS); assertEquals(1, p2.getActiveCount()); joinPool(p2); } - + /** * getCompletedTaskCount increases, but doesn't overestimate, * when tasks complete */ - public void testGetCompletedTaskCount() { + public void testGetCompletedTaskCount() throws InterruptedException { ScheduledThreadPoolExecutor p2 = new ScheduledThreadPoolExecutor(2); assertEquals(0, p2.getCompletedTaskCount()); p2.execute(new SmallRunnable()); - try { - Thread.sleep(MEDIUM_DELAY_MS); - } catch(Exception e){ - unexpectedException(); - } + Thread.sleep(MEDIUM_DELAY_MS); assertEquals(1, p2.getCompletedTaskCount()); joinPool(p2); } - + /** - * getCorePoolSize returns size given in constructor if not otherwise set + * getCorePoolSize returns size given in constructor if not otherwise set */ - public void testGetCorePoolSize() { + public void testGetCorePoolSize() throws InterruptedException { ScheduledThreadPoolExecutor p1 = new ScheduledThreadPoolExecutor(1); assertEquals(1, p1.getCorePoolSize()); joinPool(p1); } - + /** * getLargestPoolSize increases, but doesn't overestimate, when * multiple threads active */ - public void testGetLargestPoolSize() { + public void testGetLargestPoolSize() throws InterruptedException { ScheduledThreadPoolExecutor p2 = new ScheduledThreadPoolExecutor(2); assertEquals(0, p2.getLargestPoolSize()); p2.execute(new SmallRunnable()); p2.execute(new SmallRunnable()); - try { - Thread.sleep(SHORT_DELAY_MS); - } catch(Exception e){ - unexpectedException(); - } + Thread.sleep(SHORT_DELAY_MS); assertEquals(2, p2.getLargestPoolSize()); joinPool(p2); } - + /** * getPoolSize increases, but doesn't overestimate, when threads * become active */ - public void testGetPoolSize() { + public void testGetPoolSize() throws InterruptedException { ScheduledThreadPoolExecutor p1 = new ScheduledThreadPoolExecutor(1); assertEquals(0, p1.getPoolSize()); p1.execute(new SmallRunnable()); assertEquals(1, p1.getPoolSize()); joinPool(p1); } - + /** * getTaskCount increases, but doesn't overestimate, when tasks * submitted */ - public void testGetTaskCount() { + public void testGetTaskCount() throws InterruptedException { ScheduledThreadPoolExecutor p1 = new ScheduledThreadPoolExecutor(1); assertEquals(0, p1.getTaskCount()); - for(int i = 0; i < 5; i++) + for (int i = 0; i < 5; i++) p1.execute(new SmallRunnable()); - try { - Thread.sleep(SHORT_DELAY_MS); - } catch(Exception e){ - unexpectedException(); - } + Thread.sleep(SHORT_DELAY_MS); assertEquals(5, p1.getTaskCount()); joinPool(p1); } - /** + /** * getThreadFactory returns factory in constructor if not set */ - public void testGetThreadFactory() { + public void testGetThreadFactory() throws InterruptedException { ThreadFactory tf = new SimpleThreadFactory(); ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1, tf); assertSame(tf, p.getThreadFactory()); joinPool(p); } - /** + /** * setThreadFactory sets the thread factory returned by getThreadFactory */ - public void testSetThreadFactory() { + public void testSetThreadFactory() throws InterruptedException { ThreadFactory tf = new SimpleThreadFactory(); ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); p.setThreadFactory(tf); @@ -397,10 +339,10 @@ public class ScheduledExecutorTest extends JSR166TestCase { joinPool(p); } - /** + /** * setThreadFactory(null) throws NPE */ - public void testSetThreadFactoryNull() { + public void testSetThreadFactoryNull() throws InterruptedException { ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); try { p.setThreadFactory(null); @@ -410,78 +352,69 @@ public class ScheduledExecutorTest extends JSR166TestCase { joinPool(p); } } - + /** * is isShutDown is false before shutdown, true after */ public void testIsShutdown() { - + ScheduledThreadPoolExecutor p1 = new ScheduledThreadPoolExecutor(1); try { assertFalse(p1.isShutdown()); } finally { - try { p1.shutdown(); } catch(SecurityException ok) { return; } + try { p1.shutdown(); } catch (SecurityException ok) { return; } } assertTrue(p1.isShutdown()); } - + /** * isTerminated is false before termination, true after */ - public void testIsTerminated() { + public void testIsTerminated() throws InterruptedException { ScheduledThreadPoolExecutor p1 = new ScheduledThreadPoolExecutor(1); try { p1.execute(new SmallRunnable()); } finally { - try { p1.shutdown(); } catch(SecurityException ok) { return; } + try { p1.shutdown(); } catch (SecurityException ok) { return; } } - try { - assertTrue(p1.awaitTermination(LONG_DELAY_MS, TimeUnit.MILLISECONDS)); - assertTrue(p1.isTerminated()); - } catch(Exception e){ - unexpectedException(); - } + assertTrue(p1.awaitTermination(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(p1.isTerminated()); } /** * isTerminating is not true when running or when terminated */ - public void testIsTerminating() { + public void testIsTerminating() throws InterruptedException { ScheduledThreadPoolExecutor p1 = new ScheduledThreadPoolExecutor(1); assertFalse(p1.isTerminating()); try { p1.execute(new SmallRunnable()); assertFalse(p1.isTerminating()); } finally { - try { p1.shutdown(); } catch(SecurityException ok) { return; } + try { p1.shutdown(); } catch (SecurityException ok) { return; } } - try { - assertTrue(p1.awaitTermination(LONG_DELAY_MS, TimeUnit.MILLISECONDS)); - assertTrue(p1.isTerminated()); - assertFalse(p1.isTerminating()); - } catch(Exception e){ - unexpectedException(); - } + + assertTrue(p1.awaitTermination(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(p1.isTerminated()); + assertFalse(p1.isTerminating()); } /** * getQueue returns the work queue, which contains queued tasks */ - public void testGetQueue() { + public void testGetQueue() throws InterruptedException { ScheduledThreadPoolExecutor p1 = new ScheduledThreadPoolExecutor(1); ScheduledFuture[] tasks = new ScheduledFuture[5]; - for(int i = 0; i < 5; i++){ - tasks[i] = p1.schedule(new SmallPossiblyInterruptedRunnable(), 1, TimeUnit.MILLISECONDS); + for (int i = 0; i < 5; i++) { + tasks[i] = p1.schedule(new SmallPossiblyInterruptedRunnable(), 1, MILLISECONDS); } try { Thread.sleep(SHORT_DELAY_MS); BlockingQueue<Runnable> q = p1.getQueue(); assertTrue(q.contains(tasks[4])); assertFalse(q.contains(tasks[0])); - } catch(Exception e) { - unexpectedException(); } finally { joinPool(p1); } @@ -490,11 +423,11 @@ public class ScheduledExecutorTest extends JSR166TestCase { /** * remove(task) removes queued task, and fails to remove active task */ - public void testRemove() { + public void testRemove() throws InterruptedException { ScheduledThreadPoolExecutor p1 = new ScheduledThreadPoolExecutor(1); ScheduledFuture[] tasks = new ScheduledFuture[5]; - for(int i = 0; i < 5; i++){ - tasks[i] = p1.schedule(new SmallPossiblyInterruptedRunnable(), 1, TimeUnit.MILLISECONDS); + for (int i = 0; i < 5; i++) { + tasks[i] = p1.schedule(new SmallPossiblyInterruptedRunnable(), 1, MILLISECONDS); } try { Thread.sleep(SHORT_DELAY_MS); @@ -508,8 +441,6 @@ public class ScheduledExecutorTest extends JSR166TestCase { assertTrue(q.contains((Runnable)tasks[3])); assertTrue(p1.remove((Runnable)tasks[3])); assertFalse(q.contains((Runnable)tasks[3])); - } catch(Exception e) { - unexpectedException(); } finally { joinPool(p1); } @@ -518,11 +449,11 @@ public class ScheduledExecutorTest extends JSR166TestCase { /** * purge removes cancelled tasks from the queue */ - public void testPurge() { + public void testPurge() throws InterruptedException { ScheduledThreadPoolExecutor p1 = new ScheduledThreadPoolExecutor(1); ScheduledFuture[] tasks = new ScheduledFuture[5]; - for(int i = 0; i < 5; i++){ - tasks[i] = p1.schedule(new SmallPossiblyInterruptedRunnable(), SHORT_DELAY_MS, TimeUnit.MILLISECONDS); + for (int i = 0; i < 5; i++) { + tasks[i] = p1.schedule(new SmallPossiblyInterruptedRunnable(), SHORT_DELAY_MS, MILLISECONDS); } try { int max = 5; @@ -539,8 +470,6 @@ public class ScheduledExecutorTest extends JSR166TestCase { Thread.sleep(1); } assertTrue(k < SMALL_DELAY_MS); - } catch(Exception e) { - unexpectedException(); } finally { joinPool(p1); } @@ -549,14 +478,14 @@ public class ScheduledExecutorTest extends JSR166TestCase { /** * shutDownNow returns a list containing tasks that were not run */ - public void testShutDownNow() { + public void testShutDownNow() throws InterruptedException { ScheduledThreadPoolExecutor p1 = new ScheduledThreadPoolExecutor(1); - for(int i = 0; i < 5; i++) - p1.schedule(new SmallPossiblyInterruptedRunnable(), SHORT_DELAY_MS, TimeUnit.MILLISECONDS); + for (int i = 0; i < 5; i++) + p1.schedule(new SmallPossiblyInterruptedRunnable(), SHORT_DELAY_MS, MILLISECONDS); List l; try { l = p1.shutdownNow(); - } catch (SecurityException ok) { + } catch (SecurityException ok) { return; } assertTrue(p1.isShutdown()); @@ -568,31 +497,25 @@ public class ScheduledExecutorTest extends JSR166TestCase { * In default setting, shutdown cancels periodic but not delayed * tasks at shutdown */ - public void testShutDown1() { - try { - ScheduledThreadPoolExecutor p1 = new ScheduledThreadPoolExecutor(1); - assertTrue(p1.getExecuteExistingDelayedTasksAfterShutdownPolicy()); - assertFalse(p1.getContinueExistingPeriodicTasksAfterShutdownPolicy()); - - ScheduledFuture[] tasks = new ScheduledFuture[5]; - for(int i = 0; i < 5; i++) - tasks[i] = p1.schedule(new NoOpRunnable(), SHORT_DELAY_MS, TimeUnit.MILLISECONDS); - try { p1.shutdown(); } catch(SecurityException ok) { return; } - BlockingQueue q = p1.getQueue(); - for (Iterator it = q.iterator(); it.hasNext();) { - ScheduledFuture t = (ScheduledFuture)it.next(); - assertFalse(t.isCancelled()); - } - assertTrue(p1.isShutdown()); - Thread.sleep(SMALL_DELAY_MS); - for (int i = 0; i < 5; ++i) { - assertTrue(tasks[i].isDone()); - assertFalse(tasks[i].isCancelled()); - } - + public void testShutDown1() throws InterruptedException { + ScheduledThreadPoolExecutor p1 = new ScheduledThreadPoolExecutor(1); + assertTrue(p1.getExecuteExistingDelayedTasksAfterShutdownPolicy()); + assertFalse(p1.getContinueExistingPeriodicTasksAfterShutdownPolicy()); + + ScheduledFuture[] tasks = new ScheduledFuture[5]; + for (int i = 0; i < 5; i++) + tasks[i] = p1.schedule(new NoOpRunnable(), SHORT_DELAY_MS, MILLISECONDS); + try { p1.shutdown(); } catch (SecurityException ok) { return; } + BlockingQueue q = p1.getQueue(); + for (Iterator it = q.iterator(); it.hasNext();) { + ScheduledFuture t = (ScheduledFuture)it.next(); + assertFalse(t.isCancelled()); } - catch(Exception ex) { - unexpectedException(); + assertTrue(p1.isShutdown()); + Thread.sleep(SMALL_DELAY_MS); + for (int i = 0; i < 5; ++i) { + assertTrue(tasks[i].isDone()); + assertFalse(tasks[i].isCancelled()); } } @@ -601,23 +524,18 @@ public class ScheduledExecutorTest extends JSR166TestCase { * If setExecuteExistingDelayedTasksAfterShutdownPolicy is false, * delayed tasks are cancelled at shutdown */ - public void testShutDown2() { - try { - ScheduledThreadPoolExecutor p1 = new ScheduledThreadPoolExecutor(1); - p1.setExecuteExistingDelayedTasksAfterShutdownPolicy(false); - ScheduledFuture[] tasks = new ScheduledFuture[5]; - for(int i = 0; i < 5; i++) - tasks[i] = p1.schedule(new NoOpRunnable(), SHORT_DELAY_MS, TimeUnit.MILLISECONDS); - try { p1.shutdown(); } catch(SecurityException ok) { return; } - assertTrue(p1.isShutdown()); - BlockingQueue q = p1.getQueue(); - assertTrue(q.isEmpty()); - Thread.sleep(SMALL_DELAY_MS); - assertTrue(p1.isTerminated()); - } - catch(Exception ex) { - unexpectedException(); - } + public void testShutDown2() throws InterruptedException { + ScheduledThreadPoolExecutor p1 = new ScheduledThreadPoolExecutor(1); + p1.setExecuteExistingDelayedTasksAfterShutdownPolicy(false); + ScheduledFuture[] tasks = new ScheduledFuture[5]; + for (int i = 0; i < 5; i++) + tasks[i] = p1.schedule(new NoOpRunnable(), SHORT_DELAY_MS, MILLISECONDS); + try { p1.shutdown(); } catch (SecurityException ok) { return; } + assertTrue(p1.isShutdown()); + BlockingQueue q = p1.getQueue(); + assertTrue(q.isEmpty()); + Thread.sleep(SMALL_DELAY_MS); + assertTrue(p1.isTerminated()); } @@ -625,36 +543,31 @@ public class ScheduledExecutorTest extends JSR166TestCase { * If setContinueExistingPeriodicTasksAfterShutdownPolicy is set false, * periodic tasks are not cancelled at shutdown */ - public void testShutDown3() { - try { - ScheduledThreadPoolExecutor p1 = new ScheduledThreadPoolExecutor(1); - p1.setContinueExistingPeriodicTasksAfterShutdownPolicy(false); - ScheduledFuture task = - p1.scheduleAtFixedRate(new NoOpRunnable(), 5, 5, TimeUnit.MILLISECONDS); - try { p1.shutdown(); } catch(SecurityException ok) { return; } - assertTrue(p1.isShutdown()); - BlockingQueue q = p1.getQueue(); - assertTrue(q.isEmpty()); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(p1.isTerminated()); - } - catch(Exception ex) { - unexpectedException(); - } + public void testShutDown3() throws InterruptedException { + ScheduledThreadPoolExecutor p1 = new ScheduledThreadPoolExecutor(1); + p1.setContinueExistingPeriodicTasksAfterShutdownPolicy(false); + ScheduledFuture task = + p1.scheduleAtFixedRate(new NoOpRunnable(), 5, 5, MILLISECONDS); + try { p1.shutdown(); } catch (SecurityException ok) { return; } + assertTrue(p1.isShutdown()); + BlockingQueue q = p1.getQueue(); + assertTrue(q.isEmpty()); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(p1.isTerminated()); } /** * if setContinueExistingPeriodicTasksAfterShutdownPolicy is true, * periodic tasks are cancelled at shutdown */ - public void testShutDown4() { + public void testShutDown4() throws InterruptedException { ScheduledThreadPoolExecutor p1 = new ScheduledThreadPoolExecutor(1); try { p1.setContinueExistingPeriodicTasksAfterShutdownPolicy(true); ScheduledFuture task = - p1.scheduleAtFixedRate(new NoOpRunnable(), 1, 1, TimeUnit.MILLISECONDS); + p1.scheduleAtFixedRate(new NoOpRunnable(), 1, 1, MILLISECONDS); assertFalse(task.isCancelled()); - try { p1.shutdown(); } catch(SecurityException ok) { return; } + try { p1.shutdown(); } catch (SecurityException ok) { return; } assertFalse(task.isCancelled()); assertFalse(p1.isTerminated()); assertTrue(p1.isShutdown()); @@ -665,10 +578,7 @@ public class ScheduledExecutorTest extends JSR166TestCase { Thread.sleep(SHORT_DELAY_MS); assertTrue(p1.isTerminated()); } - catch(Exception ex) { - unexpectedException(); - } - finally { + finally { joinPool(p1); } } @@ -676,18 +586,12 @@ public class ScheduledExecutorTest extends JSR166TestCase { /** * completed submit of callable returns result */ - public void testSubmitCallable() { + public void testSubmitCallable() throws Exception { ExecutorService e = new ScheduledThreadPoolExecutor(2); try { Future<String> future = e.submit(new StringTask()); String result = future.get(); assertSame(TEST_STRING, result); - } - catch (ExecutionException ex) { - unexpectedException(); - } - catch (InterruptedException ex) { - unexpectedException(); } finally { joinPool(e); } @@ -696,18 +600,12 @@ public class ScheduledExecutorTest extends JSR166TestCase { /** * completed submit of runnable returns successfully */ - public void testSubmitRunnable() { + public void testSubmitRunnable() throws Exception { ExecutorService e = new ScheduledThreadPoolExecutor(2); try { Future<?> future = e.submit(new NoOpRunnable()); future.get(); assertTrue(future.isDone()); - } - catch (ExecutionException ex) { - unexpectedException(); - } - catch (InterruptedException ex) { - unexpectedException(); } finally { joinPool(e); } @@ -716,18 +614,12 @@ public class ScheduledExecutorTest extends JSR166TestCase { /** * completed submit of (runnable, result) returns result */ - public void testSubmitRunnable2() { + public void testSubmitRunnable2() throws Exception { ExecutorService e = new ScheduledThreadPoolExecutor(2); try { Future<String> future = e.submit(new NoOpRunnable(), TEST_STRING); String result = future.get(); assertSame(TEST_STRING, result); - } - catch (ExecutionException ex) { - unexpectedException(); - } - catch (InterruptedException ex) { - unexpectedException(); } finally { joinPool(e); } @@ -736,13 +628,12 @@ public class ScheduledExecutorTest extends JSR166TestCase { /** * invokeAny(null) throws NPE */ - public void testInvokeAny1() { + public void testInvokeAny1() throws Exception { ExecutorService e = new ScheduledThreadPoolExecutor(2); try { e.invokeAny(null); + shouldThrow(); } catch (NullPointerException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -751,13 +642,12 @@ public class ScheduledExecutorTest extends JSR166TestCase { /** * invokeAny(empty collection) throws IAE */ - public void testInvokeAny2() { + public void testInvokeAny2() throws Exception { ExecutorService e = new ScheduledThreadPoolExecutor(2); try { e.invokeAny(new ArrayList<Callable<String>>()); + shouldThrow(); } catch (IllegalArgumentException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -766,17 +656,18 @@ public class ScheduledExecutorTest extends JSR166TestCase { /** * invokeAny(c) throws NPE if c has null elements */ - public void testInvokeAny3() { + public void testInvokeAny3() throws Exception { + CountDownLatch latch = new CountDownLatch(1); ExecutorService e = new ScheduledThreadPoolExecutor(2); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(latchAwaitingStringTask(latch)); + l.add(null); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); - l.add(new StringTask()); - l.add(null); e.invokeAny(l); + shouldThrow(); } catch (NullPointerException success) { - } catch(Exception ex) { - unexpectedException(); } finally { + latch.countDown(); joinPool(e); } } @@ -784,15 +675,15 @@ public class ScheduledExecutorTest extends JSR166TestCase { /** * invokeAny(c) throws ExecutionException if no task completes */ - public void testInvokeAny4() { + public void testInvokeAny4() throws Exception { ExecutorService e = new ScheduledThreadPoolExecutor(2); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new NPETask()); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); - l.add(new NPETask()); e.invokeAny(l); + shouldThrow(); } catch (ExecutionException success) { - } catch(Exception ex) { - unexpectedException(); + assertTrue(success.getCause() instanceof NullPointerException); } finally { joinPool(e); } @@ -801,17 +692,14 @@ public class ScheduledExecutorTest extends JSR166TestCase { /** * invokeAny(c) returns result of some task */ - public void testInvokeAny5() { + public void testInvokeAny5() throws Exception { ExecutorService e = new ScheduledThreadPoolExecutor(2); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); + List<Callable<String>> l = new ArrayList<Callable<String>>(); l.add(new StringTask()); l.add(new StringTask()); String result = e.invokeAny(l); assertSame(TEST_STRING, result); - } catch (ExecutionException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -820,13 +708,12 @@ public class ScheduledExecutorTest extends JSR166TestCase { /** * invokeAll(null) throws NPE */ - public void testInvokeAll1() { + public void testInvokeAll1() throws Exception { ExecutorService e = new ScheduledThreadPoolExecutor(2); try { e.invokeAll(null); + shouldThrow(); } catch (NullPointerException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -835,13 +722,11 @@ public class ScheduledExecutorTest extends JSR166TestCase { /** * invokeAll(empty collection) returns empty collection */ - public void testInvokeAll2() { + public void testInvokeAll2() throws Exception { ExecutorService e = new ScheduledThreadPoolExecutor(2); try { List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>()); assertTrue(r.isEmpty()); - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -850,16 +735,15 @@ public class ScheduledExecutorTest extends JSR166TestCase { /** * invokeAll(c) throws NPE if c has null elements */ - public void testInvokeAll3() { + public void testInvokeAll3() throws Exception { ExecutorService e = new ScheduledThreadPoolExecutor(2); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new StringTask()); + l.add(null); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); - l.add(new StringTask()); - l.add(null); e.invokeAll(l); + shouldThrow(); } catch (NullPointerException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -868,18 +752,17 @@ public class ScheduledExecutorTest extends JSR166TestCase { /** * get of invokeAll(c) throws exception on failed task */ - public void testInvokeAll4() { + public void testInvokeAll4() throws Exception { ExecutorService e = new ScheduledThreadPoolExecutor(2); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new NPETask()); + List<Future<String>> futures = e.invokeAll(l); + assertEquals(1, futures.size()); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); - l.add(new NPETask()); - List<Future<String>> result = e.invokeAll(l); - assertEquals(1, result.size()); - for (Iterator<Future<String>> it = result.iterator(); it.hasNext();) - it.next().get(); - } catch(ExecutionException success) { - } catch(Exception ex) { - unexpectedException(); + futures.get(0).get(); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); } finally { joinPool(e); } @@ -888,19 +771,16 @@ public class ScheduledExecutorTest extends JSR166TestCase { /** * invokeAll(c) returns results of all completed tasks */ - public void testInvokeAll5() { + public void testInvokeAll5() throws Exception { ExecutorService e = new ScheduledThreadPoolExecutor(2); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); + List<Callable<String>> l = new ArrayList<Callable<String>>(); l.add(new StringTask()); l.add(new StringTask()); - List<Future<String>> result = e.invokeAll(l); - assertEquals(2, result.size()); - for (Iterator<Future<String>> it = result.iterator(); it.hasNext();) - assertSame(TEST_STRING, it.next().get()); - } catch (ExecutionException success) { - } catch(Exception ex) { - unexpectedException(); + List<Future<String>> futures = e.invokeAll(l); + assertEquals(2, futures.size()); + for (Future<String> future : futures) + assertSame(TEST_STRING, future.get()); } finally { joinPool(e); } @@ -909,13 +789,12 @@ public class ScheduledExecutorTest extends JSR166TestCase { /** * timed invokeAny(null) throws NPE */ - public void testTimedInvokeAny1() { + public void testTimedInvokeAny1() throws Exception { ExecutorService e = new ScheduledThreadPoolExecutor(2); try { - e.invokeAny(null, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); + e.invokeAny(null, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); } catch (NullPointerException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -924,15 +803,14 @@ public class ScheduledExecutorTest extends JSR166TestCase { /** * timed invokeAny(,,null) throws NPE */ - public void testTimedInvokeAnyNullTimeUnit() { + public void testTimedInvokeAnyNullTimeUnit() throws Exception { ExecutorService e = new ScheduledThreadPoolExecutor(2); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new StringTask()); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); - l.add(new StringTask()); e.invokeAny(l, MEDIUM_DELAY_MS, null); + shouldThrow(); } catch (NullPointerException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -941,13 +819,12 @@ public class ScheduledExecutorTest extends JSR166TestCase { /** * timed invokeAny(empty collection) throws IAE */ - public void testTimedInvokeAny2() { + public void testTimedInvokeAny2() throws Exception { ExecutorService e = new ScheduledThreadPoolExecutor(2); try { - e.invokeAny(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); + e.invokeAny(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); } catch (IllegalArgumentException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -956,18 +833,18 @@ public class ScheduledExecutorTest extends JSR166TestCase { /** * timed invokeAny(c) throws NPE if c has null elements */ - public void testTimedInvokeAny3() { + public void testTimedInvokeAny3() throws Exception { + CountDownLatch latch = new CountDownLatch(1); ExecutorService e = new ScheduledThreadPoolExecutor(2); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(latchAwaitingStringTask(latch)); + l.add(null); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); - l.add(new StringTask()); - l.add(null); - e.invokeAny(l, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); + e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); } catch (NullPointerException success) { - } catch(Exception ex) { - ex.printStackTrace(); - unexpectedException(); } finally { + latch.countDown(); joinPool(e); } } @@ -975,15 +852,15 @@ public class ScheduledExecutorTest extends JSR166TestCase { /** * timed invokeAny(c) throws ExecutionException if no task completes */ - public void testTimedInvokeAny4() { + public void testTimedInvokeAny4() throws Exception { ExecutorService e = new ScheduledThreadPoolExecutor(2); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new NPETask()); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); - l.add(new NPETask()); - e.invokeAny(l, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); - } catch(ExecutionException success) { - } catch(Exception ex) { - unexpectedException(); + e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); } finally { joinPool(e); } @@ -992,17 +869,14 @@ public class ScheduledExecutorTest extends JSR166TestCase { /** * timed invokeAny(c) returns result of some task */ - public void testTimedInvokeAny5() { + public void testTimedInvokeAny5() throws Exception { ExecutorService e = new ScheduledThreadPoolExecutor(2); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); + List<Callable<String>> l = new ArrayList<Callable<String>>(); l.add(new StringTask()); l.add(new StringTask()); - String result = e.invokeAny(l, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); + String result = e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS); assertSame(TEST_STRING, result); - } catch (ExecutionException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -1011,13 +885,12 @@ public class ScheduledExecutorTest extends JSR166TestCase { /** * timed invokeAll(null) throws NPE */ - public void testTimedInvokeAll1() { + public void testTimedInvokeAll1() throws Exception { ExecutorService e = new ScheduledThreadPoolExecutor(2); try { - e.invokeAll(null, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); + e.invokeAll(null, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); } catch (NullPointerException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -1026,15 +899,14 @@ public class ScheduledExecutorTest extends JSR166TestCase { /** * timed invokeAll(,,null) throws NPE */ - public void testTimedInvokeAllNullTimeUnit() { + public void testTimedInvokeAllNullTimeUnit() throws Exception { ExecutorService e = new ScheduledThreadPoolExecutor(2); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new StringTask()); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); - l.add(new StringTask()); e.invokeAll(l, MEDIUM_DELAY_MS, null); + shouldThrow(); } catch (NullPointerException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -1043,13 +915,11 @@ public class ScheduledExecutorTest extends JSR166TestCase { /** * timed invokeAll(empty collection) returns empty collection */ - public void testTimedInvokeAll2() { + public void testTimedInvokeAll2() throws Exception { ExecutorService e = new ScheduledThreadPoolExecutor(2); try { - List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); + List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS); assertTrue(r.isEmpty()); - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -1058,16 +928,15 @@ public class ScheduledExecutorTest extends JSR166TestCase { /** * timed invokeAll(c) throws NPE if c has null elements */ - public void testTimedInvokeAll3() { + public void testTimedInvokeAll3() throws Exception { ExecutorService e = new ScheduledThreadPoolExecutor(2); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new StringTask()); + l.add(null); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); - l.add(new StringTask()); - l.add(null); - e.invokeAll(l, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); + e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); } catch (NullPointerException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -1076,18 +945,18 @@ public class ScheduledExecutorTest extends JSR166TestCase { /** * get of element of invokeAll(c) throws exception on failed task */ - public void testTimedInvokeAll4() { + public void testTimedInvokeAll4() throws Exception { ExecutorService e = new ScheduledThreadPoolExecutor(2); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new NPETask()); + List<Future<String>> futures = + e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS); + assertEquals(1, futures.size()); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); - l.add(new NPETask()); - List<Future<String>> result = e.invokeAll(l, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); - assertEquals(1, result.size()); - for (Iterator<Future<String>> it = result.iterator(); it.hasNext();) - it.next().get(); - } catch(ExecutionException success) { - } catch(Exception ex) { - unexpectedException(); + futures.get(0).get(); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); } finally { joinPool(e); } @@ -1096,19 +965,17 @@ public class ScheduledExecutorTest extends JSR166TestCase { /** * timed invokeAll(c) returns results of all completed tasks */ - public void testTimedInvokeAll5() { + public void testTimedInvokeAll5() throws Exception { ExecutorService e = new ScheduledThreadPoolExecutor(2); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); + List<Callable<String>> l = new ArrayList<Callable<String>>(); l.add(new StringTask()); l.add(new StringTask()); - List<Future<String>> result = e.invokeAll(l, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); - assertEquals(2, result.size()); - for (Iterator<Future<String>> it = result.iterator(); it.hasNext();) - assertSame(TEST_STRING, it.next().get()); - } catch (ExecutionException success) { - } catch(Exception ex) { - unexpectedException(); + List<Future<String>> futures = + e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS); + assertEquals(2, futures.size()); + for (Future<String> future : futures) + assertSame(TEST_STRING, future.get()); } finally { joinPool(e); } @@ -1117,16 +984,17 @@ public class ScheduledExecutorTest extends JSR166TestCase { /** * timed invokeAll(c) cancels tasks not completed by timeout */ - public void testTimedInvokeAll6() { + public void testTimedInvokeAll6() throws Exception { ExecutorService e = new ScheduledThreadPoolExecutor(2); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); + List<Callable<String>> l = new ArrayList<Callable<String>>(); l.add(new StringTask()); l.add(Executors.callable(new MediumPossiblyInterruptedRunnable(), TEST_STRING)); l.add(new StringTask()); - List<Future<String>> result = e.invokeAll(l, SHORT_DELAY_MS, TimeUnit.MILLISECONDS); - assertEquals(3, result.size()); - Iterator<Future<String>> it = result.iterator(); + List<Future<String>> futures = + e.invokeAll(l, SHORT_DELAY_MS, MILLISECONDS); + assertEquals(3, futures.size()); + Iterator<Future<String>> it = futures.iterator(); Future<String> f1 = it.next(); Future<String> f2 = it.next(); Future<String> f3 = it.next(); @@ -1135,8 +1003,6 @@ public class ScheduledExecutorTest extends JSR166TestCase { assertTrue(f3.isDone()); assertFalse(f1.isCancelled()); assertTrue(f2.isCancelled()); - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/SemaphoreTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/SemaphoreTest.java index 3f2ff33..c27893c 100755 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/SemaphoreTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/SemaphoreTest.java @@ -2,15 +2,16 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.*; import java.util.concurrent.*; +import static java.util.concurrent.TimeUnit.MILLISECONDS; import java.io.*; public class SemaphoreTest extends JSR166TestCase { @@ -23,10 +24,10 @@ public class SemaphoreTest extends JSR166TestCase { */ static class PublicSemaphore extends Semaphore { PublicSemaphore(int p, boolean f) { super(p, f); } - public Collection<Thread> getQueuedThreads() { - return super.getQueuedThreads(); + public Collection<Thread> getQueuedThreads() { + return super.getQueuedThreads(); } - public void reducePermits(int p) { + public void reducePermits(int p) { super.reducePermits(p); } } @@ -34,29 +35,26 @@ public class SemaphoreTest extends JSR166TestCase { /** * A runnable calling acquire */ - class InterruptibleLockRunnable implements Runnable { + class InterruptibleLockRunnable extends CheckedRunnable { final Semaphore lock; InterruptibleLockRunnable(Semaphore l) { lock = l; } - public void run() { + public void realRun() { try { lock.acquire(); - } catch(InterruptedException success){} + } + catch (InterruptedException ignored) {} } } /** - * A runnable calling acquire that expects to be - * interrupted + * A runnable calling acquire that expects to be interrupted */ - class InterruptedLockRunnable implements Runnable { + class InterruptedLockRunnable extends CheckedInterruptedRunnable { final Semaphore lock; InterruptedLockRunnable(Semaphore l) { lock = l; } - public void run() { - try { - lock.acquire(); - threadShouldThrow(); - } catch(InterruptedException success){} + public void realRun() throws InterruptedException { + lock.acquire(); } } @@ -64,30 +62,24 @@ public class SemaphoreTest extends JSR166TestCase { * Zero, negative, and positive initial values are allowed in constructor */ public void testConstructor() { - Semaphore s0 = new Semaphore(0, false); - assertEquals(0, s0.availablePermits()); - assertFalse(s0.isFair()); - Semaphore s1 = new Semaphore(-1, false); - assertEquals(-1, s1.availablePermits()); - assertFalse(s1.isFair()); - Semaphore s2 = new Semaphore(-1, false); - assertEquals(-1, s2.availablePermits()); - assertFalse(s2.isFair()); + for (int permits : new int[] { -1, 0, 1 }) { + for (boolean fair : new boolean[] { false, true }) { + Semaphore s = new Semaphore(permits, fair); + assertEquals(permits, s.availablePermits()); + assertEquals(fair, s.isFair()); + } + } } /** * Constructor without fairness argument behaves as nonfair */ public void testConstructor2() { - Semaphore s0 = new Semaphore(0); - assertEquals(0, s0.availablePermits()); - assertFalse(s0.isFair()); - Semaphore s1 = new Semaphore(-1); - assertEquals(-1, s1.availablePermits()); - assertFalse(s1.isFair()); - Semaphore s2 = new Semaphore(-1); - assertEquals(-1, s2.availablePermits()); - assertFalse(s2.isFair()); + for (int permits : new int[] { -1, 0, 1 }) { + Semaphore s = new Semaphore(permits); + assertEquals(permits, s.availablePermits()); + assertFalse(s.isFair()); + } } /** @@ -105,296 +97,245 @@ public class SemaphoreTest extends JSR166TestCase { /** * Acquire and release of semaphore succeed if initially available */ - public void testAcquireReleaseInSameThread() { + public void testAcquireReleaseInSameThread() + throws InterruptedException { Semaphore s = new Semaphore(1, false); - try { - s.acquire(); - s.release(); - s.acquire(); - s.release(); - s.acquire(); - s.release(); - s.acquire(); - s.release(); - s.acquire(); - s.release(); - assertEquals(1, s.availablePermits()); - } catch( InterruptedException e){ - unexpectedException(); - } + s.acquire(); + s.release(); + s.acquire(); + s.release(); + s.acquire(); + s.release(); + s.acquire(); + s.release(); + s.acquire(); + s.release(); + assertEquals(1, s.availablePermits()); } /** * Uninterruptible acquire and release of semaphore succeed if * initially available */ - public void testAcquireUninterruptiblyReleaseInSameThread() { + public void testAcquireUninterruptiblyReleaseInSameThread() + throws InterruptedException { Semaphore s = new Semaphore(1, false); - try { - s.acquireUninterruptibly(); - s.release(); - s.acquireUninterruptibly(); - s.release(); - s.acquireUninterruptibly(); - s.release(); - s.acquireUninterruptibly(); - s.release(); - s.acquireUninterruptibly(); - s.release(); - assertEquals(1, s.availablePermits()); - } finally { - } + s.acquireUninterruptibly(); + s.release(); + s.acquireUninterruptibly(); + s.release(); + s.acquireUninterruptibly(); + s.release(); + s.acquireUninterruptibly(); + s.release(); + s.acquireUninterruptibly(); + s.release(); + assertEquals(1, s.availablePermits()); } /** * Timed Acquire and release of semaphore succeed if * initially available */ - public void testTimedAcquireReleaseInSameThread() { + public void testTimedAcquireReleaseInSameThread() + throws InterruptedException { Semaphore s = new Semaphore(1, false); - try { - assertTrue(s.tryAcquire(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - s.release(); - assertTrue(s.tryAcquire(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - s.release(); - assertTrue(s.tryAcquire(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - s.release(); - assertTrue(s.tryAcquire(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - s.release(); - assertTrue(s.tryAcquire(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - s.release(); - assertEquals(1, s.availablePermits()); - } catch( InterruptedException e){ - unexpectedException(); - } + assertTrue(s.tryAcquire(SHORT_DELAY_MS, MILLISECONDS)); + s.release(); + assertTrue(s.tryAcquire(SHORT_DELAY_MS, MILLISECONDS)); + s.release(); + assertTrue(s.tryAcquire(SHORT_DELAY_MS, MILLISECONDS)); + s.release(); + assertTrue(s.tryAcquire(SHORT_DELAY_MS, MILLISECONDS)); + s.release(); + assertTrue(s.tryAcquire(SHORT_DELAY_MS, MILLISECONDS)); + s.release(); + assertEquals(1, s.availablePermits()); } /** * A release in one thread enables an acquire in another thread */ - public void testAcquireReleaseInDifferentThreads() { + public void testAcquireReleaseInDifferentThreads() + throws InterruptedException { final Semaphore s = new Semaphore(0, false); - Thread t = new Thread(new Runnable() { - public void run() { - try { - s.acquire(); - s.release(); - s.release(); - s.acquire(); - } catch(InterruptedException ie){ - threadUnexpectedException(); - } - } - }); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - s.release(); - s.release(); - s.acquire(); - s.acquire(); - s.release(); - t.join(); - } catch( InterruptedException e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + s.acquire(); + s.release(); + s.release(); + s.acquire(); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + s.release(); + s.release(); + s.acquire(); + s.acquire(); + s.release(); + t.join(); } /** * A release in one thread enables an uninterruptible acquire in another thread */ - public void testUninterruptibleAcquireReleaseInDifferentThreads() { + public void testUninterruptibleAcquireReleaseInDifferentThreads() + throws InterruptedException { final Semaphore s = new Semaphore(0, false); - Thread t = new Thread(new Runnable() { - public void run() { - s.acquireUninterruptibly(); - s.release(); - s.release(); - s.acquireUninterruptibly(); - } - }); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - s.release(); - s.release(); - s.acquireUninterruptibly(); - s.acquireUninterruptibly(); - s.release(); - t.join(); - } catch( InterruptedException e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + s.acquireUninterruptibly(); + s.release(); + s.release(); + s.acquireUninterruptibly(); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + s.release(); + s.release(); + s.acquireUninterruptibly(); + s.acquireUninterruptibly(); + s.release(); + t.join(); } /** * A release in one thread enables a timed acquire in another thread */ - public void testTimedAcquireReleaseInDifferentThreads() { + public void testTimedAcquireReleaseInDifferentThreads() + throws InterruptedException { final Semaphore s = new Semaphore(1, false); - Thread t = new Thread(new Runnable() { - public void run() { - try { - s.release(); - threadAssertTrue(s.tryAcquire(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - s.release(); - threadAssertTrue(s.tryAcquire(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - - } catch(InterruptedException ie){ - threadUnexpectedException(); - } - } - }); - try { - t.start(); - assertTrue(s.tryAcquire(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - s.release(); - assertTrue(s.tryAcquire(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - s.release(); - s.release(); - t.join(); - } catch( InterruptedException e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + s.release(); + assertTrue(s.tryAcquire(SHORT_DELAY_MS, MILLISECONDS)); + s.release(); + assertTrue(s.tryAcquire(SHORT_DELAY_MS, MILLISECONDS)); + }}); + + t.start(); + assertTrue(s.tryAcquire(SHORT_DELAY_MS, MILLISECONDS)); + s.release(); + assertTrue(s.tryAcquire(SHORT_DELAY_MS, MILLISECONDS)); + s.release(); + s.release(); + t.join(); } /** * A waiting acquire blocks interruptibly */ - public void testAcquire_InterruptedException() { + public void testAcquire_InterruptedException() + throws InterruptedException { final Semaphore s = new Semaphore(0, false); - Thread t = new Thread(new Runnable() { - public void run() { - try { - s.acquire(); - threadShouldThrow(); - } catch(InterruptedException success){} - } - }); + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + s.acquire(); + }}); + t.start(); - try { - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } catch(InterruptedException e){ - unexpectedException(); - } + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } - + /** * A waiting timed acquire blocks interruptibly */ - public void testTryAcquire_InterruptedException() { + public void testTryAcquire_InterruptedException() + throws InterruptedException { final Semaphore s = new Semaphore(0, false); - Thread t = new Thread(new Runnable() { - public void run() { - try { - s.tryAcquire(MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); - threadShouldThrow(); - } catch(InterruptedException success){ - } - } - }); + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + s.tryAcquire(MEDIUM_DELAY_MS, MILLISECONDS); + }}); + t.start(); - try { - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } catch(InterruptedException e){ - unexpectedException(); - } + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } /** * hasQueuedThreads reports whether there are waiting threads */ - public void testHasQueuedThreads() { + public void testHasQueuedThreads() throws InterruptedException { final Semaphore lock = new Semaphore(1, false); Thread t1 = new Thread(new InterruptedLockRunnable(lock)); Thread t2 = new Thread(new InterruptibleLockRunnable(lock)); - try { - assertFalse(lock.hasQueuedThreads()); - lock.acquireUninterruptibly(); - t1.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(lock.hasQueuedThreads()); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(lock.hasQueuedThreads()); - t1.interrupt(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(lock.hasQueuedThreads()); - lock.release(); - Thread.sleep(SHORT_DELAY_MS); - assertFalse(lock.hasQueuedThreads()); - t1.join(); - t2.join(); - } catch(Exception e){ - unexpectedException(); - } - } + assertFalse(lock.hasQueuedThreads()); + lock.acquireUninterruptibly(); + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(lock.hasQueuedThreads()); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(lock.hasQueuedThreads()); + t1.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(lock.hasQueuedThreads()); + lock.release(); + Thread.sleep(SHORT_DELAY_MS); + assertFalse(lock.hasQueuedThreads()); + t1.join(); + t2.join(); + } /** * getQueueLength reports number of waiting threads */ - public void testGetQueueLength() { + public void testGetQueueLength() throws InterruptedException { final Semaphore lock = new Semaphore(1, false); Thread t1 = new Thread(new InterruptedLockRunnable(lock)); Thread t2 = new Thread(new InterruptibleLockRunnable(lock)); - try { - assertEquals(0, lock.getQueueLength()); - lock.acquireUninterruptibly(); - t1.start(); - Thread.sleep(SHORT_DELAY_MS); - assertEquals(1, lock.getQueueLength()); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - assertEquals(2, lock.getQueueLength()); - t1.interrupt(); - Thread.sleep(SHORT_DELAY_MS); - assertEquals(1, lock.getQueueLength()); - lock.release(); - Thread.sleep(SHORT_DELAY_MS); - assertEquals(0, lock.getQueueLength()); - t1.join(); - t2.join(); - } catch(Exception e){ - unexpectedException(); - } - } + assertEquals(0, lock.getQueueLength()); + lock.acquireUninterruptibly(); + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(1, lock.getQueueLength()); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(2, lock.getQueueLength()); + t1.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(1, lock.getQueueLength()); + lock.release(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(0, lock.getQueueLength()); + t1.join(); + t2.join(); + } /** * getQueuedThreads includes waiting threads */ - public void testGetQueuedThreads() { + public void testGetQueuedThreads() throws InterruptedException { final PublicSemaphore lock = new PublicSemaphore(1, false); Thread t1 = new Thread(new InterruptedLockRunnable(lock)); Thread t2 = new Thread(new InterruptibleLockRunnable(lock)); - try { - assertTrue(lock.getQueuedThreads().isEmpty()); - lock.acquireUninterruptibly(); - assertTrue(lock.getQueuedThreads().isEmpty()); - t1.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(lock.getQueuedThreads().contains(t1)); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(lock.getQueuedThreads().contains(t1)); - assertTrue(lock.getQueuedThreads().contains(t2)); - t1.interrupt(); - Thread.sleep(SHORT_DELAY_MS); - assertFalse(lock.getQueuedThreads().contains(t1)); - assertTrue(lock.getQueuedThreads().contains(t2)); - lock.release(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(lock.getQueuedThreads().isEmpty()); - t1.join(); - t2.join(); - } catch(Exception e){ - unexpectedException(); - } - } + assertTrue(lock.getQueuedThreads().isEmpty()); + lock.acquireUninterruptibly(); + assertTrue(lock.getQueuedThreads().isEmpty()); + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(lock.getQueuedThreads().contains(t1)); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(lock.getQueuedThreads().contains(t1)); + assertTrue(lock.getQueuedThreads().contains(t2)); + t1.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + assertFalse(lock.getQueuedThreads().contains(t1)); + assertTrue(lock.getQueuedThreads().contains(t2)); + lock.release(); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(lock.getQueuedThreads().isEmpty()); + t1.join(); + t2.join(); + } /** * drainPermits reports and removes given number of permits @@ -425,26 +366,22 @@ public class SemaphoreTest extends JSR166TestCase { /** * a deserialized serialized semaphore has same number of permits */ - public void testSerialization() { + public void testSerialization() throws Exception { Semaphore l = new Semaphore(3, false); - try { - l.acquire(); - l.release(); - ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); - ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); - out.writeObject(l); - out.close(); - - ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); - ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); - Semaphore r = (Semaphore) in.readObject(); - assertEquals(3, r.availablePermits()); - assertFalse(r.isFair()); - r.acquire(); - r.release(); - } catch(Exception e){ - unexpectedException(); - } + l.acquire(); + l.release(); + ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); + ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); + out.writeObject(l); + out.close(); + + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); + Semaphore r = (Semaphore) in.readObject(); + assertEquals(3, r.availablePermits()); + assertFalse(r.isFair()); + r.acquire(); + r.release(); } @@ -487,45 +424,39 @@ public class SemaphoreTest extends JSR166TestCase { /** * Acquire and release of semaphore succeed if initially available */ - public void testAcquireReleaseInSameThread_fair() { + public void testAcquireReleaseInSameThread_fair() + throws InterruptedException { Semaphore s = new Semaphore(1, true); - try { - s.acquire(); - s.release(); - s.acquire(); - s.release(); - s.acquire(); - s.release(); - s.acquire(); - s.release(); - s.acquire(); - s.release(); - assertEquals(1, s.availablePermits()); - } catch( InterruptedException e){ - unexpectedException(); - } + s.acquire(); + s.release(); + s.acquire(); + s.release(); + s.acquire(); + s.release(); + s.acquire(); + s.release(); + s.acquire(); + s.release(); + assertEquals(1, s.availablePermits()); } /** * Acquire(n) and release(n) of semaphore succeed if initially available */ - public void testAcquireReleaseNInSameThread_fair() { + public void testAcquireReleaseNInSameThread_fair() + throws InterruptedException { Semaphore s = new Semaphore(1, true); - try { - s.release(1); - s.acquire(1); - s.release(2); - s.acquire(2); - s.release(3); - s.acquire(3); - s.release(4); - s.acquire(4); - s.release(5); - s.acquire(5); - assertEquals(1, s.availablePermits()); - } catch( InterruptedException e){ - unexpectedException(); - } + s.release(1); + s.acquire(1); + s.release(2); + s.acquire(2); + s.release(3); + s.acquire(3); + s.release(4); + s.acquire(4); + s.release(5); + s.acquire(5); + assertEquals(1, s.availablePermits()); } /** @@ -533,369 +464,287 @@ public class SemaphoreTest extends JSR166TestCase { */ public void testAcquireUninterruptiblyReleaseNInSameThread_fair() { Semaphore s = new Semaphore(1, true); - try { - s.release(1); - s.acquireUninterruptibly(1); - s.release(2); - s.acquireUninterruptibly(2); - s.release(3); - s.acquireUninterruptibly(3); - s.release(4); - s.acquireUninterruptibly(4); - s.release(5); - s.acquireUninterruptibly(5); - assertEquals(1, s.availablePermits()); - } finally { - } + s.release(1); + s.acquireUninterruptibly(1); + s.release(2); + s.acquireUninterruptibly(2); + s.release(3); + s.acquireUninterruptibly(3); + s.release(4); + s.acquireUninterruptibly(4); + s.release(5); + s.acquireUninterruptibly(5); + assertEquals(1, s.availablePermits()); } /** * release(n) in one thread enables timed acquire(n) in another thread */ - public void testTimedAcquireReleaseNInSameThread_fair() { + public void testTimedAcquireReleaseNInSameThread_fair() + throws InterruptedException { Semaphore s = new Semaphore(1, true); - try { - s.release(1); - assertTrue(s.tryAcquire(1, SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - s.release(2); - assertTrue(s.tryAcquire(2, SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - s.release(3); - assertTrue(s.tryAcquire(3, SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - s.release(4); - assertTrue(s.tryAcquire(4, SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - s.release(5); - assertTrue(s.tryAcquire(5, SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - assertEquals(1, s.availablePermits()); - } catch( InterruptedException e){ - unexpectedException(); - } + s.release(1); + assertTrue(s.tryAcquire(1, SHORT_DELAY_MS, MILLISECONDS)); + s.release(2); + assertTrue(s.tryAcquire(2, SHORT_DELAY_MS, MILLISECONDS)); + s.release(3); + assertTrue(s.tryAcquire(3, SHORT_DELAY_MS, MILLISECONDS)); + s.release(4); + assertTrue(s.tryAcquire(4, SHORT_DELAY_MS, MILLISECONDS)); + s.release(5); + assertTrue(s.tryAcquire(5, SHORT_DELAY_MS, MILLISECONDS)); + assertEquals(1, s.availablePermits()); } /** * release in one thread enables timed acquire in another thread */ - public void testTimedAcquireReleaseInSameThread_fair() { + public void testTimedAcquireReleaseInSameThread_fair() + throws InterruptedException { Semaphore s = new Semaphore(1, true); - try { - assertTrue(s.tryAcquire(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - s.release(); - assertTrue(s.tryAcquire(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - s.release(); - assertTrue(s.tryAcquire(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - s.release(); - assertTrue(s.tryAcquire(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - s.release(); - assertTrue(s.tryAcquire(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - s.release(); - assertEquals(1, s.availablePermits()); - } catch( InterruptedException e){ - unexpectedException(); - } + assertTrue(s.tryAcquire(SHORT_DELAY_MS, MILLISECONDS)); + s.release(); + assertTrue(s.tryAcquire(SHORT_DELAY_MS, MILLISECONDS)); + s.release(); + assertTrue(s.tryAcquire(SHORT_DELAY_MS, MILLISECONDS)); + s.release(); + assertTrue(s.tryAcquire(SHORT_DELAY_MS, MILLISECONDS)); + s.release(); + assertTrue(s.tryAcquire(SHORT_DELAY_MS, MILLISECONDS)); + s.release(); + assertEquals(1, s.availablePermits()); } /** * A release in one thread enables an acquire in another thread */ - public void testAcquireReleaseInDifferentThreads_fair() { + public void testAcquireReleaseInDifferentThreads_fair() + throws InterruptedException { final Semaphore s = new Semaphore(0, true); - Thread t = new Thread(new Runnable() { - public void run() { - try { - s.acquire(); - s.acquire(); - s.acquire(); - s.acquire(); - } catch(InterruptedException ie){ - threadUnexpectedException(); - } - } - }); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - s.release(); - s.release(); - s.release(); - s.release(); - s.release(); - s.release(); - t.join(); - assertEquals(2, s.availablePermits()); - } catch( InterruptedException e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + s.acquire(); + s.acquire(); + s.acquire(); + s.acquire(); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + s.release(); + s.release(); + s.release(); + s.release(); + s.release(); + s.release(); + t.join(); + assertEquals(2, s.availablePermits()); } /** * release(n) in one thread enables acquire(n) in another thread */ - public void testAcquireReleaseNInDifferentThreads_fair() { + public void testAcquireReleaseNInDifferentThreads_fair() + throws InterruptedException { final Semaphore s = new Semaphore(0, true); - Thread t = new Thread(new Runnable() { - public void run() { - try { - s.acquire(); - s.release(2); - s.acquire(); - } catch(InterruptedException ie){ - threadUnexpectedException(); - } - } - }); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - s.release(2); - s.acquire(2); - s.release(1); - t.join(); - } catch( InterruptedException e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + s.acquire(); + s.release(2); + s.acquire(); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + s.release(2); + s.acquire(2); + s.release(1); + t.join(); } /** * release(n) in one thread enables acquire(n) in another thread */ - public void testAcquireReleaseNInDifferentThreads_fair2() { + public void testAcquireReleaseNInDifferentThreads_fair2() + throws InterruptedException { final Semaphore s = new Semaphore(0, true); - Thread t = new Thread(new Runnable() { - public void run() { - try { - s.acquire(2); - s.acquire(2); - s.release(4); - } catch(InterruptedException ie){ - threadUnexpectedException(); - } - } - }); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - s.release(6); - s.acquire(2); - s.acquire(2); - s.release(2); - t.join(); - } catch( InterruptedException e){ - unexpectedException(); - } - } - - + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + s.acquire(2); + s.acquire(2); + s.release(4); + }}); + t.start(); + Thread.sleep(SHORT_DELAY_MS); + s.release(6); + s.acquire(2); + s.acquire(2); + s.release(2); + t.join(); + } /** * release in one thread enables timed acquire in another thread */ - public void testTimedAcquireReleaseInDifferentThreads_fair() { + public void testTimedAcquireReleaseInDifferentThreads_fair() + throws InterruptedException { final Semaphore s = new Semaphore(1, true); - Thread t = new Thread(new Runnable() { - public void run() { - try { - threadAssertTrue(s.tryAcquire(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - threadAssertTrue(s.tryAcquire(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - threadAssertTrue(s.tryAcquire(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - threadAssertTrue(s.tryAcquire(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - threadAssertTrue(s.tryAcquire(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - - } catch(InterruptedException ie){ - threadUnexpectedException(); - } - } - }); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertTrue(s.tryAcquire(SHORT_DELAY_MS, MILLISECONDS)); + assertTrue(s.tryAcquire(SHORT_DELAY_MS, MILLISECONDS)); + assertTrue(s.tryAcquire(SHORT_DELAY_MS, MILLISECONDS)); + assertTrue(s.tryAcquire(SHORT_DELAY_MS, MILLISECONDS)); + assertTrue(s.tryAcquire(SHORT_DELAY_MS, MILLISECONDS)); + }}); + t.start(); - try { - s.release(); - s.release(); - s.release(); - s.release(); - s.release(); - t.join(); - } catch( InterruptedException e){ - unexpectedException(); - } + s.release(); + s.release(); + s.release(); + s.release(); + s.release(); + t.join(); } /** * release(n) in one thread enables timed acquire(n) in another thread */ - public void testTimedAcquireReleaseNInDifferentThreads_fair() { + public void testTimedAcquireReleaseNInDifferentThreads_fair() + throws InterruptedException { final Semaphore s = new Semaphore(2, true); - Thread t = new Thread(new Runnable() { - public void run() { - try { - threadAssertTrue(s.tryAcquire(2, SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - s.release(2); - threadAssertTrue(s.tryAcquire(2, SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - s.release(2); - } catch(InterruptedException ie){ - threadUnexpectedException(); - } - } - }); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertTrue(s.tryAcquire(2, SHORT_DELAY_MS, MILLISECONDS)); + s.release(2); + assertTrue(s.tryAcquire(2, SHORT_DELAY_MS, MILLISECONDS)); + s.release(2); + }}); + t.start(); - try { - assertTrue(s.tryAcquire(2, SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - s.release(2); - assertTrue(s.tryAcquire(2, SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - s.release(2); - t.join(); - } catch( InterruptedException e){ - unexpectedException(); - } + assertTrue(s.tryAcquire(2, SHORT_DELAY_MS, MILLISECONDS)); + s.release(2); + assertTrue(s.tryAcquire(2, SHORT_DELAY_MS, MILLISECONDS)); + s.release(2); + t.join(); } /** * A waiting acquire blocks interruptibly */ - public void testAcquire_InterruptedException_fair() { + public void testAcquire_InterruptedException_fair() + throws InterruptedException { final Semaphore s = new Semaphore(0, true); - Thread t = new Thread(new Runnable() { - public void run() { - try { - s.acquire(); - threadShouldThrow(); - } catch(InterruptedException success){} - } - }); + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + s.acquire(); + }}); + t.start(); - try { - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } catch(InterruptedException e){ - unexpectedException(); - } + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } /** * A waiting acquire(n) blocks interruptibly */ - public void testAcquireN_InterruptedException_fair() { + public void testAcquireN_InterruptedException_fair() + throws InterruptedException { final Semaphore s = new Semaphore(2, true); - Thread t = new Thread(new Runnable() { - public void run() { - try { - s.acquire(3); - threadShouldThrow(); - } catch(InterruptedException success){} - } - }); + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + s.acquire(3); + }}); + t.start(); - try { - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } catch(InterruptedException e){ - unexpectedException(); - } + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } - + /** * A waiting tryAcquire blocks interruptibly */ - public void testTryAcquire_InterruptedException_fair() { + public void testTryAcquire_InterruptedException_fair() + throws InterruptedException { final Semaphore s = new Semaphore(0, true); - Thread t = new Thread(new Runnable() { - public void run() { - try { - s.tryAcquire(MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); - threadShouldThrow(); - } catch(InterruptedException success){ - } - } - }); + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + s.tryAcquire(MEDIUM_DELAY_MS, MILLISECONDS); + }}); + t.start(); - try { - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } catch(InterruptedException e){ - unexpectedException(); - } + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } /** * A waiting tryAcquire(n) blocks interruptibly */ - public void testTryAcquireN_InterruptedException_fair() { + public void testTryAcquireN_InterruptedException_fair() + throws InterruptedException { final Semaphore s = new Semaphore(1, true); - Thread t = new Thread(new Runnable() { - public void run() { - try { - s.tryAcquire(4, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); - threadShouldThrow(); - } catch(InterruptedException success){ - } - } - }); + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + s.tryAcquire(4, MEDIUM_DELAY_MS, MILLISECONDS); + }}); + t.start(); - try { - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } catch(InterruptedException e){ - unexpectedException(); - } + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } /** * getQueueLength reports number of waiting threads */ - public void testGetQueueLength_fair() { + public void testGetQueueLength_fair() throws InterruptedException { final Semaphore lock = new Semaphore(1, true); Thread t1 = new Thread(new InterruptedLockRunnable(lock)); Thread t2 = new Thread(new InterruptibleLockRunnable(lock)); - try { - assertEquals(0, lock.getQueueLength()); - lock.acquireUninterruptibly(); - t1.start(); - Thread.sleep(SHORT_DELAY_MS); - assertEquals(1, lock.getQueueLength()); - t2.start(); - Thread.sleep(SHORT_DELAY_MS); - assertEquals(2, lock.getQueueLength()); - t1.interrupt(); - Thread.sleep(SHORT_DELAY_MS); - assertEquals(1, lock.getQueueLength()); - lock.release(); - Thread.sleep(SHORT_DELAY_MS); - assertEquals(0, lock.getQueueLength()); - t1.join(); - t2.join(); - } catch(Exception e){ - unexpectedException(); - } - } + assertEquals(0, lock.getQueueLength()); + lock.acquireUninterruptibly(); + t1.start(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(1, lock.getQueueLength()); + t2.start(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(2, lock.getQueueLength()); + t1.interrupt(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(1, lock.getQueueLength()); + lock.release(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(0, lock.getQueueLength()); + t1.join(); + t2.join(); + } /** * a deserialized serialized semaphore has same number of permits */ - public void testSerialization_fair() { + public void testSerialization_fair() throws Exception { Semaphore l = new Semaphore(3, true); - try { - l.acquire(); - l.release(); - ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); - ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); - out.writeObject(l); - out.close(); - - ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); - ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); - Semaphore r = (Semaphore) in.readObject(); - assertEquals(3, r.availablePermits()); - assertTrue(r.isFair()); - r.acquire(); - r.release(); - } catch(Exception e){ - unexpectedException(); - } + l.acquire(); + l.release(); + ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); + ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); + out.writeObject(l); + out.close(); + + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); + Semaphore r = (Semaphore) in.readObject(); + assertEquals(3, r.availablePermits()); + assertTrue(r.isFair()); + r.acquire(); + r.release(); } /** diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/SynchronousQueueTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/SynchronousQueueTest.java index c2ae396..9393c5c 100755 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/SynchronousQueueTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/SynchronousQueueTest.java @@ -2,15 +2,16 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.*; import java.util.concurrent.*; +import static java.util.concurrent.TimeUnit.MILLISECONDS; import java.io.*; public class SynchronousQueueTest extends JSR166TestCase { @@ -48,7 +49,7 @@ public class SynchronousQueueTest extends JSR166TestCase { SynchronousQueue q = new SynchronousQueue(); q.offer(null); shouldThrow(); - } catch (NullPointerException success) { } + } catch (NullPointerException success) {} } /** @@ -59,7 +60,7 @@ public class SynchronousQueueTest extends JSR166TestCase { SynchronousQueue q = new SynchronousQueue(); q.add(null); shouldThrow(); - } catch (NullPointerException success) { } + } catch (NullPointerException success) {} } /** @@ -79,8 +80,7 @@ public class SynchronousQueueTest extends JSR166TestCase { assertEquals(0, q.remainingCapacity()); q.add(one); shouldThrow(); - } catch (IllegalStateException success){ - } + } catch (IllegalStateException success) {} } /** @@ -91,8 +91,7 @@ public class SynchronousQueueTest extends JSR166TestCase { SynchronousQueue q = new SynchronousQueue(); q.addAll(null); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** @@ -103,8 +102,7 @@ public class SynchronousQueueTest extends JSR166TestCase { SynchronousQueue q = new SynchronousQueue(); q.addAll(q); shouldThrow(); - } - catch (IllegalArgumentException success) {} + } catch (IllegalArgumentException success) {} } /** @@ -116,8 +114,7 @@ public class SynchronousQueueTest extends JSR166TestCase { Integer[] ints = new Integer[1]; q.addAll(Arrays.asList(ints)); shouldThrow(); - } - catch (NullPointerException success) {} + } catch (NullPointerException success) {} } /** * addAll throws ISE if no active taker @@ -130,243 +127,171 @@ public class SynchronousQueueTest extends JSR166TestCase { ints[i] = new Integer(i); q.addAll(Arrays.asList(ints)); shouldThrow(); - } - catch (IllegalStateException success) {} + } catch (IllegalStateException success) {} } /** * put(null) throws NPE */ - public void testPutNull() { + public void testPutNull() throws InterruptedException { try { SynchronousQueue q = new SynchronousQueue(); q.put(null); shouldThrow(); - } - catch (NullPointerException success){ - } - catch (InterruptedException ie) { - unexpectedException(); - } + } catch (NullPointerException success) {} } /** * put blocks interruptibly if no active taker */ - public void testBlockingPut() { - Thread t = new Thread(new Runnable() { - public void run() { - try { - SynchronousQueue q = new SynchronousQueue(); - q.put(zero); - threadShouldThrow(); - } catch (InterruptedException ie){ - } - }}); + public void testBlockingPut() throws InterruptedException { + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + SynchronousQueue q = new SynchronousQueue(); + q.put(zero); + }}); + t.start(); - try { - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } - catch (InterruptedException ie) { - unexpectedException(); - } + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } /** - * put blocks waiting for take + * put blocks waiting for take */ - public void testPutWithTake() { + public void testPutWithTake() throws InterruptedException { final SynchronousQueue q = new SynchronousQueue(); - Thread t = new Thread(new Runnable() { - public void run() { - int added = 0; - try { - q.put(new Object()); - ++added; - q.put(new Object()); - ++added; - q.put(new Object()); - ++added; - q.put(new Object()); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + int added = 0; + try { + while (true) { + q.put(added); ++added; - threadShouldThrow(); - } catch (InterruptedException e){ - assertTrue(added >= 1); } + } catch (InterruptedException success) { + assertTrue(added == 1); } - }); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - q.take(); - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } catch (Exception e){ - unexpectedException(); - } + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(0, q.take()); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } /** * timed offer times out if elements not taken */ - public void testTimedOffer() { + public void testTimedOffer() throws InterruptedException { final SynchronousQueue q = new SynchronousQueue(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - - threadAssertFalse(q.offer(new Object(), SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - q.offer(new Object(), LONG_DELAY_MS, TimeUnit.MILLISECONDS); - threadShouldThrow(); - } catch (InterruptedException success){} - } - }); - - try { - t.start(); - Thread.sleep(SMALL_DELAY_MS); - t.interrupt(); - t.join(); - } catch (Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(q.offer(new Object(), SHORT_DELAY_MS, MILLISECONDS)); + q.offer(new Object(), LONG_DELAY_MS, MILLISECONDS); + }}); + + t.start(); + Thread.sleep(SMALL_DELAY_MS); + t.interrupt(); + t.join(); } /** * take blocks interruptibly when empty */ - public void testTakeFromEmpty() { + public void testTakeFromEmpty() throws InterruptedException { final SynchronousQueue q = new SynchronousQueue(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - q.take(); - threadShouldThrow(); - } catch (InterruptedException success){ } - } - }); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } catch (Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + q.take(); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } /** * put blocks interruptibly if no active taker */ - public void testFairBlockingPut() { - Thread t = new Thread(new Runnable() { - public void run() { - try { - SynchronousQueue q = new SynchronousQueue(true); - q.put(zero); - threadShouldThrow(); - } catch (InterruptedException ie){ - } - }}); + public void testFairBlockingPut() throws InterruptedException { + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + SynchronousQueue q = new SynchronousQueue(true); + q.put(zero); + }}); + t.start(); - try { - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } - catch (InterruptedException ie) { - unexpectedException(); - } + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } /** - * put blocks waiting for take + * put blocks waiting for take */ - public void testFairPutWithTake() { + public void testFairPutWithTake() throws InterruptedException { final SynchronousQueue q = new SynchronousQueue(true); - Thread t = new Thread(new Runnable() { - public void run() { - int added = 0; - try { - q.put(new Object()); - ++added; - q.put(new Object()); - ++added; - q.put(new Object()); - ++added; - q.put(new Object()); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + int added = 0; + try { + while (true) { + q.put(added); ++added; - threadShouldThrow(); - } catch (InterruptedException e){ - assertTrue(added >= 1); } + } catch (InterruptedException success) { + assertTrue(added == 1); } - }); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - q.take(); - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } catch (Exception e){ - unexpectedException(); - } + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(0, q.take()); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } /** * timed offer times out if elements not taken */ - public void testFairTimedOffer() { + public void testFairTimedOffer() throws InterruptedException { final SynchronousQueue q = new SynchronousQueue(true); - Thread t = new Thread(new Runnable() { - public void run() { - try { - - threadAssertFalse(q.offer(new Object(), SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - q.offer(new Object(), LONG_DELAY_MS, TimeUnit.MILLISECONDS); - threadShouldThrow(); - } catch (InterruptedException success){} - } - }); - - try { - t.start(); - Thread.sleep(SMALL_DELAY_MS); - t.interrupt(); - t.join(); - } catch (Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(q.offer(new Object(), SHORT_DELAY_MS, MILLISECONDS)); + q.offer(new Object(), LONG_DELAY_MS, MILLISECONDS); + }}); + + t.start(); + Thread.sleep(SMALL_DELAY_MS); + t.interrupt(); + t.join(); } /** * take blocks interruptibly when empty */ - public void testFairTakeFromEmpty() { + public void testFairTakeFromEmpty() throws InterruptedException { final SynchronousQueue q = new SynchronousQueue(true); - Thread t = new Thread(new Runnable() { - public void run() { - try { - q.take(); - threadShouldThrow(); - } catch (InterruptedException success){ } - } - }); - try { - t.start(); - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } catch (Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + q.take(); + }}); + + t.start(); + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } /** @@ -380,128 +305,98 @@ public class SynchronousQueueTest extends JSR166TestCase { /** * timed pool with zero timeout times out if no active taker */ - public void testTimedPoll0() { - try { - SynchronousQueue q = new SynchronousQueue(); - assertNull(q.poll(0, TimeUnit.MILLISECONDS)); - } catch (InterruptedException e){ - unexpectedException(); - } + public void testTimedPoll0() throws InterruptedException { + SynchronousQueue q = new SynchronousQueue(); + assertNull(q.poll(0, MILLISECONDS)); } /** * timed pool with nonzero timeout times out if no active taker */ - public void testTimedPoll() { - try { - SynchronousQueue q = new SynchronousQueue(); - assertNull(q.poll(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - } catch (InterruptedException e){ - unexpectedException(); - } + public void testTimedPoll() throws InterruptedException { + SynchronousQueue q = new SynchronousQueue(); + assertNull(q.poll(SHORT_DELAY_MS, MILLISECONDS)); } /** * Interrupted timed poll throws InterruptedException instead of * returning timeout status */ - public void testInterruptedTimedPoll() { - Thread t = new Thread(new Runnable() { - public void run() { - try { - SynchronousQueue q = new SynchronousQueue(); - assertNull(q.poll(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - } catch (InterruptedException success){ - } - }}); + public void testInterruptedTimedPoll() throws InterruptedException { + final SynchronousQueue q = new SynchronousQueue(); + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + q.poll(SMALL_DELAY_MS, MILLISECONDS); + }}); + t.start(); - try { - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } - catch (InterruptedException ie) { - unexpectedException(); - } + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } /** * timed poll before a delayed offer fails; after offer succeeds; * on interruption throws */ - public void testTimedPollWithOffer() { + public void testTimedPollWithOffer() throws InterruptedException { final SynchronousQueue q = new SynchronousQueue(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - threadAssertNull(q.poll(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - q.poll(LONG_DELAY_MS, TimeUnit.MILLISECONDS); - q.poll(LONG_DELAY_MS, TimeUnit.MILLISECONDS); - threadShouldThrow(); - } catch (InterruptedException success) { } - } - }); - try { - t.start(); - Thread.sleep(SMALL_DELAY_MS); - assertTrue(q.offer(zero, SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - t.interrupt(); - t.join(); - } catch (Exception e){ - unexpectedException(); - } - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertNull(q.poll(SHORT_DELAY_MS, MILLISECONDS)); + assertSame(zero, q.poll(LONG_DELAY_MS, MILLISECONDS)); + try { + q.poll(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + t.start(); + Thread.sleep(SMALL_DELAY_MS); + assertTrue(q.offer(zero, SHORT_DELAY_MS, MILLISECONDS)); + t.interrupt(); + t.join(); + } /** * Interrupted timed poll throws InterruptedException instead of * returning timeout status */ - public void testFairInterruptedTimedPoll() { - Thread t = new Thread(new Runnable() { - public void run() { - try { - SynchronousQueue q = new SynchronousQueue(true); - assertNull(q.poll(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - } catch (InterruptedException success){ - } - }}); + public void testFairInterruptedTimedPoll() throws InterruptedException { + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + SynchronousQueue q = new SynchronousQueue(true); + q.poll(SMALL_DELAY_MS, MILLISECONDS); + }}); + t.start(); - try { - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } - catch (InterruptedException ie) { - unexpectedException(); - } + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } /** * timed poll before a delayed offer fails; after offer succeeds; * on interruption throws */ - public void testFairTimedPollWithOffer() { + public void testFairTimedPollWithOffer() throws InterruptedException { final SynchronousQueue q = new SynchronousQueue(true); - Thread t = new Thread(new Runnable() { - public void run() { - try { - threadAssertNull(q.poll(SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - q.poll(LONG_DELAY_MS, TimeUnit.MILLISECONDS); - q.poll(LONG_DELAY_MS, TimeUnit.MILLISECONDS); - threadShouldThrow(); - } catch (InterruptedException success) { } - } - }); - try { - t.start(); - Thread.sleep(SMALL_DELAY_MS); - assertTrue(q.offer(zero, SHORT_DELAY_MS, TimeUnit.MILLISECONDS)); - t.interrupt(); - t.join(); - } catch (Exception e){ - unexpectedException(); - } - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertNull(q.poll(SHORT_DELAY_MS, MILLISECONDS)); + assertSame(zero, q.poll(LONG_DELAY_MS, MILLISECONDS)); + try { + q.poll(LONG_DELAY_MS, MILLISECONDS); + threadShouldThrow(); + } catch (InterruptedException success) {} + }}); + + t.start(); + Thread.sleep(SMALL_DELAY_MS); + assertTrue(q.offer(zero, SHORT_DELAY_MS, MILLISECONDS)); + t.interrupt(); + t.join(); + } /** @@ -520,8 +415,7 @@ public class SynchronousQueueTest extends JSR166TestCase { try { q.element(); shouldThrow(); - } - catch (NoSuchElementException success) {} + } catch (NoSuchElementException success) {} } /** @@ -532,8 +426,7 @@ public class SynchronousQueueTest extends JSR166TestCase { try { q.remove(); shouldThrow(); - } catch (NoSuchElementException success){ - } + } catch (NoSuchElementException success) {} } /** @@ -544,7 +437,7 @@ public class SynchronousQueueTest extends JSR166TestCase { assertFalse(q.remove(zero)); assertTrue(q.isEmpty()); } - + /** * contains returns false */ @@ -613,16 +506,16 @@ public class SynchronousQueueTest extends JSR166TestCase { Integer[] ints = new Integer[1]; assertNull(ints[0]); } - + /** * toArray(null) throws NPE */ public void testToArray_BadArg() { + SynchronousQueue q = new SynchronousQueue(); try { - SynchronousQueue q = new SynchronousQueue(); Object o[] = q.toArray(null); shouldThrow(); - } catch(NullPointerException success){} + } catch (NullPointerException success) {} } @@ -636,8 +529,7 @@ public class SynchronousQueueTest extends JSR166TestCase { try { Object x = it.next(); shouldThrow(); - } - catch (NoSuchElementException success) {} + } catch (NoSuchElementException success) {} } /** @@ -649,8 +541,9 @@ public class SynchronousQueueTest extends JSR166TestCase { try { it.remove(); shouldThrow(); + } catch (IllegalStateException success) { + } catch (UnsupportedOperationException success) { // android-added } - catch (IllegalStateException success) {} } /** @@ -660,7 +553,7 @@ public class SynchronousQueueTest extends JSR166TestCase { SynchronousQueue q = new SynchronousQueue(); String s = q.toString(); assertNotNull(s); - } + } /** @@ -669,35 +562,21 @@ public class SynchronousQueueTest extends JSR166TestCase { public void testOfferInExecutor() { final SynchronousQueue q = new SynchronousQueue(); ExecutorService executor = Executors.newFixedThreadPool(2); - final Integer one = new Integer(1); - executor.execute(new Runnable() { - public void run() { - threadAssertFalse(q.offer(one)); - try { - threadAssertTrue(q.offer(one, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS)); - threadAssertEquals(0, q.remainingCapacity()); - } - catch (InterruptedException e) { - threadUnexpectedException(); - } - } - }); + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(q.offer(one)); + assertTrue(q.offer(one, MEDIUM_DELAY_MS, MILLISECONDS)); + assertEquals(0, q.remainingCapacity()); + }}); - executor.execute(new Runnable() { - public void run() { - try { - Thread.sleep(SMALL_DELAY_MS); - threadAssertEquals(one, q.take()); - } - catch (InterruptedException e) { - threadUnexpectedException(); - } - } - }); - - joinPool(executor); + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + Thread.sleep(SMALL_DELAY_MS); + assertSame(one, q.take()); + }}); + joinPool(executor); } /** @@ -706,84 +585,65 @@ public class SynchronousQueueTest extends JSR166TestCase { public void testPollInExecutor() { final SynchronousQueue q = new SynchronousQueue(); ExecutorService executor = Executors.newFixedThreadPool(2); - executor.execute(new Runnable() { - public void run() { - threadAssertNull(q.poll()); - try { - threadAssertTrue(null != q.poll(MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS)); - threadAssertTrue(q.isEmpty()); - } - catch (InterruptedException e) { - threadUnexpectedException(); - } - } - }); + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertNull(q.poll()); + assertSame(one, q.poll(MEDIUM_DELAY_MS, MILLISECONDS)); + assertTrue(q.isEmpty()); + }}); + + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + Thread.sleep(SHORT_DELAY_MS); + q.put(one); + }}); - executor.execute(new Runnable() { - public void run() { - try { - Thread.sleep(SMALL_DELAY_MS); - q.put(new Integer(1)); - } - catch (InterruptedException e) { - threadUnexpectedException(); - } - } - }); - joinPool(executor); } /** * a deserialized serialized queue is usable */ - public void testSerialization() { + public void testSerialization() throws Exception { SynchronousQueue q = new SynchronousQueue(); - try { - ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); - ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); - out.writeObject(q); - out.close(); - - ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); - ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); - SynchronousQueue r = (SynchronousQueue)in.readObject(); - assertEquals(q.size(), r.size()); - while (!q.isEmpty()) - assertEquals(q.remove(), r.remove()); - } catch(Exception e){ - e.printStackTrace(); - unexpectedException(); - } + ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); + ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); + out.writeObject(q); + out.close(); + + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); + SynchronousQueue r = (SynchronousQueue)in.readObject(); + assertEquals(q.size(), r.size()); + while (!q.isEmpty()) + assertEquals(q.remove(), r.remove()); } /** * drainTo(null) throws NPE - */ + */ public void testDrainToNull() { SynchronousQueue q = new SynchronousQueue(); try { q.drainTo(null); shouldThrow(); - } catch(NullPointerException success) { - } + } catch (NullPointerException success) {} } /** * drainTo(this) throws IAE - */ + */ public void testDrainToSelf() { SynchronousQueue q = new SynchronousQueue(); try { q.drainTo(q); shouldThrow(); - } catch(IllegalArgumentException success) { - } + } catch (IllegalArgumentException success) {} } /** * drainTo(c) of empty queue doesn't transfer elements - */ + */ public void testDrainTo() { SynchronousQueue q = new SynchronousQueue(); ArrayList l = new ArrayList(); @@ -794,98 +654,74 @@ public class SynchronousQueueTest extends JSR166TestCase { /** * drainTo empties queue, unblocking a waiting put. - */ - public void testDrainToWithActivePut() { + */ + public void testDrainToWithActivePut() throws InterruptedException { final SynchronousQueue q = new SynchronousQueue(); - Thread t = new Thread(new Runnable() { - public void run() { - try { - q.put(new Integer(1)); - } catch (InterruptedException ie){ - threadUnexpectedException(); - } - } - }); - try { - t.start(); - ArrayList l = new ArrayList(); - Thread.sleep(SHORT_DELAY_MS); - q.drainTo(l); - assertTrue(l.size() <= 1); - if (l.size() > 0) - assertEquals(l.get(0), new Integer(1)); - t.join(); - assertTrue(l.size() <= 1); - } catch(Exception e){ - unexpectedException(); - } + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + q.put(new Integer(1)); + }}); + + t.start(); + ArrayList l = new ArrayList(); + Thread.sleep(SHORT_DELAY_MS); + q.drainTo(l); + assertTrue(l.size() <= 1); + if (l.size() > 0) + assertEquals(l.get(0), new Integer(1)); + t.join(); + assertTrue(l.size() <= 1); } /** * drainTo(null, n) throws NPE - */ + */ public void testDrainToNullN() { SynchronousQueue q = new SynchronousQueue(); try { q.drainTo(null, 0); shouldThrow(); - } catch(NullPointerException success) { - } + } catch (NullPointerException success) {} } /** * drainTo(this, n) throws IAE - */ + */ public void testDrainToSelfN() { SynchronousQueue q = new SynchronousQueue(); try { q.drainTo(q, 0); shouldThrow(); - } catch(IllegalArgumentException success) { - } + } catch (IllegalArgumentException success) {} } /** * drainTo(c, n) empties up to n elements of queue into c - */ - public void testDrainToN() { + */ + public void testDrainToN() throws InterruptedException { final SynchronousQueue q = new SynchronousQueue(); - Thread t1 = new Thread(new Runnable() { - public void run() { - try { - q.put(one); - } catch (InterruptedException ie){ - threadUnexpectedException(); - } - } - }); - Thread t2 = new Thread(new Runnable() { - public void run() { - try { - q.put(two); - } catch (InterruptedException ie){ - threadUnexpectedException(); - } - } - }); - - try { - t1.start(); - t2.start(); - ArrayList l = new ArrayList(); - Thread.sleep(SHORT_DELAY_MS); - q.drainTo(l, 1); - assertTrue(l.size() == 1); - q.drainTo(l, 1); - assertTrue(l.size() == 2); - assertTrue(l.contains(one)); - assertTrue(l.contains(two)); - t1.join(); - t2.join(); - } catch(Exception e){ - unexpectedException(); - } + Thread t1 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + q.put(one); + }}); + + Thread t2 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + q.put(two); + }}); + + t1.start(); + t2.start(); + ArrayList l = new ArrayList(); + Thread.sleep(SHORT_DELAY_MS); + q.drainTo(l, 1); + assertTrue(l.size() == 1); + q.drainTo(l, 1); + assertTrue(l.size() == 2); + assertTrue(l.contains(one)); + assertTrue(l.contains(two)); + t1.join(); + t2.join(); } - } diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/SystemTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/SystemTest.java index 439039a..e906186 100644 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/SystemTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/SystemTest.java @@ -2,11 +2,11 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; @@ -15,9 +15,9 @@ public class SystemTest extends JSR166TestCase { return new TestSuite(SystemTest.class); } - /** + /** * Worst case rounding for millisecs; set for 60 cycle millis clock. - * This value might need to be changed os JVMs with coarser + * This value might need to be changed on JVMs with coarser * System.currentTimeMillis clocks. */ static final long MILLIS_ROUND = 17; @@ -27,24 +27,19 @@ public class SystemTest extends JSR166TestCase { * possible rounding). * This shows only that nano timing not (much) worse than milli. */ - public void testNanoTime1() { - try { - long m1 = System.currentTimeMillis(); - Thread.sleep(1); - long n1 = System.nanoTime(); - Thread.sleep(SHORT_DELAY_MS); - long n2 = System.nanoTime(); - Thread.sleep(1); - long m2 = System.currentTimeMillis(); - long millis = m2 - m1; - long nanos = n2 - n1; - assertTrue(nanos >= 0); - long nanosAsMillis = nanos / 1000000; - assertTrue(nanosAsMillis <= millis + MILLIS_ROUND); - } - catch(InterruptedException ie) { - unexpectedException(); - } + public void testNanoTime1() throws InterruptedException { + long m1 = System.currentTimeMillis(); + Thread.sleep(1); + long n1 = System.nanoTime(); + Thread.sleep(SHORT_DELAY_MS); + long n2 = System.nanoTime(); + Thread.sleep(1); + long m2 = System.currentTimeMillis(); + long millis = m2 - m1; + long nanos = n2 - n1; + assertTrue(nanos >= 0); + long nanosAsMillis = nanos / 1000000; + assertTrue(nanosAsMillis <= millis + MILLIS_ROUND); } /** @@ -52,26 +47,20 @@ public class SystemTest extends JSR166TestCase { * for rounding. * This shows only that nano timing not (much) worse than milli. */ - public void testNanoTime2() { - try { - long n1 = System.nanoTime(); - Thread.sleep(1); - long m1 = System.currentTimeMillis(); - Thread.sleep(SHORT_DELAY_MS); - long m2 = System.currentTimeMillis(); - Thread.sleep(1); - long n2 = System.nanoTime(); - long millis = m2 - m1; - long nanos = n2 - n1; - - assertTrue(nanos >= 0); - long nanosAsMillis = nanos / 1000000; - assertTrue(millis <= nanosAsMillis + MILLIS_ROUND); - } - catch(InterruptedException ie) { - unexpectedException(); - } + public void testNanoTime2() throws InterruptedException { + long n1 = System.nanoTime(); + Thread.sleep(1); + long m1 = System.currentTimeMillis(); + Thread.sleep(SHORT_DELAY_MS); + long m2 = System.currentTimeMillis(); + Thread.sleep(1); + long n2 = System.nanoTime(); + long millis = m2 - m1; + long nanos = n2 - n1; + + assertTrue(nanos >= 0); + long nanosAsMillis = nanos / 1000000; + assertTrue(millis <= nanosAsMillis + MILLIS_ROUND); } } - diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/ThreadLocalTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/ThreadLocalTest.java index b9b7ba5..d54bce0 100644 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/ThreadLocalTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/ThreadLocalTest.java @@ -2,11 +2,11 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.concurrent.Semaphore; @@ -27,7 +27,7 @@ public class ThreadLocalTest extends JSR166TestCase { protected Integer initialValue() { return zero; } - + protected Integer childValue(Integer parentValue) { return new Integer(parentValue.intValue() + 1); } @@ -37,11 +37,11 @@ public class ThreadLocalTest extends JSR166TestCase { * remove causes next access to return initial value */ public void testRemove() { - assertEquals(tl.get(), one); + assertSame(tl.get(), one); tl.set(two); - assertEquals(tl.get(), two); + assertSame(tl.get(), two); tl.remove(); - assertEquals(tl.get(), one); + assertSame(tl.get(), one); } /** @@ -49,11 +49,11 @@ public class ThreadLocalTest extends JSR166TestCase { * initial value */ public void testRemoveITL() { - assertEquals(itl.get(), zero); + assertSame(itl.get(), zero); itl.set(two); - assertEquals(itl.get(), two); + assertSame(itl.get(), two); itl.remove(); - assertEquals(itl.get(), zero); + assertSame(itl.get(), zero); } private class ITLThread extends Thread { @@ -66,18 +66,18 @@ public class ThreadLocalTest extends JSR166TestCase { child.start(); } Thread.currentThread().yield(); - + int threadId = itl.get().intValue(); for (int j = 0; j < threadId; j++) { x[threadId]++; Thread.currentThread().yield(); } - + if (child != null) { // Wait for child (if any) try { child.join(); - } catch(InterruptedException e) { - threadUnexpectedException(); + } catch (InterruptedException e) { + threadUnexpectedException(e); } } } @@ -86,19 +86,14 @@ public class ThreadLocalTest extends JSR166TestCase { /** * InheritableThreadLocal propagates generic values. */ - public void testGenericITL() { + public void testGenericITL() throws InterruptedException { final int threadCount = 10; final int x[] = new int[threadCount]; Thread progenitor = new ITLThread(x); - try { - progenitor.start(); - progenitor.join(); - for(int i = 0; i < threadCount; i++) { - assertEquals(i, x[i]); - } - } catch(InterruptedException e) { - unexpectedException(); + progenitor.start(); + progenitor.join(); + for (int i = 0; i < threadCount; i++) { + assertEquals(i, x[i]); } } } - diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/ThreadPoolExecutorSubclassTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/ThreadPoolExecutorSubclassTest.java new file mode 100644 index 0000000..911a35f --- /dev/null +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/ThreadPoolExecutorSubclassTest.java @@ -0,0 +1,1578 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +package tests.api.java.util.concurrent; // android-added + +import java.util.concurrent.*; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import java.util.concurrent.locks.*; + +import junit.framework.*; +import java.util.*; + +public class ThreadPoolExecutorSubclassTest extends JSR166TestCase { + public static Test suite() { + return new TestSuite(ThreadPoolExecutorSubclassTest.class); + } + + static class CustomTask<V> implements RunnableFuture<V> { + final Callable<V> callable; + final ReentrantLock lock = new ReentrantLock(); + final Condition cond = lock.newCondition(); + boolean done; + boolean cancelled; + V result; + Thread thread; + Exception exception; + CustomTask(Callable<V> c) { + if (c == null) throw new NullPointerException(); + callable = c; + } + CustomTask(final Runnable r, final V res) { + if (r == null) throw new NullPointerException(); + callable = new Callable<V>() { + public V call() throws Exception { r.run(); return res; }}; + } + public boolean isDone() { + lock.lock(); try { return done; } finally { lock.unlock() ; } + } + public boolean isCancelled() { + lock.lock(); try { return cancelled; } finally { lock.unlock() ; } + } + public boolean cancel(boolean mayInterrupt) { + lock.lock(); + try { + if (!done) { + cancelled = true; + done = true; + if (mayInterrupt && thread != null) + thread.interrupt(); + return true; + } + return false; + } + finally { lock.unlock() ; } + } + public void run() { + boolean runme; + lock.lock(); + try { + runme = !done; + if (!runme) + thread = Thread.currentThread(); + } + finally { lock.unlock() ; } + if (!runme) return; + V v = null; + Exception e = null; + try { + v = callable.call(); + } + catch (Exception ex) { + e = ex; + } + lock.lock(); + try { + result = v; + exception = e; + done = true; + thread = null; + cond.signalAll(); + } + finally { lock.unlock(); } + } + public V get() throws InterruptedException, ExecutionException { + lock.lock(); + try { + while (!done) + cond.await(); + if (exception != null) + throw new ExecutionException(exception); + return result; + } + finally { lock.unlock(); } + } + public V get(long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { + long nanos = unit.toNanos(timeout); + lock.lock(); + try { + for (;;) { + if (done) break; + if (nanos < 0) + throw new TimeoutException(); + nanos = cond.awaitNanos(nanos); + } + if (exception != null) + throw new ExecutionException(exception); + return result; + } + finally { lock.unlock(); } + } + } + + + static class CustomTPE extends ThreadPoolExecutor { + protected <V> RunnableFuture<V> newTaskFor(Callable<V> c) { + return new CustomTask<V>(c); + } + protected <V> RunnableFuture<V> newTaskFor(Runnable r, V v) { + return new CustomTask<V>(r, v); + } + + CustomTPE(int corePoolSize, + int maximumPoolSize, + long keepAliveTime, + TimeUnit unit, + BlockingQueue<Runnable> workQueue) { + super(corePoolSize, maximumPoolSize, keepAliveTime, unit, + workQueue); + } + CustomTPE(int corePoolSize, + int maximumPoolSize, + long keepAliveTime, + TimeUnit unit, + BlockingQueue<Runnable> workQueue, + ThreadFactory threadFactory) { + super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, + threadFactory); + } + + CustomTPE(int corePoolSize, + int maximumPoolSize, + long keepAliveTime, + TimeUnit unit, + BlockingQueue<Runnable> workQueue, + RejectedExecutionHandler handler) { + super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, + handler); + } + CustomTPE(int corePoolSize, + int maximumPoolSize, + long keepAliveTime, + TimeUnit unit, + BlockingQueue<Runnable> workQueue, + ThreadFactory threadFactory, + RejectedExecutionHandler handler) { + super(corePoolSize, maximumPoolSize, keepAliveTime, unit, + workQueue, threadFactory, handler); + } + + volatile boolean beforeCalled = false; + volatile boolean afterCalled = false; + volatile boolean terminatedCalled = false; + public CustomTPE() { + super(1, 1, LONG_DELAY_MS, MILLISECONDS, new SynchronousQueue<Runnable>()); + } + protected void beforeExecute(Thread t, Runnable r) { + beforeCalled = true; + } + protected void afterExecute(Runnable r, Throwable t) { + afterCalled = true; + } + protected void terminated() { + terminatedCalled = true; + } + + } + + static class FailingThreadFactory implements ThreadFactory { + int calls = 0; + public Thread newThread(Runnable r) { + if (++calls > 1) return null; + return new Thread(r); + } + } + + + /** + * execute successfully executes a runnable + */ + public void testExecute() throws InterruptedException { + ThreadPoolExecutor p1 = new CustomTPE(1, 1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + try { + p1.execute(new ShortRunnable()); + Thread.sleep(SMALL_DELAY_MS); + } finally { + joinPool(p1); + } + } + + /** + * getActiveCount increases but doesn't overestimate, when a + * thread becomes active + */ + public void testGetActiveCount() throws InterruptedException { + ThreadPoolExecutor p2 = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + assertEquals(0, p2.getActiveCount()); + p2.execute(new MediumRunnable()); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(1, p2.getActiveCount()); + joinPool(p2); + } + + /** + * prestartCoreThread starts a thread if under corePoolSize, else doesn't + */ + public void testPrestartCoreThread() { + ThreadPoolExecutor p2 = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + assertEquals(0, p2.getPoolSize()); + assertTrue(p2.prestartCoreThread()); + assertEquals(1, p2.getPoolSize()); + assertTrue(p2.prestartCoreThread()); + assertEquals(2, p2.getPoolSize()); + assertFalse(p2.prestartCoreThread()); + assertEquals(2, p2.getPoolSize()); + joinPool(p2); + } + + /** + * prestartAllCoreThreads starts all corePoolSize threads + */ + public void testPrestartAllCoreThreads() { + ThreadPoolExecutor p2 = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + assertEquals(0, p2.getPoolSize()); + p2.prestartAllCoreThreads(); + assertEquals(2, p2.getPoolSize()); + p2.prestartAllCoreThreads(); + assertEquals(2, p2.getPoolSize()); + joinPool(p2); + } + + /** + * getCompletedTaskCount increases, but doesn't overestimate, + * when tasks complete + */ + public void testGetCompletedTaskCount() throws InterruptedException { + ThreadPoolExecutor p2 = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + assertEquals(0, p2.getCompletedTaskCount()); + p2.execute(new ShortRunnable()); + Thread.sleep(SMALL_DELAY_MS); + assertEquals(1, p2.getCompletedTaskCount()); + try { p2.shutdown(); } catch (SecurityException ok) { return; } + joinPool(p2); + } + + /** + * getCorePoolSize returns size given in constructor if not otherwise set + */ + public void testGetCorePoolSize() { + ThreadPoolExecutor p1 = new CustomTPE(1, 1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + assertEquals(1, p1.getCorePoolSize()); + joinPool(p1); + } + + /** + * getKeepAliveTime returns value given in constructor if not otherwise set + */ + public void testGetKeepAliveTime() { + ThreadPoolExecutor p2 = new CustomTPE(2, 2, 1000, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + assertEquals(1, p2.getKeepAliveTime(TimeUnit.SECONDS)); + joinPool(p2); + } + + + /** + * getThreadFactory returns factory in constructor if not set + */ + public void testGetThreadFactory() { + ThreadFactory tf = new SimpleThreadFactory(); + ThreadPoolExecutor p = new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10), tf, new NoOpREHandler()); + assertSame(tf, p.getThreadFactory()); + joinPool(p); + } + + /** + * setThreadFactory sets the thread factory returned by getThreadFactory + */ + public void testSetThreadFactory() { + ThreadPoolExecutor p = new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + ThreadFactory tf = new SimpleThreadFactory(); + p.setThreadFactory(tf); + assertSame(tf, p.getThreadFactory()); + joinPool(p); + } + + + /** + * setThreadFactory(null) throws NPE + */ + public void testSetThreadFactoryNull() { + ThreadPoolExecutor p = new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + try { + p.setThreadFactory(null); + shouldThrow(); + } catch (NullPointerException success) { + } finally { + joinPool(p); + } + } + + /** + * getRejectedExecutionHandler returns handler in constructor if not set + */ + public void testGetRejectedExecutionHandler() { + RejectedExecutionHandler h = new NoOpREHandler(); + ThreadPoolExecutor p = new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10), h); + assertSame(h, p.getRejectedExecutionHandler()); + joinPool(p); + } + + /** + * setRejectedExecutionHandler sets the handler returned by + * getRejectedExecutionHandler + */ + public void testSetRejectedExecutionHandler() { + ThreadPoolExecutor p = new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + RejectedExecutionHandler h = new NoOpREHandler(); + p.setRejectedExecutionHandler(h); + assertSame(h, p.getRejectedExecutionHandler()); + joinPool(p); + } + + + /** + * setRejectedExecutionHandler(null) throws NPE + */ + public void testSetRejectedExecutionHandlerNull() { + ThreadPoolExecutor p = new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + try { + p.setRejectedExecutionHandler(null); + shouldThrow(); + } catch (NullPointerException success) { + } finally { + joinPool(p); + } + } + + + /** + * getLargestPoolSize increases, but doesn't overestimate, when + * multiple threads active + */ + public void testGetLargestPoolSize() throws InterruptedException { + ThreadPoolExecutor p2 = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + assertEquals(0, p2.getLargestPoolSize()); + p2.execute(new MediumRunnable()); + p2.execute(new MediumRunnable()); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(2, p2.getLargestPoolSize()); + joinPool(p2); + } + + /** + * getMaximumPoolSize returns value given in constructor if not + * otherwise set + */ + public void testGetMaximumPoolSize() { + ThreadPoolExecutor p2 = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + assertEquals(2, p2.getMaximumPoolSize()); + joinPool(p2); + } + + /** + * getPoolSize increases, but doesn't overestimate, when threads + * become active + */ + public void testGetPoolSize() { + ThreadPoolExecutor p1 = new CustomTPE(1, 1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + assertEquals(0, p1.getPoolSize()); + p1.execute(new MediumRunnable()); + assertEquals(1, p1.getPoolSize()); + joinPool(p1); + } + + /** + * getTaskCount increases, but doesn't overestimate, when tasks submitted + */ + public void testGetTaskCount() throws InterruptedException { + ThreadPoolExecutor p1 = new CustomTPE(1, 1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + assertEquals(0, p1.getTaskCount()); + p1.execute(new MediumRunnable()); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(1, p1.getTaskCount()); + joinPool(p1); + } + + /** + * isShutDown is false before shutdown, true after + */ + public void testIsShutdown() { + + ThreadPoolExecutor p1 = new CustomTPE(1, 1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + assertFalse(p1.isShutdown()); + try { p1.shutdown(); } catch (SecurityException ok) { return; } + assertTrue(p1.isShutdown()); + joinPool(p1); + } + + + /** + * isTerminated is false before termination, true after + */ + public void testIsTerminated() throws InterruptedException { + ThreadPoolExecutor p1 = new CustomTPE(1, 1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + assertFalse(p1.isTerminated()); + try { + p1.execute(new MediumRunnable()); + } finally { + try { p1.shutdown(); } catch (SecurityException ok) { return; } + } + assertTrue(p1.awaitTermination(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(p1.isTerminated()); + } + + /** + * isTerminating is not true when running or when terminated + */ + public void testIsTerminating() throws InterruptedException { + ThreadPoolExecutor p1 = new CustomTPE(1, 1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + assertFalse(p1.isTerminating()); + try { + p1.execute(new SmallRunnable()); + assertFalse(p1.isTerminating()); + } finally { + try { p1.shutdown(); } catch (SecurityException ok) { return; } + } + assertTrue(p1.awaitTermination(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(p1.isTerminated()); + assertFalse(p1.isTerminating()); + } + + /** + * getQueue returns the work queue, which contains queued tasks + */ + public void testGetQueue() throws InterruptedException { + BlockingQueue<Runnable> q = new ArrayBlockingQueue<Runnable>(10); + ThreadPoolExecutor p1 = new CustomTPE(1, 1, LONG_DELAY_MS, MILLISECONDS, q); + FutureTask[] tasks = new FutureTask[5]; + for (int i = 0; i < 5; i++) { + tasks[i] = new FutureTask(new MediumPossiblyInterruptedRunnable(), Boolean.TRUE); + p1.execute(tasks[i]); + } + try { + Thread.sleep(SHORT_DELAY_MS); + BlockingQueue<Runnable> wq = p1.getQueue(); + assertSame(q, wq); + assertFalse(wq.contains(tasks[0])); + assertTrue(wq.contains(tasks[4])); + for (int i = 1; i < 5; ++i) + tasks[i].cancel(true); + p1.shutdownNow(); + } finally { + joinPool(p1); + } + } + + /** + * remove(task) removes queued task, and fails to remove active task + */ + public void testRemove() throws InterruptedException { + BlockingQueue<Runnable> q = new ArrayBlockingQueue<Runnable>(10); + ThreadPoolExecutor p1 = new CustomTPE(1, 1, LONG_DELAY_MS, MILLISECONDS, q); + FutureTask[] tasks = new FutureTask[5]; + for (int i = 0; i < 5; i++) { + tasks[i] = new FutureTask(new MediumPossiblyInterruptedRunnable(), Boolean.TRUE); + p1.execute(tasks[i]); + } + try { + Thread.sleep(SHORT_DELAY_MS); + assertFalse(p1.remove(tasks[0])); + assertTrue(q.contains(tasks[4])); + assertTrue(q.contains(tasks[3])); + assertTrue(p1.remove(tasks[4])); + assertFalse(p1.remove(tasks[4])); + assertFalse(q.contains(tasks[4])); + assertTrue(q.contains(tasks[3])); + assertTrue(p1.remove(tasks[3])); + assertFalse(q.contains(tasks[3])); + } finally { + joinPool(p1); + } + } + + /** + * purge removes cancelled tasks from the queue + */ + public void testPurge() { + ThreadPoolExecutor p1 = new CustomTPE(1, 1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + FutureTask[] tasks = new FutureTask[5]; + for (int i = 0; i < 5; i++) { + tasks[i] = new FutureTask(new MediumPossiblyInterruptedRunnable(), Boolean.TRUE); + p1.execute(tasks[i]); + } + tasks[4].cancel(true); + tasks[3].cancel(true); + p1.purge(); + long count = p1.getTaskCount(); + assertTrue(count >= 2 && count < 5); + joinPool(p1); + } + + /** + * shutDownNow returns a list containing tasks that were not run + */ + public void testShutDownNow() { + ThreadPoolExecutor p1 = new CustomTPE(1, 1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + List l; + try { + for (int i = 0; i < 5; i++) + p1.execute(new MediumPossiblyInterruptedRunnable()); + } + finally { + try { + l = p1.shutdownNow(); + } catch (SecurityException ok) { return; } + } + assertTrue(p1.isShutdown()); + assertTrue(l.size() <= 4); + } + + // Exception Tests + + + /** + * Constructor throws if corePoolSize argument is less than zero + */ + public void testConstructor1() { + try { + new CustomTPE(-1,1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if maximumPoolSize is less than zero + */ + public void testConstructor2() { + try { + new CustomTPE(1,-1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if maximumPoolSize is equal to zero + */ + public void testConstructor3() { + try { + new CustomTPE(1,0,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if keepAliveTime is less than zero + */ + public void testConstructor4() { + try { + new CustomTPE(1,2,-1L,MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if corePoolSize is greater than the maximumPoolSize + */ + public void testConstructor5() { + try { + new CustomTPE(2,1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if workQueue is set to null + */ + public void testConstructorNullPointerException() { + try { + new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS,null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + + + /** + * Constructor throws if corePoolSize argument is less than zero + */ + public void testConstructor6() { + try { + new CustomTPE(-1,1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if maximumPoolSize is less than zero + */ + public void testConstructor7() { + try { + new CustomTPE(1,-1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if maximumPoolSize is equal to zero + */ + public void testConstructor8() { + try { + new CustomTPE(1,0,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if keepAliveTime is less than zero + */ + public void testConstructor9() { + try { + new CustomTPE(1,2,-1L,MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if corePoolSize is greater than the maximumPoolSize + */ + public void testConstructor10() { + try { + new CustomTPE(2,1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if workQueue is set to null + */ + public void testConstructorNullPointerException2() { + try { + new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS,null,new SimpleThreadFactory()); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Constructor throws if threadFactory is set to null + */ + public void testConstructorNullPointerException3() { + try { + ThreadFactory f = null; + new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS,new ArrayBlockingQueue<Runnable>(10),f); + shouldThrow(); + } catch (NullPointerException success) {} + } + + + /** + * Constructor throws if corePoolSize argument is less than zero + */ + public void testConstructor11() { + try { + new CustomTPE(-1,1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new NoOpREHandler()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if maximumPoolSize is less than zero + */ + public void testConstructor12() { + try { + new CustomTPE(1,-1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new NoOpREHandler()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if maximumPoolSize is equal to zero + */ + public void testConstructor13() { + try { + new CustomTPE(1,0,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new NoOpREHandler()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if keepAliveTime is less than zero + */ + public void testConstructor14() { + try { + new CustomTPE(1,2,-1L,MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new NoOpREHandler()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if corePoolSize is greater than the maximumPoolSize + */ + public void testConstructor15() { + try { + new CustomTPE(2,1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new NoOpREHandler()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if workQueue is set to null + */ + public void testConstructorNullPointerException4() { + try { + new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS,null,new NoOpREHandler()); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Constructor throws if handler is set to null + */ + public void testConstructorNullPointerException5() { + try { + RejectedExecutionHandler r = null; + new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS,new ArrayBlockingQueue<Runnable>(10),r); + shouldThrow(); + } catch (NullPointerException success) {} + } + + + /** + * Constructor throws if corePoolSize argument is less than zero + */ + public void testConstructor16() { + try { + new CustomTPE(-1,1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory(),new NoOpREHandler()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if maximumPoolSize is less than zero + */ + public void testConstructor17() { + try { + new CustomTPE(1,-1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory(),new NoOpREHandler()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if maximumPoolSize is equal to zero + */ + public void testConstructor18() { + try { + new CustomTPE(1,0,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory(),new NoOpREHandler()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if keepAliveTime is less than zero + */ + public void testConstructor19() { + try { + new CustomTPE(1,2,-1L,MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory(),new NoOpREHandler()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if corePoolSize is greater than the maximumPoolSize + */ + public void testConstructor20() { + try { + new CustomTPE(2,1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory(),new NoOpREHandler()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if workQueue is set to null + */ + public void testConstructorNullPointerException6() { + try { + new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS,null,new SimpleThreadFactory(),new NoOpREHandler()); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Constructor throws if handler is set to null + */ + public void testConstructorNullPointerException7() { + try { + RejectedExecutionHandler r = null; + new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS,new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory(),r); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Constructor throws if ThreadFactory is set top null + */ + public void testConstructorNullPointerException8() { + try { + ThreadFactory f = null; + new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS,new ArrayBlockingQueue<Runnable>(10),f,new NoOpREHandler()); + shouldThrow(); + } catch (NullPointerException success) {} + } + + + /** + * execute throws RejectedExecutionException + * if saturated. + */ + public void testSaturatedExecute() { + ThreadPoolExecutor p = new CustomTPE(1,1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(1)); + try { + + for (int i = 0; i < 5; ++i) { + p.execute(new MediumRunnable()); + } + shouldThrow(); + } catch (RejectedExecutionException success) {} + joinPool(p); + } + + /** + * executor using CallerRunsPolicy runs task if saturated. + */ + public void testSaturatedExecute2() { + RejectedExecutionHandler h = new CustomTPE.CallerRunsPolicy(); + ThreadPoolExecutor p = new CustomTPE(1,1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(1), h); + try { + + TrackedNoOpRunnable[] tasks = new TrackedNoOpRunnable[5]; + for (int i = 0; i < 5; ++i) { + tasks[i] = new TrackedNoOpRunnable(); + } + TrackedLongRunnable mr = new TrackedLongRunnable(); + p.execute(mr); + for (int i = 0; i < 5; ++i) { + p.execute(tasks[i]); + } + for (int i = 1; i < 5; ++i) { + assertTrue(tasks[i].done); + } + try { p.shutdownNow(); } catch (SecurityException ok) { return; } + } finally { + joinPool(p); + } + } + + /** + * executor using DiscardPolicy drops task if saturated. + */ + public void testSaturatedExecute3() { + RejectedExecutionHandler h = new CustomTPE.DiscardPolicy(); + ThreadPoolExecutor p = new CustomTPE(1,1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(1), h); + try { + + TrackedNoOpRunnable[] tasks = new TrackedNoOpRunnable[5]; + for (int i = 0; i < 5; ++i) { + tasks[i] = new TrackedNoOpRunnable(); + } + p.execute(new TrackedLongRunnable()); + for (int i = 0; i < 5; ++i) { + p.execute(tasks[i]); + } + for (int i = 0; i < 5; ++i) { + assertFalse(tasks[i].done); + } + try { p.shutdownNow(); } catch (SecurityException ok) { return; } + } finally { + joinPool(p); + } + } + + /** + * executor using DiscardOldestPolicy drops oldest task if saturated. + */ + public void testSaturatedExecute4() { + RejectedExecutionHandler h = new CustomTPE.DiscardOldestPolicy(); + ThreadPoolExecutor p = new CustomTPE(1,1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(1), h); + try { + p.execute(new TrackedLongRunnable()); + TrackedLongRunnable r2 = new TrackedLongRunnable(); + p.execute(r2); + assertTrue(p.getQueue().contains(r2)); + TrackedNoOpRunnable r3 = new TrackedNoOpRunnable(); + p.execute(r3); + assertFalse(p.getQueue().contains(r2)); + assertTrue(p.getQueue().contains(r3)); + try { p.shutdownNow(); } catch (SecurityException ok) { return; } + } finally { + joinPool(p); + } + } + + /** + * execute throws RejectedExecutionException if shutdown + */ + public void testRejectedExecutionExceptionOnShutdown() { + ThreadPoolExecutor tpe = + new CustomTPE(1,1,LONG_DELAY_MS, MILLISECONDS,new ArrayBlockingQueue<Runnable>(1)); + try { tpe.shutdown(); } catch (SecurityException ok) { return; } + try { + tpe.execute(new NoOpRunnable()); + shouldThrow(); + } catch (RejectedExecutionException success) {} + + joinPool(tpe); + } + + /** + * execute using CallerRunsPolicy drops task on shutdown + */ + public void testCallerRunsOnShutdown() { + RejectedExecutionHandler h = new CustomTPE.CallerRunsPolicy(); + ThreadPoolExecutor p = new CustomTPE(1,1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(1), h); + + try { p.shutdown(); } catch (SecurityException ok) { return; } + try { + TrackedNoOpRunnable r = new TrackedNoOpRunnable(); + p.execute(r); + assertFalse(r.done); + } finally { + joinPool(p); + } + } + + /** + * execute using DiscardPolicy drops task on shutdown + */ + public void testDiscardOnShutdown() { + RejectedExecutionHandler h = new CustomTPE.DiscardPolicy(); + ThreadPoolExecutor p = new CustomTPE(1,1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(1), h); + + try { p.shutdown(); } catch (SecurityException ok) { return; } + try { + TrackedNoOpRunnable r = new TrackedNoOpRunnable(); + p.execute(r); + assertFalse(r.done); + } finally { + joinPool(p); + } + } + + + /** + * execute using DiscardOldestPolicy drops task on shutdown + */ + public void testDiscardOldestOnShutdown() { + RejectedExecutionHandler h = new CustomTPE.DiscardOldestPolicy(); + ThreadPoolExecutor p = new CustomTPE(1,1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(1), h); + + try { p.shutdown(); } catch (SecurityException ok) { return; } + try { + TrackedNoOpRunnable r = new TrackedNoOpRunnable(); + p.execute(r); + assertFalse(r.done); + } finally { + joinPool(p); + } + } + + + /** + * execute (null) throws NPE + */ + public void testExecuteNull() { + ThreadPoolExecutor tpe = null; + try { + tpe = new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS,new ArrayBlockingQueue<Runnable>(10)); + tpe.execute(null); + shouldThrow(); + } catch (NullPointerException success) {} + + joinPool(tpe); + } + + /** + * setCorePoolSize of negative value throws IllegalArgumentException + */ + public void testCorePoolSizeIllegalArgumentException() { + ThreadPoolExecutor tpe = + new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS,new ArrayBlockingQueue<Runnable>(10)); + try { + tpe.setCorePoolSize(-1); + shouldThrow(); + } catch (IllegalArgumentException success) { + } finally { + try { tpe.shutdown(); } catch (SecurityException ok) { return; } + } + joinPool(tpe); + } + + /** + * setMaximumPoolSize(int) throws IllegalArgumentException if + * given a value less the core pool size + */ + public void testMaximumPoolSizeIllegalArgumentException() { + ThreadPoolExecutor tpe = + new CustomTPE(2,3,LONG_DELAY_MS, MILLISECONDS,new ArrayBlockingQueue<Runnable>(10)); + try { + tpe.setMaximumPoolSize(1); + shouldThrow(); + } catch (IllegalArgumentException success) { + } finally { + try { tpe.shutdown(); } catch (SecurityException ok) { return; } + } + joinPool(tpe); + } + + /** + * setMaximumPoolSize throws IllegalArgumentException + * if given a negative value + */ + public void testMaximumPoolSizeIllegalArgumentException2() { + ThreadPoolExecutor tpe = + new CustomTPE(2,3,LONG_DELAY_MS, MILLISECONDS,new ArrayBlockingQueue<Runnable>(10)); + try { + tpe.setMaximumPoolSize(-1); + shouldThrow(); + } catch (IllegalArgumentException success) { + } finally { + try { tpe.shutdown(); } catch (SecurityException ok) { return; } + } + joinPool(tpe); + } + + + /** + * setKeepAliveTime throws IllegalArgumentException + * when given a negative value + */ + public void testKeepAliveTimeIllegalArgumentException() { + ThreadPoolExecutor tpe = + new CustomTPE(2,3,LONG_DELAY_MS, MILLISECONDS,new ArrayBlockingQueue<Runnable>(10)); + + try { + tpe.setKeepAliveTime(-1,MILLISECONDS); + shouldThrow(); + } catch (IllegalArgumentException success) { + } finally { + try { tpe.shutdown(); } catch (SecurityException ok) { return; } + } + joinPool(tpe); + } + + /** + * terminated() is called on termination + */ + public void testTerminated() { + CustomTPE tpe = new CustomTPE(); + try { tpe.shutdown(); } catch (SecurityException ok) { return; } + assertTrue(tpe.terminatedCalled); + joinPool(tpe); + } + + /** + * beforeExecute and afterExecute are called when executing task + */ + public void testBeforeAfter() throws InterruptedException { + CustomTPE tpe = new CustomTPE(); + try { + TrackedNoOpRunnable r = new TrackedNoOpRunnable(); + tpe.execute(r); + Thread.sleep(SHORT_DELAY_MS); + assertTrue(r.done); + assertTrue(tpe.beforeCalled); + assertTrue(tpe.afterCalled); + try { tpe.shutdown(); } catch (SecurityException ok) { return; } + } finally { + joinPool(tpe); + } + } + + /** + * completed submit of callable returns result + */ + public void testSubmitCallable() throws Exception { + ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + try { + Future<String> future = e.submit(new StringTask()); + String result = future.get(); + assertSame(TEST_STRING, result); + } finally { + joinPool(e); + } + } + + /** + * completed submit of runnable returns successfully + */ + public void testSubmitRunnable() throws Exception { + ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + try { + Future<?> future = e.submit(new NoOpRunnable()); + future.get(); + assertTrue(future.isDone()); + } finally { + joinPool(e); + } + } + + /** + * completed submit of (runnable, result) returns result + */ + public void testSubmitRunnable2() throws Exception { + ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + try { + Future<String> future = e.submit(new NoOpRunnable(), TEST_STRING); + String result = future.get(); + assertSame(TEST_STRING, result); + } finally { + joinPool(e); + } + } + + + /** + * invokeAny(null) throws NPE + */ + public void testInvokeAny1() throws Exception { + ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + try { + e.invokeAny(null); + shouldThrow(); + } catch (NullPointerException success) { + } finally { + joinPool(e); + } + } + + /** + * invokeAny(empty collection) throws IAE + */ + public void testInvokeAny2() throws Exception { + ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + try { + e.invokeAny(new ArrayList<Callable<String>>()); + shouldThrow(); + } catch (IllegalArgumentException success) { + } finally { + joinPool(e); + } + } + + /** + * invokeAny(c) throws NPE if c has null elements + */ + public void testInvokeAny3() throws Exception { + CountDownLatch latch = new CountDownLatch(1); + ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(latchAwaitingStringTask(latch)); + l.add(null); + try { + e.invokeAny(l); + shouldThrow(); + } catch (NullPointerException success) { + } finally { + latch.countDown(); + joinPool(e); + } + } + + /** + * invokeAny(c) throws ExecutionException if no task completes + */ + public void testInvokeAny4() throws Exception { + ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new NPETask()); + try { + e.invokeAny(l); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } finally { + joinPool(e); + } + } + + /** + * invokeAny(c) returns result of some task + */ + public void testInvokeAny5() throws Exception { + ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + try { + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new StringTask()); + l.add(new StringTask()); + String result = e.invokeAny(l); + assertSame(TEST_STRING, result); + } finally { + joinPool(e); + } + } + + /** + * invokeAll(null) throws NPE + */ + public void testInvokeAll1() throws Exception { + ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + try { + e.invokeAll(null); + shouldThrow(); + } catch (NullPointerException success) { + } finally { + joinPool(e); + } + } + + /** + * invokeAll(empty collection) returns empty collection + */ + public void testInvokeAll2() throws Exception { + ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + try { + List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>()); + assertTrue(r.isEmpty()); + } finally { + joinPool(e); + } + } + + /** + * invokeAll(c) throws NPE if c has null elements + */ + public void testInvokeAll3() throws Exception { + ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new StringTask()); + l.add(null); + try { + e.invokeAll(l); + shouldThrow(); + } catch (NullPointerException success) { + } finally { + joinPool(e); + } + } + + /** + * get of element of invokeAll(c) throws exception on failed task + */ + public void testInvokeAll4() throws Exception { + ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new NPETask()); + List<Future<String>> futures = e.invokeAll(l); + assertEquals(1, futures.size()); + try { + futures.get(0).get(); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } finally { + joinPool(e); + } + } + + /** + * invokeAll(c) returns results of all completed tasks + */ + public void testInvokeAll5() throws Exception { + ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + try { + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new StringTask()); + l.add(new StringTask()); + List<Future<String>> futures = e.invokeAll(l); + assertEquals(2, futures.size()); + for (Future<String> future : futures) + assertSame(TEST_STRING, future.get()); + } finally { + joinPool(e); + } + } + + + + /** + * timed invokeAny(null) throws NPE + */ + public void testTimedInvokeAny1() throws Exception { + ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + try { + e.invokeAny(null, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) { + } finally { + joinPool(e); + } + } + + /** + * timed invokeAny(,,null) throws NPE + */ + public void testTimedInvokeAnyNullTimeUnit() throws Exception { + ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new StringTask()); + try { + e.invokeAny(l, MEDIUM_DELAY_MS, null); + shouldThrow(); + } catch (NullPointerException success) { + } finally { + joinPool(e); + } + } + + /** + * timed invokeAny(empty collection) throws IAE + */ + public void testTimedInvokeAny2() throws Exception { + ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + try { + e.invokeAny(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (IllegalArgumentException success) { + } finally { + joinPool(e); + } + } + + /** + * timed invokeAny(c) throws NPE if c has null elements + */ + public void testTimedInvokeAny3() throws Exception { + CountDownLatch latch = new CountDownLatch(1); + ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(latchAwaitingStringTask(latch)); + l.add(null); + try { + e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) { + } finally { + latch.countDown(); + joinPool(e); + } + } + + /** + * timed invokeAny(c) throws ExecutionException if no task completes + */ + public void testTimedInvokeAny4() throws Exception { + ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new NPETask()); + try { + e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } finally { + joinPool(e); + } + } + + /** + * timed invokeAny(c) returns result of some task + */ + public void testTimedInvokeAny5() throws Exception { + ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + try { + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new StringTask()); + l.add(new StringTask()); + String result = e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS); + assertSame(TEST_STRING, result); + } finally { + joinPool(e); + } + } + + /** + * timed invokeAll(null) throws NPE + */ + public void testTimedInvokeAll1() throws Exception { + ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + try { + e.invokeAll(null, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) { + } finally { + joinPool(e); + } + } + + /** + * timed invokeAll(,,null) throws NPE + */ + public void testTimedInvokeAllNullTimeUnit() throws Exception { + ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new StringTask()); + try { + e.invokeAll(l, MEDIUM_DELAY_MS, null); + shouldThrow(); + } catch (NullPointerException success) { + } finally { + joinPool(e); + } + } + + /** + * timed invokeAll(empty collection) returns empty collection + */ + public void testTimedInvokeAll2() throws Exception { + ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + try { + List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS); + assertTrue(r.isEmpty()); + } finally { + joinPool(e); + } + } + + /** + * timed invokeAll(c) throws NPE if c has null elements + */ + public void testTimedInvokeAll3() throws Exception { + ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new StringTask()); + l.add(null); + try { + e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) { + } finally { + joinPool(e); + } + } + + /** + * get of element of invokeAll(c) throws exception on failed task + */ + public void testTimedInvokeAll4() throws Exception { + ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new NPETask()); + List<Future<String>> futures = + e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS); + assertEquals(1, futures.size()); + try { + futures.get(0).get(); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } finally { + joinPool(e); + } + } + + /** + * timed invokeAll(c) returns results of all completed tasks + */ + public void testTimedInvokeAll5() throws Exception { + ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + try { + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new StringTask()); + l.add(new StringTask()); + List<Future<String>> futures = + e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS); + assertEquals(2, futures.size()); + for (Future<String> future : futures) + assertSame(TEST_STRING, future.get()); + } finally { + joinPool(e); + } + } + + /** + * timed invokeAll(c) cancels tasks not completed by timeout + */ + public void testTimedInvokeAll6() throws Exception { + ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + try { + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new StringTask()); + l.add(Executors.callable(new MediumPossiblyInterruptedRunnable(), TEST_STRING)); + l.add(new StringTask()); + List<Future<String>> futures = + e.invokeAll(l, SHORT_DELAY_MS, MILLISECONDS); + assertEquals(3, futures.size()); + Iterator<Future<String>> it = futures.iterator(); + Future<String> f1 = it.next(); + Future<String> f2 = it.next(); + Future<String> f3 = it.next(); + assertTrue(f1.isDone()); + assertTrue(f2.isDone()); + assertTrue(f3.isDone()); + assertFalse(f1.isCancelled()); + assertTrue(f2.isCancelled()); + } finally { + joinPool(e); + } + } + + /** + * Execution continues if there is at least one thread even if + * thread factory fails to create more + */ + public void testFailingThreadFactory() throws InterruptedException { + ExecutorService e = new CustomTPE(100, 100, LONG_DELAY_MS, MILLISECONDS, new LinkedBlockingQueue<Runnable>(), new FailingThreadFactory()); + try { + for (int k = 0; k < 100; ++k) { + e.execute(new NoOpRunnable()); + } + Thread.sleep(LONG_DELAY_MS); + } finally { + joinPool(e); + } + } + + /** + * allowsCoreThreadTimeOut is by default false. + */ + public void testAllowsCoreThreadTimeOut() { + ThreadPoolExecutor tpe = new CustomTPE(2, 2, 1000, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + assertFalse(tpe.allowsCoreThreadTimeOut()); + joinPool(tpe); + } + + /** + * allowCoreThreadTimeOut(true) causes idle threads to time out + */ + public void testAllowCoreThreadTimeOut_true() throws InterruptedException { + ThreadPoolExecutor tpe = new CustomTPE(2, 10, 10, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + tpe.allowCoreThreadTimeOut(true); + tpe.execute(new NoOpRunnable()); + try { + Thread.sleep(MEDIUM_DELAY_MS); + assertEquals(0, tpe.getPoolSize()); + } finally { + joinPool(tpe); + } + } + + /** + * allowCoreThreadTimeOut(false) causes idle threads not to time out + */ + public void testAllowCoreThreadTimeOut_false() throws InterruptedException { + ThreadPoolExecutor tpe = new CustomTPE(2, 10, 10, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + tpe.allowCoreThreadTimeOut(false); + tpe.execute(new NoOpRunnable()); + try { + Thread.sleep(MEDIUM_DELAY_MS); + assertTrue(tpe.getPoolSize() >= 1); + } finally { + joinPool(tpe); + } + } + +} diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/ThreadPoolExecutorTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/ThreadPoolExecutorTest.java index ee27e51..9b7fcac 100755 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/ThreadPoolExecutorTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/ThreadPoolExecutorTest.java @@ -2,13 +2,14 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import java.util.concurrent.*; +import static java.util.concurrent.TimeUnit.MILLISECONDS; import java.util.concurrent.atomic.*; import junit.framework.*; import java.util.*; @@ -17,13 +18,13 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { public static Test suite() { return new TestSuite(ThreadPoolExecutorTest.class); } - + static class ExtendedTPE extends ThreadPoolExecutor { volatile boolean beforeCalled = false; volatile boolean afterCalled = false; volatile boolean terminatedCalled = false; public ExtendedTPE() { - super(1, 1, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>()); + super(1, 1, LONG_DELAY_MS, MILLISECONDS, new SynchronousQueue<Runnable>()); } protected void beforeExecute(Thread t, Runnable r) { beforeCalled = true; @@ -36,50 +37,37 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { } } - static class FailingThreadFactory implements ThreadFactory{ + static class FailingThreadFactory implements ThreadFactory { int calls = 0; - public Thread newThread(Runnable r){ + public Thread newThread(Runnable r) { if (++calls > 1) return null; return new Thread(r); - } + } } - + /** * execute successfully executes a runnable */ - public void testExecute() { - ThreadPoolExecutor p1 = new ThreadPoolExecutor(1, 1, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + public void testExecute() throws InterruptedException { + ThreadPoolExecutor p1 = new ThreadPoolExecutor(1, 1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); try { - p1.execute(new Runnable() { - public void run() { - try { - Thread.sleep(SHORT_DELAY_MS); - } catch(InterruptedException e){ - threadUnexpectedException(); - } - } - }); + p1.execute(new ShortRunnable()); Thread.sleep(SMALL_DELAY_MS); - } catch(InterruptedException e){ - unexpectedException(); - } - joinPool(p1); + } finally { + joinPool(p1); + } } /** * getActiveCount increases but doesn't overestimate, when a * thread becomes active */ - public void testGetActiveCount() { - ThreadPoolExecutor p2 = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + public void testGetActiveCount() throws InterruptedException { + ThreadPoolExecutor p2 = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); assertEquals(0, p2.getActiveCount()); p2.execute(new MediumRunnable()); - try { - Thread.sleep(SHORT_DELAY_MS); - } catch(Exception e){ - unexpectedException(); - } + Thread.sleep(SHORT_DELAY_MS); assertEquals(1, p2.getActiveCount()); joinPool(p2); } @@ -88,7 +76,7 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { * prestartCoreThread starts a thread if under corePoolSize, else doesn't */ public void testPrestartCoreThread() { - ThreadPoolExecutor p2 = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + ThreadPoolExecutor p2 = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); assertEquals(0, p2.getPoolSize()); assertTrue(p2.prestartCoreThread()); assertEquals(1, p2.getPoolSize()); @@ -103,7 +91,7 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { * prestartAllCoreThreads starts all corePoolSize threads */ public void testPrestartAllCoreThreads() { - ThreadPoolExecutor p2 = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + ThreadPoolExecutor p2 = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); assertEquals(0, p2.getPoolSize()); p2.prestartAllCoreThreads(); assertEquals(2, p2.getPoolSize()); @@ -111,59 +99,55 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { assertEquals(2, p2.getPoolSize()); joinPool(p2); } - + /** * getCompletedTaskCount increases, but doesn't overestimate, * when tasks complete */ - public void testGetCompletedTaskCount() { - ThreadPoolExecutor p2 = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + public void testGetCompletedTaskCount() throws InterruptedException { + ThreadPoolExecutor p2 = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); assertEquals(0, p2.getCompletedTaskCount()); p2.execute(new ShortRunnable()); - try { - Thread.sleep(SMALL_DELAY_MS); - } catch(Exception e){ - unexpectedException(); - } + Thread.sleep(SMALL_DELAY_MS); assertEquals(1, p2.getCompletedTaskCount()); - try { p2.shutdown(); } catch(SecurityException ok) { return; } + try { p2.shutdown(); } catch (SecurityException ok) { return; } joinPool(p2); } - + /** * getCorePoolSize returns size given in constructor if not otherwise set */ public void testGetCorePoolSize() { - ThreadPoolExecutor p1 = new ThreadPoolExecutor(1, 1, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + ThreadPoolExecutor p1 = new ThreadPoolExecutor(1, 1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); assertEquals(1, p1.getCorePoolSize()); joinPool(p1); } - + /** * getKeepAliveTime returns value given in constructor if not otherwise set */ public void testGetKeepAliveTime() { - ThreadPoolExecutor p2 = new ThreadPoolExecutor(2, 2, 1000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + ThreadPoolExecutor p2 = new ThreadPoolExecutor(2, 2, 1000, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); assertEquals(1, p2.getKeepAliveTime(TimeUnit.SECONDS)); joinPool(p2); } - /** + /** * getThreadFactory returns factory in constructor if not set */ public void testGetThreadFactory() { ThreadFactory tf = new SimpleThreadFactory(); - ThreadPoolExecutor p = new ThreadPoolExecutor(1,2,LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10), tf, new NoOpREHandler()); + ThreadPoolExecutor p = new ThreadPoolExecutor(1,2,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10), tf, new NoOpREHandler()); assertSame(tf, p.getThreadFactory()); joinPool(p); } - /** + /** * setThreadFactory sets the thread factory returned by getThreadFactory */ public void testSetThreadFactory() { - ThreadPoolExecutor p = new ThreadPoolExecutor(1,2,LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + ThreadPoolExecutor p = new ThreadPoolExecutor(1,2,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); ThreadFactory tf = new SimpleThreadFactory(); p.setThreadFactory(tf); assertSame(tf, p.getThreadFactory()); @@ -171,11 +155,11 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { } - /** + /** * setThreadFactory(null) throws NPE */ public void testSetThreadFactoryNull() { - ThreadPoolExecutor p = new ThreadPoolExecutor(1,2,LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + ThreadPoolExecutor p = new ThreadPoolExecutor(1,2,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); try { p.setThreadFactory(null); shouldThrow(); @@ -185,22 +169,22 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { } } - /** + /** * getRejectedExecutionHandler returns handler in constructor if not set */ public void testGetRejectedExecutionHandler() { RejectedExecutionHandler h = new NoOpREHandler(); - ThreadPoolExecutor p = new ThreadPoolExecutor(1,2,LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10), h); + ThreadPoolExecutor p = new ThreadPoolExecutor(1,2,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10), h); assertSame(h, p.getRejectedExecutionHandler()); joinPool(p); } - /** + /** * setRejectedExecutionHandler sets the handler returned by * getRejectedExecutionHandler */ public void testSetRejectedExecutionHandler() { - ThreadPoolExecutor p = new ThreadPoolExecutor(1,2,LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + ThreadPoolExecutor p = new ThreadPoolExecutor(1,2,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); RejectedExecutionHandler h = new NoOpREHandler(); p.setRejectedExecutionHandler(h); assertSame(h, p.getRejectedExecutionHandler()); @@ -208,11 +192,11 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { } - /** + /** * setRejectedExecutionHandler(null) throws NPE */ public void testSetRejectedExecutionHandlerNull() { - ThreadPoolExecutor p = new ThreadPoolExecutor(1,2,LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + ThreadPoolExecutor p = new ThreadPoolExecutor(1,2,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); try { p.setRejectedExecutionHandler(null); shouldThrow(); @@ -222,124 +206,108 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { } } - + /** * getLargestPoolSize increases, but doesn't overestimate, when * multiple threads active */ - public void testGetLargestPoolSize() { - ThreadPoolExecutor p2 = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); - try { - assertEquals(0, p2.getLargestPoolSize()); - p2.execute(new MediumRunnable()); - p2.execute(new MediumRunnable()); - Thread.sleep(SHORT_DELAY_MS); - assertEquals(2, p2.getLargestPoolSize()); - } catch(Exception e){ - unexpectedException(); - } + public void testGetLargestPoolSize() throws InterruptedException { + ThreadPoolExecutor p2 = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + assertEquals(0, p2.getLargestPoolSize()); + p2.execute(new MediumRunnable()); + p2.execute(new MediumRunnable()); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(2, p2.getLargestPoolSize()); joinPool(p2); } - + /** * getMaximumPoolSize returns value given in constructor if not * otherwise set */ public void testGetMaximumPoolSize() { - ThreadPoolExecutor p2 = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + ThreadPoolExecutor p2 = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); assertEquals(2, p2.getMaximumPoolSize()); joinPool(p2); } - + /** * getPoolSize increases, but doesn't overestimate, when threads * become active */ public void testGetPoolSize() { - ThreadPoolExecutor p1 = new ThreadPoolExecutor(1, 1, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + ThreadPoolExecutor p1 = new ThreadPoolExecutor(1, 1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); assertEquals(0, p1.getPoolSize()); p1.execute(new MediumRunnable()); assertEquals(1, p1.getPoolSize()); joinPool(p1); } - + /** * getTaskCount increases, but doesn't overestimate, when tasks submitted */ - public void testGetTaskCount() { - ThreadPoolExecutor p1 = new ThreadPoolExecutor(1, 1, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); - try { - assertEquals(0, p1.getTaskCount()); - p1.execute(new MediumRunnable()); - Thread.sleep(SHORT_DELAY_MS); - assertEquals(1, p1.getTaskCount()); - } catch(Exception e){ - unexpectedException(); - } + public void testGetTaskCount() throws InterruptedException { + ThreadPoolExecutor p1 = new ThreadPoolExecutor(1, 1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + assertEquals(0, p1.getTaskCount()); + p1.execute(new MediumRunnable()); + Thread.sleep(SHORT_DELAY_MS); + assertEquals(1, p1.getTaskCount()); joinPool(p1); } - + /** * isShutDown is false before shutdown, true after */ public void testIsShutdown() { - - ThreadPoolExecutor p1 = new ThreadPoolExecutor(1, 1, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + + ThreadPoolExecutor p1 = new ThreadPoolExecutor(1, 1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); assertFalse(p1.isShutdown()); - try { p1.shutdown(); } catch(SecurityException ok) { return; } + try { p1.shutdown(); } catch (SecurityException ok) { return; } assertTrue(p1.isShutdown()); joinPool(p1); } - + /** * isTerminated is false before termination, true after */ - public void testIsTerminated() { - ThreadPoolExecutor p1 = new ThreadPoolExecutor(1, 1, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + public void testIsTerminated() throws InterruptedException { + ThreadPoolExecutor p1 = new ThreadPoolExecutor(1, 1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); assertFalse(p1.isTerminated()); try { p1.execute(new MediumRunnable()); } finally { - try { p1.shutdown(); } catch(SecurityException ok) { return; } + try { p1.shutdown(); } catch (SecurityException ok) { return; } } - try { - assertTrue(p1.awaitTermination(LONG_DELAY_MS, TimeUnit.MILLISECONDS)); - assertTrue(p1.isTerminated()); - } catch(Exception e){ - unexpectedException(); - } + assertTrue(p1.awaitTermination(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(p1.isTerminated()); } /** * isTerminating is not true when running or when terminated */ - public void testIsTerminating() { - ThreadPoolExecutor p1 = new ThreadPoolExecutor(1, 1, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + public void testIsTerminating() throws InterruptedException { + ThreadPoolExecutor p1 = new ThreadPoolExecutor(1, 1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); assertFalse(p1.isTerminating()); try { p1.execute(new SmallRunnable()); assertFalse(p1.isTerminating()); } finally { - try { p1.shutdown(); } catch(SecurityException ok) { return; } + try { p1.shutdown(); } catch (SecurityException ok) { return; } } - try { - assertTrue(p1.awaitTermination(LONG_DELAY_MS, TimeUnit.MILLISECONDS)); - assertTrue(p1.isTerminated()); - assertFalse(p1.isTerminating()); - } catch(Exception e){ - unexpectedException(); - } + assertTrue(p1.awaitTermination(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(p1.isTerminated()); + assertFalse(p1.isTerminating()); } /** * getQueue returns the work queue, which contains queued tasks */ - public void testGetQueue() { + public void testGetQueue() throws InterruptedException { BlockingQueue<Runnable> q = new ArrayBlockingQueue<Runnable>(10); - ThreadPoolExecutor p1 = new ThreadPoolExecutor(1, 1, LONG_DELAY_MS, TimeUnit.MILLISECONDS, q); + ThreadPoolExecutor p1 = new ThreadPoolExecutor(1, 1, LONG_DELAY_MS, MILLISECONDS, q); FutureTask[] tasks = new FutureTask[5]; - for(int i = 0; i < 5; i++){ + for (int i = 0; i < 5; i++) { tasks[i] = new FutureTask(new MediumPossiblyInterruptedRunnable(), Boolean.TRUE); p1.execute(tasks[i]); } @@ -352,8 +320,6 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { for (int i = 1; i < 5; ++i) tasks[i].cancel(true); p1.shutdownNow(); - } catch(Exception e) { - unexpectedException(); } finally { joinPool(p1); } @@ -362,11 +328,11 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { /** * remove(task) removes queued task, and fails to remove active task */ - public void testRemove() { + public void testRemove() throws InterruptedException { BlockingQueue<Runnable> q = new ArrayBlockingQueue<Runnable>(10); - ThreadPoolExecutor p1 = new ThreadPoolExecutor(1, 1, LONG_DELAY_MS, TimeUnit.MILLISECONDS, q); + ThreadPoolExecutor p1 = new ThreadPoolExecutor(1, 1, LONG_DELAY_MS, MILLISECONDS, q); FutureTask[] tasks = new FutureTask[5]; - for(int i = 0; i < 5; i++){ + for (int i = 0; i < 5; i++) { tasks[i] = new FutureTask(new MediumPossiblyInterruptedRunnable(), Boolean.TRUE); p1.execute(tasks[i]); } @@ -381,8 +347,6 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { assertTrue(q.contains(tasks[3])); assertTrue(p1.remove(tasks[3])); assertFalse(q.contains(tasks[3])); - } catch(Exception e) { - unexpectedException(); } finally { joinPool(p1); } @@ -392,9 +356,9 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { * purge removes cancelled tasks from the queue */ public void testPurge() { - ThreadPoolExecutor p1 = new ThreadPoolExecutor(1, 1, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + ThreadPoolExecutor p1 = new ThreadPoolExecutor(1, 1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); FutureTask[] tasks = new FutureTask[5]; - for(int i = 0; i < 5; i++){ + for (int i = 0; i < 5; i++) { tasks[i] = new FutureTask(new MediumPossiblyInterruptedRunnable(), Boolean.TRUE); p1.execute(tasks[i]); } @@ -410,355 +374,334 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { * shutDownNow returns a list containing tasks that were not run */ public void testShutDownNow() { - ThreadPoolExecutor p1 = new ThreadPoolExecutor(1, 1, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + ThreadPoolExecutor p1 = new ThreadPoolExecutor(1, 1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); List l; try { - for(int i = 0; i < 5; i++) + for (int i = 0; i < 5; i++) p1.execute(new MediumPossiblyInterruptedRunnable()); } finally { try { l = p1.shutdownNow(); } catch (SecurityException ok) { return; } - } assertTrue(p1.isShutdown()); assertTrue(l.size() <= 4); } // Exception Tests - - /** - * Constructor throws if corePoolSize argument is less than zero + + /** + * Constructor throws if corePoolSize argument is less than zero */ public void testConstructor1() { try { - new ThreadPoolExecutor(-1,1,LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + new ThreadPoolExecutor(-1,1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); shouldThrow(); - } - catch (IllegalArgumentException success){} + } catch (IllegalArgumentException success) {} } - - /** - * Constructor throws if maximumPoolSize is less than zero + + /** + * Constructor throws if maximumPoolSize is less than zero */ public void testConstructor2() { try { - new ThreadPoolExecutor(1,-1,LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + new ThreadPoolExecutor(1,-1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); shouldThrow(); - } - catch (IllegalArgumentException success){} + } catch (IllegalArgumentException success) {} } - - /** - * Constructor throws if maximumPoolSize is equal to zero + + /** + * Constructor throws if maximumPoolSize is equal to zero */ public void testConstructor3() { try { - new ThreadPoolExecutor(1,0,LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + new ThreadPoolExecutor(1,0,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); shouldThrow(); - } - catch (IllegalArgumentException success){} + } catch (IllegalArgumentException success) {} } - /** - * Constructor throws if keepAliveTime is less than zero + /** + * Constructor throws if keepAliveTime is less than zero */ public void testConstructor4() { try { - new ThreadPoolExecutor(1,2,-1L,TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + new ThreadPoolExecutor(1,2,-1L,MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); shouldThrow(); - } - catch (IllegalArgumentException success){} + } catch (IllegalArgumentException success) {} } - /** - * Constructor throws if corePoolSize is greater than the maximumPoolSize + /** + * Constructor throws if corePoolSize is greater than the maximumPoolSize */ public void testConstructor5() { try { - new ThreadPoolExecutor(2,1,LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + new ThreadPoolExecutor(2,1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); shouldThrow(); - } - catch (IllegalArgumentException success){} + } catch (IllegalArgumentException success) {} } - - /** - * Constructor throws if workQueue is set to null + + /** + * Constructor throws if workQueue is set to null */ public void testConstructorNullPointerException() { try { - new ThreadPoolExecutor(1,2,LONG_DELAY_MS, TimeUnit.MILLISECONDS,null); + new ThreadPoolExecutor(1,2,LONG_DELAY_MS, MILLISECONDS,null); shouldThrow(); - } - catch (NullPointerException success){} + } catch (NullPointerException success) {} } - - - /** - * Constructor throws if corePoolSize argument is less than zero + + + /** + * Constructor throws if corePoolSize argument is less than zero */ public void testConstructor6() { try { - new ThreadPoolExecutor(-1,1,LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory()); + new ThreadPoolExecutor(-1,1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory()); shouldThrow(); - } catch (IllegalArgumentException success){} + } catch (IllegalArgumentException success) {} } - - /** - * Constructor throws if maximumPoolSize is less than zero + + /** + * Constructor throws if maximumPoolSize is less than zero */ public void testConstructor7() { try { - new ThreadPoolExecutor(1,-1,LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory()); + new ThreadPoolExecutor(1,-1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory()); shouldThrow(); - } - catch (IllegalArgumentException success){} + } catch (IllegalArgumentException success) {} } - /** - * Constructor throws if maximumPoolSize is equal to zero + /** + * Constructor throws if maximumPoolSize is equal to zero */ public void testConstructor8() { try { - new ThreadPoolExecutor(1,0,LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory()); + new ThreadPoolExecutor(1,0,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory()); shouldThrow(); - } - catch (IllegalArgumentException success){} + } catch (IllegalArgumentException success) {} } - /** - * Constructor throws if keepAliveTime is less than zero + /** + * Constructor throws if keepAliveTime is less than zero */ public void testConstructor9() { try { - new ThreadPoolExecutor(1,2,-1L,TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory()); + new ThreadPoolExecutor(1,2,-1L,MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory()); shouldThrow(); - } - catch (IllegalArgumentException success){} + } catch (IllegalArgumentException success) {} } - /** - * Constructor throws if corePoolSize is greater than the maximumPoolSize + /** + * Constructor throws if corePoolSize is greater than the maximumPoolSize */ public void testConstructor10() { try { - new ThreadPoolExecutor(2,1,LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory()); + new ThreadPoolExecutor(2,1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory()); shouldThrow(); - } - catch (IllegalArgumentException success){} + } catch (IllegalArgumentException success) {} } - /** - * Constructor throws if workQueue is set to null + /** + * Constructor throws if workQueue is set to null */ public void testConstructorNullPointerException2() { try { - new ThreadPoolExecutor(1,2,LONG_DELAY_MS, TimeUnit.MILLISECONDS,null,new SimpleThreadFactory()); + new ThreadPoolExecutor(1,2,LONG_DELAY_MS, MILLISECONDS,null,new SimpleThreadFactory()); shouldThrow(); - } - catch (NullPointerException success){} + } catch (NullPointerException success) {} } - /** - * Constructor throws if threadFactory is set to null + /** + * Constructor throws if threadFactory is set to null */ public void testConstructorNullPointerException3() { try { ThreadFactory f = null; - new ThreadPoolExecutor(1,2,LONG_DELAY_MS, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<Runnable>(10),f); + new ThreadPoolExecutor(1,2,LONG_DELAY_MS, MILLISECONDS,new ArrayBlockingQueue<Runnable>(10),f); shouldThrow(); - } - catch (NullPointerException success){} + } catch (NullPointerException success) {} } - - - /** - * Constructor throws if corePoolSize argument is less than zero + + + /** + * Constructor throws if corePoolSize argument is less than zero */ public void testConstructor11() { try { - new ThreadPoolExecutor(-1,1,LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new NoOpREHandler()); + new ThreadPoolExecutor(-1,1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new NoOpREHandler()); shouldThrow(); - } - catch (IllegalArgumentException success){} + } catch (IllegalArgumentException success) {} } - /** - * Constructor throws if maximumPoolSize is less than zero + /** + * Constructor throws if maximumPoolSize is less than zero */ public void testConstructor12() { try { - new ThreadPoolExecutor(1,-1,LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new NoOpREHandler()); + new ThreadPoolExecutor(1,-1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new NoOpREHandler()); shouldThrow(); - } - catch (IllegalArgumentException success){} + } catch (IllegalArgumentException success) {} } - /** - * Constructor throws if maximumPoolSize is equal to zero + /** + * Constructor throws if maximumPoolSize is equal to zero */ public void testConstructor13() { try { - new ThreadPoolExecutor(1,0,LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new NoOpREHandler()); + new ThreadPoolExecutor(1,0,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new NoOpREHandler()); shouldThrow(); - } - catch (IllegalArgumentException success){} + } catch (IllegalArgumentException success) {} } - /** - * Constructor throws if keepAliveTime is less than zero + /** + * Constructor throws if keepAliveTime is less than zero */ public void testConstructor14() { try { - new ThreadPoolExecutor(1,2,-1L,TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new NoOpREHandler()); + new ThreadPoolExecutor(1,2,-1L,MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new NoOpREHandler()); shouldThrow(); - } - catch (IllegalArgumentException success){} + } catch (IllegalArgumentException success) {} } - /** - * Constructor throws if corePoolSize is greater than the maximumPoolSize + /** + * Constructor throws if corePoolSize is greater than the maximumPoolSize */ public void testConstructor15() { try { - new ThreadPoolExecutor(2,1,LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new NoOpREHandler()); + new ThreadPoolExecutor(2,1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new NoOpREHandler()); shouldThrow(); - } - catch (IllegalArgumentException success){} + } catch (IllegalArgumentException success) {} } - /** - * Constructor throws if workQueue is set to null + /** + * Constructor throws if workQueue is set to null */ public void testConstructorNullPointerException4() { try { - new ThreadPoolExecutor(1,2,LONG_DELAY_MS, TimeUnit.MILLISECONDS,null,new NoOpREHandler()); + new ThreadPoolExecutor(1,2,LONG_DELAY_MS, MILLISECONDS,null,new NoOpREHandler()); shouldThrow(); - } - catch (NullPointerException success){} + } catch (NullPointerException success) {} } - /** - * Constructor throws if handler is set to null + /** + * Constructor throws if handler is set to null */ public void testConstructorNullPointerException5() { try { RejectedExecutionHandler r = null; - new ThreadPoolExecutor(1,2,LONG_DELAY_MS, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<Runnable>(10),r); + new ThreadPoolExecutor(1,2,LONG_DELAY_MS, MILLISECONDS,new ArrayBlockingQueue<Runnable>(10),r); shouldThrow(); - } - catch (NullPointerException success){} + } catch (NullPointerException success) {} } - - /** - * Constructor throws if corePoolSize argument is less than zero + + /** + * Constructor throws if corePoolSize argument is less than zero */ public void testConstructor16() { try { - new ThreadPoolExecutor(-1,1,LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory(),new NoOpREHandler()); + new ThreadPoolExecutor(-1,1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory(),new NoOpREHandler()); shouldThrow(); - } - catch (IllegalArgumentException success){} + } catch (IllegalArgumentException success) {} } - /** - * Constructor throws if maximumPoolSize is less than zero + /** + * Constructor throws if maximumPoolSize is less than zero */ public void testConstructor17() { try { - new ThreadPoolExecutor(1,-1,LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory(),new NoOpREHandler()); + new ThreadPoolExecutor(1,-1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory(),new NoOpREHandler()); shouldThrow(); - } - catch (IllegalArgumentException success){} + } catch (IllegalArgumentException success) {} } - /** - * Constructor throws if maximumPoolSize is equal to zero + /** + * Constructor throws if maximumPoolSize is equal to zero */ public void testConstructor18() { try { - new ThreadPoolExecutor(1,0,LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory(),new NoOpREHandler()); + new ThreadPoolExecutor(1,0,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory(),new NoOpREHandler()); shouldThrow(); - } - catch (IllegalArgumentException success){} + } catch (IllegalArgumentException success) {} } - /** - * Constructor throws if keepAliveTime is less than zero + /** + * Constructor throws if keepAliveTime is less than zero */ public void testConstructor19() { try { - new ThreadPoolExecutor(1,2,-1L,TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory(),new NoOpREHandler()); + new ThreadPoolExecutor(1,2,-1L,MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory(),new NoOpREHandler()); shouldThrow(); - } - catch (IllegalArgumentException success){} + } catch (IllegalArgumentException success) {} } - /** - * Constructor throws if corePoolSize is greater than the maximumPoolSize + /** + * Constructor throws if corePoolSize is greater than the maximumPoolSize */ public void testConstructor20() { try { - new ThreadPoolExecutor(2,1,LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory(),new NoOpREHandler()); + new ThreadPoolExecutor(2,1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory(),new NoOpREHandler()); shouldThrow(); - } - catch (IllegalArgumentException success){} + } catch (IllegalArgumentException success) {} } - /** - * Constructor throws if workQueue is set to null + /** + * Constructor throws if workQueue is set to null */ public void testConstructorNullPointerException6() { try { - new ThreadPoolExecutor(1,2,LONG_DELAY_MS, TimeUnit.MILLISECONDS,null,new SimpleThreadFactory(),new NoOpREHandler()); + new ThreadPoolExecutor(1,2,LONG_DELAY_MS, MILLISECONDS,null,new SimpleThreadFactory(),new NoOpREHandler()); shouldThrow(); - } - catch (NullPointerException success){} + } catch (NullPointerException success) {} } - /** - * Constructor throws if handler is set to null + /** + * Constructor throws if handler is set to null */ public void testConstructorNullPointerException7() { try { RejectedExecutionHandler r = null; - new ThreadPoolExecutor(1,2,LONG_DELAY_MS, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory(),r); + new ThreadPoolExecutor(1,2,LONG_DELAY_MS, MILLISECONDS,new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory(),r); shouldThrow(); - } - catch (NullPointerException success){} + } catch (NullPointerException success) {} } - /** - * Constructor throws if ThreadFactory is set top null + /** + * Constructor throws if ThreadFactory is set top null */ public void testConstructorNullPointerException8() { try { ThreadFactory f = null; - new ThreadPoolExecutor(1,2,LONG_DELAY_MS, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<Runnable>(10),f,new NoOpREHandler()); + new ThreadPoolExecutor(1,2,LONG_DELAY_MS, MILLISECONDS,new ArrayBlockingQueue<Runnable>(10),f,new NoOpREHandler()); shouldThrow(); - } - catch (NullPointerException successdn8){} + } catch (NullPointerException success) {} } - + /** * execute throws RejectedExecutionException * if saturated. */ public void testSaturatedExecute() { - ThreadPoolExecutor p = new ThreadPoolExecutor(1,1, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(1)); + ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue<Runnable>(1)); try { - - for(int i = 0; i < 5; ++i){ + for (int i = 0; i < 2; ++i) p.execute(new MediumRunnable()); + for (int i = 0; i < 2; ++i) { + try { + p.execute(new MediumRunnable()); + shouldThrow(); + } catch (RejectedExecutionException success) {} } - shouldThrow(); - } catch(RejectedExecutionException success){} - joinPool(p); + } finally { + joinPool(p); + } } /** @@ -766,24 +709,22 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { */ public void testSaturatedExecute2() { RejectedExecutionHandler h = new ThreadPoolExecutor.CallerRunsPolicy(); - ThreadPoolExecutor p = new ThreadPoolExecutor(1,1, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(1), h); + ThreadPoolExecutor p = new ThreadPoolExecutor(1,1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(1), h); try { - + TrackedNoOpRunnable[] tasks = new TrackedNoOpRunnable[5]; - for(int i = 0; i < 5; ++i){ + for (int i = 0; i < 5; ++i) { tasks[i] = new TrackedNoOpRunnable(); } TrackedLongRunnable mr = new TrackedLongRunnable(); p.execute(mr); - for(int i = 0; i < 5; ++i){ + for (int i = 0; i < 5; ++i) { p.execute(tasks[i]); } - for(int i = 1; i < 5; ++i) { + for (int i = 1; i < 5; ++i) { assertTrue(tasks[i].done); } - try { p.shutdownNow(); } catch(SecurityException ok) { return; } - } catch(RejectedExecutionException ex){ - unexpectedException(); + try { p.shutdownNow(); } catch (SecurityException ok) { return; } } finally { joinPool(p); } @@ -794,23 +735,21 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { */ public void testSaturatedExecute3() { RejectedExecutionHandler h = new ThreadPoolExecutor.DiscardPolicy(); - ThreadPoolExecutor p = new ThreadPoolExecutor(1,1, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(1), h); + ThreadPoolExecutor p = new ThreadPoolExecutor(1,1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(1), h); try { - + TrackedNoOpRunnable[] tasks = new TrackedNoOpRunnable[5]; - for(int i = 0; i < 5; ++i){ + for (int i = 0; i < 5; ++i) { tasks[i] = new TrackedNoOpRunnable(); } p.execute(new TrackedLongRunnable()); - for(int i = 0; i < 5; ++i){ + for (int i = 0; i < 5; ++i) { p.execute(tasks[i]); } - for(int i = 0; i < 5; ++i){ + for (int i = 0; i < 5; ++i) { assertFalse(tasks[i].done); } - try { p.shutdownNow(); } catch(SecurityException ok) { return; } - } catch(RejectedExecutionException ex){ - unexpectedException(); + try { p.shutdownNow(); } catch (SecurityException ok) { return; } } finally { joinPool(p); } @@ -821,7 +760,7 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { */ public void testSaturatedExecute4() { RejectedExecutionHandler h = new ThreadPoolExecutor.DiscardOldestPolicy(); - ThreadPoolExecutor p = new ThreadPoolExecutor(1,1, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(1), h); + ThreadPoolExecutor p = new ThreadPoolExecutor(1,1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(1), h); try { p.execute(new TrackedLongRunnable()); TrackedLongRunnable r2 = new TrackedLongRunnable(); @@ -831,9 +770,7 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { p.execute(r3); assertFalse(p.getQueue().contains(r2)); assertTrue(p.getQueue().contains(r3)); - try { p.shutdownNow(); } catch(SecurityException ok) { return; } - } catch(RejectedExecutionException ex){ - unexpectedException(); + try { p.shutdownNow(); } catch (SecurityException ok) { return; } } finally { joinPool(p); } @@ -843,14 +780,14 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { * execute throws RejectedExecutionException if shutdown */ public void testRejectedExecutionExceptionOnShutdown() { - ThreadPoolExecutor tpe = - new ThreadPoolExecutor(1,1,LONG_DELAY_MS, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<Runnable>(1)); - try { tpe.shutdown(); } catch(SecurityException ok) { return; } + ThreadPoolExecutor tpe = + new ThreadPoolExecutor(1,1,LONG_DELAY_MS, MILLISECONDS,new ArrayBlockingQueue<Runnable>(1)); + try { tpe.shutdown(); } catch (SecurityException ok) { return; } try { tpe.execute(new NoOpRunnable()); shouldThrow(); - } catch(RejectedExecutionException success){} - + } catch (RejectedExecutionException success) {} + joinPool(tpe); } @@ -859,15 +796,13 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { */ public void testCallerRunsOnShutdown() { RejectedExecutionHandler h = new ThreadPoolExecutor.CallerRunsPolicy(); - ThreadPoolExecutor p = new ThreadPoolExecutor(1,1, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(1), h); + ThreadPoolExecutor p = new ThreadPoolExecutor(1,1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(1), h); - try { p.shutdown(); } catch(SecurityException ok) { return; } + try { p.shutdown(); } catch (SecurityException ok) { return; } try { TrackedNoOpRunnable r = new TrackedNoOpRunnable(); p.execute(r); assertFalse(r.done); - } catch(RejectedExecutionException success){ - unexpectedException(); } finally { joinPool(p); } @@ -878,15 +813,13 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { */ public void testDiscardOnShutdown() { RejectedExecutionHandler h = new ThreadPoolExecutor.DiscardPolicy(); - ThreadPoolExecutor p = new ThreadPoolExecutor(1,1, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(1), h); + ThreadPoolExecutor p = new ThreadPoolExecutor(1,1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(1), h); - try { p.shutdown(); } catch(SecurityException ok) { return; } + try { p.shutdown(); } catch (SecurityException ok) { return; } try { TrackedNoOpRunnable r = new TrackedNoOpRunnable(); p.execute(r); assertFalse(r.done); - } catch(RejectedExecutionException success){ - unexpectedException(); } finally { joinPool(p); } @@ -898,15 +831,13 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { */ public void testDiscardOldestOnShutdown() { RejectedExecutionHandler h = new ThreadPoolExecutor.DiscardOldestPolicy(); - ThreadPoolExecutor p = new ThreadPoolExecutor(1,1, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(1), h); + ThreadPoolExecutor p = new ThreadPoolExecutor(1,1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(1), h); - try { p.shutdown(); } catch(SecurityException ok) { return; } + try { p.shutdown(); } catch (SecurityException ok) { return; } try { TrackedNoOpRunnable r = new TrackedNoOpRunnable(); p.execute(r); assertFalse(r.done); - } catch(RejectedExecutionException success){ - unexpectedException(); } finally { joinPool(p); } @@ -917,89 +848,87 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { * execute (null) throws NPE */ public void testExecuteNull() { - ThreadPoolExecutor tpe = null; + ThreadPoolExecutor tpe = new ThreadPoolExecutor(1,2,LONG_DELAY_MS, MILLISECONDS,new ArrayBlockingQueue<Runnable>(10)); try { - tpe = new ThreadPoolExecutor(1,2,LONG_DELAY_MS, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<Runnable>(10)); tpe.execute(null); shouldThrow(); - } catch(NullPointerException success){} - + } catch (NullPointerException success) {} + joinPool(tpe); } - + /** * setCorePoolSize of negative value throws IllegalArgumentException */ public void testCorePoolSizeIllegalArgumentException() { - ThreadPoolExecutor tpe = null; - try { - tpe = new ThreadPoolExecutor(1,2,LONG_DELAY_MS, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<Runnable>(10)); - } catch(Exception e){} + ThreadPoolExecutor tpe = + new ThreadPoolExecutor(1, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue<Runnable>(10)); try { tpe.setCorePoolSize(-1); shouldThrow(); - } catch(IllegalArgumentException success){ + } catch (IllegalArgumentException success) { } finally { - try { tpe.shutdown(); } catch(SecurityException ok) { return; } + try { tpe.shutdown(); } catch (SecurityException ok) { return; } } joinPool(tpe); - } + } /** * setMaximumPoolSize(int) throws IllegalArgumentException if * given a value less the core pool size - */ + */ public void testMaximumPoolSizeIllegalArgumentException() { - ThreadPoolExecutor tpe = null; - try { - tpe = new ThreadPoolExecutor(2,3,LONG_DELAY_MS, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<Runnable>(10)); - } catch(Exception e){} + ThreadPoolExecutor tpe = + new ThreadPoolExecutor(2, 3, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue<Runnable>(10)); try { tpe.setMaximumPoolSize(1); shouldThrow(); - } catch(IllegalArgumentException success){ + } catch (IllegalArgumentException success) { } finally { - try { tpe.shutdown(); } catch(SecurityException ok) { return; } + try { tpe.shutdown(); } catch (SecurityException ok) { return; } } joinPool(tpe); } - + /** * setMaximumPoolSize throws IllegalArgumentException * if given a negative value */ public void testMaximumPoolSizeIllegalArgumentException2() { - ThreadPoolExecutor tpe = null; - try { - tpe = new ThreadPoolExecutor(2,3,LONG_DELAY_MS, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<Runnable>(10)); - } catch(Exception e){} + ThreadPoolExecutor tpe = + new ThreadPoolExecutor(2, 3, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue<Runnable>(10)); try { tpe.setMaximumPoolSize(-1); shouldThrow(); - } catch(IllegalArgumentException success){ + } catch (IllegalArgumentException success) { } finally { - try { tpe.shutdown(); } catch(SecurityException ok) { return; } + try { tpe.shutdown(); } catch (SecurityException ok) { return; } } joinPool(tpe); } - + /** * setKeepAliveTime throws IllegalArgumentException * when given a negative value */ public void testKeepAliveTimeIllegalArgumentException() { - ThreadPoolExecutor tpe = null; + ThreadPoolExecutor tpe = + new ThreadPoolExecutor(2, 3, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue<Runnable>(10)); try { - tpe = new ThreadPoolExecutor(2,3,LONG_DELAY_MS, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<Runnable>(10)); - } catch(Exception e){} - - try { - tpe.setKeepAliveTime(-1,TimeUnit.MILLISECONDS); + tpe.setKeepAliveTime(-1,MILLISECONDS); shouldThrow(); - } catch(IllegalArgumentException success){ + } catch (IllegalArgumentException success) { } finally { - try { tpe.shutdown(); } catch(SecurityException ok) { return; } + try { tpe.shutdown(); } catch (SecurityException ok) { return; } } joinPool(tpe); } @@ -1009,7 +938,7 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { */ public void testTerminated() { ExtendedTPE tpe = new ExtendedTPE(); - try { tpe.shutdown(); } catch(SecurityException ok) { return; } + try { tpe.shutdown(); } catch (SecurityException ok) { return; } assertTrue(tpe.terminatedCalled); joinPool(tpe); } @@ -1017,7 +946,7 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { /** * beforeExecute and afterExecute are called when executing task */ - public void testBeforeAfter() { + public void testBeforeAfter() throws InterruptedException { ExtendedTPE tpe = new ExtendedTPE(); try { TrackedNoOpRunnable r = new TrackedNoOpRunnable(); @@ -1026,10 +955,7 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { assertTrue(r.done); assertTrue(tpe.beforeCalled); assertTrue(tpe.afterCalled); - try { tpe.shutdown(); } catch(SecurityException ok) { return; } - } - catch(Exception ex) { - unexpectedException(); + try { tpe.shutdown(); } catch (SecurityException ok) { return; } } finally { joinPool(tpe); } @@ -1038,18 +964,12 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { /** * completed submit of callable returns result */ - public void testSubmitCallable() { - ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + public void testSubmitCallable() throws Exception { + ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); try { Future<String> future = e.submit(new StringTask()); String result = future.get(); assertSame(TEST_STRING, result); - } - catch (ExecutionException ex) { - unexpectedException(); - } - catch (InterruptedException ex) { - unexpectedException(); } finally { joinPool(e); } @@ -1058,18 +978,12 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { /** * completed submit of runnable returns successfully */ - public void testSubmitRunnable() { - ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + public void testSubmitRunnable() throws Exception { + ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); try { Future<?> future = e.submit(new NoOpRunnable()); future.get(); assertTrue(future.isDone()); - } - catch (ExecutionException ex) { - unexpectedException(); - } - catch (InterruptedException ex) { - unexpectedException(); } finally { joinPool(e); } @@ -1078,37 +992,27 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { /** * completed submit of (runnable, result) returns result */ - public void testSubmitRunnable2() { - ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + public void testSubmitRunnable2() throws Exception { + ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); try { Future<String> future = e.submit(new NoOpRunnable(), TEST_STRING); String result = future.get(); assertSame(TEST_STRING, result); - } - catch (ExecutionException ex) { - unexpectedException(); - } - catch (InterruptedException ex) { - unexpectedException(); } finally { joinPool(e); } } - - - /** * invokeAny(null) throws NPE */ - public void testInvokeAny1() { - ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + public void testInvokeAny1() throws Exception { + ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); try { e.invokeAny(null); + shouldThrow(); } catch (NullPointerException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -1117,13 +1021,12 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { /** * invokeAny(empty collection) throws IAE */ - public void testInvokeAny2() { - ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + public void testInvokeAny2() throws Exception { + ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); try { e.invokeAny(new ArrayList<Callable<String>>()); + shouldThrow(); } catch (IllegalArgumentException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -1132,17 +1035,18 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { /** * invokeAny(c) throws NPE if c has null elements */ - public void testInvokeAny3() { - ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + public void testInvokeAny3() throws Exception { + CountDownLatch latch = new CountDownLatch(1); + ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(latchAwaitingStringTask(latch)); + l.add(null); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); - l.add(new StringTask()); - l.add(null); e.invokeAny(l); + shouldThrow(); } catch (NullPointerException success) { - } catch(Exception ex) { - unexpectedException(); } finally { + latch.countDown(); joinPool(e); } } @@ -1150,15 +1054,15 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { /** * invokeAny(c) throws ExecutionException if no task completes */ - public void testInvokeAny4() { - ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + public void testInvokeAny4() throws Exception { + ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new NPETask()); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); - l.add(new NPETask()); e.invokeAny(l); + shouldThrow(); } catch (ExecutionException success) { - } catch(Exception ex) { - unexpectedException(); + assertTrue(success.getCause() instanceof NullPointerException); } finally { joinPool(e); } @@ -1167,17 +1071,14 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { /** * invokeAny(c) returns result of some task */ - public void testInvokeAny5() { - ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + public void testInvokeAny5() throws Exception { + ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); + List<Callable<String>> l = new ArrayList<Callable<String>>(); l.add(new StringTask()); l.add(new StringTask()); String result = e.invokeAny(l); assertSame(TEST_STRING, result); - } catch (ExecutionException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -1186,13 +1087,12 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { /** * invokeAll(null) throws NPE */ - public void testInvokeAll1() { - ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + public void testInvokeAll1() throws Exception { + ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); try { e.invokeAll(null); + shouldThrow(); } catch (NullPointerException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -1201,13 +1101,11 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { /** * invokeAll(empty collection) returns empty collection */ - public void testInvokeAll2() { - ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + public void testInvokeAll2() throws InterruptedException { + ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); try { List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>()); assertTrue(r.isEmpty()); - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -1216,16 +1114,15 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { /** * invokeAll(c) throws NPE if c has null elements */ - public void testInvokeAll3() { - ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + public void testInvokeAll3() throws Exception { + ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new StringTask()); + l.add(null); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); - l.add(new StringTask()); - l.add(null); e.invokeAll(l); + shouldThrow(); } catch (NullPointerException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -1234,18 +1131,19 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { /** * get of element of invokeAll(c) throws exception on failed task */ - public void testInvokeAll4() { - ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + public void testInvokeAll4() throws Exception { + ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); + List<Callable<String>> l = new ArrayList<Callable<String>>(); l.add(new NPETask()); - List<Future<String>> result = e.invokeAll(l); - assertEquals(1, result.size()); - for (Iterator<Future<String>> it = result.iterator(); it.hasNext();) - it.next().get(); - } catch(ExecutionException success) { - } catch(Exception ex) { - unexpectedException(); + List<Future<String>> futures = e.invokeAll(l); + assertEquals(1, futures.size()); + try { + futures.get(0).get(); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } } finally { joinPool(e); } @@ -1254,19 +1152,16 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { /** * invokeAll(c) returns results of all completed tasks */ - public void testInvokeAll5() { - ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + public void testInvokeAll5() throws Exception { + ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); + List<Callable<String>> l = new ArrayList<Callable<String>>(); l.add(new StringTask()); l.add(new StringTask()); - List<Future<String>> result = e.invokeAll(l); - assertEquals(2, result.size()); - for (Iterator<Future<String>> it = result.iterator(); it.hasNext();) - assertSame(TEST_STRING, it.next().get()); - } catch (ExecutionException success) { - } catch(Exception ex) { - unexpectedException(); + List<Future<String>> futures = e.invokeAll(l); + assertEquals(2, futures.size()); + for (Future<String> future : futures) + assertSame(TEST_STRING, future.get()); } finally { joinPool(e); } @@ -1277,13 +1172,12 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { /** * timed invokeAny(null) throws NPE */ - public void testTimedInvokeAny1() { - ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + public void testTimedInvokeAny1() throws Exception { + ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); try { - e.invokeAny(null, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); + e.invokeAny(null, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); } catch (NullPointerException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -1292,15 +1186,14 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { /** * timed invokeAny(,,null) throws NPE */ - public void testTimedInvokeAnyNullTimeUnit() { - ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + public void testTimedInvokeAnyNullTimeUnit() throws Exception { + ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new StringTask()); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); - l.add(new StringTask()); e.invokeAny(l, MEDIUM_DELAY_MS, null); + shouldThrow(); } catch (NullPointerException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -1309,13 +1202,12 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { /** * timed invokeAny(empty collection) throws IAE */ - public void testTimedInvokeAny2() { - ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + public void testTimedInvokeAny2() throws Exception { + ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); try { - e.invokeAny(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); + e.invokeAny(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); } catch (IllegalArgumentException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -1324,18 +1216,18 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { /** * timed invokeAny(c) throws NPE if c has null elements */ - public void testTimedInvokeAny3() { - ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + public void testTimedInvokeAny3() throws Exception { + CountDownLatch latch = new CountDownLatch(1); + ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(latchAwaitingStringTask(latch)); + l.add(null); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); - l.add(new StringTask()); - l.add(null); - e.invokeAny(l, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); + e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); } catch (NullPointerException success) { - } catch(Exception ex) { - ex.printStackTrace(); - unexpectedException(); } finally { + latch.countDown(); joinPool(e); } } @@ -1343,15 +1235,15 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { /** * timed invokeAny(c) throws ExecutionException if no task completes */ - public void testTimedInvokeAny4() { - ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + public void testTimedInvokeAny4() throws Exception { + ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new NPETask()); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); - l.add(new NPETask()); - e.invokeAny(l, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); - } catch(ExecutionException success) { - } catch(Exception ex) { - unexpectedException(); + e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); } finally { joinPool(e); } @@ -1360,17 +1252,14 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { /** * timed invokeAny(c) returns result of some task */ - public void testTimedInvokeAny5() { - ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + public void testTimedInvokeAny5() throws Exception { + ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); + List<Callable<String>> l = new ArrayList<Callable<String>>(); l.add(new StringTask()); l.add(new StringTask()); - String result = e.invokeAny(l, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); + String result = e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS); assertSame(TEST_STRING, result); - } catch (ExecutionException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -1379,13 +1268,12 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { /** * timed invokeAll(null) throws NPE */ - public void testTimedInvokeAll1() { - ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + public void testTimedInvokeAll1() throws Exception { + ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); try { - e.invokeAll(null, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); + e.invokeAll(null, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); } catch (NullPointerException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -1394,15 +1282,14 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { /** * timed invokeAll(,,null) throws NPE */ - public void testTimedInvokeAllNullTimeUnit() { - ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + public void testTimedInvokeAllNullTimeUnit() throws Exception { + ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new StringTask()); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); - l.add(new StringTask()); e.invokeAll(l, MEDIUM_DELAY_MS, null); + shouldThrow(); } catch (NullPointerException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -1411,13 +1298,11 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { /** * timed invokeAll(empty collection) returns empty collection */ - public void testTimedInvokeAll2() { - ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + public void testTimedInvokeAll2() throws InterruptedException { + ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); try { - List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); + List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS); assertTrue(r.isEmpty()); - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -1426,16 +1311,15 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { /** * timed invokeAll(c) throws NPE if c has null elements */ - public void testTimedInvokeAll3() { - ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + public void testTimedInvokeAll3() throws Exception { + ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new StringTask()); + l.add(null); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); - l.add(new StringTask()); - l.add(null); - e.invokeAll(l, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); + e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); } catch (NullPointerException success) { - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -1444,18 +1328,18 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { /** * get of element of invokeAll(c) throws exception on failed task */ - public void testTimedInvokeAll4() { - ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + public void testTimedInvokeAll4() throws Exception { + ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + List<Callable<String>> l = new ArrayList<Callable<String>>(); + l.add(new NPETask()); + List<Future<String>> futures = + e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS); + assertEquals(1, futures.size()); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); - l.add(new NPETask()); - List<Future<String>> result = e.invokeAll(l, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); - assertEquals(1, result.size()); - for (Iterator<Future<String>> it = result.iterator(); it.hasNext();) - it.next().get(); - } catch(ExecutionException success) { - } catch(Exception ex) { - unexpectedException(); + futures.get(0).get(); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); } finally { joinPool(e); } @@ -1464,19 +1348,17 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { /** * timed invokeAll(c) returns results of all completed tasks */ - public void testTimedInvokeAll5() { - ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + public void testTimedInvokeAll5() throws Exception { + ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); + List<Callable<String>> l = new ArrayList<Callable<String>>(); l.add(new StringTask()); l.add(new StringTask()); - List<Future<String>> result = e.invokeAll(l, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS); - assertEquals(2, result.size()); - for (Iterator<Future<String>> it = result.iterator(); it.hasNext();) - assertSame(TEST_STRING, it.next().get()); - } catch (ExecutionException success) { - } catch(Exception ex) { - unexpectedException(); + List<Future<String>> futures = + e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS); + assertEquals(2, futures.size()); + for (Future<String> future : futures) + assertSame(TEST_STRING, future.get()); } finally { joinPool(e); } @@ -1485,16 +1367,17 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { /** * timed invokeAll(c) cancels tasks not completed by timeout */ - public void testTimedInvokeAll6() { - ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + public void testTimedInvokeAll6() throws Exception { + ExecutorService e = new ThreadPoolExecutor(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); + List<Callable<String>> l = new ArrayList<Callable<String>>(); l.add(new StringTask()); l.add(Executors.callable(new MediumPossiblyInterruptedRunnable(), TEST_STRING)); l.add(new StringTask()); - List<Future<String>> result = e.invokeAll(l, SHORT_DELAY_MS, TimeUnit.MILLISECONDS); - assertEquals(3, result.size()); - Iterator<Future<String>> it = result.iterator(); + List<Future<String>> futures = + e.invokeAll(l, SHORT_DELAY_MS, MILLISECONDS); + assertEquals(3, futures.size()); + Iterator<Future<String>> it = futures.iterator(); Future<String> f1 = it.next(); Future<String> f2 = it.next(); Future<String> f3 = it.next(); @@ -1503,8 +1386,6 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { assertTrue(f3.isDone()); assertFalse(f1.isCancelled()); assertTrue(f2.isCancelled()); - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } @@ -1514,34 +1395,71 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { * Execution continues if there is at least one thread even if * thread factory fails to create more */ - public void testFailingThreadFactory() { - ExecutorService e = new ThreadPoolExecutor(100, 100, LONG_DELAY_MS, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), new FailingThreadFactory()); + public void testFailingThreadFactory() throws InterruptedException { + ExecutorService e = new ThreadPoolExecutor(100, 100, LONG_DELAY_MS, MILLISECONDS, new LinkedBlockingQueue<Runnable>(), new FailingThreadFactory()); try { - ArrayList<Callable<String>> l = new ArrayList<Callable<String>>(); + List<Callable<String>> l = new ArrayList<Callable<String>>(); for (int k = 0; k < 100; ++k) { e.execute(new NoOpRunnable()); } Thread.sleep(LONG_DELAY_MS); - } catch(Exception ex) { - unexpectedException(); } finally { joinPool(e); } } /** + * allowsCoreThreadTimeOut is by default false. + */ + public void testAllowsCoreThreadTimeOut() { + ThreadPoolExecutor tpe = new ThreadPoolExecutor(2, 2, 1000, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + assertFalse(tpe.allowsCoreThreadTimeOut()); + joinPool(tpe); + } + + /** + * allowCoreThreadTimeOut(true) causes idle threads to time out + */ + public void testAllowCoreThreadTimeOut_true() throws InterruptedException { + ThreadPoolExecutor tpe = new ThreadPoolExecutor(2, 10, 10, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + tpe.allowCoreThreadTimeOut(true); + tpe.execute(new NoOpRunnable()); + try { + Thread.sleep(MEDIUM_DELAY_MS); + assertEquals(0, tpe.getPoolSize()); + } finally { + joinPool(tpe); + } + } + + /** + * allowCoreThreadTimeOut(false) causes idle threads not to time out + */ + public void testAllowCoreThreadTimeOut_false() throws InterruptedException { + ThreadPoolExecutor tpe = new ThreadPoolExecutor(2, 10, 10, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10)); + tpe.allowCoreThreadTimeOut(false); + tpe.execute(new NoOpRunnable()); + try { + Thread.sleep(MEDIUM_DELAY_MS); + assertTrue(tpe.getPoolSize() >= 1); + } finally { + joinPool(tpe); + } + } + + /** * execute allows the same task to be submitted multiple times, even * if rejected */ - public void testRejectedRecycledTask() { + public void testRejectedRecycledTask() throws InterruptedException { final int nTasks = 1000; final AtomicInteger nRun = new AtomicInteger(0); final Runnable recycledTask = new Runnable() { public void run() { nRun.getAndIncrement(); } }; - final ThreadPoolExecutor p = - new ThreadPoolExecutor(1, 30, 60, TimeUnit.SECONDS, + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 30, 60, TimeUnit.SECONDS, new ArrayBlockingQueue(30)); try { for (int i = 0; i < nTasks; ++i) { @@ -1556,12 +1474,9 @@ public class ThreadPoolExecutorTest extends JSR166TestCase { } Thread.sleep(5000); // enough time to run all tasks assertEquals(nRun.get(), nTasks); - } catch(Exception ex) { - ex.printStackTrace(); - unexpectedException(); } finally { p.shutdown(); } } - + } diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/ThreadTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/ThreadTest.java index 3885c48..e9f28ac 100755 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/ThreadTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/ThreadTest.java @@ -2,11 +2,11 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; @@ -20,7 +20,7 @@ public class ThreadTest extends JSR166TestCase { e.printStackTrace(); } } - + /** * getUncaughtExceptionHandler returns ThreadGroup unless set, * otherwise returning value of last setUncaughtExceptionHandler. @@ -40,7 +40,7 @@ public class ThreadTest extends JSR166TestCase { /** * getDefaultUncaughtExceptionHandler returns value of last - * setDefaultUncaughtExceptionHandler. + * setDefaultUncaughtExceptionHandler. */ public void testGetAndSetDefaultUncaughtExceptionHandler() { assertEquals(null, Thread.getDefaultUncaughtExceptionHandler()); @@ -54,12 +54,12 @@ public class ThreadTest extends JSR166TestCase { assertEquals(eh, Thread.getDefaultUncaughtExceptionHandler()); Thread.setDefaultUncaughtExceptionHandler(null); } - catch(SecurityException ok) { + catch (SecurityException ok) { } assertEquals(null, Thread.getDefaultUncaughtExceptionHandler()); } - + // How to test actually using UEH within junit? } diff --git a/concurrent/src/test/java/tests/api/java/util/concurrent/TimeUnitTest.java b/concurrent/src/test/java/tests/api/java/util/concurrent/TimeUnitTest.java index f6504d8..84be0c4 100755 --- a/concurrent/src/test/java/tests/api/java/util/concurrent/TimeUnitTest.java +++ b/concurrent/src/test/java/tests/api/java/util/concurrent/TimeUnitTest.java @@ -2,11 +2,11 @@ * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain - * Other contributors include Andrew Wright, Jeffrey Hayes, - * Pat Fisher, Mike Judd. + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. */ -package tests.api.java.util.concurrent; +package tests.api.java.util.concurrent; // android-added import junit.framework.*; import java.util.concurrent.*; @@ -24,57 +24,93 @@ public class TimeUnitTest extends JSR166TestCase { */ public void testConvert() { for (long t = 0; t < 88888; ++t) { + assertEquals(t*60*60*24, + TimeUnit.SECONDS.convert(t, + TimeUnit.DAYS)); + assertEquals(t*60*60, + TimeUnit.SECONDS.convert(t, + TimeUnit.HOURS)); + assertEquals(t*60, + TimeUnit.SECONDS.convert(t, + TimeUnit.MINUTES)); assertEquals(t, - TimeUnit.SECONDS.convert(t, + TimeUnit.SECONDS.convert(t, TimeUnit.SECONDS)); - assertEquals(t, - TimeUnit.SECONDS.convert(1000L*t, + assertEquals(t, + TimeUnit.SECONDS.convert(1000L*t, TimeUnit.MILLISECONDS)); - assertEquals(t, - TimeUnit.SECONDS.convert(1000000L*t, + assertEquals(t, + TimeUnit.SECONDS.convert(1000000L*t, TimeUnit.MICROSECONDS)); - assertEquals(t, - TimeUnit.SECONDS.convert(1000000000L*t, + assertEquals(t, + TimeUnit.SECONDS.convert(1000000000L*t, TimeUnit.NANOSECONDS)); + assertEquals(1000L*t*60*60*24, + TimeUnit.MILLISECONDS.convert(t, + TimeUnit.DAYS)); + assertEquals(1000L*t*60*60, + TimeUnit.MILLISECONDS.convert(t, + TimeUnit.HOURS)); + assertEquals(1000L*t*60, + TimeUnit.MILLISECONDS.convert(t, + TimeUnit.MINUTES)); assertEquals(1000L*t, - TimeUnit.MILLISECONDS.convert(t, + TimeUnit.MILLISECONDS.convert(t, TimeUnit.SECONDS)); - assertEquals(t, - TimeUnit.MILLISECONDS.convert(t, + assertEquals(t, + TimeUnit.MILLISECONDS.convert(t, TimeUnit.MILLISECONDS)); - assertEquals(t, - TimeUnit.MILLISECONDS.convert(1000L*t, + assertEquals(t, + TimeUnit.MILLISECONDS.convert(1000L*t, TimeUnit.MICROSECONDS)); - assertEquals(t, - TimeUnit.MILLISECONDS.convert(1000000L*t, + assertEquals(t, + TimeUnit.MILLISECONDS.convert(1000000L*t, TimeUnit.NANOSECONDS)); + assertEquals(1000000L*t*60*60*24, + TimeUnit.MICROSECONDS.convert(t, + TimeUnit.DAYS)); + assertEquals(1000000L*t*60*60, + TimeUnit.MICROSECONDS.convert(t, + TimeUnit.HOURS)); + assertEquals(1000000L*t*60, + TimeUnit.MICROSECONDS.convert(t, + TimeUnit.MINUTES)); assertEquals(1000000L*t, - TimeUnit.MICROSECONDS.convert(t, + TimeUnit.MICROSECONDS.convert(t, TimeUnit.SECONDS)); - assertEquals(1000L*t, - TimeUnit.MICROSECONDS.convert(t, + assertEquals(1000L*t, + TimeUnit.MICROSECONDS.convert(t, TimeUnit.MILLISECONDS)); - assertEquals(t, - TimeUnit.MICROSECONDS.convert(t, + assertEquals(t, + TimeUnit.MICROSECONDS.convert(t, TimeUnit.MICROSECONDS)); - assertEquals(t, - TimeUnit.MICROSECONDS.convert(1000L*t, + assertEquals(t, + TimeUnit.MICROSECONDS.convert(1000L*t, TimeUnit.NANOSECONDS)); + assertEquals(1000000000L*t*60*60*24, + TimeUnit.NANOSECONDS.convert(t, + TimeUnit.DAYS)); + assertEquals(1000000000L*t*60*60, + TimeUnit.NANOSECONDS.convert(t, + TimeUnit.HOURS)); + assertEquals(1000000000L*t*60, + TimeUnit.NANOSECONDS.convert(t, + TimeUnit.MINUTES)); assertEquals(1000000000L*t, - TimeUnit.NANOSECONDS.convert(t, + TimeUnit.NANOSECONDS.convert(t, TimeUnit.SECONDS)); - assertEquals(1000000L*t, - TimeUnit.NANOSECONDS.convert(t, + assertEquals(1000000L*t, + TimeUnit.NANOSECONDS.convert(t, TimeUnit.MILLISECONDS)); - assertEquals(1000L*t, - TimeUnit.NANOSECONDS.convert(t, + assertEquals(1000L*t, + TimeUnit.NANOSECONDS.convert(t, TimeUnit.MICROSECONDS)); - assertEquals(t, - TimeUnit.NANOSECONDS.convert(t, + assertEquals(t, + TimeUnit.NANOSECONDS.convert(t, TimeUnit.NANOSECONDS)); } } @@ -85,13 +121,19 @@ public class TimeUnitTest extends JSR166TestCase { */ public void testToNanos() { for (long t = 0; t < 88888; ++t) { + assertEquals(t*1000000000L*60*60*24, + TimeUnit.DAYS.toNanos(t)); + assertEquals(t*1000000000L*60*60, + TimeUnit.HOURS.toNanos(t)); + assertEquals(t*1000000000L*60, + TimeUnit.MINUTES.toNanos(t)); assertEquals(1000000000L*t, TimeUnit.SECONDS.toNanos(t)); - assertEquals(1000000L*t, + assertEquals(1000000L*t, TimeUnit.MILLISECONDS.toNanos(t)); - assertEquals(1000L*t, + assertEquals(1000L*t, TimeUnit.MICROSECONDS.toNanos(t)); - assertEquals(t, + assertEquals(t, TimeUnit.NANOSECONDS.toNanos(t)); } } @@ -102,13 +144,19 @@ public class TimeUnitTest extends JSR166TestCase { */ public void testToMicros() { for (long t = 0; t < 88888; ++t) { + assertEquals(t*1000000L*60*60*24, + TimeUnit.DAYS.toMicros(t)); + assertEquals(t*1000000L*60*60, + TimeUnit.HOURS.toMicros(t)); + assertEquals(t*1000000L*60, + TimeUnit.MINUTES.toMicros(t)); assertEquals(1000000L*t, TimeUnit.SECONDS.toMicros(t)); - assertEquals(1000L*t, + assertEquals(1000L*t, TimeUnit.MILLISECONDS.toMicros(t)); - assertEquals(t, + assertEquals(t, TimeUnit.MICROSECONDS.toMicros(t)); - assertEquals(t, + assertEquals(t, TimeUnit.NANOSECONDS.toMicros(t*1000L)); } } @@ -119,13 +167,19 @@ public class TimeUnitTest extends JSR166TestCase { */ public void testToMillis() { for (long t = 0; t < 88888; ++t) { + assertEquals(t*1000L*60*60*24, + TimeUnit.DAYS.toMillis(t)); + assertEquals(t*1000L*60*60, + TimeUnit.HOURS.toMillis(t)); + assertEquals(t*1000L*60, + TimeUnit.MINUTES.toMillis(t)); assertEquals(1000L*t, TimeUnit.SECONDS.toMillis(t)); - assertEquals(t, + assertEquals(t, TimeUnit.MILLISECONDS.toMillis(t)); - assertEquals(t, + assertEquals(t, TimeUnit.MICROSECONDS.toMillis(t*1000L)); - assertEquals(t, + assertEquals(t, TimeUnit.NANOSECONDS.toMillis(t*1000000L)); } } @@ -136,19 +190,95 @@ public class TimeUnitTest extends JSR166TestCase { */ public void testToSeconds() { for (long t = 0; t < 88888; ++t) { + assertEquals(t*60*60*24, + TimeUnit.DAYS.toSeconds(t)); + assertEquals(t*60*60, + TimeUnit.HOURS.toSeconds(t)); + assertEquals(t*60, + TimeUnit.MINUTES.toSeconds(t)); assertEquals(t, TimeUnit.SECONDS.toSeconds(t)); - assertEquals(t, + assertEquals(t, TimeUnit.MILLISECONDS.toSeconds(t*1000L)); - assertEquals(t, + assertEquals(t, TimeUnit.MICROSECONDS.toSeconds(t*1000000L)); - assertEquals(t, + assertEquals(t, TimeUnit.NANOSECONDS.toSeconds(t*1000000000L)); } } /** - * convert saturates positive too-large values to Long.MAX_VALUE + * toMinutes correctly converts sample values in different units to + * minutes + */ + public void testToMinutes() { + for (long t = 0; t < 88888; ++t) { + assertEquals(t*60*24, + TimeUnit.DAYS.toMinutes(t)); + assertEquals(t*60, + TimeUnit.HOURS.toMinutes(t)); + assertEquals(t, + TimeUnit.MINUTES.toMinutes(t)); + assertEquals(t, + TimeUnit.SECONDS.toMinutes(t*60)); + assertEquals(t, + TimeUnit.MILLISECONDS.toMinutes(t*1000L*60)); + assertEquals(t, + TimeUnit.MICROSECONDS.toMinutes(t*1000000L*60)); + assertEquals(t, + TimeUnit.NANOSECONDS.toMinutes(t*1000000000L*60)); + } + } + + /** + * toHours correctly converts sample values in different units to + * hours + */ + public void testToHours() { + for (long t = 0; t < 88888; ++t) { + assertEquals(t*24, + TimeUnit.DAYS.toHours(t)); + assertEquals(t, + TimeUnit.HOURS.toHours(t)); + assertEquals(t, + TimeUnit.MINUTES.toHours(t*60)); + assertEquals(t, + TimeUnit.SECONDS.toHours(t*60*60)); + assertEquals(t, + TimeUnit.MILLISECONDS.toHours(t*1000L*60*60)); + assertEquals(t, + TimeUnit.MICROSECONDS.toHours(t*1000000L*60*60)); + assertEquals(t, + TimeUnit.NANOSECONDS.toHours(t*1000000000L*60*60)); + } + } + + /** + * toDays correctly converts sample values in different units to + * days + */ + public void testToDays() { + for (long t = 0; t < 88888; ++t) { + assertEquals(t, + TimeUnit.DAYS.toDays(t)); + assertEquals(t, + TimeUnit.HOURS.toDays(t*24)); + assertEquals(t, + TimeUnit.MINUTES.toDays(t*60*24)); + assertEquals(t, + TimeUnit.SECONDS.toDays(t*60*60*24)); + assertEquals(t, + TimeUnit.MILLISECONDS.toDays(t*1000L*60*60*24)); + assertEquals(t, + TimeUnit.MICROSECONDS.toDays(t*1000000L*60*60*24)); + assertEquals(t, + TimeUnit.NANOSECONDS.toDays(t*1000000000L*60*60*24)); + } + } + + + /** + * convert saturates positive too-large values to Long.MAX_VALUE * and negative to LONG.MIN_VALUE */ public void testConvertSaturate() { @@ -158,18 +288,35 @@ public class TimeUnitTest extends JSR166TestCase { assertEquals(Long.MIN_VALUE, TimeUnit.NANOSECONDS.convert(-Long.MAX_VALUE / 4, TimeUnit.SECONDS)); - + assertEquals(Long.MAX_VALUE, + TimeUnit.NANOSECONDS.convert(Long.MAX_VALUE / 2, + TimeUnit.MINUTES)); + assertEquals(Long.MIN_VALUE, + TimeUnit.NANOSECONDS.convert(-Long.MAX_VALUE / 4, + TimeUnit.MINUTES)); + assertEquals(Long.MAX_VALUE, + TimeUnit.NANOSECONDS.convert(Long.MAX_VALUE / 2, + TimeUnit.HOURS)); + assertEquals(Long.MIN_VALUE, + TimeUnit.NANOSECONDS.convert(-Long.MAX_VALUE / 4, + TimeUnit.HOURS)); + assertEquals(Long.MAX_VALUE, + TimeUnit.NANOSECONDS.convert(Long.MAX_VALUE / 2, + TimeUnit.DAYS)); + assertEquals(Long.MIN_VALUE, + TimeUnit.NANOSECONDS.convert(-Long.MAX_VALUE / 4, + TimeUnit.DAYS)); } /** - * toNanos saturates positive too-large values to Long.MAX_VALUE + * toNanos saturates positive too-large values to Long.MAX_VALUE * and negative to LONG.MIN_VALUE */ public void testToNanosSaturate() { - assertEquals(Long.MAX_VALUE, - TimeUnit.MILLISECONDS.toNanos(Long.MAX_VALUE / 2)); - assertEquals(Long.MIN_VALUE, - TimeUnit.MILLISECONDS.toNanos(-Long.MAX_VALUE / 3)); + assertEquals(Long.MAX_VALUE, + TimeUnit.MILLISECONDS.toNanos(Long.MAX_VALUE / 2)); + assertEquals(Long.MIN_VALUE, + TimeUnit.MILLISECONDS.toNanos(-Long.MAX_VALUE / 3)); } @@ -181,151 +328,100 @@ public class TimeUnitTest extends JSR166TestCase { assertTrue(s.indexOf("ECOND") >= 0); } - + /** * Timed wait without holding lock throws * IllegalMonitorStateException */ - public void testTimedWait_IllegalMonitorException() { - //created a new thread with anonymous runnable - - Thread t = new Thread(new Runnable() { - public void run() { - Object o = new Object(); - TimeUnit tu = TimeUnit.MILLISECONDS; - try { - tu.timedWait(o,LONG_DELAY_MS); - threadShouldThrow(); - } - catch (InterruptedException ie) { - threadUnexpectedException(); - } - catch(IllegalMonitorStateException success) { - } - - } - }); + public void testTimedWait_IllegalMonitorException() throws Exception { + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + Object o = new Object(); + TimeUnit tu = TimeUnit.MILLISECONDS; + try { + tu.timedWait(o,LONG_DELAY_MS); + threadShouldThrow(); + } catch (IllegalMonitorStateException success) {}}}); + t.start(); - try { - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } catch(Exception e) { - unexpectedException(); - } + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } - + /** * timedWait throws InterruptedException when interrupted */ - public void testTimedWait() { - Thread t = new Thread(new Runnable() { - public void run() { - Object o = new Object(); - - TimeUnit tu = TimeUnit.MILLISECONDS; - try { - synchronized(o) { - tu.timedWait(o,MEDIUM_DELAY_MS); - } - threadShouldThrow(); - } - catch(InterruptedException success) {} - catch(IllegalMonitorStateException failure) { - threadUnexpectedException(); - } + public void testTimedWait() throws InterruptedException { + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + Object o = new Object(); + + TimeUnit tu = TimeUnit.MILLISECONDS; + synchronized(o) { + tu.timedWait(o,MEDIUM_DELAY_MS); } - }); + }}); t.start(); - try { - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } catch(Exception e) { - unexpectedException(); - } + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } - - + + /** * timedJoin throws InterruptedException when interrupted */ - public void testTimedJoin() { - Thread t = new Thread(new Runnable() { - public void run() { - TimeUnit tu = TimeUnit.MILLISECONDS; - try { - Thread s = new Thread(new Runnable() { - public void run() { - try { - Thread.sleep(MEDIUM_DELAY_MS); - } catch(InterruptedException success){} - } - }); - s.start(); - tu.timedJoin(s,MEDIUM_DELAY_MS); - threadShouldThrow(); - } - catch(Exception e) {} - } - }); + public void testTimedJoin() throws InterruptedException { + final Thread s = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + Thread.sleep(MEDIUM_DELAY_MS); + }}); + final Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + TimeUnit tu = TimeUnit.MILLISECONDS; + tu.timedJoin(s, MEDIUM_DELAY_MS); + }});; + s.start(); t.start(); - try { - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } catch(Exception e) { - unexpectedException(); - } + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); + s.interrupt(); + s.join(); } - + /** * timedSleep throws InterruptedException when interrupted */ - public void testTimedSleep() { - //created a new thread with anonymous runnable - - Thread t = new Thread(new Runnable() { - public void run() { - TimeUnit tu = TimeUnit.MILLISECONDS; - try { - tu.sleep(MEDIUM_DELAY_MS); - threadShouldThrow(); - } - catch(InterruptedException success) {} - } - }); + public void testTimedSleep() throws InterruptedException { + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + TimeUnit tu = TimeUnit.MILLISECONDS; + tu.sleep(MEDIUM_DELAY_MS); + }}); + t.start(); - try { - Thread.sleep(SHORT_DELAY_MS); - t.interrupt(); - t.join(); - } catch(Exception e) { - unexpectedException(); - } + Thread.sleep(SHORT_DELAY_MS); + t.interrupt(); + t.join(); } /** - * a deserialized serialized unit is equal + * a deserialized serialized unit is the same instance */ - public void testSerialization() { + public void testSerialization() throws Exception { TimeUnit q = TimeUnit.MILLISECONDS; - try { - ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); - ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); - out.writeObject(q); - out.close(); - - ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); - ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); - TimeUnit r = (TimeUnit)in.readObject(); - - assertEquals(q.toString(), r.toString()); - } catch(Exception e){ - e.printStackTrace(); - unexpectedException(); - } + ByteArrayOutputStream bout = new ByteArrayOutputStream(10000); + ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(bout)); + out.writeObject(q); + out.close(); + + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bin)); + TimeUnit r = (TimeUnit)in.readObject(); + assertSame(q, r); } } diff --git a/luni-kernel/src/main/java/java/lang/Thread.java b/luni-kernel/src/main/java/java/lang/Thread.java index 2dbba37..625d718 100644 --- a/luni-kernel/src/main/java/java/lang/Thread.java +++ b/luni-kernel/src/main/java/java/lang/Thread.java @@ -192,6 +192,9 @@ public class Thread implements Runnable { /** the park state of the thread */ private int parkState = ParkState.UNPARKED; + /** The synchronization object responsible for this thread parking. */ + private Object parkBlocker; + /** * Constructs a new {@code Thread} with no {@code Runnable} object and a * newly generated name. The new {@code Thread} will belong to the same diff --git a/luni/src/main/java/java/util/AbstractMap.java b/luni/src/main/java/java/util/AbstractMap.java index c98a25f..86b4740 100644 --- a/luni/src/main/java/java/util/AbstractMap.java +++ b/luni/src/main/java/java/util/AbstractMap.java @@ -17,6 +17,8 @@ package java.util; +import java.io.Serializable; + /** * This class is an abstract implementation of the {@code Map} interface. This * implementation does not support adding. A subclass must implement the @@ -32,6 +34,240 @@ public abstract class AbstractMap<K, V> implements Map<K, V> { Collection<V> valuesCollection; /** + * An immutable key-value mapping. + * + * @param <K> + * the type of key + * @param <V> + * the type of value + * + * @since 1.6 + */ + public static class SimpleImmutableEntry<K, V> implements Map.Entry<K, V>, + Serializable { + + private static final long serialVersionUID = 7138329143949025153L; + + private K key; + + private V value; + + /** + * Constructs a new instance by key and value. + * + * @param theKey + * the key + * @param theValue + * the value + */ + public SimpleImmutableEntry(K theKey, V theValue) { + key = theKey; + value = theValue; + } + + /** + * Constructs a new instance by an entry + * + * @param entry + * the entry + */ + public SimpleImmutableEntry(Map.Entry<? extends K, ? extends V> entry) { + key = entry.getKey(); + value = entry.getValue(); + } + + /** + * {@inheritDoc} + * + * @see java.util.Map.Entry#getKey() + */ + public K getKey() { + return key; + } + + /** + * {@inheritDoc} + * + * @see java.util.Map.Entry#getValue() + */ + public V getValue() { + return value; + } + + /** + * Throws an UnsupportedOperationException. + * + * @param object + * new value + * @return (Does not) + * @throws UnsupportedOperationException + * always + * + * @see java.util.Map.Entry#setValue(java.lang.Object) + */ + public V setValue(V object) { + throw new UnsupportedOperationException(); + } + + /** + * Returns whether the object is equal to this entry. This works across + * all kinds of the Map.Entry interface. + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (object instanceof Map.Entry) { + Map.Entry<?, ?> entry = (Map.Entry<?, ?>) object; + return (key == null ? entry.getKey() == null : key.equals(entry + .getKey())) + && (value == null ? entry.getValue() == null : value + .equals(entry.getValue())); + } + return false; + } + + /** + * Returns the hash code of this entry. + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return (key == null ? 0 : key.hashCode()) + ^ (value == null ? 0 : value.hashCode()); + } + + /** + * Returns a String representation of this entry. + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return key + "=" + value; //$NON-NLS-1$ + } + } + + /** + * A key-value mapping. + * + * @param <K> + * the type of key + * @param <V> + * the type of value + * + * @since 1.6 + */ + public static class SimpleEntry<K, V> implements Map.Entry<K, V>, + Serializable { + + private static final long serialVersionUID = -8499721149061103585L; + + private K key; + + private V value; + + /** + * Constructs a new instance by key and value. + * + * @param theKey + * the key + * @param theValue + * the value + */ + public SimpleEntry(K theKey, V theValue) { + key = theKey; + value = theValue; + } + + /** + * Constructs a new instance by an entry + * + * @param entry + * the entry + */ + public SimpleEntry(Map.Entry<? extends K, ? extends V> entry) { + key = entry.getKey(); + value = entry.getValue(); + } + + /** + * {@inheritDoc} + * + * @see java.util.Map.Entry#getKey() + */ + public K getKey() { + return key; + } + + /** + * {@inheritDoc} + * + * @see java.util.Map.Entry#getValue() + */ + public V getValue() { + return value; + } + + /** + * {@inheritDoc} + * + * @see java.util.Map.Entry#setValue(java.lang.Object) + */ + public V setValue(V object) { + V result = value; + value = object; + return result; + } + + /** + * Returns whether the object is equal to this entry. This works across + * all kinds of the Map.Entry interface. + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (object instanceof Map.Entry) { + Map.Entry<?, ?> entry = (Map.Entry<?, ?>) object; + return (key == null ? entry.getKey() == null : key.equals(entry + .getKey())) + && (value == null ? entry.getValue() == null : value + .equals(entry.getValue())); + } + return false; + } + + /** + * Returns the hash code of this entry. + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return (key == null ? 0 : key.hashCode()) + ^ (value == null ? 0 : value.hashCode()); + } + + /** + * Returns a String representation of this entry. + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return key + "=" + value; //$NON-NLS-1$ + } + } + + /** * Constructs a new instance of this {@code AbstractMap}. */ protected AbstractMap() { @@ -453,4 +689,4 @@ public abstract class AbstractMap<K, V> implements Map<K, V> { result.valuesCollection = null; return result; } -} +}
\ No newline at end of file diff --git a/luni/src/main/java/java/util/ArrayDeque.java b/luni/src/main/java/java/util/ArrayDeque.java new file mode 100644 index 0000000..2e2fe3a --- /dev/null +++ b/luni/src/main/java/java/util/ArrayDeque.java @@ -0,0 +1,885 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.util; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.lang.reflect.Array; + +/** + * An implementation of Deque, backed by an array. + * + * ArrayDeques have no size limit, can not contain null element, and they are + * not thread-safe. + * + * All optional operations are supported, and the elements can be any objects. + * + * @param <E> + * the type of elements in this collection + * + * @since 1.6 + */ +public class ArrayDeque<E> extends AbstractCollection<E> implements Deque<E>, + Cloneable, Serializable { + + private static final long serialVersionUID = 2340985798034038923L; + + private static final int DEFAULT_SIZE = 16; + + private enum DequeStatus { + Empty, Normal, Full; + } + + private transient DequeStatus status; + + private transient int modCount; + + // the pointer of the head element + private transient int front; + + // the pointer of the "next" position of the tail element + private transient int rear; + + private transient E[] elements; + + @SuppressWarnings("hiding") + private class ArrayDequeIterator<E> implements Iterator<E> { + private int pos; + + private final int expectedModCount; + + private boolean canRemove; + + @SuppressWarnings("synthetic-access") + ArrayDequeIterator() { + super(); + pos = front; + expectedModCount = modCount; + canRemove = false; + } + + @SuppressWarnings("synthetic-access") + public boolean hasNext() { + if (expectedModCount != modCount) { + return false; + } + return hasNextInternal(); + } + + private boolean hasNextInternal() { + // canRemove means "next" method is called, and the Full + // status can ensure that this method is not called just + // after "remove" method is call.(so, canRemove can keep + // true after "next" method called) + return (pos != rear) + || ((status == DequeStatus.Full) && !canRemove); + } + + @SuppressWarnings( { "synthetic-access", "unchecked" }) + public E next() { + if (hasNextInternal()) { + E result = (E) elements[pos]; + if (expectedModCount == modCount && null != result) { + canRemove = true; + pos = circularBiggerPos(pos); + return result; + } + throw new ConcurrentModificationException(); + } + throw new NoSuchElementException(); + } + + @SuppressWarnings("synthetic-access") + public void remove() { + if (canRemove) { + int removedPos = circularSmallerPos(pos); + if (expectedModCount == modCount + && null != elements[removedPos]) { + removeInternal(removedPos, true); + canRemove = false; + return; + } + throw new ConcurrentModificationException(); + } + throw new IllegalStateException(); + } + } + + /* + * NOTES:descendingIterator is not fail-fast, according to the documentation + * and test case. + */ + @SuppressWarnings("hiding") + private class ReverseArrayDequeIterator<E> implements Iterator<E> { + private int pos; + + private final int expectedModCount; + + private boolean canRemove; + + @SuppressWarnings("synthetic-access") + ReverseArrayDequeIterator() { + super(); + expectedModCount = modCount; + pos = circularSmallerPos(rear); + canRemove = false; + } + + @SuppressWarnings("synthetic-access") + public boolean hasNext() { + if (expectedModCount != modCount) { + return false; + } + return hasNextInternal(); + } + + private boolean hasNextInternal() { + // canRemove means "next" method is called, and the Full + // status can ensure that this method is not called just + // after "remove" method is call.(so, canRemove can keep + // true after "next" method called) + return (circularBiggerPos(pos) != front) + || ((status == DequeStatus.Full) && !canRemove); + } + + @SuppressWarnings( { "synthetic-access", "unchecked" }) + public E next() { + if (hasNextInternal()) { + E result = (E) elements[pos]; + canRemove = true; + pos = circularSmallerPos(pos); + return result; + } + throw new NoSuchElementException(); + } + + @SuppressWarnings("synthetic-access") + public void remove() { + if (canRemove) { + removeInternal(circularBiggerPos(pos), false); + canRemove = false; + return; + } + throw new IllegalStateException(); + } + } + + /** + * Constructs a new empty instance of ArrayDeque big enough for 16 elements. + */ + public ArrayDeque() { + this(DEFAULT_SIZE); + } + + /** + * Constructs a new empty instance of ArrayDeque big enough for specified + * number of elements. + * + * @param minSize + * the smallest size of the ArrayDeque + */ + @SuppressWarnings("unchecked") + public ArrayDeque(final int minSize) { + int size = countInitSize(minSize); + elements = (E[]) new Object[size]; + front = rear = 0; + status = DequeStatus.Empty; + modCount = 0; + } + + /* + * count out the size for a new deque, and ensure that size >= minSize + */ + private int countInitSize(final int minSize) { + int size = Math.max(minSize, DEFAULT_SIZE); + // get the smallest number that not smaller than size, + // and is a power of 2. + size = Integer.highestOneBit(size - 1) << 1; + if (0 >= size) { + size = minSize; + } + return size; + } + + /** + * Constructs a new instance of ArrayDeque containing the elements of the + * specified collection, with the order returned by the collection's + * iterator. + * + * @param c + * the source of the elements + * @throws NullPointerException + * if the collection is null + */ + @SuppressWarnings("unchecked") + public ArrayDeque(Collection<? extends E> c) { + elements = (E[]) new Object[countInitSize(c.size())]; + front = rear = 0; + status = DequeStatus.Empty; + modCount = 0; + Iterator<? extends E> it = c.iterator(); + while (it.hasNext()) { + addLastImpl(it.next()); + } + } + + /** + * {@inheritDoc} + * + * @param e + * the element + * @throws NullPointerException + * if the element is null + * @see java.util.Deque#addFirst(java.lang.Object) + */ + public void addFirst(E e) { + offerFirst(e); + } + + /** + * {@inheritDoc} + * + * @param e + * the element + * @throws NullPointerException + * if the element is null + * @see java.util.Deque#addLast(java.lang.Object) + */ + public void addLast(E e) { + addLastImpl(e); + } + + /** + * {@inheritDoc} + * + * @param e + * the element + * @return true + * @throws NullPointerException + * if the element is null + * @see java.util.Deque#offerFirst(java.lang.Object) + */ + public boolean offerFirst(E e) { + checkNull(e); + checkAndExpand(); + front = circularSmallerPos(front); + elements[front] = e; + resetStatus(true); + modCount++; + return true; + } + + /** + * {@inheritDoc} + * + * @param e + * the element + * @return true if the operation succeeds or false if it fails + * @throws NullPointerException + * if the element is null + * @see java.util.Deque#offerLast(java.lang.Object) + */ + public boolean offerLast(E e) { + return addLastImpl(e); + } + + /** + * Inserts the element at the tail of the deque. + * + * @param e + * the element + * @return true if the operation succeeds or false if it fails. + * @throws NullPointerException + * if the element is null + * @see java.util.Queue#offer(java.lang.Object) + */ + public boolean offer(E e) { + return addLastImpl(e); + } + + /** + * Inserts the element to the tail of the deque. + * + * @param e + * the element + * @return true + * @see java.util.AbstractCollection#add(java.lang.Object) + */ + @Override + public boolean add(E e) { + return addLastImpl(e); + } + + /** + * {@inheritDoc} + * + * @param e + * the element to push + * @throws NullPointerException + * if the element is null + * @see java.util.Deque#push(java.lang.Object) + */ + public void push(E e) { + offerFirst(e); + } + + /** + * {@inheritDoc} + * + * @return the head element + * @throws NoSuchElementException + * if the deque is empty + * @see java.util.Deque#removeFirst() + */ + public E removeFirst() { + checkEmpty(); + return removePollFirstImpl(); + } + + /** + * Gets and removes the head element of this deque. This method throws an + * exception if the deque is empty. + * + * @return the head element + * @throws NoSuchElementException + * if the deque is empty + * @see java.util.Queue#remove() + */ + public E remove() { + return removeFirst(); + } + + /** + * {@inheritDoc} + * + * @return the head element + * @throws NoSuchElementException + * if the deque is empty + * @see java.util.Deque#pop() + */ + public E pop() { + return removeFirst(); + } + + /** + * {@inheritDoc} + * + * @return the tail element + * @throws NoSuchElementException + * if the deque is empty + * @see java.util.Deque#removeLast() + */ + public E removeLast() { + checkEmpty(); + return removeLastImpl(); + } + + /** + * {@inheritDoc} + * + * @return the head element or null if the deque is empty + * @see java.util.Deque#pollFirst() + */ + public E pollFirst() { + return (status == DequeStatus.Empty) ? null : removePollFirstImpl(); + } + + /** + * Gets and removes the head element of this deque. This method returns null + * if the deque is empty. + * + * @return the head element or null if the deque is empty + * @see java.util.Queue#poll() + */ + public E poll() { + return pollFirst(); + } + + /** + * {@inheritDoc} + * + * @return the tail element or null if the deque is empty + * @see java.util.Deque#pollLast() + */ + public E pollLast() { + return (status == DequeStatus.Empty) ? null : removeLastImpl(); + } + + /** + * {@inheritDoc} + * + * @return the head element + * @throws NoSuchElementException + * if the deque is empty + * @see java.util.Deque#getFirst() + */ + public E getFirst() { + checkEmpty(); + return elements[front]; + } + + /** + * Gets but does not remove the head element of this deque. It throws an + * exception if the deque is empty. + * + * @return the head element + * @throws NoSuchElementException + * if the deque is empty + * @see java.util.Queue#element() + */ + public E element() { + return getFirst(); + } + + /** + * {@inheritDoc} + * + * @return the tail element + * @throws NoSuchElementException + * if the deque is empty + * @see java.util.Deque#getLast() + */ + public E getLast() { + checkEmpty(); + return elements[circularSmallerPos(rear)]; + } + + /** + * {@inheritDoc} + * + * @return the head element or null if the deque is empty + * @see java.util.Deque#peekFirst() + */ + public E peekFirst() { + return (status == DequeStatus.Empty) ? null : elements[front]; + } + + /** + * Gets but not removes the head element of this deque. This method returns + * null if the deque is empty. + * + * @return the head element or null if the deque is empty + * @see java.util.Queue#peek() + */ + public E peek() { + return (status == DequeStatus.Empty) ? null : elements[front]; + } + + /** + * {@inheritDoc} + * + * @return the tail element or null if the deque is empty + * @see java.util.Deque#peekLast() + */ + public E peekLast() { + return (status == DequeStatus.Empty) ? null + : elements[circularSmallerPos(rear)]; + } + + private void checkNull(E e) { + if (null == e) { + throw new NullPointerException(); + } + } + + private void checkEmpty() { + if (status == DequeStatus.Empty) { + throw new NoSuchElementException(); + } + } + + private int circularSmallerPos(int current) { + return (current - 1 < 0) ? (elements.length - 1) : current - 1; + } + + private int circularBiggerPos(int current) { + return (current + 1 >= elements.length) ? 0 : current + 1; + } + + @SuppressWarnings("unchecked") + /* + * If array of elements is full, there will be a new bigger array to store + * the elements. + */ + private void checkAndExpand() { + if (status != DequeStatus.Full) { + return; + } + if (Integer.MAX_VALUE == elements.length) { + throw new IllegalStateException(); + } + int length = elements.length; + int newLength = length << 1; + // bigger than Integer.MAX_VALUE + if (newLength < 0) { + newLength = Integer.MAX_VALUE; + } + E[] newElements = (E[]) new Object[newLength]; + System.arraycopy(elements, front, newElements, 0, length - front); + System.arraycopy(elements, 0, newElements, length - front, front); + front = 0; + rear = length; + status = DequeStatus.Normal; + elements = newElements; + } + + /** + * Resets the status after adding or removing operation. + * + * @param adding + * if the method is called after an "adding" operation + */ + private void resetStatus(boolean adding) { + if (front == rear) { + status = adding ? DequeStatus.Full : DequeStatus.Empty; + } else { + status = DequeStatus.Normal; + } + } + + private boolean addLastImpl(E e) { + checkNull(e); + checkAndExpand(); + elements[rear] = e; + rear = circularBiggerPos(rear); + resetStatus(true); + modCount++; + return true; + } + + private E removePollFirstImpl() { + E element = elements[front]; + elements[front] = null; + front = circularBiggerPos(front); + resetStatus(false); + modCount++; + return element; + } + + private E removeLastImpl() { + int last = circularSmallerPos(rear); + E element = elements[last]; + elements[last] = null; + rear = last; + resetStatus(false); + modCount++; + return element; + } + + /** + * {@inheritDoc} + * + * @param obj + * the element to be removed + * @return true if the operation succeeds or false if the deque does not + * contain the element + * @see java.util.Deque#removeFirstOccurrence(java.lang.Object) + */ + public boolean removeFirstOccurrence(Object obj) { + return removeFirstOccurrenceImpl(obj); + } + + /** + * Removes the first equivalent element of the specified object. If the + * deque does not contain the element, it is unchanged and returns false. + * + * @param obj + * the element to be removed + * @return true if the operation succeeds or false if the deque does not + * contain the element + * @see java.util.AbstractCollection#remove(java.lang.Object) + */ + @Override + public boolean remove(Object obj) { + return removeFirstOccurrenceImpl(obj); + } + + /** + * {@inheritDoc} + * + * @param obj + * the element to be removed + * @return true if the operation succeeds or false if the deque does not + * contain the element. + * @see java.util.Deque#removeLastOccurrence(java.lang.Object) + */ + public boolean removeLastOccurrence(final Object obj) { + if (null != obj) { + Iterator<E> iter = descendingIterator(); + while (iter.hasNext()) { + if (iter.next().equals(obj)) { + iter.remove(); + return true; + } + } + } + return false; + } + + private boolean removeFirstOccurrenceImpl(final Object obj) { + if (null != obj) { + Iterator<E> iter = iterator(); + while (iter.hasNext()) { + if (iter.next().equals(obj)) { + iter.remove(); + return true; + } + } + } + return false; + } + + /* + * Removes the element in the cursor position and shifts front elements to + * fill the gap if frontShift is true, shifts rear elements otherwise. + * + */ + private void removeInternal(final int current, final boolean frontShift) { + int cursor = current; + if (frontShift) { + while (cursor != front) { + int next = circularSmallerPos(cursor); + elements[cursor] = elements[next]; + cursor = next; + } + front = circularBiggerPos(front); + } else { + while (cursor != rear) { + int next = circularBiggerPos(cursor); + elements[cursor] = elements[next]; + cursor = next; + } + rear = circularSmallerPos(rear); + } + elements[cursor] = null; + resetStatus(false); + } + + /** + * Returns the size of the deque. + * + * @return the size of the deque + * @see java.util.AbstractCollection#size() + */ + @Override + public int size() { + if (status == DequeStatus.Full) { + return elements.length; + } + return (front <= rear) ? (rear - front) + : (rear + elements.length - front); + } + + /** + * Returns true if the deque has no elements. + * + * @return true if the deque has no elements, false otherwise + * @see java.util.AbstractCollection#isEmpty() + */ + @Override + public boolean isEmpty() { + return 0 == size(); + } + + /** + * Returns true if the specified element is in the deque. + * + * @param obj + * the element + * @return true if the element is in the deque, false otherwise + * @see java.util.AbstractCollection#contains(java.lang.Object) + */ + @SuppressWarnings("cast") + @Override + public boolean contains(final Object obj) { + if (null != obj) { + Iterator<E> it = new ArrayDequeIterator<E>(); + while (it.hasNext()) { + if (obj.equals((E) it.next())) { + return true; + } + } + } + return false; + } + + /** + * Empty the deque. + * + * @see java.util.AbstractCollection#clear() + */ + @SuppressWarnings("cast") + @Override + public void clear() { + if (status != DequeStatus.Empty) { + int cursor = front; + do { + elements[cursor] = null; + cursor = circularBiggerPos(cursor); + } while (cursor != rear); + status = DequeStatus.Empty; + } + front = rear = 0; + modCount = 0; + } + + /** + * Returns a clone of the deque. + * + * @return the clone of the deque + * @see java.lang.Object#clone() + * @see java.lang.Cloneable + */ + @SuppressWarnings("unchecked") + @Override + public ArrayDeque<E> clone() { + try { + ArrayDeque<E> newDeque = (ArrayDeque<E>) super.clone(); + newDeque.elements = elements.clone(); + return newDeque; + } catch (CloneNotSupportedException e) { + return null; + } + } + + /** + * Returns all the elements in an array from head to tail. The result is a + * copy of all the elements. + * + * @return the Array of all the elements + * @see java.util.AbstractCollection#toArray() + */ + @Override + public Object[] toArray() { + return newArray(new Object[size()]); + } + + /** + * Returns all the elements in an array from head to tail, and the type of + * the result array is the type of the argument array. If the argument array + * is big enough, the elements from the deque will be stored in it(elements + * following the tail of the deque is set to null, if any); otherwise, it + * will return a new array with the size of the argument array and size of + * the deque. + * + * @param <T> + * the type of elements in the array + * @param array + * the array stores all the elements from the deque, if it has + * enough space; otherwise, a new array of the same type and the + * size of the deque will be used + * @return the Array of all the elements + * @throws ArrayStoreException + * if the type of the argument array is not compatible with + * every element in the deque + * @throws NullPointerException + * if the argument array is null + * @see java.util.AbstractCollection#toArray + */ + @Override + public <T> T[] toArray(T[] array) { + return newArray(array); + } + + @SuppressWarnings("unchecked") + private <T> T[] newArray(T[] array) { + int size = size(); + if (size > array.length) { + Class<?> clazz = array.getClass().getComponentType(); + array = (T[]) Array.newInstance(clazz, size); + } + if (front < rear) { + System.arraycopy(elements, front, array, 0, size); + } else if (size != 0) { + int length = elements.length; + System.arraycopy(elements, front, array, 0, length - front); + System.arraycopy(elements, 0, array, length - front, rear); + } + if (size < array.length) { + array[size] = null; + } + return array; + } + + /** + * Returns the iterator of the deque. The elements will be ordered from head + * to tail. + * + * @return the iterator + * @see java.util.AbstractCollection#iterator() + */ + @SuppressWarnings("synthetic-access") + @Override + public Iterator<E> iterator() { + return new ArrayDequeIterator<E>(); + } + + /** + * {@inheritDoc} + * + * @return the reverse order Iterator + * @see java.util.Deque#descendingIterator() + */ + public Iterator<E> descendingIterator() { + return new ReverseArrayDequeIterator<E>(); + } + + /** + * Deserialization method. + * + * @param stream + * the ObjectInputStream + * @throws IOException + * @throws ClassNotFoundException + */ + @SuppressWarnings("unchecked") + private void readObject(ObjectInputStream stream) throws IOException, + ClassNotFoundException { + stream.defaultReadObject(); + int size = stream.readInt(); + elements = (E[]) new Object[countInitSize(size)]; + front = rear = 0; + status = DequeStatus.Empty; + modCount = 0; + for (int i = 0; i < size; i++) { + addLastImpl((E) stream.readObject()); + } + } + + /** + * Serialization method. + * + * @param stream + * the ObjectOutputStream + * @serialData The current size of the deque, followed by all the elements + * from head to tail. + * @throws IOException + * + */ + private void writeObject(ObjectOutputStream stream) throws IOException { + stream.defaultWriteObject(); + stream.writeInt(size()); + Iterator<?> it = new ArrayDequeIterator<E>(); + while (it.hasNext()) { + stream.writeObject(it.next()); + } + } + +}
\ No newline at end of file diff --git a/luni/src/main/java/java/util/Deque.java b/luni/src/main/java/java/util/Deque.java new file mode 100644 index 0000000..b13cdb0 --- /dev/null +++ b/luni/src/main/java/java/util/Deque.java @@ -0,0 +1,255 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.util; + +/** + * A kind of collection that can insert or remove element at both ends("double + * ended queue"). Mostly a deque has no limit of its size. + * + * Extending from Queue, a deque can be used as a Queue which behavior is + * first-in-first-out. Furthermore, a deque can also be used as a Stack(legacy + * class) which behavior is last-in-first-out. + * + * A typical deque does not allow null to be inserted as its element, while some + * implementations allow it. But null should not be inserted even in these + * implementations, since method poll return null to indicate that there is no + * element left in the deque. + * + * A deque can also remove interior elements by removeFirstOccurrence and + * removeLastOccurrence methods. A deque can not access elements by index. + * + * @param <E> + * the type of elements in this collection + * @since 1.6 + */ +public interface Deque<E> extends Queue<E> { + + /** + * Inserts an element at the head of this deque if it dose not violate size + * limit immediately. It is better to use offerFirst(E) if a deque is + * size-limited. + * + * @param e + * the element + * @throws IllegalStateException + * if it can not add now due to size limit + * @throws ClassCastException + * if the class of element can not be added into this deque + * @throws NullPointerException + * if the element is null and the deque can not contain null + * element + * @throws IllegalArgumentException + * if the element can not be added due to some property. + */ + void addFirst(E e); + + /** + * Inserts an element at the tail of this deque if it dose not violate size + * limit immediately. It is better to use offerLast(E) if a deque is + * size-limited. + * + * @param e + * the element + * @throws IllegalStateException + * if it can not add now due to size limit + * @throws ClassCastException + * if the class of element can not be added into this deque + * @throws NullPointerException + * if the element is null and the deque can not contain null + * element + * @throws IllegalArgumentException + * if the element can not be added due to some property. + */ + void addLast(E e); + + /** + * Inserts an element at the head of this deque unless it would violate size + * limit. It is better than the addFirst(E) method in a size-limited deque, + * because the latter one may fail to add the element only by throwing an + * exception. + * + * @param e + * the element + * @return true if the operation succeeds or false if it fails. + * @throws ClassCastException + * if the class of element can not be added into this deque + * @throws NullPointerException + * if the element is null and the deque can not contain null + * element + * @throws IllegalArgumentException + * if the element can not be added due to some property. + */ + boolean offerFirst(E e); + + /** + * Inserts an element at the tail of this deque unless it would violate size + * limit. It is better than the addLast(E) method in a size-limited deque, + * because the latter one may fail to add the element only by throwing an + * exception. + * + * @param e + * the element + * @return true if the operation succeeds or false if it fails + * @throws ClassCastException + * if the class of element can not be added into this deque + * @throws NullPointerException + * if the element is null and the deque can not contain null + * element + * @throws IllegalArgumentException + * if the element can not be added due to some property + */ + boolean offerLast(E e); + + /** + * Gets and removes the head element of this deque. This method throws an + * exception if the deque is empty. + * + * @return the head element + * @throws NoSuchElementException + * if the deque is empty + */ + E removeFirst(); + + /** + * Gets and removes the tail element of this deque. This method throws an + * exception if the deque is empty. + * + * @return the tail element + * @throws NoSuchElementException + * if the deque is empty + */ + E removeLast(); + + /** + * Gets and removes the head element of this deque. This method returns null + * if the deque is empty. + * + * @return the head element or null if the deque is empty + */ + E pollFirst(); + + /** + * Gets and removes the tail element of this deque. This method returns null + * if the deque is empty. + * + * @return the tail element or null if the deque is empty + */ + E pollLast(); + + /** + * Gets but not removes the head element of this deque. This method throws + * an exception if the deque is empty. + * + * @return the head element + * @throws NoSuchElementException + * if the deque is empty + */ + E getFirst(); + + /** + * Gets but not removes the tail element of this deque. This method throws + * an exception if the deque is empty. + * + * @return the tail element + * @throws NoSuchElementException + * if the deque is empty + */ + E getLast(); + + /** + * Gets but not removes the head element of this deque. This method returns + * null if the deque is empty. + * + * @return the head element or null if the deque is empty + */ + E peekFirst(); + + /** + * Gets but not removes the tail element of this deque. This method returns + * null if the deque is empty. + * + * @return the tail element or null if the deque is empty + */ + E peekLast(); + + /** + * Removes the first equivalent element of the specified object. If the + * deque does not contain the element, it is unchanged and returns false. + * + * @param o + * the element to be removed + * @return true if the operation succeeds or false if the deque does not + * contain the element. + * @throws ClassCastException + * if the class of the element is incompatible with the deque + * @throws NullPointerException + * if the element is null and the deque can not contain null + * element + */ + boolean removeFirstOccurrence(Object o); + + /** + * Removes the last equivalent element of the specified object. If the deque + * does not contain the element, it is unchanged and returns false. + * + * @param o + * the element to be removed + * @return true if the operation succeeds or false if the deque does not + * contain the element. + * @throws ClassCastException + * if the class of the element is incompatible with the deque + * @throws NullPointerException + * if the element is null and the deque can not contain null + * element + */ + boolean removeLastOccurrence(Object o); + + /** + * Pushes the element to the deque(at the head of the deque), just same as + * addFirst(E). + * + * @param e + * the element + * @throws IllegalStateException + * if it can not add now due to size limit + * @throws ClassCastException + * if the class of element can not be added into this deque + * @throws NullPointerException + * if the element is null and the deque can not contain null + * element + * @throws IllegalArgumentException + * if the element can not be added due to some property. + */ + void push(E e); + + /** + * Pops the head element of the deque, just same as removeFirst(). + * + * @return the head element + * @throws NoSuchElementException + * if the deque is empty + */ + E pop(); + + /** + * Returns the iterator in reverse order, from tail to head. + * + * @return the iterator in reverse order + */ + Iterator<E> descendingIterator(); +}
\ No newline at end of file diff --git a/luni/src/main/java/java/util/NavigableMap.java b/luni/src/main/java/java/util/NavigableMap.java new file mode 100644 index 0000000..a87a8c0 --- /dev/null +++ b/luni/src/main/java/java/util/NavigableMap.java @@ -0,0 +1,262 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.util; + +/** + * NavigableMap is a SortedMap with navigation methods answering the closest + * matches for specified item. + * + * @param <K> + * the type of key + * @param <V> + * the type of value + * @since 1.6 + */ +public interface NavigableMap<K, V> extends SortedMap<K, V> { + /** + * Returns the entry with the smallest key, or null if the map is empty. + * + * @return the entry with the smallest key, or null if the map is empty + */ + Map.Entry<K, V> firstEntry(); + + /** + * Returns the entry with the biggest key, or null if the map is empty. + * + * @return the entry with the biggest key, or null if the map is empty + */ + Map.Entry<K, V> lastEntry(); + + /** + * Deletes and returns the entry with the smallest key, or null if the map + * is empty. + * + * @return the entry with the smallest key, or null if the map is empty + */ + Map.Entry<K, V> pollFirstEntry(); + + /** + * Deletes and returns the entry with the biggest key, or null if the map is + * empty. + * + * @return the entry with the biggest key, or null if the map is empty + */ + Map.Entry<K, V> pollLastEntry(); + + /** + * Returns an entry related with the smallest key greater than or equal to + * the specified key, or null if no such key. + * + * @param key + * the key + * @return the entry, or null if no such key + * @throws ClassCastException + * if the key cannot be compared with the keys in the map + * @throws NullPointerException + * if the key is null and the map can not contain null key + */ + Map.Entry<K, V> ceilingEntry(K key); + + /** + * Returns the smallest key greater than or equal to the specified key, or + * null if no such key. + * + * @param key + * the key + * @return the smallest key greater than or equal to key, or null if no such + * key + * @throws ClassCastException + * if the key cannot be compared with the keys in the map + * @throws NullPointerException + * if the key is null and the map can not contain null key + */ + K ceilingKey(K key); + + /** + * Returns an entry related with the smallest key greater than the specified + * key, or null if no such key. + * + * @param key + * the key + * @return the entry, or null if no such key + * @throws ClassCastException + * if the key cannot be compared with the keys in the map + * @throws NullPointerException + * if the key is null and the map can not contain null key + */ + Map.Entry<K, V> higherEntry(K key); + + /** + * Returns the smallest key greater than the specified key, or null if no + * such key. + * + * @param key + * the key + * @return the smallest key greater than key, or null if no such key + * @throws ClassCastException + * if the key cannot be compared with the keys in the map + * @throws NullPointerException + * if the key is null and the map can not contain null key + */ + K higherKey(K key); + + /** + * Returns an entry related with the biggest key less than or equal to the + * specified key, or null if no such key. + * + * @param key + * the key + * @return the entry, or null if no such key + * @throws ClassCastException + * if the key cannot be compared with the keys in the map + * @throws NullPointerException + * if the key is null and the map can not contain null key + */ + Map.Entry<K, V> floorEntry(K key); + + /** + * Returns the biggest key less than or equal to the specified key, or null + * if no such key. + * + * @param key + * the key + * @return the biggest key less than or equal to key, or null if no such key + * @throws ClassCastException + * if the key cannot be compared with the keys in the map + * @throws NullPointerException + * if the key is null and the map can not contain null key + */ + K floorKey(K key); + + /** + * Returns an entry related with the biggest key less than the specified + * key, or null if no such key. + * + * @param key + * the key + * @return the entry, or null if no such key + * @throws ClassCastException + * if the key cannot be compared with the keys in the map + * @throws NullPointerException + * if the key is null and the map can not contain null key + */ + Map.Entry<K, V> lowerEntry(K key); + + /** + * Returns the biggest key less than the specified key, or null if no such + * key. + * + * @param key + * the key + * @return the biggest key less than key, or null if no such key + * @throws ClassCastException + * if the key cannot be compared with the keys in the map + * @throws NullPointerException + * if the key is null and the map can not contain null key + */ + K lowerKey(K key); + + /** + * Returns a NavigableSet view of the keys in ascending order. + * + * @return the navigable set view + */ + NavigableSet<K> navigableKeySet(); + + /** + * Returns a reverse order view of the map. + * + * @return the reverse order view of the map + */ + NavigableMap<K, V> descendingMap(); + + /** + * Returns a NavigableSet view of the keys in descending order. + * + * @return the navigable set view + */ + NavigableSet<K> descendingKeySet(); + + /** + * Returns a view of part of the map whose keys is from startKey to endKey. + * + * @param startKey + * the start key + * @param startInclusive + * true if the start key is in the returned map + * @param endKey + * the end key + * @param endInclusive + * true if the end key is in the returned map + * @return the sub-map view + * + * @exception ClassCastException + * when the class of the start or end key is inappropriate + * for this SubMap + * @exception NullPointerException + * when the start or end key is null and this SortedMap does + * not support null keys + * @exception IllegalArgumentException + * when the start key is greater than the end key + */ + NavigableMap<K, V> subMap(K startKey, boolean startInclusive, K endKey, + boolean endInclusive); + + /** + * Returns a view of the head of the map whose keys are smaller than (or + * equal to, depends on inclusive argument) endKey. + * + * @param endKey + * the end key + * @param inclusive + * true if the end key is in the returned map + * @return the head-map view + * + * @exception ClassCastException + * when the class of the end key is inappropriate for this + * SubMap + * @exception NullPointerException + * when the end key is null and this SortedMap does not + * support null keys + * @exception IllegalArgumentException + * when the map is range-limited and end key is out of the + * range of the map + */ + NavigableMap<K, V> headMap(K endKey, boolean inclusive); + + /** + * Returns a view of the tail of the map whose keys are bigger than (or + * equal to, depends on inclusive argument) startKey. + * + * @param startKey + * the start key + * @param inclusive + * true if the start key is in the returned map + * @return the tail-map view + * + * @exception ClassCastException + * when the class of the start key is inappropriate for this + * SubMap + * @exception NullPointerException + * when the start key is null and this SortedMap does not + * support null keys + * @exception IllegalArgumentException + * when the map is range-limited and start key is out of the + * range of the map + */ + NavigableMap<K, V> tailMap(K startKey, boolean inclusive); +}
\ No newline at end of file diff --git a/luni/src/main/java/java/util/NavigableSet.java b/luni/src/main/java/java/util/NavigableSet.java new file mode 100644 index 0000000..ae94b77 --- /dev/null +++ b/luni/src/main/java/java/util/NavigableSet.java @@ -0,0 +1,192 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.util; + +/** + * NavigableSet is a SortedSet with navigation methods answering the closest + * matches for specified item. + * + * @param <E> + * the type of element + * @since 1.6 + */ +public interface NavigableSet<E> extends SortedSet<E> { + + /** + * Deletes and returns the smallest element, or null if the set is empty. + * + * @return the smallest element, or null if the set is empty + */ + E pollFirst(); + + /** + * Deletes and returns the biggest element, or null if the set is empty. + * + * @return the biggest element, or null if the set is empty + */ + E pollLast(); + + /** + * Returns the smallest element bigger than the specified one, or null if no + * such element. + * + * @param e + * the specified element + * @return the smallest element bigger than the specified one, or null if no + * such element + * @throws ClassCastException + * if the element cannot be compared with the ones in the set + * @throws NullPointerException + * if the element is null and the set can not contain null + */ + E higher(E e); + + /** + * Returns the smallest element bigger than or equal to the specified one, + * or null if no such element. + * + * @param e + * the specified element + * @return the smallest element bigger than or equal to the specified one, + * or null if no such element + * @throws ClassCastException + * if the element cannot be compared with the ones in the set + * @throws NullPointerException + * if the element is null and the set can not contain null + */ + E ceiling(E e); + + /** + * Returns the biggest element less than the specified one, or null if no + * such element. + * + * @param e + * the specified element + * @return the biggest element less than the specified one, or null if no + * such element + * @throws ClassCastException + * if the element cannot be compared with the ones in the set + * @throws NullPointerException + * if the element is null and the set can not contain null + */ + E lower(E e); + + /** + * Returns the biggest element less than or equal to the specified one, or + * null if no such element. + * + * @param e + * the specified element + * @return the biggest element less than or equal to the specified one, or + * null if no such element + * @throws ClassCastException + * if the element cannot be compared with the ones in the set + * @throws NullPointerException + * if the element is null and the set can not contain null + */ + E floor(E e); + + /** + * Returns a descending iterator of this set. + * + * @return the descending iterator + */ + Iterator<E> descendingIterator(); + + /** + * Returns a reverse order view of this set. + * + * @return the reverse order view + */ + NavigableSet<E> descendingSet(); + + /** + * Returns a NavigableSet of the specified portion of this set which + * contains elements greater (or equal to, depends on startInclusive) the + * start element but less than (or equal to, depends on endInclusive) the + * end element. The returned NavigableSet is backed by this set so changes + * to one are reflected by the other. + * + * @param start + * the start element + * @param startInclusive + * true if the start element is in the returned set + * @param end + * the end element + * @param endInclusive + * true if the end element is in the returned set + * @return the subset + * + * @throws ClassCastException + * when the start or end object cannot be compared with the + * elements in this set + * @throws NullPointerException + * when the start or end object is null and the set cannot + * contain null + * @throws IllegalArgumentException + * when the start is bigger than end; or start or end is out of + * range and the set has a range + */ + NavigableSet<E> subSet(E start, boolean startInclusive, E end, + boolean endInclusive); + + /** + * Returns a NavigableSet of the specified portion of this set which + * contains elements less than (or equal to, depends on endInclusive) the + * end element. The returned NavigableSet is backed by this set so changes + * to one are reflected by the other. + * + * @param end + * the end element + * @param endInclusive + * true if the end element is in the returned set + * @return the subset + * + * @throws ClassCastException + * when the end object cannot be compared with the elements in + * this set + * @throws NullPointerException + * when the end object is null and the set cannot contain handle + * null + * @throws IllegalArgumentException + * when end is out of range and the set has a range + */ + NavigableSet<E> headSet(E end, boolean endInclusive); + + /** + * Returns a NavigableSet of the specified portion of this set which + * contains elements greater (or equal to, depends on startInclusive) the + * start element. The returned NavigableSet is backed by this set so changes + * to one are reflected by the other. + * + * @param start + * the start element + * @param startInclusive + * true if the start element is in the returned set + * @return the subset + * + * @throws ClassCastException + * when the start object cannot be compared with the elements in + * this set + * @throws NullPointerException + * when the start object is null and the set cannot contain null + * @throws IllegalArgumentException + * when start is out of range and the set has a range + */ + NavigableSet<E> tailSet(E start, boolean startInclusive); +}
\ No newline at end of file diff --git a/suncompat/src/main/java/sun/misc/Unsafe.java b/suncompat/src/main/java/sun/misc/Unsafe.java index 6ae572f..5c6aa01 100644 --- a/suncompat/src/main/java/sun/misc/Unsafe.java +++ b/suncompat/src/main/java/sun/misc/Unsafe.java @@ -17,11 +17,9 @@ package sun.misc; import dalvik.system.VMStack; - -import org.apache.harmony.kernel.vm.LangAccess; - import java.lang.reflect.Field; import java.lang.reflect.Modifier; +import org.apache.harmony.kernel.vm.LangAccess; /** * The package name notwithstanding, this class is the quasi-standard @@ -106,7 +104,6 @@ public final class Unsafe { * Helper for {@link #arrayBaseOffset}, which does all the work, * assuming the parameter is deemed valid. * - * @param field non-null; the instance field * @return the offset to the field */ private static native int arrayBaseOffset0(Class clazz); @@ -130,7 +127,6 @@ public final class Unsafe { * Helper for {@link #arrayIndexScale}, which does all the work, * assuming the parameter is deemed valid. * - * @param field non-null; the instance field * @return the offset to the field */ private static native int arrayIndexScale0(Class clazz); @@ -258,7 +254,15 @@ public final class Unsafe { * @param newValue the value to store */ public native void putInt(Object obj, long offset, int newValue); - + + /** + * Lazy set an int field. + */ + public void putOrderedInt(Object obj, long offset, int newValue) { + // TODO: this should be an intrinsic that executes a store fence followed by a write + putIntVolatile(obj, offset, newValue); + } + /** * Gets a <code>long</code> field from the given object. * @@ -278,6 +282,14 @@ public final class Unsafe { public native void putLong(Object obj, long offset, long newValue); /** + * Lazy set a long field. + */ + public void putOrderedLong(Object obj, long offset, long newValue) { + // TODO: this should be an intrinsic that executes a store fence followed by a write + putLongVolatile(obj, offset, newValue); + } + + /** * Gets an <code>Object</code> field from the given object. * * @param obj non-null; object containing the field @@ -296,6 +308,14 @@ public final class Unsafe { public native void putObject(Object obj, long offset, Object newValue); /** + * Lazy set an object field. + */ + public void putOrderedObject(Object obj, long offset, Object newValue) { + // TODO: this should be an intrinsic that executes a store fence followed by a write + putObjectVolatile(obj, offset, newValue); + } + + /** * Parks the calling thread for the specified amount of time, * unless the "permit" for the thread is already available (due to * a previous call to {@link #unpark}. This method may also return @@ -333,6 +353,4 @@ public final class Unsafe { throw new IllegalArgumentException("valid for Threads only"); } } - - // TODO(danfuzz): Stuff goes here. } |