mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8211283: Miscellaneous changes imported from jsr166 CVS 2018-11
Reviewed-by: martin, chegar
This commit is contained in:
parent
5a5aa52772
commit
53d3a4f50c
14 changed files with 218 additions and 213 deletions
|
@ -37,7 +37,6 @@ package java.util;
|
|||
import java.io.Serializable;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
|
||||
/**
|
||||
|
|
|
@ -2542,6 +2542,8 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
|||
setTabAt(tab, i, fwd);
|
||||
advance = true;
|
||||
}
|
||||
else if (f instanceof ReservationNode)
|
||||
throw new IllegalStateException("Recursive update");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -564,8 +564,8 @@ public class Exchanger<V> {
|
|||
Object item = (x == null) ? NULL_ITEM : x; // translate null args
|
||||
if (((a = arena) != null ||
|
||||
(v = slotExchange(item, false, 0L)) == null) &&
|
||||
((Thread.interrupted() || // disambiguates null return
|
||||
(v = arenaExchange(item, false, 0L)) == null)))
|
||||
(Thread.interrupted() || // disambiguates null return
|
||||
(v = arenaExchange(item, false, 0L)) == null))
|
||||
throw new InterruptedException();
|
||||
return (v == NULL_ITEM) ? null : (V)v;
|
||||
}
|
||||
|
@ -620,8 +620,8 @@ public class Exchanger<V> {
|
|||
long ns = unit.toNanos(timeout);
|
||||
if ((arena != null ||
|
||||
(v = slotExchange(item, true, ns)) == null) &&
|
||||
((Thread.interrupted() ||
|
||||
(v = arenaExchange(item, true, ns)) == null)))
|
||||
(Thread.interrupted() ||
|
||||
(v = arenaExchange(item, true, ns)) == null))
|
||||
throw new InterruptedException();
|
||||
if (v == TIMED_OUT)
|
||||
throw new TimeoutException();
|
||||
|
|
|
@ -1230,14 +1230,13 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
|||
/**
|
||||
* Immediately performs the base action of this task and returns
|
||||
* true if, upon return from this method, this task is guaranteed
|
||||
* to have completed normally. This method may return false
|
||||
* otherwise, to indicate that this task is not necessarily
|
||||
* complete (or is not known to be complete), for example in
|
||||
* asynchronous actions that require explicit invocations of
|
||||
* completion methods. This method may also throw an (unchecked)
|
||||
* exception to indicate abnormal exit. This method is designed to
|
||||
* support extensions, and should not in general be called
|
||||
* otherwise.
|
||||
* to have completed. This method may return false otherwise, to
|
||||
* indicate that this task is not necessarily complete (or is not
|
||||
* known to be complete), for example in asynchronous actions that
|
||||
* require explicit invocations of completion methods. This method
|
||||
* may also throw an (unchecked) exception to indicate abnormal
|
||||
* exit. This method is designed to support extensions, and should
|
||||
* not in general be called otherwise.
|
||||
*
|
||||
* @return {@code true} if this task is known to have completed normally
|
||||
*/
|
||||
|
|
|
@ -199,10 +199,11 @@ public class LockSupport {
|
|||
* 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:
|
||||
* <p>If the specified waiting time is zero or negative, the
|
||||
* method does nothing. Otherwise, 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
|
||||
|
@ -327,10 +328,11 @@ public class LockSupport {
|
|||
* 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:
|
||||
* <p>If the specified waiting time is zero or negative, the
|
||||
* method does nothing. Otherwise, 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
|
||||
|
|
|
@ -65,22 +65,23 @@ import jdk.internal.vm.annotation.ReservedStackAccess;
|
|||
* and timed versions of {@code tryReadLock} are also provided.
|
||||
*
|
||||
* <li><b>Optimistic Reading.</b> Method {@link #tryOptimisticRead}
|
||||
* returns a non-zero stamp only if the lock is not currently held
|
||||
* in write mode. Method {@link #validate} returns true if the lock
|
||||
* has not been acquired in write mode since obtaining a given
|
||||
* stamp. This mode can be thought of as an extremely weak version
|
||||
* of a read-lock, that can be broken by a writer at any time. The
|
||||
* use of optimistic mode for short read-only code segments often
|
||||
* reduces contention and improves throughput. However, its use is
|
||||
* inherently fragile. Optimistic read sections should only read
|
||||
* fields and hold them in local variables for later use after
|
||||
* validation. Fields read while in optimistic mode may be wildly
|
||||
* inconsistent, so usage applies only when you are familiar enough
|
||||
* with data representations to check consistency and/or repeatedly
|
||||
* invoke method {@code validate()}. For example, such steps are
|
||||
* typically required when first reading an object or array
|
||||
* reference, and then accessing one of its fields, elements or
|
||||
* methods.
|
||||
* returns a non-zero stamp only if the lock is not currently held in
|
||||
* write mode. Method {@link #validate} returns true if the lock has not
|
||||
* been acquired in write mode since obtaining a given stamp, in which
|
||||
* case all actions prior to the most recent write lock release
|
||||
* happen-before actions following the call to {@code tryOptimisticRead}.
|
||||
* This mode can be thought of as an extremely weak version of a
|
||||
* read-lock, that can be broken by a writer at any time. The use of
|
||||
* optimistic read mode for short read-only code segments often reduces
|
||||
* contention and improves throughput. However, its use is inherently
|
||||
* fragile. Optimistic read sections should only read fields and hold
|
||||
* them in local variables for later use after validation. Fields read
|
||||
* while in optimistic read mode may be wildly inconsistent, so usage
|
||||
* applies only when you are familiar enough with data representations to
|
||||
* check consistency and/or repeatedly invoke method {@code validate()}.
|
||||
* For example, such steps are typically required when first reading an
|
||||
* object or array reference, and then accessing one of its fields,
|
||||
* elements or methods.
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
|
@ -88,8 +89,8 @@ import jdk.internal.vm.annotation.ReservedStackAccess;
|
|||
* conversions across the three modes. For example, method {@link
|
||||
* #tryConvertToWriteLock} attempts to "upgrade" a mode, returning
|
||||
* a valid write stamp if (1) already in writing mode (2) in reading
|
||||
* mode and there are no other readers or (3) in optimistic mode and
|
||||
* the lock is available. The forms of these methods are designed to
|
||||
* mode and there are no other readers or (3) in optimistic read mode
|
||||
* and the lock is available. The forms of these methods are designed to
|
||||
* help reduce some of the code bloat that otherwise occurs in
|
||||
* retry-based designs.
|
||||
*
|
||||
|
@ -129,6 +130,19 @@ import jdk.internal.vm.annotation.ReservedStackAccess;
|
|||
* #asReadWriteLock()} in applications requiring only the associated
|
||||
* set of functionality.
|
||||
*
|
||||
* <p><b>Memory Synchronization.</b> Methods with the effect of
|
||||
* successfully locking in any mode have the same memory
|
||||
* synchronization effects as a <em>Lock</em> action described in
|
||||
* <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4">
|
||||
* Chapter 17 of <cite>The Java™ Language Specification</cite></a>.
|
||||
* Methods successfully unlocking in write mode have the same memory
|
||||
* synchronization effects as an <em>Unlock</em> action. In optimistic
|
||||
* read usages, actions prior to the most recent write mode unlock action
|
||||
* are guaranteed to happen-before those following a tryOptimisticRead
|
||||
* only if a later validate returns true; otherwise there is no guarantee
|
||||
* that the reads between tryOptimisticRead and validate obtain a
|
||||
* consistent snapshot.
|
||||
*
|
||||
* <p><b>Sample Usage.</b> The following illustrates some usage idioms
|
||||
* in a class that maintains simple two-dimensional points. The sample
|
||||
* code illustrates some try/catch conventions even though they are
|
||||
|
|
|
@ -93,14 +93,14 @@ public class LongAdderDemo {
|
|||
report(nthreads, incs, timeTasks(phaser), a.sum());
|
||||
}
|
||||
|
||||
static void report(int nthreads, int incs, long time, long sum) {
|
||||
static void report(int nthreads, int incs, long elapsedNanos, long sum) {
|
||||
long total = (long)nthreads * incs;
|
||||
if (sum != total)
|
||||
throw new Error(sum + " != " + total);
|
||||
double secs = (double)time / (1000L * 1000 * 1000);
|
||||
long rate = total * (1000L) / time;
|
||||
double elapsedSecs = (double)elapsedNanos / (1000L * 1000 * 1000);
|
||||
long rate = total * 1000L / elapsedNanos;
|
||||
System.out.printf("threads:%3d Time: %7.3fsec Incs per microsec: %4d\n",
|
||||
nthreads, secs, rate);
|
||||
nthreads, elapsedSecs, rate);
|
||||
}
|
||||
|
||||
static long timeTasks(Phaser phaser) {
|
||||
|
|
|
@ -953,17 +953,19 @@ public class CompletableFutureTest extends JSR166TestCase {
|
|||
for (boolean createIncomplete : new boolean[] { true, false })
|
||||
for (Integer v1 : new Integer[] { 1, null })
|
||||
{
|
||||
final AtomicInteger ran = new AtomicInteger(0);
|
||||
final CompletableFuture<Integer> f = new CompletableFuture<>();
|
||||
if (!createIncomplete) assertTrue(f.complete(v1));
|
||||
final CompletableFuture<Integer> g = m.exceptionally
|
||||
(f, (Throwable t) -> {
|
||||
threadFail("should not be called");
|
||||
return null; // unreached
|
||||
ran.getAndIncrement();
|
||||
throw new AssertionError("should not be called");
|
||||
});
|
||||
if (createIncomplete) assertTrue(f.complete(v1));
|
||||
|
||||
checkCompletedNormally(g, v1);
|
||||
checkCompletedNormally(f, v1);
|
||||
assertEquals(0, ran.get());
|
||||
}}
|
||||
|
||||
/**
|
||||
|
@ -975,21 +977,21 @@ public class CompletableFutureTest extends JSR166TestCase {
|
|||
for (boolean createIncomplete : new boolean[] { true, false })
|
||||
for (Integer v1 : new Integer[] { 1, null })
|
||||
{
|
||||
final AtomicInteger a = new AtomicInteger(0);
|
||||
final AtomicInteger ran = new AtomicInteger(0);
|
||||
final CFException ex = new CFException();
|
||||
final CompletableFuture<Integer> f = new CompletableFuture<>();
|
||||
if (!createIncomplete) f.completeExceptionally(ex);
|
||||
final CompletableFuture<Integer> g = m.exceptionally
|
||||
(f, (Throwable t) -> {
|
||||
m.checkExecutionMode();
|
||||
threadAssertSame(t, ex);
|
||||
a.getAndIncrement();
|
||||
assertSame(t, ex);
|
||||
ran.getAndIncrement();
|
||||
return v1;
|
||||
});
|
||||
if (createIncomplete) f.completeExceptionally(ex);
|
||||
|
||||
checkCompletedNormally(g, v1);
|
||||
assertEquals(1, a.get());
|
||||
assertEquals(1, ran.get());
|
||||
}}
|
||||
|
||||
/**
|
||||
|
@ -1000,7 +1002,7 @@ public class CompletableFutureTest extends JSR166TestCase {
|
|||
for (ExecutionMode m : ExecutionMode.values())
|
||||
for (boolean createIncomplete : new boolean[] { true, false })
|
||||
{
|
||||
final AtomicInteger a = new AtomicInteger(0);
|
||||
final AtomicInteger ran = new AtomicInteger(0);
|
||||
final CFException ex1 = new CFException();
|
||||
final CFException ex2 = new CFException();
|
||||
final CompletableFuture<Integer> f = new CompletableFuture<>();
|
||||
|
@ -1008,15 +1010,15 @@ public class CompletableFutureTest extends JSR166TestCase {
|
|||
final CompletableFuture<Integer> g = m.exceptionally
|
||||
(f, (Throwable t) -> {
|
||||
m.checkExecutionMode();
|
||||
threadAssertSame(t, ex1);
|
||||
a.getAndIncrement();
|
||||
assertSame(t, ex1);
|
||||
ran.getAndIncrement();
|
||||
throw ex2;
|
||||
});
|
||||
if (createIncomplete) f.completeExceptionally(ex1);
|
||||
|
||||
checkCompletedWithWrappedException(g, ex2);
|
||||
checkCompletedExceptionally(f, ex1);
|
||||
assertEquals(1, a.get());
|
||||
assertEquals(1, ran.get());
|
||||
}}
|
||||
|
||||
/**
|
||||
|
@ -1028,22 +1030,22 @@ public class CompletableFutureTest extends JSR166TestCase {
|
|||
for (boolean createIncomplete : new boolean[] { true, false })
|
||||
for (Integer v1 : new Integer[] { 1, null })
|
||||
{
|
||||
final AtomicInteger a = new AtomicInteger(0);
|
||||
final AtomicInteger ran = new AtomicInteger(0);
|
||||
final CompletableFuture<Integer> f = new CompletableFuture<>();
|
||||
if (!createIncomplete) assertTrue(f.complete(v1));
|
||||
final CompletableFuture<Integer> g = m.whenComplete
|
||||
(f,
|
||||
(Integer result, Throwable t) -> {
|
||||
m.checkExecutionMode();
|
||||
threadAssertSame(result, v1);
|
||||
threadAssertNull(t);
|
||||
a.getAndIncrement();
|
||||
assertSame(result, v1);
|
||||
assertNull(t);
|
||||
ran.getAndIncrement();
|
||||
});
|
||||
if (createIncomplete) assertTrue(f.complete(v1));
|
||||
|
||||
checkCompletedNormally(g, v1);
|
||||
checkCompletedNormally(f, v1);
|
||||
assertEquals(1, a.get());
|
||||
assertEquals(1, ran.get());
|
||||
}}
|
||||
|
||||
/**
|
||||
|
@ -1054,7 +1056,7 @@ public class CompletableFutureTest extends JSR166TestCase {
|
|||
for (ExecutionMode m : ExecutionMode.values())
|
||||
for (boolean createIncomplete : new boolean[] { true, false })
|
||||
{
|
||||
final AtomicInteger a = new AtomicInteger(0);
|
||||
final AtomicInteger ran = new AtomicInteger(0);
|
||||
final CFException ex = new CFException();
|
||||
final CompletableFuture<Integer> f = new CompletableFuture<>();
|
||||
if (!createIncomplete) f.completeExceptionally(ex);
|
||||
|
@ -1062,15 +1064,15 @@ public class CompletableFutureTest extends JSR166TestCase {
|
|||
(f,
|
||||
(Integer result, Throwable t) -> {
|
||||
m.checkExecutionMode();
|
||||
threadAssertNull(result);
|
||||
threadAssertSame(t, ex);
|
||||
a.getAndIncrement();
|
||||
assertNull(result);
|
||||
assertSame(t, ex);
|
||||
ran.getAndIncrement();
|
||||
});
|
||||
if (createIncomplete) f.completeExceptionally(ex);
|
||||
|
||||
checkCompletedWithWrappedException(g, ex);
|
||||
checkCompletedExceptionally(f, ex);
|
||||
assertEquals(1, a.get());
|
||||
assertEquals(1, ran.get());
|
||||
}}
|
||||
|
||||
/**
|
||||
|
@ -1082,22 +1084,22 @@ public class CompletableFutureTest extends JSR166TestCase {
|
|||
for (boolean mayInterruptIfRunning : new boolean[] { true, false })
|
||||
for (boolean createIncomplete : new boolean[] { true, false })
|
||||
{
|
||||
final AtomicInteger a = new AtomicInteger(0);
|
||||
final AtomicInteger ran = new AtomicInteger(0);
|
||||
final CompletableFuture<Integer> f = new CompletableFuture<>();
|
||||
if (!createIncomplete) assertTrue(f.cancel(mayInterruptIfRunning));
|
||||
final CompletableFuture<Integer> g = m.whenComplete
|
||||
(f,
|
||||
(Integer result, Throwable t) -> {
|
||||
m.checkExecutionMode();
|
||||
threadAssertNull(result);
|
||||
threadAssertTrue(t instanceof CancellationException);
|
||||
a.getAndIncrement();
|
||||
assertNull(result);
|
||||
assertTrue(t instanceof CancellationException);
|
||||
ran.getAndIncrement();
|
||||
});
|
||||
if (createIncomplete) assertTrue(f.cancel(mayInterruptIfRunning));
|
||||
|
||||
checkCompletedWithWrappedCancellationException(g);
|
||||
checkCancelled(f);
|
||||
assertEquals(1, a.get());
|
||||
assertEquals(1, ran.get());
|
||||
}}
|
||||
|
||||
/**
|
||||
|
@ -1109,7 +1111,7 @@ public class CompletableFutureTest extends JSR166TestCase {
|
|||
for (ExecutionMode m : ExecutionMode.values())
|
||||
for (Integer v1 : new Integer[] { 1, null })
|
||||
{
|
||||
final AtomicInteger a = new AtomicInteger(0);
|
||||
final AtomicInteger ran = new AtomicInteger(0);
|
||||
final CFException ex = new CFException();
|
||||
final CompletableFuture<Integer> f = new CompletableFuture<>();
|
||||
if (!createIncomplete) assertTrue(f.complete(v1));
|
||||
|
@ -1117,16 +1119,16 @@ public class CompletableFutureTest extends JSR166TestCase {
|
|||
(f,
|
||||
(Integer result, Throwable t) -> {
|
||||
m.checkExecutionMode();
|
||||
threadAssertSame(result, v1);
|
||||
threadAssertNull(t);
|
||||
a.getAndIncrement();
|
||||
assertSame(result, v1);
|
||||
assertNull(t);
|
||||
ran.getAndIncrement();
|
||||
throw ex;
|
||||
});
|
||||
if (createIncomplete) assertTrue(f.complete(v1));
|
||||
|
||||
checkCompletedWithWrappedException(g, ex);
|
||||
checkCompletedNormally(f, v1);
|
||||
assertEquals(1, a.get());
|
||||
assertEquals(1, ran.get());
|
||||
}}
|
||||
|
||||
/**
|
||||
|
@ -1138,7 +1140,7 @@ public class CompletableFutureTest extends JSR166TestCase {
|
|||
for (boolean createIncomplete : new boolean[] { true, false })
|
||||
for (ExecutionMode m : ExecutionMode.values())
|
||||
{
|
||||
final AtomicInteger a = new AtomicInteger(0);
|
||||
final AtomicInteger ran = new AtomicInteger(0);
|
||||
final CFException ex1 = new CFException();
|
||||
final CFException ex2 = new CFException();
|
||||
final CompletableFuture<Integer> f = new CompletableFuture<>();
|
||||
|
@ -1148,9 +1150,9 @@ public class CompletableFutureTest extends JSR166TestCase {
|
|||
(f,
|
||||
(Integer result, Throwable t) -> {
|
||||
m.checkExecutionMode();
|
||||
threadAssertSame(t, ex1);
|
||||
threadAssertNull(result);
|
||||
a.getAndIncrement();
|
||||
assertSame(t, ex1);
|
||||
assertNull(result);
|
||||
ran.getAndIncrement();
|
||||
throw ex2;
|
||||
});
|
||||
if (createIncomplete) f.completeExceptionally(ex1);
|
||||
|
@ -1161,7 +1163,7 @@ public class CompletableFutureTest extends JSR166TestCase {
|
|||
assertEquals(1, ex1.getSuppressed().length);
|
||||
assertSame(ex2, ex1.getSuppressed()[0]);
|
||||
}
|
||||
assertEquals(1, a.get());
|
||||
assertEquals(1, ran.get());
|
||||
}}
|
||||
|
||||
/**
|
||||
|
@ -1174,22 +1176,22 @@ public class CompletableFutureTest extends JSR166TestCase {
|
|||
for (Integer v1 : new Integer[] { 1, null })
|
||||
{
|
||||
final CompletableFuture<Integer> f = new CompletableFuture<>();
|
||||
final AtomicInteger a = new AtomicInteger(0);
|
||||
final AtomicInteger ran = new AtomicInteger(0);
|
||||
if (!createIncomplete) assertTrue(f.complete(v1));
|
||||
final CompletableFuture<Integer> g = m.handle
|
||||
(f,
|
||||
(Integer result, Throwable t) -> {
|
||||
m.checkExecutionMode();
|
||||
threadAssertSame(result, v1);
|
||||
threadAssertNull(t);
|
||||
a.getAndIncrement();
|
||||
assertSame(result, v1);
|
||||
assertNull(t);
|
||||
ran.getAndIncrement();
|
||||
return inc(v1);
|
||||
});
|
||||
if (createIncomplete) assertTrue(f.complete(v1));
|
||||
|
||||
checkCompletedNormally(g, inc(v1));
|
||||
checkCompletedNormally(f, v1);
|
||||
assertEquals(1, a.get());
|
||||
assertEquals(1, ran.get());
|
||||
}}
|
||||
|
||||
/**
|
||||
|
@ -1202,23 +1204,23 @@ public class CompletableFutureTest extends JSR166TestCase {
|
|||
for (Integer v1 : new Integer[] { 1, null })
|
||||
{
|
||||
final CompletableFuture<Integer> f = new CompletableFuture<>();
|
||||
final AtomicInteger a = new AtomicInteger(0);
|
||||
final AtomicInteger ran = new AtomicInteger(0);
|
||||
final CFException ex = new CFException();
|
||||
if (!createIncomplete) f.completeExceptionally(ex);
|
||||
final CompletableFuture<Integer> g = m.handle
|
||||
(f,
|
||||
(Integer result, Throwable t) -> {
|
||||
m.checkExecutionMode();
|
||||
threadAssertNull(result);
|
||||
threadAssertSame(t, ex);
|
||||
a.getAndIncrement();
|
||||
assertNull(result);
|
||||
assertSame(t, ex);
|
||||
ran.getAndIncrement();
|
||||
return v1;
|
||||
});
|
||||
if (createIncomplete) f.completeExceptionally(ex);
|
||||
|
||||
checkCompletedNormally(g, v1);
|
||||
checkCompletedExceptionally(f, ex);
|
||||
assertEquals(1, a.get());
|
||||
assertEquals(1, ran.get());
|
||||
}}
|
||||
|
||||
/**
|
||||
|
@ -1232,22 +1234,22 @@ public class CompletableFutureTest extends JSR166TestCase {
|
|||
for (Integer v1 : new Integer[] { 1, null })
|
||||
{
|
||||
final CompletableFuture<Integer> f = new CompletableFuture<>();
|
||||
final AtomicInteger a = new AtomicInteger(0);
|
||||
final AtomicInteger ran = new AtomicInteger(0);
|
||||
if (!createIncomplete) assertTrue(f.cancel(mayInterruptIfRunning));
|
||||
final CompletableFuture<Integer> g = m.handle
|
||||
(f,
|
||||
(Integer result, Throwable t) -> {
|
||||
m.checkExecutionMode();
|
||||
threadAssertNull(result);
|
||||
threadAssertTrue(t instanceof CancellationException);
|
||||
a.getAndIncrement();
|
||||
assertNull(result);
|
||||
assertTrue(t instanceof CancellationException);
|
||||
ran.getAndIncrement();
|
||||
return v1;
|
||||
});
|
||||
if (createIncomplete) assertTrue(f.cancel(mayInterruptIfRunning));
|
||||
|
||||
checkCompletedNormally(g, v1);
|
||||
checkCancelled(f);
|
||||
assertEquals(1, a.get());
|
||||
assertEquals(1, ran.get());
|
||||
}}
|
||||
|
||||
/**
|
||||
|
@ -1260,23 +1262,23 @@ public class CompletableFutureTest extends JSR166TestCase {
|
|||
for (Integer v1 : new Integer[] { 1, null })
|
||||
{
|
||||
final CompletableFuture<Integer> f = new CompletableFuture<>();
|
||||
final AtomicInteger a = new AtomicInteger(0);
|
||||
final AtomicInteger ran = new AtomicInteger(0);
|
||||
final CFException ex = new CFException();
|
||||
if (!createIncomplete) assertTrue(f.complete(v1));
|
||||
final CompletableFuture<Integer> g = m.handle
|
||||
(f,
|
||||
(Integer result, Throwable t) -> {
|
||||
m.checkExecutionMode();
|
||||
threadAssertSame(result, v1);
|
||||
threadAssertNull(t);
|
||||
a.getAndIncrement();
|
||||
assertSame(result, v1);
|
||||
assertNull(t);
|
||||
ran.getAndIncrement();
|
||||
throw ex;
|
||||
});
|
||||
if (createIncomplete) assertTrue(f.complete(v1));
|
||||
|
||||
checkCompletedWithWrappedException(g, ex);
|
||||
checkCompletedNormally(f, v1);
|
||||
assertEquals(1, a.get());
|
||||
assertEquals(1, ran.get());
|
||||
}}
|
||||
|
||||
/**
|
||||
|
@ -1288,7 +1290,7 @@ public class CompletableFutureTest extends JSR166TestCase {
|
|||
for (boolean createIncomplete : new boolean[] { true, false })
|
||||
for (ExecutionMode m : ExecutionMode.values())
|
||||
{
|
||||
final AtomicInteger a = new AtomicInteger(0);
|
||||
final AtomicInteger ran = new AtomicInteger(0);
|
||||
final CFException ex1 = new CFException();
|
||||
final CFException ex2 = new CFException();
|
||||
final CompletableFuture<Integer> f = new CompletableFuture<>();
|
||||
|
@ -1298,16 +1300,16 @@ public class CompletableFutureTest extends JSR166TestCase {
|
|||
(f,
|
||||
(Integer result, Throwable t) -> {
|
||||
m.checkExecutionMode();
|
||||
threadAssertNull(result);
|
||||
threadAssertSame(ex1, t);
|
||||
a.getAndIncrement();
|
||||
assertNull(result);
|
||||
assertSame(ex1, t);
|
||||
ran.getAndIncrement();
|
||||
throw ex2;
|
||||
});
|
||||
if (createIncomplete) f.completeExceptionally(ex1);
|
||||
|
||||
checkCompletedWithWrappedException(g, ex2);
|
||||
checkCompletedExceptionally(f, ex1);
|
||||
assertEquals(1, a.get());
|
||||
assertEquals(1, ran.get());
|
||||
}}
|
||||
|
||||
/**
|
||||
|
@ -3143,30 +3145,30 @@ public class CompletableFutureTest extends JSR166TestCase {
|
|||
case 0:
|
||||
assertTrue(f.complete(v1));
|
||||
assertTrue(g.completeExceptionally(ex));
|
||||
h = m.thenCompose(f, (x -> g));
|
||||
h = m.thenCompose(f, x -> g);
|
||||
break;
|
||||
case 1:
|
||||
assertTrue(f.complete(v1));
|
||||
h = m.thenCompose(f, (x -> g));
|
||||
h = m.thenCompose(f, x -> g);
|
||||
assertTrue(g.completeExceptionally(ex));
|
||||
break;
|
||||
case 2:
|
||||
assertTrue(g.completeExceptionally(ex));
|
||||
assertTrue(f.complete(v1));
|
||||
h = m.thenCompose(f, (x -> g));
|
||||
h = m.thenCompose(f, x -> g);
|
||||
break;
|
||||
case 3:
|
||||
assertTrue(g.completeExceptionally(ex));
|
||||
h = m.thenCompose(f, (x -> g));
|
||||
h = m.thenCompose(f, x -> g);
|
||||
assertTrue(f.complete(v1));
|
||||
break;
|
||||
case 4:
|
||||
h = m.thenCompose(f, (x -> g));
|
||||
h = m.thenCompose(f, x -> g);
|
||||
assertTrue(f.complete(v1));
|
||||
assertTrue(g.completeExceptionally(ex));
|
||||
break;
|
||||
case 5:
|
||||
h = m.thenCompose(f, (x -> g));
|
||||
h = m.thenCompose(f, x -> g);
|
||||
assertTrue(f.complete(v1));
|
||||
assertTrue(g.completeExceptionally(ex));
|
||||
break;
|
||||
|
@ -3258,30 +3260,30 @@ public class CompletableFutureTest extends JSR166TestCase {
|
|||
case 0:
|
||||
assertTrue(f.completeExceptionally(ex0));
|
||||
assertTrue(g.completeExceptionally(ex));
|
||||
h = m.exceptionallyCompose(f, (x -> g));
|
||||
h = m.exceptionallyCompose(f, x -> g);
|
||||
break;
|
||||
case 1:
|
||||
assertTrue(f.completeExceptionally(ex0));
|
||||
h = m.exceptionallyCompose(f, (x -> g));
|
||||
h = m.exceptionallyCompose(f, x -> g);
|
||||
assertTrue(g.completeExceptionally(ex));
|
||||
break;
|
||||
case 2:
|
||||
assertTrue(g.completeExceptionally(ex));
|
||||
assertTrue(f.completeExceptionally(ex0));
|
||||
h = m.exceptionallyCompose(f, (x -> g));
|
||||
h = m.exceptionallyCompose(f, x -> g);
|
||||
break;
|
||||
case 3:
|
||||
assertTrue(g.completeExceptionally(ex));
|
||||
h = m.exceptionallyCompose(f, (x -> g));
|
||||
h = m.exceptionallyCompose(f, x -> g);
|
||||
assertTrue(f.completeExceptionally(ex0));
|
||||
break;
|
||||
case 4:
|
||||
h = m.exceptionallyCompose(f, (x -> g));
|
||||
h = m.exceptionallyCompose(f, x -> g);
|
||||
assertTrue(f.completeExceptionally(ex0));
|
||||
assertTrue(g.completeExceptionally(ex));
|
||||
break;
|
||||
case 5:
|
||||
h = m.exceptionallyCompose(f, (x -> g));
|
||||
h = m.exceptionallyCompose(f, x -> g);
|
||||
assertTrue(f.completeExceptionally(ex0));
|
||||
assertTrue(g.completeExceptionally(ex));
|
||||
break;
|
||||
|
@ -3672,12 +3674,6 @@ public class CompletableFutureTest extends JSR166TestCase {
|
|||
final CompletableFuture<Integer> complete = CompletableFuture.completedFuture(v);
|
||||
final CompletableFuture<Integer> incomplete = new CompletableFuture<>();
|
||||
|
||||
List<CompletableFuture<?>> futures = new ArrayList<>();
|
||||
|
||||
List<CompletableFuture<Integer>> srcs = new ArrayList<>();
|
||||
srcs.add(complete);
|
||||
srcs.add(incomplete);
|
||||
|
||||
List<CompletableFuture<?>> fs = new ArrayList<>();
|
||||
fs.add(incomplete.thenRunAsync(() -> {}, e));
|
||||
fs.add(incomplete.thenAcceptAsync(z -> {}, e));
|
||||
|
@ -4862,18 +4858,21 @@ public class CompletableFutureTest extends JSR166TestCase {
|
|||
for (boolean createIncomplete : new boolean[] { true, false })
|
||||
for (Integer v1 : new Integer[] { 1, null })
|
||||
{
|
||||
final AtomicInteger ran = new AtomicInteger(0);
|
||||
final CompletableFuture<Integer> f = new CompletableFuture<>();
|
||||
final DelegatedCompletionStage<Integer> d =
|
||||
new DelegatedCompletionStage<Integer>(f);
|
||||
if (!createIncomplete) assertTrue(f.complete(v1));
|
||||
final CompletionStage<Integer> g = d.exceptionallyAsync
|
||||
((Throwable t) -> {
|
||||
threadFail("should not be called");
|
||||
return null; // unreached
|
||||
ran.getAndIncrement();
|
||||
throw new AssertionError("should not be called");
|
||||
});
|
||||
if (createIncomplete) assertTrue(f.complete(v1));
|
||||
|
||||
checkCompletedNormally(g.toCompletableFuture(), v1);
|
||||
checkCompletedNormally(f, v1);
|
||||
assertEquals(0, ran.get());
|
||||
}}
|
||||
|
||||
/**
|
||||
|
@ -4884,7 +4883,7 @@ public class CompletableFutureTest extends JSR166TestCase {
|
|||
for (boolean createIncomplete : new boolean[] { true, false })
|
||||
for (Integer v1 : new Integer[] { 1, null })
|
||||
{
|
||||
final AtomicInteger a = new AtomicInteger(0);
|
||||
final AtomicInteger ran = new AtomicInteger(0);
|
||||
final CFException ex = new CFException();
|
||||
final CompletableFuture<Integer> f = new CompletableFuture<>();
|
||||
final DelegatedCompletionStage<Integer> d =
|
||||
|
@ -4892,14 +4891,15 @@ public class CompletableFutureTest extends JSR166TestCase {
|
|||
if (!createIncomplete) f.completeExceptionally(ex);
|
||||
final CompletionStage<Integer> g = d.exceptionallyAsync
|
||||
((Throwable t) -> {
|
||||
threadAssertSame(t, ex);
|
||||
a.getAndIncrement();
|
||||
assertSame(t, ex);
|
||||
ran.getAndIncrement();
|
||||
return v1;
|
||||
});
|
||||
if (createIncomplete) f.completeExceptionally(ex);
|
||||
|
||||
checkCompletedNormally(g.toCompletableFuture(), v1);
|
||||
assertEquals(1, a.get());
|
||||
checkCompletedExceptionally(f, ex);
|
||||
assertEquals(1, ran.get());
|
||||
}}
|
||||
|
||||
/**
|
||||
|
@ -4910,7 +4910,7 @@ public class CompletableFutureTest extends JSR166TestCase {
|
|||
public void testDefaultExceptionallyAsync_exceptionalCompletionActionFailed() {
|
||||
for (boolean createIncomplete : new boolean[] { true, false })
|
||||
{
|
||||
final AtomicInteger a = new AtomicInteger(0);
|
||||
final AtomicInteger ran = new AtomicInteger(0);
|
||||
final CFException ex1 = new CFException();
|
||||
final CFException ex2 = new CFException();
|
||||
final CompletableFuture<Integer> f = new CompletableFuture<>();
|
||||
|
@ -4919,8 +4919,8 @@ public class CompletableFutureTest extends JSR166TestCase {
|
|||
if (!createIncomplete) f.completeExceptionally(ex1);
|
||||
final CompletionStage<Integer> g = d.exceptionallyAsync
|
||||
((Throwable t) -> {
|
||||
threadAssertSame(t, ex1);
|
||||
a.getAndIncrement();
|
||||
assertSame(t, ex1);
|
||||
ran.getAndIncrement();
|
||||
throw ex2;
|
||||
});
|
||||
if (createIncomplete) f.completeExceptionally(ex1);
|
||||
|
@ -4928,7 +4928,7 @@ public class CompletableFutureTest extends JSR166TestCase {
|
|||
checkCompletedWithWrappedException(g.toCompletableFuture(), ex2);
|
||||
checkCompletedExceptionally(f, ex1);
|
||||
checkCompletedExceptionally(d.toCompletableFuture(), ex1);
|
||||
assertEquals(1, a.get());
|
||||
assertEquals(1, ran.get());
|
||||
}}
|
||||
|
||||
/**
|
||||
|
|
|
@ -865,4 +865,20 @@ public class ConcurrentHashMapTest extends JSR166TestCase {
|
|||
assertEquals(mapSize, map.size());
|
||||
}
|
||||
|
||||
public void testReentrantComputeIfAbsent() {
|
||||
ConcurrentHashMap<Integer, Integer> map = new ConcurrentHashMap<>(16);
|
||||
try {
|
||||
for (int i = 0; i < 100; i++) { // force a resize
|
||||
map.computeIfAbsent(i, key -> findValue(map, key));
|
||||
}
|
||||
fail("recursive computeIfAbsent should throw IllegalStateException");
|
||||
} catch (IllegalStateException success) {}
|
||||
}
|
||||
|
||||
private Integer findValue(ConcurrentHashMap<Integer, Integer> map,
|
||||
Integer key) {
|
||||
return (key % 5 == 0) ? key :
|
||||
map.computeIfAbsent(key + 1, k -> findValue(map, k));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -136,7 +136,7 @@ public class ForkJoinPoolTest extends JSR166TestCase {
|
|||
return n;
|
||||
FibTask f1 = new FibTask(n - 1);
|
||||
f1.fork();
|
||||
return (new FibTask(n - 2)).compute() + f1.join();
|
||||
return new FibTask(n - 2).compute() + f1.join();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -144,13 +144,21 @@ import junit.framework.TestSuite;
|
|||
*
|
||||
* <ol>
|
||||
*
|
||||
* <li>All assertions in code running in generated threads must use
|
||||
* the forms {@link #threadFail}, {@link #threadAssertTrue}, {@link
|
||||
* #threadAssertEquals}, or {@link #threadAssertNull}, (not
|
||||
* {@code fail}, {@code assertTrue}, etc.) It is OK (but not
|
||||
* particularly recommended) for other code to use these forms too.
|
||||
* <li>All code not running in the main test thread (manually spawned threads
|
||||
* or the common fork join pool) must be checked for failure (and completion!).
|
||||
* Mechanisms that can be used to ensure this are:
|
||||
* <ol>
|
||||
* <li>Signalling via a synchronizer like AtomicInteger or CountDownLatch
|
||||
* that the task completed normally, which is checked before returning from
|
||||
* the test method in the main thread.
|
||||
* <li>Using the forms {@link #threadFail}, {@link #threadAssertTrue},
|
||||
* or {@link #threadAssertNull}, (not {@code fail}, {@code assertTrue}, etc.)
|
||||
* Only the most typically used JUnit assertion methods are defined
|
||||
* this way, but enough to live with.
|
||||
* <li>Recording failure explicitly using {@link #threadUnexpectedException}
|
||||
* or {@link #threadRecordFailure}.
|
||||
* <li>Using a wrapper like CheckedRunnable that uses one the mechanisms above.
|
||||
* </ol>
|
||||
*
|
||||
* <li>If you override {@link #setUp} or {@link #tearDown}, make sure
|
||||
* to invoke {@code super.setUp} and {@code super.tearDown} within
|
||||
|
@ -1318,22 +1326,33 @@ public class JSR166TestCase extends TestCase {
|
|||
/**
|
||||
* Spin-waits up to the specified number of milliseconds for the given
|
||||
* thread to enter a wait state: BLOCKED, WAITING, or TIMED_WAITING.
|
||||
* @param waitingForGodot if non-null, an additional condition to satisfy
|
||||
*/
|
||||
void waitForThreadToEnterWaitState(Thread thread, long timeoutMillis) {
|
||||
long startTime = 0L;
|
||||
for (;;) {
|
||||
Thread.State s = thread.getState();
|
||||
if (s == Thread.State.BLOCKED ||
|
||||
s == Thread.State.WAITING ||
|
||||
s == Thread.State.TIMED_WAITING)
|
||||
void waitForThreadToEnterWaitState(Thread thread, long timeoutMillis,
|
||||
Callable<Boolean> waitingForGodot) {
|
||||
for (long startTime = 0L;;) {
|
||||
switch (thread.getState()) {
|
||||
default: break;
|
||||
case BLOCKED: case WAITING: case TIMED_WAITING:
|
||||
try {
|
||||
if (waitingForGodot == null || waitingForGodot.call())
|
||||
return;
|
||||
else if (s == Thread.State.TERMINATED)
|
||||
} catch (Throwable fail) { threadUnexpectedException(fail); }
|
||||
break;
|
||||
case TERMINATED:
|
||||
fail("Unexpected thread termination");
|
||||
else if (startTime == 0L)
|
||||
}
|
||||
|
||||
if (startTime == 0L)
|
||||
startTime = System.nanoTime();
|
||||
else if (millisElapsedSince(startTime) > timeoutMillis) {
|
||||
threadAssertTrue(thread.isAlive());
|
||||
assertTrue(thread.isAlive());
|
||||
if (waitingForGodot == null
|
||||
|| thread.getState() == Thread.State.RUNNABLE)
|
||||
fail("timed out waiting for thread to enter wait state");
|
||||
else
|
||||
fail("timed out waiting for condition, thread state="
|
||||
+ thread.getState());
|
||||
}
|
||||
Thread.yield();
|
||||
}
|
||||
|
@ -1341,32 +1360,10 @@ public class JSR166TestCase extends TestCase {
|
|||
|
||||
/**
|
||||
* Spin-waits up to the specified number of milliseconds for the given
|
||||
* thread to enter a wait state: BLOCKED, WAITING, or TIMED_WAITING,
|
||||
* and additionally satisfy the given condition.
|
||||
* thread to enter a wait state: BLOCKED, WAITING, or TIMED_WAITING.
|
||||
*/
|
||||
void waitForThreadToEnterWaitState(
|
||||
Thread thread, long timeoutMillis, Callable<Boolean> waitingForGodot) {
|
||||
long startTime = 0L;
|
||||
for (;;) {
|
||||
Thread.State s = thread.getState();
|
||||
if (s == Thread.State.BLOCKED ||
|
||||
s == Thread.State.WAITING ||
|
||||
s == Thread.State.TIMED_WAITING) {
|
||||
try {
|
||||
if (waitingForGodot.call())
|
||||
return;
|
||||
} catch (Throwable fail) { threadUnexpectedException(fail); }
|
||||
}
|
||||
else if (s == Thread.State.TERMINATED)
|
||||
fail("Unexpected thread termination");
|
||||
else if (startTime == 0L)
|
||||
startTime = System.nanoTime();
|
||||
else if (millisElapsedSince(startTime) > timeoutMillis) {
|
||||
threadAssertTrue(thread.isAlive());
|
||||
fail("timed out waiting for thread to enter wait state");
|
||||
}
|
||||
Thread.yield();
|
||||
}
|
||||
void waitForThreadToEnterWaitState(Thread thread, long timeoutMillis) {
|
||||
waitForThreadToEnterWaitState(thread, timeoutMillis, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1374,7 +1371,7 @@ public class JSR166TestCase extends TestCase {
|
|||
* enter a wait state: BLOCKED, WAITING, or TIMED_WAITING.
|
||||
*/
|
||||
void waitForThreadToEnterWaitState(Thread thread) {
|
||||
waitForThreadToEnterWaitState(thread, LONG_DELAY_MS);
|
||||
waitForThreadToEnterWaitState(thread, LONG_DELAY_MS, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1382,8 +1379,8 @@ public class JSR166TestCase extends TestCase {
|
|||
* enter a wait state: BLOCKED, WAITING, or TIMED_WAITING,
|
||||
* and additionally satisfy the given condition.
|
||||
*/
|
||||
void waitForThreadToEnterWaitState(
|
||||
Thread thread, Callable<Boolean> waitingForGodot) {
|
||||
void waitForThreadToEnterWaitState(Thread thread,
|
||||
Callable<Boolean> waitingForGodot) {
|
||||
waitForThreadToEnterWaitState(thread, LONG_DELAY_MS, waitingForGodot);
|
||||
}
|
||||
|
||||
|
@ -1491,11 +1488,12 @@ public class JSR166TestCase extends TestCase {
|
|||
public final void run() {
|
||||
try {
|
||||
realRun();
|
||||
threadShouldThrow(exceptionClass.getSimpleName());
|
||||
} catch (Throwable t) {
|
||||
if (! exceptionClass.isInstance(t))
|
||||
threadUnexpectedException(t);
|
||||
return;
|
||||
}
|
||||
threadShouldThrow(exceptionClass.getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1505,12 +1503,13 @@ public class JSR166TestCase extends TestCase {
|
|||
public final void run() {
|
||||
try {
|
||||
realRun();
|
||||
threadShouldThrow("InterruptedException");
|
||||
} catch (InterruptedException success) {
|
||||
threadAssertFalse(Thread.interrupted());
|
||||
return;
|
||||
} catch (Throwable fail) {
|
||||
threadUnexpectedException(fail);
|
||||
}
|
||||
threadShouldThrow("InterruptedException");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1522,26 +1521,8 @@ public class JSR166TestCase extends TestCase {
|
|||
return realCall();
|
||||
} catch (Throwable fail) {
|
||||
threadUnexpectedException(fail);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class CheckedInterruptedCallable<T>
|
||||
implements Callable<T> {
|
||||
protected abstract T realCall() throws Throwable;
|
||||
|
||||
public final T call() {
|
||||
try {
|
||||
T result = realCall();
|
||||
threadShouldThrow("InterruptedException");
|
||||
return result;
|
||||
} catch (InterruptedException success) {
|
||||
threadAssertFalse(Thread.interrupted());
|
||||
} catch (Throwable fail) {
|
||||
threadUnexpectedException(fail);
|
||||
}
|
||||
return null;
|
||||
throw new AssertionError("unreached");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1656,14 +1637,6 @@ public class JSR166TestCase extends TestCase {
|
|||
public String call() { throw new NullPointerException(); }
|
||||
}
|
||||
|
||||
public class SmallPossiblyInterruptedRunnable extends CheckedRunnable {
|
||||
protected void realRun() {
|
||||
try {
|
||||
delay(SMALL_DELAY_MS);
|
||||
} catch (InterruptedException ok) {}
|
||||
}
|
||||
}
|
||||
|
||||
public Runnable possiblyInterruptedRunnable(final long timeoutMillis) {
|
||||
return new CheckedRunnable() {
|
||||
protected void realRun() {
|
||||
|
@ -1719,8 +1692,8 @@ public class JSR166TestCase extends TestCase {
|
|||
return realCompute();
|
||||
} catch (Throwable fail) {
|
||||
threadUnexpectedException(fail);
|
||||
return null;
|
||||
}
|
||||
throw new AssertionError("unreached");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -225,7 +225,7 @@ public class RecursiveTaskTest extends JSR166TestCase {
|
|||
return n;
|
||||
FibTask f1 = new FibTask(n - 1);
|
||||
f1.fork();
|
||||
return (new FibTask(n - 2)).compute() + f1.join();
|
||||
return new FibTask(n - 2).compute() + f1.join();
|
||||
}
|
||||
|
||||
public void publicSetRawResult(Integer result) {
|
||||
|
@ -244,7 +244,7 @@ public class RecursiveTaskTest extends JSR166TestCase {
|
|||
throw new FJException();
|
||||
FailingFibTask f1 = new FailingFibTask(n - 1);
|
||||
f1.fork();
|
||||
return (new FibTask(n - 2)).compute() + f1.join();
|
||||
return new FibTask(n - 2).compute() + f1.join();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -676,7 +676,7 @@ public class ScheduledExecutorSubclassTest extends JSR166TestCase {
|
|||
final CustomExecutor p = new CustomExecutor(1);
|
||||
try (PoolCleaner cleaner = cleaner(p, releaser)) {
|
||||
for (int i = 0; i < tasks.length; i++)
|
||||
tasks[i] = p.schedule(new SmallPossiblyInterruptedRunnable(),
|
||||
tasks[i] = p.schedule(possiblyInterruptedRunnable(SMALL_DELAY_MS),
|
||||
LONG_DELAY_MS, MILLISECONDS);
|
||||
int max = tasks.length;
|
||||
if (tasks[4].cancel(true)) --max;
|
||||
|
|
|
@ -634,7 +634,7 @@ public class ScheduledExecutorTest extends JSR166TestCase {
|
|||
final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
|
||||
try (PoolCleaner cleaner = cleaner(p, releaser)) {
|
||||
for (int i = 0; i < tasks.length; i++)
|
||||
tasks[i] = p.schedule(new SmallPossiblyInterruptedRunnable(),
|
||||
tasks[i] = p.schedule(possiblyInterruptedRunnable(SMALL_DELAY_MS),
|
||||
LONG_DELAY_MS, MILLISECONDS);
|
||||
int max = tasks.length;
|
||||
if (tasks[4].cancel(true)) --max;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue