undefect. CWE-407 — 63 sites patched across 27 ecosystems

Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
This commit is contained in:
russell@unturf.com 2026-03-26 17:11:57 -04:00
commit 0a580b313d
70422 changed files with 17213626 additions and 0 deletions

View file

@ -0,0 +1,766 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Martin Buchholz with assistance from members of JCP
* JSR-166 Expert Group and released to the public domain, as
* explained at http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* @test
* @modules java.base/java.util.concurrent:open
* @run testng WhiteBox
* @summary White box tests of implementation details
*/
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static org.testng.Assert.*;
import org.testng.annotations.Test;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.BooleanSupplier;
@Test
public class WhiteBox {
final ThreadLocalRandom rnd = ThreadLocalRandom.current();
final MethodHandles.Lookup lookup = MethodHandles.lookup();
final VarHandle ITRS, ITEMS, TAKEINDEX, PUTINDEX, COUNT, HEAD, NEXT, PREVTAKEINDEX;
WhiteBox() throws ReflectiveOperationException {
Class<?> qClass = ArrayBlockingQueue.class;
Class<?> itrClass = Class.forName(qClass.getName() + "$Itr");
Class<?> itrsClass = Class.forName(qClass.getName() + "$Itrs");
Class<?> nodeClass = Class.forName(itrsClass.getName() + "$Node");
ITRS = findVarHandle(qClass, "itrs", itrsClass);
ITEMS = findVarHandle(qClass, "items", Object[].class);
TAKEINDEX = findVarHandle(qClass, "takeIndex", int.class);
PUTINDEX = findVarHandle(qClass, "putIndex", int.class);
COUNT = findVarHandle(qClass, "count", int.class);
HEAD = findVarHandle(itrsClass, "head", nodeClass);
NEXT = findVarHandle(nodeClass, "next", nodeClass);
PREVTAKEINDEX = findVarHandle(itrClass, "prevTakeIndex", int.class);
}
VarHandle findVarHandle(Class<?> recv, String name, Class<?> type)
throws ReflectiveOperationException {
return MethodHandles.privateLookupIn(recv, lookup)
.findVarHandle(recv, name, type);
}
Object itrs(ArrayBlockingQueue q) { return ITRS.get(q); }
Object[] items(ArrayBlockingQueue q) { return (Object[]) ITEMS.get(q); }
int takeIndex(ArrayBlockingQueue q) { return (int) TAKEINDEX.get(q); }
int putIndex(ArrayBlockingQueue q) { return (int) PUTINDEX.get(q); }
int count(ArrayBlockingQueue q) { return (int) COUNT.get(q); }
Object head(Object itrs) { return HEAD.get(itrs); }
Object next(Object node) { return NEXT.get(node); }
int prevTakeIndex(Iterator itr) { return (int) PREVTAKEINDEX.get(itr); }
boolean isDetached(Iterator it) {
return prevTakeIndex(it) < 0;
}
void assertIteratorExhausted(Iterator it) {
if (rnd.nextBoolean()) {
assertTrue(!it.hasNext());
assertTrue(isDetached(it));
}
if (rnd.nextBoolean()) {
it.forEachRemaining(e -> { throw new AssertionError(); });
assertTrue(isDetached(it));
}
if (rnd.nextBoolean())
try { it.next(); fail("should throw"); }
catch (NoSuchElementException success) {}
}
List<Iterator> trackedIterators(ArrayBlockingQueue q) {
List<Iterator> its = new ArrayList<>();
Object itrs = itrs(q);
if (itrs != null) {
for (Object p = head(itrs); p != null; p = next(p))
its.add(((WeakReference<Iterator>)(p)).get());
Collections.reverse(its);
}
return its;
}
List<Iterator> attachedIterators(ArrayBlockingQueue q) {
List<Iterator> its = new ArrayList<>();
Object itrs = itrs(q);
if (itrs != null) {
for (Object p = head(itrs); p != null; p = next(p)) {
Iterator it = ((WeakReference<Iterator>)(p)).get();
if (it != null && !isDetached(it))
its.add(it);
}
Collections.reverse(its);
}
return its;
}
void assertRemoveThrowsISE(Iterator it) {
if (rnd.nextBoolean())
try { it.remove(); fail("should throw"); }
catch (IllegalStateException success) {}
}
void assertRemoveHasNoEffect(Iterator it, Collection c) {
if (rnd.nextBoolean()) {
int size = c.size();
it.remove(); // no effect
assertEquals(c.size(), size);
assertRemoveThrowsISE(it);
}
}
void checkIterationSanity(Queue q) {
if (rnd.nextBoolean())
return;
int size = q.size();
Object[] a = q.toArray();
Object[] b = new Object[size+2];
Arrays.fill(b, Boolean.TRUE);
Object[] c = q.toArray(b);
assertEquals(a.length, size);
assertSame(b, c);
assertNull(b[size]);
assertSame(b[size+1], Boolean.TRUE);
assertEquals(q.toString(), Arrays.toString(a));
Integer[] xx = null, yy = null;
if (size > 0) {
xx = new Integer[size - 1];
Arrays.fill(xx, 42);
yy = ((Queue<Integer>)q).toArray(xx);
for (Integer zz : xx)
assertEquals(42, (int) zz);
}
Iterator it = q.iterator();
for (int i = 0; i < size; i++) {
if (rnd.nextBoolean()) assertTrue(it.hasNext());
Object x = it.next();
assertSame(x, a[i]);
assertSame(x, b[i]);
assertSame(x, yy[i]);
}
if (rnd.nextBoolean()) assertTrue(!it.hasNext());
}
/**
* Instead of having putIndex (and takeIndex) at the initial
* default of 0, move them to a random location.
*/
void randomizePutIndex(ArrayBlockingQueue q) {
assertTrue(q.isEmpty());
int capacity = q.remainingCapacity();
int n = rnd.nextInt(capacity + 1);
int putIndex = putIndex(q);
for (int i = n; i-->0; ) q.add(Boolean.TRUE);
for (int i = n; i-->0; ) q.remove();
assertEquals(putIndex(q), (putIndex + n) % items(q).length);
}
/** No guarantees, but effective in practice. */
static void forceFullGc() {
long timeoutMillis = 1000L;
CountDownLatch finalized = new CountDownLatch(1);
ReferenceQueue<Object> queue = new ReferenceQueue<>();
WeakReference<Object> ref = new WeakReference<>(
new Object() { protected void finalize() { finalized.countDown(); }},
queue);
try {
for (int tries = 3; tries--> 0; ) {
System.gc();
if (finalized.await(timeoutMillis, MILLISECONDS)
&& queue.remove(timeoutMillis) != null
&& ref.get() == null) {
System.runFinalization(); // try to pick up stragglers
return;
}
timeoutMillis *= 4;
}
} catch (InterruptedException unexpected) {
throw new AssertionError("unexpected InterruptedException");
}
throw new AssertionError("failed to do a \"full\" gc");
}
static void gcAwait(BooleanSupplier s) {
for (int i = 0; i < 10; i++) {
if (s.getAsBoolean())
return;
forceFullGc();
}
throw new AssertionError("failed to satisfy condition");
}
public void clear_willClearItrs() {
boolean fair = rnd.nextBoolean();
int capacity = rnd.nextInt(2, 10);
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
randomizePutIndex(q);
List<Iterator> its = new ArrayList<>();
for (int i = 0; i < capacity; i++)
assertTrue(q.add(i));
assertNull(itrs(q));
for (int i = 0; i < capacity; i++) {
its.add(q.iterator());
assertEquals(trackedIterators(q), its);
q.poll();
q.add(capacity + i);
}
q.clear();
assertNull(itrs(q));
int j = 0;
for (Iterator it : its) {
assertTrue(isDetached(it));
if (rnd.nextBoolean()) assertTrue(it.hasNext());
if (rnd.nextBoolean()) {
assertEquals(it.next(), j);
assertIteratorExhausted(it);
}
j++;
}
}
public void queueEmptyingWillClearItrs() {
boolean fair = rnd.nextBoolean();
int capacity = rnd.nextInt(2, 10);
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
randomizePutIndex(q);
List<Iterator> its = new ArrayList<>();
for (int i = 0; i < capacity; i++)
q.add(i);
assertNull(itrs(q));
for (int i = 0; i < capacity; i++) {
its.add(q.iterator());
assertEquals(trackedIterators(q), its);
q.poll();
q.add(capacity+i);
}
for (int i = 0; i < capacity; i++)
q.poll();
assertNull(itrs(q));
int j = 0;
for (Iterator it : its) {
assertTrue(isDetached(it));
if (rnd.nextBoolean()) assertTrue(it.hasNext());
if (rnd.nextBoolean()) {
assertEquals(it.next(), j);
assertIteratorExhausted(it);
}
j++;
}
}
public void advancing2CyclesWillRemoveIterators() {
boolean fair = rnd.nextBoolean();
int capacity = rnd.nextInt(2, 10);
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
List<Iterator> its = new ArrayList<>();
for (int i = 0; i < capacity; i++)
q.add(i);
assertNull(itrs(q));
for (int i = capacity; i < 3 * capacity; i++) {
its.add(q.iterator());
assertEquals(trackedIterators(q), its);
q.poll();
q.add(i);
}
for (int i = 3 * capacity; i < 4 * capacity; i++) {
assertEquals(trackedIterators(q), its.subList(capacity,2*capacity));
q.poll();
q.add(i);
}
assertNull(itrs(q));
int j = 0;
for (Iterator it : its) {
assertTrue(isDetached(it));
if (rnd.nextBoolean()) assertTrue(it.hasNext());
if (rnd.nextBoolean()) {
assertEquals(it.next(), j);
assertIteratorExhausted(it);
}
j++;
}
}
/**
* Interior removal of elements used by an iterator will cause it
* to be untracked.
*/
public void interiorRemovalOfElementsUsedByIterator() {
boolean fair = rnd.nextBoolean();
int capacity = rnd.nextInt(10, 20);
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
randomizePutIndex(q);
q.add(0);
for (int i = 1; i < 2 * capacity; i++) {
q.add(i);
Integer[] elts = { -1, -2, -3 };
for (Integer elt : elts) q.add(elt);
assertEquals(q.remove(), i - 1);
Iterator it = q.iterator();
assertEquals(it.next(), i);
assertEquals(it.next(), elts[0]);
Collections.shuffle(Arrays.asList(elts));
assertTrue(q.remove(elts[0]));
assertTrue(q.remove(elts[1]));
assertEquals(trackedIterators(q), Collections.singletonList(it));
assertTrue(q.remove(elts[2]));
assertNull(itrs(q));
assertEquals(it.next(), -2);
assertIteratorExhausted(it);
assertTrue(isDetached(it));
}
}
public void iteratorsOnEmptyQueue() {
boolean fair = rnd.nextBoolean();
int capacity = rnd.nextInt(1, 10);
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
randomizePutIndex(q);
for (int i = 0; i < 4; i++) {
Iterator it = q.iterator();
assertNull(itrs(q));
assertIteratorExhausted(it);
assertTrue(isDetached(it));
assertRemoveThrowsISE(it);
}
}
public void interiorRemovalOfIteratorsLastElement() {
boolean fair = rnd.nextBoolean();
int capacity = rnd.nextInt(3, 10);
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
randomizePutIndex(q);
List<Iterator> its = new ArrayList<>();
for (int i = 0; i < capacity; i++)
q.add(i);
for (int i = 0; i < capacity; i++) {
Iterator it = q.iterator();
its.add(it);
for (int j = 0; j < i; j++)
assertEquals(j, it.next());
assertEquals(attachedIterators(q), its);
}
q.remove(capacity - 1);
assertEquals(attachedIterators(q), its);
for (int i = 1; i < capacity - 1; i++) {
q.remove(capacity - i - 1);
Iterator it = its.get(capacity - i);
assertTrue(isDetached(it));
assertEquals(attachedIterators(q), its.subList(0, capacity - i));
if (rnd.nextBoolean()) assertTrue(it.hasNext());
assertEquals(it.next(), capacity - i);
assertIteratorExhausted(it);
}
assertEquals(attachedIterators(q), its.subList(0, 2));
q.remove(0);
assertTrue(q.isEmpty());
assertNull(itrs(q));
Iterator it = its.get(0);
assertEquals(it.next(), 0);
assertRemoveHasNoEffect(it, q);
assertIteratorExhausted(it);
assertTrue(isDetached(it));
assertRemoveHasNoEffect(its.get(1), q);
}
/**
* Checks "interior" removal of alternating elements, straddling 2 cycles
*/
public void interiorRemovalOfAlternatingElements() {
boolean fair = rnd.nextBoolean();
int capacity = 2 * rnd.nextInt(2, 10);
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
List<Iterator> its = new ArrayList<>();
// Move takeIndex to middle
for (int i = 0; i < capacity/2; i++) {
assertTrue(q.add(i));
assertEquals(q.poll(), i);
}
assertEquals(takeIndex(q), capacity/2);
for (int i = 0; i < capacity; i++)
q.add(i);
for (int i = 0; i < capacity; i++) {
Iterator it = q.iterator();
its.add(it);
for (int j = 0; j < i; j++)
assertEquals(j, it.next());
assertEquals(attachedIterators(q), its);
}
// Remove all even elements, in either direction, using
// q.remove(), or iterator.remove()
switch (rnd.nextInt(3)) {
case 0:
for (int i = 0; i < capacity; i+=2) assertTrue(q.remove(i));
break;
case 1:
for (int i = capacity - 2; i >= 0; i-=2) assertTrue(q.remove(i));
break;
case 2:
Iterator it = q.iterator();
while (it.hasNext()) {
int i = (Integer) it.next();
if ((i & 1) == 0)
it.remove();
}
break;
default: throw new AssertionError();
}
assertEquals(attachedIterators(q), its);
for (int i = 0; i < capacity; i++) {
Iterator it = its.get(i);
boolean even = ((i & 1) == 0);
if (even) {
if (rnd.nextBoolean()) assertTrue(it.hasNext());
assertEquals(i, it.next());
for (int j = i+1; j < capacity; j += 2)
assertEquals(j, it.next());
assertTrue(!isDetached(it));
assertTrue(!it.hasNext());
assertTrue(isDetached(it));
} else { /* odd */
if (rnd.nextBoolean()) assertTrue(it.hasNext());
assertRemoveHasNoEffect(it, q);
assertEquals(i, it.next());
for (int j = i+2; j < capacity; j += 2)
assertEquals(j, it.next());
assertTrue(!isDetached(it));
assertTrue(!it.hasNext());
assertTrue(isDetached(it));
}
}
assertEquals(trackedIterators(q), Collections.emptyList());
assertNull(itrs(q));
}
public void garbageCollectionOfUnreachableIterators() {
boolean fair = rnd.nextBoolean();
int capacity = rnd.nextInt(1, 10);
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
randomizePutIndex(q);
List<Iterator> its = new ArrayList<>();
for (int i = 0; i < capacity; i++) q.add(i);
for (int i = 0; i < capacity; i++) its.add(q.iterator());
assertEquals(attachedIterators(q), its);
its = null;
gcAwait(() -> {
List<Iterator> trackedIterators = trackedIterators(q);
assertEquals(trackedIterators.size(), capacity);
for (Iterator x : trackedIterators)
if (x != null) return false;
return true;
});
Iterator it = q.iterator(); //
assertEquals(trackedIterators(q), Collections.singletonList(it));
}
public void garbageCollectionOfUnreachableIteratorsWithRandomlyRetainedSubset() {
boolean fair = rnd.nextBoolean();
int capacity = rnd.nextInt(10, 20);
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
randomizePutIndex(q);
List<Iterator> its = new ArrayList<>();
List<Iterator> retained = new ArrayList<>();
final int size = 1 + rnd.nextInt(capacity);
for (int i = 0; i < size; i++) q.add(i);
for (int i = 0; i < size; i++) its.add(q.iterator());
assertEquals(attachedIterators(q), its);
// Leave sufficient gaps in retained
for (int i = 0; i < size; i+= 2+rnd.nextInt(3))
retained.add(its.get(i));
its = null;
gcAwait(() -> {
List<Iterator> trackedIterators = trackedIterators(q);
assertEquals(trackedIterators.size(), size);
for (Iterator it : trackedIterators)
if ((it != null) ^ retained.contains(it)) return false;
return true;
});
Iterator it = q.iterator(); // trigger another sweep
retained.add(it);
assertEquals(trackedIterators(q), retained);
}
/**
* Checks incremental sweeping of unreachable iterators.
* Excessively white box?!
*/
public void incrementalSweepingOfUnreachableIterators() {
boolean fair = rnd.nextBoolean();
int capacity = rnd.nextInt(10, 20);
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
randomizePutIndex(q);
final int SHORT_SWEEP_PROBES = 4;
final int LONG_SWEEP_PROBES = 16;
final int PROBE_HOP = LONG_SWEEP_PROBES + 6 * SHORT_SWEEP_PROBES;
final int PROBE_HOP_COUNT = 10;
// Expect around 8 sweeps per PROBE_HOP
final int SWEEPS_PER_PROBE_HOP = 8;
List<Iterator> its = new ArrayList<>();
for (int i = 0; i < capacity; i++)
q.add(i);
for (int i = 0; i < PROBE_HOP_COUNT * PROBE_HOP; i++)
its.add(q.iterator());
assertEquals(attachedIterators(q), its);
// make some garbage, separated by PROBE_HOP
for (int i = 0; i < its.size(); i += PROBE_HOP)
its.set(i, null);
its.removeIf(it -> it == null);
forceFullGc();
int retries;
for (retries = 0;
trackedIterators(q).contains(null) && retries < 1000;
retries++)
// one round of sweeping
its.add(q.iterator());
assertTrue(retries >= PROBE_HOP_COUNT * (SWEEPS_PER_PROBE_HOP - 2));
assertTrue(retries <= PROBE_HOP_COUNT * (SWEEPS_PER_PROBE_HOP + 2));
assertEquals(trackedIterators(q), its);
}
public void Iterator_remove_safetyWhileInDetachedMode() {
boolean fair = rnd.nextBoolean();
int capacity = rnd.nextInt(10, 20);
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
List<Iterator> its = new ArrayList<>();
for (int i = 0; i < capacity/2; i++) {
q.add(i);
q.remove();
}
assertEquals(takeIndex(q), capacity/2);
for (int i = 0; i < capacity; i++)
q.add(i);
for (int i = 0; i < capacity; i++) {
Iterator it = q.iterator();
its.add(it);
for (int j = 0; j < i; j++)
assertEquals(j, it.next());
}
assertEquals(attachedIterators(q), its);
for (int i = capacity - 1; i >= 0; i--) {
Iterator it = its.get(i);
assertEquals(i, it.next()); // last element
assertTrue(!isDetached(it));
assertTrue(!it.hasNext()); // first hasNext failure
assertTrue(isDetached(it));
int size = q.size();
assertTrue(q.contains(i));
switch (rnd.nextInt(3)) {
case 0:
it.remove();
assertTrue(!q.contains(i));
assertEquals(q.size(), size - 1);
break;
case 1:
// replace i with impostor
if (q.remainingCapacity() == 0) {
assertTrue(q.remove(i));
assertTrue(q.add(-1));
} else {
assertTrue(q.add(-1));
assertTrue(q.remove(i));
}
it.remove(); // should have no effect
assertEquals(size, q.size());
assertTrue(q.contains(-1));
assertTrue(q.remove(-1));
break;
case 2:
// replace i with true impostor
if (i != 0) {
assertTrue(q.remove(i));
assertTrue(q.add(i));
}
it.remove();
assertTrue(!q.contains(i));
assertEquals(q.size(), size - 1);
break;
default: throw new AssertionError();
}
assertRemoveThrowsISE(it);
assertTrue(isDetached(it));
assertTrue(!trackedIterators(q).contains(it));
}
assertTrue(q.isEmpty());
assertNull(itrs(q));
for (Iterator it : its)
assertIteratorExhausted(it);
}
/**
* Checks dequeues bypassing iterators' current positions.
*/
public void dequeuesBypassingIteratorCurrentPositions() {
boolean fair = rnd.nextBoolean();
int capacity = rnd.nextInt(10, 20);
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
Queue<Iterator> its0 = new ArrayDeque<>();
Queue<Iterator> itsMid = new ArrayDeque<>();
List<Iterator> its = new ArrayList<>();
for (int i = 0; i < capacity; i++)
q.add(i);
for (int i = 0; i < 2 * capacity + 1; i++) {
Iterator it = q.iterator();
its.add(it);
its0.add(it);
}
for (int i = 0; i < 2 * capacity + 1; i++) {
Iterator it = q.iterator();
for (int j = 0; j < capacity/2; j++)
assertEquals(j, it.next());
its.add(it);
itsMid.add(it);
}
for (int i = capacity; i < 3 * capacity; i++) {
Iterator it;
it = its0.remove();
assertRemoveThrowsISE(it);
if (rnd.nextBoolean()) assertTrue(it.hasNext());
assertEquals(0, it.next());
int victim = i - capacity;
for (int j = victim + (victim == 0 ? 1 : 0); j < i; j++) {
if (rnd.nextBoolean()) assertTrue(it.hasNext());
assertEquals(j, it.next());
}
assertIteratorExhausted(it);
it = itsMid.remove();
if (victim >= capacity/2)
assertRemoveHasNoEffect(it, q);
assertEquals(capacity/2, it.next());
if (victim > capacity/2)
assertRemoveHasNoEffect(it, q);
for (int j = Math.max(victim, capacity/2 + 1); j < i; j++) {
if (rnd.nextBoolean()) assertTrue(it.hasNext());
assertEquals(j, it.next());
}
assertIteratorExhausted(it);
if (rnd.nextBoolean()) {
assertEquals(victim, q.remove());
} else {
ArrayList list = new ArrayList(1);
q.drainTo(list, 1);
assertEquals(list.size(), 1);
assertEquals(victim, list.get(0));
}
assertTrue(q.add(i));
}
// takeIndex has wrapped twice.
Iterator it0 = its0.remove();
Iterator itMid = itsMid.remove();
assertTrue(isDetached(it0));
assertTrue(isDetached(itMid));
if (rnd.nextBoolean()) assertTrue(it0.hasNext());
if (rnd.nextBoolean()) assertTrue(itMid.hasNext());
assertRemoveThrowsISE(it0);
assertRemoveHasNoEffect(itMid, q);
if (rnd.nextBoolean()) assertEquals(0, it0.next());
if (rnd.nextBoolean()) assertEquals(capacity/2, itMid.next());
assertTrue(isDetached(it0));
assertTrue(isDetached(itMid));
assertEquals(capacity, q.size());
assertEquals(0, q.remainingCapacity());
}
/**
* Checks collective sanity of iteration, toArray() and toString().
*/
public void collectiveSanity() {
boolean fair = rnd.nextBoolean();
int capacity = rnd.nextInt(10, 20);
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
randomizePutIndex(q);
for (int i = 0; i < capacity; i++) {
checkIterationSanity(q);
assertEquals(capacity, q.size() + q.remainingCapacity());
q.add(i);
}
for (int i = 0; i < (capacity + (capacity >> 1)); i++) {
checkIterationSanity(q);
assertEquals(capacity, q.size() + q.remainingCapacity());
assertEquals(i, q.peek());
assertEquals(i, q.poll());
checkIterationSanity(q);
assertEquals(capacity, q.size() + q.remainingCapacity());
q.add(capacity + i);
}
for (int i = 0; i < capacity; i++) {
checkIterationSanity(q);
assertEquals(capacity, q.size() + q.remainingCapacity());
int expected = i + capacity + (capacity >> 1);
assertEquals(expected, q.peek());
assertEquals(expected, q.poll());
}
checkIterationSanity(q);
}
public void iteratorsDetachedWhenExhaustedAndLastRetRemoved() {
boolean fair = rnd.nextBoolean();
int capacity = rnd.nextInt(2, 10);
ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair);
randomizePutIndex(q);
int size = rnd.nextInt(1, capacity + 1);
for (int i = 0; i < size; i++) q.add(i);
Iterator it = q.iterator();
for (int i = 0; i < size - 1; i++) assertEquals(i, it.next());
assertEquals(trackedIterators(q), Collections.singletonList(it));
assertFalse(isDetached(it));
switch (rnd.nextInt(2)) {
case 0: assertTrue(q.remove(size - 1)); break;
case 1: assertTrue(q.removeIf(e -> e.equals(size - 1))); break;
default: throw new AssertionError();
}
assertEquals(size - 1, it.next()); // should trigger detach
assertNull(itrs(q));
assertTrue(isDetached(it));
assertRemoveHasNoEffect(it, q);
}
}

View file

@ -0,0 +1,185 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* @test
* @bug 4486658
* @summary Checks for responsiveness of blocking queues to cancellation.
* @library /test/lib
*/
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import jdk.test.lib.Utils;
public class CancelledProducerConsumerLoops {
static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
static ExecutorService pool;
public static void main(String[] args) throws Exception {
final int maxPairs = (args.length > 0) ? Integer.parseInt(args[0]) : 5;
pool = Executors.newCachedThreadPool();
for (int i = 1; i <= maxPairs; i += (i+1) >>> 1) {
final List<BlockingQueue<Integer>> queues = new ArrayList<>();
queues.add(new ArrayBlockingQueue<Integer>(100));
queues.add(new LinkedBlockingQueue<Integer>(100));
queues.add(new LinkedBlockingDeque<Integer>(100));
queues.add(new SynchronousQueue<Integer>());
// unbounded queue implementations are prone to OOME:
// PriorityBlockingQueue, LinkedTransferQueue
for (BlockingQueue<Integer> queue : queues)
new CancelledProducerConsumerLoops(i, queue).run();
}
pool.shutdown();
if (! pool.awaitTermination(LONG_DELAY_MS, MILLISECONDS))
throw new AssertionError("timed out");
pool = null;
}
final int npairs;
final BlockingQueue<Integer> queue;
final CountDownLatch producersInterrupted;
final CountDownLatch consumersInterrupted;
final LoopHelpers.BarrierTimer timer = new LoopHelpers.BarrierTimer();
final CyclicBarrier barrier;
volatile boolean done = false;
CancelledProducerConsumerLoops(int npairs, BlockingQueue<Integer> queue) {
this.npairs = npairs;
this.queue = queue;
this.producersInterrupted = new CountDownLatch(npairs - 1);
this.consumersInterrupted = new CountDownLatch(npairs - 1);
this.barrier = new CyclicBarrier(npairs * 2 + 1, timer);
}
void run() throws Exception {
Future<?>[] prods = new Future<?>[npairs];
Future<?>[] cons = new Future<?>[npairs];
for (int i = 0; i < npairs; i++) {
prods[i] = pool.submit(new Producer());
cons[i] = pool.submit(new Consumer());
}
barrier.await();
Thread.sleep(ThreadLocalRandom.current().nextInt(5));
for (int i = 1; i < npairs; i++) {
if (!prods[i].cancel(true) ||
!cons[i].cancel(true))
throw new AssertionError("completed before done");
}
for (int i = 1; i < npairs; i++) {
assertCancelled(prods[i]);
assertCancelled(cons[i]);
}
if (!producersInterrupted.await(LONG_DELAY_MS, MILLISECONDS))
throw new AssertionError("timed out");
if (!consumersInterrupted.await(LONG_DELAY_MS, MILLISECONDS))
throw new AssertionError("timed out");
if (prods[0].isDone() || prods[0].isCancelled())
throw new AssertionError("completed too early");
done = true;
if (! (prods[0].get(LONG_DELAY_MS, MILLISECONDS) instanceof Integer))
throw new AssertionError("expected Integer");
if (! (cons[0].get(LONG_DELAY_MS, MILLISECONDS) instanceof Integer))
throw new AssertionError("expected Integer");
}
void assertCancelled(Future<?> future) throws Exception {
if (!future.isDone())
throw new AssertionError("not done");
if (!future.isCancelled())
throw new AssertionError("not cancelled");
try {
future.get(LONG_DELAY_MS, MILLISECONDS);
throw new AssertionError("should throw CancellationException");
} catch (CancellationException success) {}
}
class Producer implements Callable<Integer> {
public Integer call() throws Exception {
barrier.await();
int sum = 0;
try {
int x = 4321;
while (!done) {
if (Thread.interrupted()) throw new InterruptedException();
x = LoopHelpers.compute1(x);
sum += LoopHelpers.compute2(x);
queue.offer(new Integer(x), 1, TimeUnit.MILLISECONDS);
}
} catch (InterruptedException cancelled) {
producersInterrupted.countDown();
}
return sum;
}
}
class Consumer implements Callable<Integer> {
public Integer call() throws Exception {
barrier.await();
int sum = 0;
try {
while (!done) {
Integer x = queue.poll(1, TimeUnit.MILLISECONDS);
if (x != null)
sum += LoopHelpers.compute1(x.intValue());
}
} catch (InterruptedException cancelled) {
consumersInterrupted.countDown();
}
return sum;
}
}
}

View file

@ -0,0 +1,218 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea 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/publicdomain/zero/1.0/
*/
/*
* @test
* @summary Test drainTo failing due to c.add throwing
* @library /test/lib
*/
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.FutureTask;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.RunnableScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import jdk.test.lib.Utils;
@SuppressWarnings({"unchecked", "rawtypes"})
public class DrainToFails {
static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
final int CAPACITY = 10;
final int SMALL = 2;
void test(String[] args) throws Throwable {
testDelayQueue(new DelayQueue());
testDelayQueue(new ScheduledThreadPoolExecutor(1).getQueue());
testUnbounded(new LinkedBlockingQueue());
testUnbounded(new LinkedBlockingDeque());
testUnbounded(new PriorityBlockingQueue());
testBounded(new LinkedBlockingQueue(CAPACITY));
testBounded(new LinkedBlockingDeque(CAPACITY));
testBounded(new ArrayBlockingQueue(CAPACITY));
}
static class PDelay
extends FutureTask<Void>
implements Delayed, RunnableScheduledFuture<Void> {
int pseudodelay;
PDelay(int i) {
super(new Runnable() { public void run() {}}, null);
pseudodelay = i;
}
public int compareTo(PDelay other) {
return Integer.compare(this.pseudodelay, other.pseudodelay);
}
public int compareTo(Delayed y) {
return compareTo((PDelay)y);
}
public boolean equals(Object other) {
return (other instanceof PDelay) &&
this.pseudodelay == ((PDelay)other).pseudodelay;
}
public long getDelay(TimeUnit ignore) {
return Integer.MIN_VALUE + pseudodelay;
}
public String toString() {
return String.valueOf(pseudodelay);
}
public boolean isPeriodic() { return false; }
}
void testDelayQueue(final BlockingQueue q) throws Throwable {
System.err.println(q.getClass().getSimpleName());
for (int i = 0; i < CAPACITY; i++)
q.add(new PDelay(i));
ArrayBlockingQueue q2 = new ArrayBlockingQueue(SMALL);
try {
q.drainTo(q2, SMALL + 3);
fail("should throw");
} catch (IllegalStateException success) {
equal(SMALL, q2.size());
equal(new PDelay(0), q2.poll());
equal(new PDelay(1), q2.poll());
check(q2.isEmpty());
for (int i = SMALL; i < CAPACITY; i++)
equal(new PDelay(i), q.poll());
equal(0, q.size());
}
}
void testUnbounded(final BlockingQueue q) throws Throwable {
System.err.println(q.getClass().getSimpleName());
for (int i = 0; i < CAPACITY; i++)
q.add(i);
ArrayBlockingQueue q2 = new ArrayBlockingQueue(SMALL);
try {
q.drainTo(q2, 7);
fail("should throw");
} catch (IllegalStateException success) {
assertContentsInOrder(q2, 0, 1);
q2.clear();
equal(q.size(), CAPACITY - SMALL);
equal(SMALL, q.peek());
}
try {
q.drainTo(q2);
fail("should throw");
} catch (IllegalStateException success) {
assertContentsInOrder(q2, 2, 3);
equal(q.size(), CAPACITY - 2 * SMALL);
for (int i = 2 * SMALL; i < CAPACITY; i++)
equal(i, q.poll());
equal(0, q.size());
}
}
void testBounded(final BlockingQueue q) throws Throwable {
System.err.println(q.getClass().getSimpleName());
for (int i = 0; i < CAPACITY; i++)
q.add(i);
List<Thread> putters = new ArrayList<>();
for (int i = 0; i < 4; i++) {
Thread putter = new Thread(putter(q, 42 + i));
putters.add(putter);
putter.setDaemon(true);
putter.start();
}
ArrayBlockingQueue q2 = new ArrayBlockingQueue(SMALL);
try {
q.drainTo(q2, 7);
fail("should throw");
} catch (IllegalStateException success) {
while (q.size() < CAPACITY)
Thread.yield();
assertContentsInOrder(q2, 0, 1);
q2.clear();
}
try {
q.drainTo(q2);
fail("should throw");
} catch (IllegalStateException success) {
for (Thread putter : putters) {
putter.join(LONG_DELAY_MS);
check(! putter.isAlive());
}
assertContentsInOrder(q2, 2, 3);
for (int i = 2 * SMALL; i < CAPACITY; i++)
equal(i, q.poll());
equal(4, q.size());
check(q.contains(42));
check(q.contains(43));
check(q.contains(44));
check(q.contains(45));
}
}
Runnable putter(BlockingQueue q, int elt) {
return () -> {
try { q.put(elt); }
catch (Throwable t) { unexpected(t); }};
}
void assertContentsInOrder(Iterable it, Object... contents) {
int i = 0;
for (Object e : it)
equal(contents[i++], e);
equal(contents.length, i);
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
new DrainToFails().instanceMain(args);}
public void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}

View file

@ -0,0 +1,143 @@
/*
* Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6384064
* @summary Check proper handling of interrupts
* @author Martin Buchholz
* @library /test/lib
*/
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import jdk.test.lib.Utils;
public class Interrupt {
static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
static void checkInterrupted0(Iterable<Fun> fs, Executor ex) {
for (Fun f : fs) {
try {
ex.execute(new Runnable() {
final Thread thisThread = Thread.currentThread();
public void run() { thisThread.interrupt(); }});
f.f();
fail("Expected InterruptedException not thrown");
} catch (InterruptedException e) {
check(! Thread.interrupted());
} catch (Throwable t) { unexpected(t); }
}
}
static void checkInterrupted(Iterable<Fun> fs)
throws InterruptedException {
final Executor immediateExecutor = new Executor() {
public void execute(Runnable r) {
r.run(); }};
final ScheduledThreadPoolExecutor stpe
= new ScheduledThreadPoolExecutor(1);
final Executor delayedExecutor = new Executor() {
public void execute(Runnable r) {
stpe.schedule(r, 20, MILLISECONDS); }};
checkInterrupted0(fs, immediateExecutor);
checkInterrupted0(fs, delayedExecutor);
stpe.shutdown();
check(stpe.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
}
static void testQueue(final BlockingQueue<Object> q) {
try {
final BlockingDeque<Object> deq =
(q instanceof BlockingDeque<?>) ?
(BlockingDeque<Object>) q : null;
q.clear();
List<Fun> fs = new ArrayList<>();
fs.add(() -> q.take());
fs.add(() -> q.poll(LONG_DELAY_MS, MILLISECONDS));
if (deq != null) {
fs.add(() -> deq.takeFirst());
fs.add(() -> deq.takeLast());
fs.add(() -> deq.pollFirst(LONG_DELAY_MS, MILLISECONDS));
fs.add(() -> deq.pollLast(LONG_DELAY_MS, MILLISECONDS));
}
checkInterrupted(fs);
// fill q to capacity, to ensure insertions will block
while (q.remainingCapacity() > 0)
try { q.put(1); }
catch (Throwable t) { unexpected(t); }
fs.clear();
fs.add(() -> q.put(1));
fs.add(() -> q.offer(1, LONG_DELAY_MS, MILLISECONDS));
if (deq != null) {
fs.add(() -> deq.putFirst(1));
fs.add(() -> deq.putLast(1));
fs.add(() -> deq.offerFirst(1, LONG_DELAY_MS, MILLISECONDS));
fs.add(() -> deq.offerLast(1, LONG_DELAY_MS, MILLISECONDS));
}
checkInterrupted(fs);
} catch (Throwable t) {
System.out.printf("Failed: %s%n", q.getClass().getSimpleName());
unexpected(t);
} finally {
Thread.interrupted(); // clear interrupts, just in case
}
}
private static void realMain(final String[] args) throws Throwable {
testQueue(new SynchronousQueue<Object>());
testQueue(new ArrayBlockingQueue<Object>(1,false));
testQueue(new ArrayBlockingQueue<Object>(1,true));
testQueue(new LinkedBlockingQueue<Object>(1));
testQueue(new LinkedBlockingDeque<Object>(1));
}
//--------------------- Infrastructure ---------------------------
static volatile int passed = 0, failed = 0;
static void pass() {passed++;}
static void fail() {failed++; Thread.dumpStack();}
static void fail(String msg) {System.out.println(msg); fail();}
static void unexpected(Throwable t) {failed++; t.printStackTrace();}
static void check(boolean cond) {if (cond) pass(); else fail();}
static void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
try {realMain(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
interface Fun {void f() throws Throwable;}
}

View file

@ -0,0 +1,121 @@
/*
* Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6215625 7161229
* @modules java.base/java.util.concurrent:open
* @summary Check correct behavior when last element is removed.
* @author Martin Buchholz
*/
import java.util.Iterator;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.PriorityBlockingQueue;
public class LastElement {
void test(String[] args) throws Throwable {
testQueue(new LinkedBlockingQueue<Integer>());
testQueue(new LinkedBlockingDeque<Integer>());
testQueue(new ArrayBlockingQueue<Integer>(10, true));
testQueue(new ArrayBlockingQueue<Integer>(10, false));
testQueue(new LinkedTransferQueue<Integer>());
testQueue(new PriorityBlockingQueue<Integer>());
}
void testQueue(BlockingQueue<Integer> q) throws Throwable {
Integer one = 1;
Integer two = 2;
Integer three = 3;
// remove(Object)
q.put(one);
q.put(two);
check(! q.isEmpty() && q.size() == 2);
check(q.remove(one));
check(q.remove(two));
check(q.isEmpty() && q.size() == 0);
q.put(three);
try {check(q.take() == three);}
catch (Throwable t) {unexpected(t);}
check(q.isEmpty() && q.size() == 0);
check(noRetention(q));
// iterator().remove()
q.clear();
q.put(one);
check(q.offer(two));
check(! q.isEmpty() && q.size() == 2);
Iterator<Integer> i = q.iterator();
check(i.next() == one);
i.remove();
check(i.next() == two);
i.remove();
check(q.isEmpty() && q.size() == 0);
q.put(three);
try {check(q.take() == three);}
catch (Throwable t) {unexpected(t);}
check(q.isEmpty() && q.size() == 0);
}
boolean noRetention(BlockingQueue<?> q) {
if (q instanceof PriorityBlockingQueue) {
PriorityBlockingQueue<?> pbq = (PriorityBlockingQueue) q;
try {
java.lang.reflect.Field queue =
PriorityBlockingQueue.class.getDeclaredField("queue");
queue.setAccessible(true);
Object[] a = (Object[]) queue.get(pbq);
return a[0] == null;
}
catch (NoSuchFieldException e) {
unexpected(e);
}
catch (IllegalAccessException e) {
// ignore
}
}
return true;
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
new LastElement().instanceMain(args);}
public void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}

View file

@ -0,0 +1,103 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/**
* Misc utilities in JSR166 performance tests
*/
class LoopHelpers {
// Some mindless computation to do between synchronizations...
/**
* generates 32 bit pseudo-random numbers.
* Adapted from http://www.snippets.org
*/
public static int compute1(int x) {
int lo = 16807 * (x & 0xFFFF);
int hi = 16807 * (x >>> 16);
lo += (hi & 0x7FFF) << 16;
if ((lo & 0x80000000) != 0) {
lo &= 0x7fffffff;
++lo;
}
lo += hi >>> 15;
if (lo == 0 || (lo & 0x80000000) != 0) {
lo &= 0x7fffffff;
++lo;
}
return lo;
}
/**
* Computes a linear congruential random number a random number
* of times.
*/
public static int compute2(int x) {
int loops = (x >>> 4) & 7;
while (loops-- > 0) {
x = (x * 2147483647) % 16807;
}
return x;
}
public static class BarrierTimer implements Runnable {
public volatile long startTime;
public volatile long endTime;
public void run() {
long t = System.nanoTime();
if (startTime == 0)
startTime = t;
else
endTime = t;
}
public void clear() {
startTime = 0;
endTime = 0;
}
public long getTime() {
return endTime - startTime;
}
}
public static String rightJustify(long n) {
// There's probably a better way to do this...
String field = " ";
String num = Long.toString(n);
if (num.length() >= field.length())
return num;
StringBuilder b = new StringBuilder(field);
b.replace(b.length()-num.length(), b.length(), num);
return b.toString();
}
}

View file

@ -0,0 +1,78 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8371740
* @summary Checks for poll() (or peek) returning null when an element must exist.
*/
import java.util.*;
import java.util.concurrent.*;
public class MissedPoll {
public static void main(String... args) throws Throwable {
test(new LinkedTransferQueue<>());
test(new LinkedBlockingQueue<>());
test(new LinkedBlockingDeque<>());
test(new ArrayBlockingQueue<>(10));
}
private static void test(BlockingQueue<Integer> q)
throws ExecutionException, InterruptedException {
System.out.println(q.getClass());
try (var pool = Executors.newCachedThreadPool()) {
var futures = new ArrayList<Future<Integer>>();
var phaser = new Phaser(4) {
@Override
protected boolean onAdvance(int phase, int registeredParties) {
q.clear();
return super.onAdvance(phase, registeredParties);
}
};
for (var i = 0; i < 4; i++) {
futures.add(pool.submit(() -> {
int errors = 0;
for (int k = 0; k < 10; k++) {
for (int j = 0; j < 1000; j++) {
q.offer(j);
if (q.peek() == null)
++errors;
if (q.poll() == null)
++errors;
}
phaser.arriveAndAwaitAdvance();
}
return errors;
}));
}
for (var future : futures) {
Integer res;
if ((res = future.get()) != 0)
throw new AssertionError("Expected 0 but got " + res);
}
}
if (!q.isEmpty())
throw new AssertionError("Queue is not empty: " + q);
}
}

View file

@ -0,0 +1,160 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* @test
* @bug 4486658
* @summary multiple producers and single consumer using blocking queues
* @library /test/lib
*/
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.atomic.AtomicInteger;
import jdk.test.lib.Utils;
public class MultipleProducersSingleConsumerLoops {
static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
static ExecutorService pool;
public static void main(String[] args) throws Exception {
final int maxProducers = (args.length > 0)
? Integer.parseInt(args[0])
: 5;
pool = Executors.newCachedThreadPool();
for (int i = 1; i <= maxProducers; i += (i+1) >>> 1) {
// Adjust iterations to limit typical single runs to <= 10 ms;
// Notably, fair queues get fewer iters.
// Unbounded queues can legitimately OOME if iterations
// high enough, but we have a sufficiently low limit here.
run(new ArrayBlockingQueue<Integer>(100), i, 300);
run(new LinkedBlockingQueue<Integer>(100), i, 700);
run(new LinkedBlockingDeque<Integer>(100), i , 500);
run(new LinkedTransferQueue<Integer>(), i, 1000);
run(new PriorityBlockingQueue<Integer>(), i, 1000);
run(new SynchronousQueue<Integer>(), i, 500);
run(new SynchronousQueue<Integer>(true), i, 200);
run(new ArrayBlockingQueue<Integer>(100, true), i, 100);
}
pool.shutdown();
if (! pool.awaitTermination(LONG_DELAY_MS, MILLISECONDS))
throw new Error();
pool = null;
}
static void run(BlockingQueue<Integer> queue, int nproducers, int iters) throws Exception {
new MultipleProducersSingleConsumerLoops(queue, nproducers, iters).run();
}
final BlockingQueue<Integer> queue;
final int nproducers;
final int iters;
final LoopHelpers.BarrierTimer timer = new LoopHelpers.BarrierTimer();
final CyclicBarrier barrier;
final AtomicInteger checksum = new AtomicInteger(0);
Throwable fail;
MultipleProducersSingleConsumerLoops(BlockingQueue<Integer> queue, int nproducers, int iters) {
this.queue = queue;
this.nproducers = nproducers;
this.iters = iters;
this.barrier = new CyclicBarrier(nproducers + 2, timer);
}
void run() throws Exception {
for (int i = 0; i < nproducers; i++)
pool.execute(new Producer());
pool.execute(new Consumer());
barrier.await();
barrier.await();
System.out.printf("%s, nproducers=%d: %d ms%n",
queue.getClass().getSimpleName(), nproducers,
NANOSECONDS.toMillis(timer.getTime()));
if (checksum.get() != 0) throw new AssertionError("checksum mismatch");
if (fail != null) throw new AssertionError(fail);
}
abstract class CheckedRunnable implements Runnable {
abstract void realRun() throws Throwable;
public final void run() {
try {
realRun();
} catch (Throwable t) {
fail = t;
t.printStackTrace();
throw new AssertionError(t);
}
}
}
class Producer extends CheckedRunnable {
void realRun() throws Throwable {
barrier.await();
int s = 0;
int l = hashCode();
for (int i = 0; i < iters; i++) {
l = LoopHelpers.compute1(l);
l = LoopHelpers.compute2(l);
queue.put(new Integer(l));
s += l;
}
checksum.getAndAdd(s);
barrier.await();
}
}
class Consumer extends CheckedRunnable {
void realRun() throws Throwable {
barrier.await();
int s = 0;
for (int i = 0; i < nproducers * iters; i++) {
s += queue.take().intValue();
}
checksum.getAndAdd(-s);
barrier.await();
}
}
}

View file

@ -0,0 +1,187 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* @test
* @bug 6805775 6815766
* @library /test/lib
* @run main OfferDrainToLoops 100
* @summary Test concurrent offer vs. drainTo
*/
import java.util.ArrayList;
import java.util.List;
import java.util.SplittableRandom;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.atomic.AtomicLong;
import jdk.test.lib.Utils;
@SuppressWarnings({"unchecked", "rawtypes", "deprecation"})
public class OfferDrainToLoops {
static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
final long testDurationMillisDefault = 10_000L;
final long testDurationMillis;
OfferDrainToLoops(String[] args) {
testDurationMillis = (args.length > 0) ?
Long.valueOf(args[0]) : testDurationMillisDefault;
}
void checkNotContainsNull(Iterable it) {
for (Object x : it)
check(x != null);
}
void test(String[] args) throws Throwable {
test(new LinkedBlockingQueue());
test(new LinkedBlockingQueue(2000));
test(new LinkedBlockingDeque());
test(new LinkedBlockingDeque(2000));
test(new ArrayBlockingQueue(2000));
test(new LinkedTransferQueue());
}
void test(final BlockingQueue q) throws Throwable {
System.out.println(q.getClass().getSimpleName());
final long testDurationNanos = testDurationMillis * 1000L * 1000L;
final long quittingTimeNanos = System.nanoTime() + testDurationNanos;
final SplittableRandom rnd = new SplittableRandom();
// Poor man's bounded buffer.
final AtomicLong approximateCount = new AtomicLong(0L);
abstract class CheckedThread extends Thread {
final SplittableRandom rnd;
CheckedThread(String name, SplittableRandom rnd) {
super(name);
this.rnd = rnd;
setDaemon(true);
start();
}
/** Polls for quitting time. */
protected boolean quittingTime() {
return System.nanoTime() - quittingTimeNanos > 0;
}
/** Polls occasionally for quitting time. */
protected boolean quittingTime(long i) {
return (i % 1024) == 0 && quittingTime();
}
protected abstract void realRun();
public void run() {
try { realRun(); } catch (Throwable t) { unexpected(t); }
}
}
Thread offerer = new CheckedThread("offerer", rnd.split()) {
protected void realRun() {
long c = 0;
for (long i = 0; ! quittingTime(i); i++) {
if (q.offer(c)) {
if ((++c % 1024) == 0) {
approximateCount.getAndAdd(1024);
while (approximateCount.get() > 10000)
Thread.yield();
}
} else {
Thread.yield();
}}}};
Thread drainer = new CheckedThread("drainer", rnd.split()) {
protected void realRun() {
while (! quittingTime()) {
List list = new ArrayList();
int n = rnd.nextBoolean() ?
q.drainTo(list) :
q.drainTo(list, 100);
approximateCount.getAndAdd(-n);
equal(list.size(), n);
for (int j = 0; j < n - 1; j++)
equal((Long) list.get(j) + 1L, list.get(j + 1));
Thread.yield();
}
q.clear();
approximateCount.set(0); // Releases waiting offerer thread
}};
Thread scanner = new CheckedThread("scanner", rnd.split()) {
protected void realRun() {
while (! quittingTime()) {
switch (rnd.nextInt(3)) {
case 0: checkNotContainsNull(q); break;
case 1: q.size(); break;
case 2:
Long[] a = (Long[]) q.toArray(new Long[0]);
int n = a.length;
for (int j = 0; j < n - 1; j++) {
check(a[j] < a[j+1]);
check(a[j] != null);
}
break;
}
Thread.yield();
}}};
for (Thread thread : new Thread[] { offerer, drainer, scanner }) {
thread.join(LONG_DELAY_MS + testDurationMillis);
if (thread.isAlive()) {
System.err.printf("Hung thread: %s%n", thread.getName());
failed++;
for (StackTraceElement e : thread.getStackTrace())
System.err.println(e);
thread.join(LONG_DELAY_MS);
}
}
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
new OfferDrainToLoops(args).instanceMain(args);}
public void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}

View file

@ -0,0 +1,160 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea 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/publicdomain/zero/1.0/
*/
/*
* @test
* @bug 6236036 6264015
* @modules java.base/java.util.concurrent:open
* java.base/java.util.concurrent.locks:open
* @summary Checks for a memory leak when a sequence of aborted timed
* waits occur without a signal. Uses the strategy of detecting
* changes in the size of the object graph retained by a root object.
*/
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
public class PollMemoryLeak {
public static void main(String[] args) throws Throwable {
new PollMemoryLeak().main();
}
void main() throws Throwable {
test(new LinkedBlockingDeque(10));
test(new LinkedBlockingQueue(10));
test(new LinkedTransferQueue());
test(new ArrayBlockingQueue(10));
test(new PriorityBlockingQueue());
test(new SynchronousQueue());
test(new SynchronousQueue(true));
}
void test(BlockingQueue q) throws Throwable {
assertNoLeak(q, () -> timedPoll(q));
// A demo that the leak detection infrastructure works
// assertNoLeak(q, () -> q.add(1));
// printRetainedObjects(q);
}
static void timedPoll(BlockingQueue q) {
try { q.poll(1, TimeUnit.NANOSECONDS); }
catch (InterruptedException ex) { throw new AssertionError(ex); }
}
// -------- leak detection infrastructure ---------------
void assertNoLeak(Object root, Runnable r) {
int prev = retainedObjects(root).size();
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) r.run();
int next = retainedObjects(root).size();
if (next <= prev)
return;
prev = next;
}
throw new AssertionError(
String.format("probable memory leak in %s: %s",
root.getClass().getSimpleName(), root));
}
ConcurrentHashMap<Class<?>, Collection<Field>> classFields
= new ConcurrentHashMap<>();
Collection<Field> referenceFieldsOf(Class<?> k) {
Collection<Field> fields = classFields.get(k);
if (fields == null) {
fields = new ArrayDeque<Field>();
ArrayDeque<Field> allFields = new ArrayDeque<>();
for (Class<?> c = k; c != null; c = c.getSuperclass())
for (Field field : c.getDeclaredFields())
if (!Modifier.isStatic(field.getModifiers())
&& !field.getType().isPrimitive())
fields.add(field);
AccessibleObject.setAccessible(
fields.toArray(new AccessibleObject[0]), true);
classFields.put(k, fields);
}
return fields;
}
static Object get(Field field, Object x) {
try { return field.get(x); }
catch (IllegalAccessException ex) { throw new AssertionError(ex); }
}
Set<Object> retainedObjects(Object x) {
ArrayDeque<Object> todo = new ArrayDeque<>() {
public void push(Object x) { if (x != null) super.push(x); }};
Set<Object> uniqueObjects = Collections.newSetFromMap(
new IdentityHashMap<Object, Boolean>());
todo.push(x);
while (!todo.isEmpty()) {
Object y = todo.pop();
if (uniqueObjects.contains(y))
continue;
uniqueObjects.add(y);
Class<?> k = y.getClass();
if (k.isArray() && !k.getComponentType().isPrimitive()) {
for (int i = 0, len = Array.getLength(y); i < len; i++)
todo.push(Array.get(y, i));
} else {
for (Field field : referenceFieldsOf(k))
todo.push(get(field, y));
}
}
return uniqueObjects;
}
/** for debugging the retained object graph */
void printRetainedObjects(Object x) {
for (Object y : retainedObjects(x))
System.out.printf("%s : %s%n", y.getClass().getSimpleName(), y);
}
}

View file

@ -0,0 +1,162 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* @test
* @bug 4486658
* @summary multiple producers and consumers using blocking queues
* @library /test/lib
*/
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.atomic.AtomicInteger;
import jdk.test.lib.Utils;
public class ProducerConsumerLoops {
static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
static ExecutorService pool;
public static void main(String[] args) throws Exception {
final int maxPairs = (args.length > 0)
? Integer.parseInt(args[0])
: 5;
int iters = 10000;
pool = Executors.newCachedThreadPool();
for (int i = 1; i <= maxPairs; i += (i+1) >>> 1) {
// Adjust iterations to limit typical single runs to <= 10 ms;
// Notably, fair queues get fewer iters.
// Unbounded queues can legitimately OOME if iterations
// high enough, but we have a sufficiently low limit here.
run(new ArrayBlockingQueue<Integer>(100), i, 500);
run(new LinkedBlockingQueue<Integer>(100), i, 1000);
run(new LinkedBlockingDeque<Integer>(100), i, 1000);
run(new LinkedTransferQueue<Integer>(), i, 1000);
run(new PriorityBlockingQueue<Integer>(), i, 1000);
run(new SynchronousQueue<Integer>(), i, 400);
run(new SynchronousQueue<Integer>(true), i, 300);
run(new ArrayBlockingQueue<Integer>(100, true), i, 100);
}
pool.shutdown();
if (! pool.awaitTermination(LONG_DELAY_MS, MILLISECONDS))
throw new Error();
pool = null;
}
static void run(BlockingQueue<Integer> queue, int pairs, int iters) throws Exception {
new ProducerConsumerLoops(queue, pairs, iters).run();
}
final BlockingQueue<Integer> queue;
final int pairs;
final int iters;
final LoopHelpers.BarrierTimer timer = new LoopHelpers.BarrierTimer();
final CyclicBarrier barrier;
final AtomicInteger checksum = new AtomicInteger(0);
Throwable fail;
ProducerConsumerLoops(BlockingQueue<Integer> queue, int pairs, int iters) {
this.queue = queue;
this.pairs = pairs;
this.iters = iters;
this.barrier = new CyclicBarrier(2 * pairs + 1, timer);
}
void run() throws Exception {
for (int i = 0; i < pairs; i++) {
pool.execute(new Producer());
pool.execute(new Consumer());
}
barrier.await();
barrier.await();
System.out.printf("%s, pairs=%d: %d ms%n",
queue.getClass().getSimpleName(), pairs,
NANOSECONDS.toMillis(timer.getTime()));
if (checksum.get() != 0) throw new AssertionError("checksum mismatch");
if (fail != null) throw new AssertionError(fail);
}
abstract class CheckedRunnable implements Runnable {
abstract void realRun() throws Throwable;
public final void run() {
try {
realRun();
} catch (Throwable t) {
fail = t;
t.printStackTrace();
throw new AssertionError(t);
}
}
}
class Producer extends CheckedRunnable {
void realRun() throws Throwable {
barrier.await();
int s = 0;
int l = hashCode();
for (int i = 0; i < iters; i++) {
l = LoopHelpers.compute2(l);
queue.put(new Integer(l));
s += LoopHelpers.compute1(l);
}
checksum.getAndAdd(s);
barrier.await();
}
}
class Consumer extends CheckedRunnable {
void realRun() throws Throwable {
barrier.await();
int l = 0;
int s = 0;
for (int i = 0; i < iters; i++) {
l = LoopHelpers.compute1(queue.take().intValue());
s += l;
}
checksum.getAndAdd(-s);
barrier.await();
}
}
}

View file

@ -0,0 +1,162 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* @test
* @bug 4486658
* @summary check ordering for blocking queues with 1 producer and multiple consumers
* @library /test/lib
*/
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.SynchronousQueue;
import jdk.test.lib.Utils;
public class SingleProducerMultipleConsumerLoops {
static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
static ExecutorService pool;
public static void main(String[] args) throws Exception {
final int maxConsumers = (args.length > 0)
? Integer.parseInt(args[0])
: 5;
pool = Executors.newCachedThreadPool();
for (int i = 1; i <= maxConsumers; i += (i+1) >>> 1) {
// Adjust iterations to limit typical single runs to <= 10 ms;
// Notably, fair queues get fewer iters.
// Unbounded queues can legitimately OOME if iterations
// high enough, but we have a sufficiently low limit here.
run(new ArrayBlockingQueue<Integer>(100), i, 1000);
run(new LinkedBlockingQueue<Integer>(100), i, 1000);
run(new LinkedBlockingDeque<Integer>(100), i, 1000);
run(new LinkedTransferQueue<Integer>(), i, 700);
run(new PriorityBlockingQueue<Integer>(), i, 1000);
run(new SynchronousQueue<Integer>(), i, 300);
run(new SynchronousQueue<Integer>(true), i, 200);
run(new ArrayBlockingQueue<Integer>(100, true), i, 100);
}
pool.shutdown();
if (! pool.awaitTermination(LONG_DELAY_MS, MILLISECONDS))
throw new Error();
pool = null;
}
static void run(BlockingQueue<Integer> queue, int consumers, int iters) throws Exception {
new SingleProducerMultipleConsumerLoops(queue, consumers, iters).run();
}
final BlockingQueue<Integer> queue;
final int consumers;
final int iters;
final LoopHelpers.BarrierTimer timer = new LoopHelpers.BarrierTimer();
final CyclicBarrier barrier;
Throwable fail;
SingleProducerMultipleConsumerLoops(BlockingQueue<Integer> queue, int consumers, int iters) {
this.queue = queue;
this.consumers = consumers;
this.iters = iters;
this.barrier = new CyclicBarrier(consumers + 2, timer);
}
void run() throws Exception {
pool.execute(new Producer());
for (int i = 0; i < consumers; i++) {
pool.execute(new Consumer());
}
barrier.await();
barrier.await();
System.out.printf("%s, consumers=%d: %d ms%n",
queue.getClass().getSimpleName(), consumers,
NANOSECONDS.toMillis(timer.getTime()));
if (fail != null) throw new AssertionError(fail);
}
abstract class CheckedRunnable implements Runnable {
abstract void realRun() throws Throwable;
public final void run() {
try {
realRun();
} catch (Throwable t) {
fail = t;
t.printStackTrace();
throw new AssertionError(t);
}
}
}
class Producer extends CheckedRunnable {
volatile int result;
void realRun() throws Throwable {
barrier.await();
for (int i = 0; i < iters * consumers; i++) {
queue.put(new Integer(i));
}
barrier.await();
result = 432;
}
}
class Consumer extends CheckedRunnable {
volatile int result;
void realRun() throws Throwable {
barrier.await();
int l = 0;
int s = 0;
int last = -1;
for (int i = 0; i < iters; i++) {
Integer item = queue.take();
int v = item.intValue();
if (v < last)
throw new Error("Out-of-Order transfer");
last = v;
l = LoopHelpers.compute1(v);
s += l;
}
barrier.await();
result = s;
}
}
}

View file

@ -0,0 +1,885 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* @test
* @bug 8005696
* @summary Basic tests for CompletableFuture
* @library /test/lib
* @run main Basic
* @run main/othervm -Djava.util.concurrent.ForkJoinPool.common.parallelism=0 Basic
* @author Chris Hegarty
*/
import static java.util.concurrent.CompletableFuture.runAsync;
import static java.util.concurrent.CompletableFuture.supplyAsync;
import static java.util.concurrent.ForkJoinPool.commonPool;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
import java.lang.reflect.Array;
import java.util.concurrent.Phaser;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import jdk.test.lib.Utils;
public class Basic {
static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
static void checkCompletedNormally(CompletableFuture<?> cf, Object value) {
checkCompletedNormally(cf, value == null ? null : new Object[] { value });
}
static void checkCompletedNormally(CompletableFuture<?> cf, Object[] values) {
try { equalAnyOf(cf.join(), values); } catch (Throwable x) { unexpected(x); }
try { equalAnyOf(cf.getNow(null), values); } catch (Throwable x) { unexpected(x); }
try { equalAnyOf(cf.get(), values); } catch (Throwable x) { unexpected(x); }
try { equalAnyOf(cf.get(0L, SECONDS), values); } catch (Throwable x) { unexpected(x); }
check(cf.isDone(), "Expected isDone to be true, got:" + cf);
check(!cf.isCompletedExceptionally(), "Expected isCompletedExceptionally to return false");
check(!cf.isCancelled(), "Expected isCancelled to be false");
check(!cf.cancel(true), "Expected cancel to return false");
check(cf.toString().matches(".*\\[.*Completed normally.*\\]"));
check(cf.complete(null) == false, "Expected complete() to fail");
check(cf.completeExceptionally(new Throwable()) == false,
"Expected completeExceptionally() to fail");
}
static <T> void checkCompletedExceptionally(CompletableFuture<T> cf)
throws Exception
{
checkCompletedExceptionally(cf, false);
}
@SuppressWarnings("unchecked")
static <T> void checkCompletedExceptionally(CompletableFuture<T> cf, boolean cancelled)
throws Exception
{
try { cf.join(); fail("Excepted exception to be thrown"); }
catch (CompletionException x) { if (cancelled) fail(); else pass(); }
catch (CancellationException x) { if (cancelled) pass(); else fail(); }
try { cf.getNow(null); fail("Excepted exception to be thrown"); }
catch (CompletionException x) { if (cancelled) fail(); else pass(); }
catch (CancellationException x) { if (cancelled) pass(); else fail(); }
try { cf.get(); fail("Excepted exception to be thrown");}
catch (CancellationException x) { if (cancelled) pass(); else fail(); }
catch (ExecutionException x) { if (cancelled) check(x.getCause() instanceof CancellationException); else pass(); }
try { cf.get(0L, SECONDS); fail("Excepted exception to be thrown");}
catch (CancellationException x) { if (cancelled) pass(); else fail(); }
catch (ExecutionException x) { if (cancelled) check(x.getCause() instanceof CancellationException); else pass(); }
check(cf.isDone(), "Expected isDone to be true, got:" + cf);
check(cf.isCompletedExceptionally(), "Expected isCompletedExceptionally");
check(cf.isCancelled() == cancelled, "Expected isCancelled: " + cancelled + ", got:" + cf.isCancelled());
check(cf.cancel(true) == cancelled, "Expected cancel: " + cancelled + ", got:" + cf.cancel(true));
check(cf.toString().matches(".*\\[.*Completed exceptionally.*\\]")); // ## TODO: 'E'xceptionally
check(cf.complete((T)new Object()) == false, "Expected complete() to fail");
check(cf.completeExceptionally(new Throwable()) == false,
"Expected completeExceptionally() to fail, already completed");
}
private static void realMain(String[] args) throws Throwable {
ExecutorService pool = Executors.newFixedThreadPool(2);
try {
test(pool);
} finally {
pool.shutdown();
if (! pool.awaitTermination(LONG_DELAY_MS, MILLISECONDS))
throw new Error();
}
}
static AtomicInteger atomicInt = new AtomicInteger(0);
private static void test(ExecutorService executor) throws Throwable {
Thread.currentThread().setName("mainThread");
//----------------------------------------------------------------
// supplyAsync tests
//----------------------------------------------------------------
try {
CompletableFuture<String> cf = supplyAsync(() -> "a test string");
checkCompletedNormally(cf, cf.join());
cf = supplyAsync(() -> "a test string", commonPool());
checkCompletedNormally(cf, cf.join());
cf = supplyAsync(() -> "a test string", executor);
checkCompletedNormally(cf, cf.join());
cf = supplyAsync(() -> { throw new RuntimeException(); });
checkCompletedExceptionally(cf);
cf = supplyAsync(() -> { throw new RuntimeException(); }, commonPool());
checkCompletedExceptionally(cf);
cf = supplyAsync(() -> { throw new RuntimeException(); }, executor);
checkCompletedExceptionally(cf);
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// runAsync tests
//----------------------------------------------------------------
try {
CompletableFuture<Void> cf = runAsync(() -> {});
checkCompletedNormally(cf, cf.join());
cf = runAsync(() -> {}, commonPool());
checkCompletedNormally(cf, cf.join());
cf = runAsync(() -> {}, executor);
checkCompletedNormally(cf, cf.join());
cf = runAsync(() -> { throw new RuntimeException(); });
checkCompletedExceptionally(cf);
cf = runAsync(() -> { throw new RuntimeException(); }, commonPool());
checkCompletedExceptionally(cf);
cf = runAsync(() -> { throw new RuntimeException(); }, executor);
checkCompletedExceptionally(cf);
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// explicit completion
//----------------------------------------------------------------
try {
final Phaser phaser = new Phaser(1);
final int phase = phaser.getPhase();
CompletableFuture<Integer> cf;
cf = supplyAsync(() -> { phaser.awaitAdvance(phase); return 1; });
cf.complete(2);
phaser.arrive();
checkCompletedNormally(cf, 2);
cf = supplyAsync(() -> { phaser.awaitAdvance(phase+1); return 1; });
cf.completeExceptionally(new Throwable());
phaser.arrive();
checkCompletedExceptionally(cf);
cf = supplyAsync(() -> { phaser.awaitAdvance(phase+2); return 1; });
cf.cancel(true);
phaser.arrive();
checkCompletedExceptionally(cf, true);
cf = supplyAsync(() -> { phaser.awaitAdvance(phase+3); return 1; });
check(cf.getNow(2) == 2);
phaser.arrive();
checkCompletedNormally(cf, 1);
check(cf.getNow(2) == 1);
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// thenApplyXXX tests
//----------------------------------------------------------------
try {
CompletableFuture<Integer> cf2;
CompletableFuture<String> cf1 = supplyAsync(() -> "a test string");
cf2 = cf1.thenApply(x -> x.equals("a test string") ? 1 : 0);
checkCompletedNormally(cf1, "a test string");
checkCompletedNormally(cf2, 1);
cf1 = supplyAsync(() -> "a test string");
cf2 = cf1.thenApplyAsync(x -> x.equals("a test string") ? 1 : 0);
checkCompletedNormally(cf1, "a test string");
checkCompletedNormally(cf2, 1);
cf1 = supplyAsync(() -> "a test string");
cf2 = cf1.thenApplyAsync(x -> x.equals("a test string") ? 1 : 0, executor);
checkCompletedNormally(cf1, "a test string");
checkCompletedNormally(cf2, 1);
cf1 = supplyAsync(() -> { throw new RuntimeException(); });
cf2 = cf1.thenApply(x -> 0);
checkCompletedExceptionally(cf1);
checkCompletedExceptionally(cf2);
cf1 = supplyAsync(() -> { throw new RuntimeException(); });
cf2 = cf1.thenApplyAsync(x -> 0);
checkCompletedExceptionally(cf1);
checkCompletedExceptionally(cf2);
cf1 = supplyAsync(() -> { throw new RuntimeException(); });
cf2 = cf1.thenApplyAsync(x -> 0, executor);
checkCompletedExceptionally(cf1);
checkCompletedExceptionally(cf2);
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// thenAcceptXXX tests
//----------------------------------------------------------------
try {
CompletableFuture<Void> cf2;
int before = atomicInt.get();
CompletableFuture<String> cf1 = supplyAsync(() -> "a test string");
cf2 = cf1.thenAccept(x -> { if (x.equals("a test string")) { atomicInt.incrementAndGet(); return; } throw new RuntimeException(); });
checkCompletedNormally(cf1, "a test string");
checkCompletedNormally(cf2, null);
check(atomicInt.get() == (before + 1));
before = atomicInt.get();
cf1 = supplyAsync(() -> "a test string");
cf2 = cf1.thenAcceptAsync(x -> { if (x.equals("a test string")) { atomicInt.incrementAndGet(); return; } throw new RuntimeException(); });
checkCompletedNormally(cf1, "a test string");
checkCompletedNormally(cf2, null);
check(atomicInt.get() == (before + 1));
before = atomicInt.get();
cf1 = supplyAsync(() -> "a test string");
cf2 = cf1.thenAcceptAsync(x -> { if (x.equals("a test string")) { atomicInt.incrementAndGet(); return; } throw new RuntimeException(); }, executor);
checkCompletedNormally(cf1, "a test string");
checkCompletedNormally(cf2, null);
check(atomicInt.get() == (before + 1));
before = atomicInt.get();
cf1 = supplyAsync(() -> { throw new RuntimeException(); });
cf2 = cf1.thenAccept(x -> atomicInt.incrementAndGet());
checkCompletedExceptionally(cf1);
checkCompletedExceptionally(cf2);
check(atomicInt.get() == before);
cf1 = supplyAsync(() -> { throw new RuntimeException(); });
cf2 = cf1.thenAcceptAsync(x -> atomicInt.incrementAndGet());
checkCompletedExceptionally(cf1);
checkCompletedExceptionally(cf2);
check(atomicInt.get() == before);
cf1 = supplyAsync(() -> { throw new RuntimeException(); });
cf2 = cf1.thenAcceptAsync(x -> atomicInt.incrementAndGet(), executor );
checkCompletedExceptionally(cf1);
checkCompletedExceptionally(cf2);
check(atomicInt.get() == before);
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// thenRunXXX tests
//----------------------------------------------------------------
try {
CompletableFuture<Void> cf2;
int before = atomicInt.get();
CompletableFuture<String> cf1 = supplyAsync(() -> "a test string");
cf2 = cf1.thenRun(() -> atomicInt.incrementAndGet());
checkCompletedNormally(cf1, "a test string");
checkCompletedNormally(cf2, null);
check(atomicInt.get() == (before + 1));
before = atomicInt.get();
cf1 = supplyAsync(() -> "a test string");
cf2 = cf1.thenRunAsync(() -> atomicInt.incrementAndGet());
checkCompletedNormally(cf1, "a test string");
checkCompletedNormally(cf2, null);
check(atomicInt.get() == (before + 1));
before = atomicInt.get();
cf1 = supplyAsync(() -> "a test string");
cf2 = cf1.thenRunAsync(() -> atomicInt.incrementAndGet(), executor);
checkCompletedNormally(cf1, "a test string");
checkCompletedNormally(cf2, null);
check(atomicInt.get() == (before + 1));
before = atomicInt.get();
cf1 = supplyAsync(() -> { throw new RuntimeException(); });
cf2 = cf1.thenRun(() -> atomicInt.incrementAndGet());
checkCompletedExceptionally(cf1);
checkCompletedExceptionally(cf2);
check(atomicInt.get() == before);
cf1 = supplyAsync(() -> { throw new RuntimeException(); });
cf2 = cf1.thenRunAsync(() -> atomicInt.incrementAndGet());
checkCompletedExceptionally(cf1);
checkCompletedExceptionally(cf2);
check(atomicInt.get() == before);
cf1 = supplyAsync(() -> { throw new RuntimeException(); });
cf2 = cf1.thenRunAsync(() -> atomicInt.incrementAndGet(), executor);
checkCompletedExceptionally(cf1);
checkCompletedExceptionally(cf2);
check(atomicInt.get() == before);
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// thenCombineXXX tests
//----------------------------------------------------------------
try {
CompletableFuture<Integer> cf3;
CompletableFuture<Integer> cf1 = supplyAsync(() -> 1);
CompletableFuture<Integer> cf2 = supplyAsync(() -> 1);
cf3 = cf1.thenCombine(cf2, (x, y) -> x + y);
checkCompletedNormally(cf1, 1);
checkCompletedNormally(cf2, 1);
checkCompletedNormally(cf3, 2);
cf1 = supplyAsync(() -> 1);
cf2 = supplyAsync(() -> 1);
cf3 = cf1.thenCombineAsync(cf2, (x, y) -> x + y);
checkCompletedNormally(cf1, 1);
checkCompletedNormally(cf2, 1);
checkCompletedNormally(cf3, 2);
cf1 = supplyAsync(() -> 1);
cf2 = supplyAsync(() -> 1);
cf3 = cf1.thenCombineAsync(cf2, (x, y) -> x + y, executor);
checkCompletedNormally(cf1, 1);
checkCompletedNormally(cf2, 1);
checkCompletedNormally(cf3, 2);
cf1 = supplyAsync(() -> { throw new RuntimeException(); });
cf2 = supplyAsync(() -> 1);
cf3 = cf1.thenCombine(cf2, (x, y) -> 0);
checkCompletedExceptionally(cf1);
checkCompletedNormally(cf2, 1);
checkCompletedExceptionally(cf3);
cf1 = supplyAsync(() -> 1);
cf2 = supplyAsync(() -> { throw new RuntimeException(); });
cf3 = cf1.thenCombineAsync(cf2, (x, y) -> 0);
checkCompletedNormally(cf1, 1);
checkCompletedExceptionally(cf2);
checkCompletedExceptionally(cf3);
cf1 = supplyAsync(() -> { throw new RuntimeException(); });
cf2 = supplyAsync(() -> { throw new RuntimeException(); });
cf3 = cf1.thenCombineAsync(cf2, (x, y) -> 0, executor);
checkCompletedExceptionally(cf1);
checkCompletedExceptionally(cf2);
checkCompletedExceptionally(cf3);
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// thenAcceptBothXXX tests
//----------------------------------------------------------------
try {
CompletableFuture<Void> cf3;
int before = atomicInt.get();
CompletableFuture<Integer> cf1 = supplyAsync(() -> 1);
CompletableFuture<Integer> cf2 = supplyAsync(() -> 1);
cf3 = cf1.thenAcceptBoth(cf2, (x, y) -> { check(x + y == 2); atomicInt.incrementAndGet(); });
checkCompletedNormally(cf1, 1);
checkCompletedNormally(cf2, 1);
checkCompletedNormally(cf3, null);
check(atomicInt.get() == (before + 1));
before = atomicInt.get();
cf1 = supplyAsync(() -> 1);
cf2 = supplyAsync(() -> 1);
cf3 = cf1.thenAcceptBothAsync(cf2, (x, y) -> { check(x + y == 2); atomicInt.incrementAndGet(); });
checkCompletedNormally(cf1, 1);
checkCompletedNormally(cf2, 1);
checkCompletedNormally(cf3, null);
check(atomicInt.get() == (before + 1));
before = atomicInt.get();
cf1 = supplyAsync(() -> 1);
cf2 = supplyAsync(() -> 1);
cf3 = cf1.thenAcceptBothAsync(cf2, (x, y) -> { check(x + y == 2); atomicInt.incrementAndGet(); }, executor);
checkCompletedNormally(cf1, 1);
checkCompletedNormally(cf2, 1);
checkCompletedNormally(cf3, null);
check(atomicInt.get() == (before + 1));
before = atomicInt.get();
cf1 = supplyAsync(() -> { throw new RuntimeException(); });
cf2 = supplyAsync(() -> 1);
cf3 = cf1.thenAcceptBoth(cf2, (x, y) -> atomicInt.incrementAndGet());
checkCompletedExceptionally(cf1);
checkCompletedNormally(cf2, 1);
checkCompletedExceptionally(cf3);
check(atomicInt.get() == before);
cf1 = supplyAsync(() -> 1);
cf2 = supplyAsync(() -> { throw new RuntimeException(); });
cf3 = cf1.thenAcceptBothAsync(cf2, (x, y) -> atomicInt.incrementAndGet());
checkCompletedNormally(cf1, 1);
checkCompletedExceptionally(cf2);
checkCompletedExceptionally(cf3);
check(atomicInt.get() == before);
cf1 = supplyAsync(() -> { throw new RuntimeException(); });
cf2 = supplyAsync(() -> { throw new RuntimeException(); });
cf3 = cf1.thenAcceptBothAsync(cf2, (x, y) -> atomicInt.incrementAndGet(), executor);
checkCompletedExceptionally(cf1);
checkCompletedExceptionally(cf2);
checkCompletedExceptionally(cf3);
check(atomicInt.get() == before);
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// runAfterBothXXX tests
//----------------------------------------------------------------
try {
CompletableFuture<Void> cf3;
int before = atomicInt.get();
CompletableFuture<Integer> cf1 = supplyAsync(() -> 1);
CompletableFuture<Integer> cf2 = supplyAsync(() -> 1);
cf3 = cf1.runAfterBoth(cf2, () -> { check(cf1.isDone()); check(cf2.isDone()); atomicInt.incrementAndGet(); });
checkCompletedNormally(cf1, 1);
checkCompletedNormally(cf2, 1);
checkCompletedNormally(cf3, null);
check(atomicInt.get() == (before + 1));
before = atomicInt.get();
CompletableFuture<Integer> cfa = supplyAsync(() -> 1);
CompletableFuture<Integer> cfb = supplyAsync(() -> 1);
cf3 = cfa.runAfterBothAsync(cfb, () -> { check(cfa.isDone()); check(cfb.isDone()); atomicInt.incrementAndGet(); });
checkCompletedNormally(cfa, 1);
checkCompletedNormally(cfb, 1);
checkCompletedNormally(cf3, null);
check(atomicInt.get() == (before + 1));
before = atomicInt.get();
CompletableFuture<Integer> cfx = supplyAsync(() -> 1);
CompletableFuture<Integer> cfy = supplyAsync(() -> 1);
cf3 = cfy.runAfterBothAsync(cfx, () -> { check(cfx.isDone()); check(cfy.isDone()); atomicInt.incrementAndGet(); }, executor);
checkCompletedNormally(cfx, 1);
checkCompletedNormally(cfy, 1);
checkCompletedNormally(cf3, null);
check(atomicInt.get() == (before + 1));
before = atomicInt.get();
CompletableFuture<Integer> cf4 = supplyAsync(() -> { throw new RuntimeException(); });
CompletableFuture<Integer> cf5 = supplyAsync(() -> 1);
cf3 = cf5.runAfterBothAsync(cf4, () -> atomicInt.incrementAndGet(), executor);
checkCompletedExceptionally(cf4);
checkCompletedNormally(cf5, 1);
checkCompletedExceptionally(cf3);
check(atomicInt.get() == before);
before = atomicInt.get();
cf4 = supplyAsync(() -> 1);
cf5 = supplyAsync(() -> { throw new RuntimeException(); });
cf3 = cf5.runAfterBothAsync(cf4, () -> atomicInt.incrementAndGet());
checkCompletedNormally(cf4, 1);
checkCompletedExceptionally(cf5);
checkCompletedExceptionally(cf3);
check(atomicInt.get() == before);
before = atomicInt.get();
cf4 = supplyAsync(() -> { throw new RuntimeException(); });
cf5 = supplyAsync(() -> { throw new RuntimeException(); });
cf3 = cf5.runAfterBoth(cf4, () -> atomicInt.incrementAndGet());
checkCompletedExceptionally(cf4);
checkCompletedExceptionally(cf5);
checkCompletedExceptionally(cf3);
check(atomicInt.get() == before);
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// applyToEitherXXX tests
//----------------------------------------------------------------
try {
CompletableFuture<Integer> cf3;
CompletableFuture<Integer> cf1 = supplyAsync(() -> 1);
CompletableFuture<Integer> cf2 = supplyAsync(() -> 2);
cf3 = cf1.applyToEither(cf2, x -> { check(x == 1 || x == 2); return x; });
checkCompletedNormally(cf3, new Object[] {1, 2});
check(cf1.isDone() || cf2.isDone());
cf1 = supplyAsync(() -> 1);
cf2 = supplyAsync(() -> 2);
cf3 = cf1.applyToEitherAsync(cf2, x -> { check(x == 1 || x == 2); return x; });
checkCompletedNormally(cf3, new Object[] {1, 2});
check(cf1.isDone() || cf2.isDone());
cf1 = supplyAsync(() -> 1);
cf2 = supplyAsync(() -> 2);
cf3 = cf1.applyToEitherAsync(cf2, x -> { check(x == 1 || x == 2); return x; }, executor);
checkCompletedNormally(cf3, new Object[] {1, 2});
check(cf1.isDone() || cf2.isDone());
cf1 = supplyAsync(() -> { throw new RuntimeException(); });
cf2 = supplyAsync(() -> 2);
cf3 = cf1.applyToEither(cf2, x -> { check(x == 2); return x; });
try { check(cf3.join() == 2); } catch (CompletionException x) { pass(); }
check(cf3.isDone());
check(cf1.isDone() || cf2.isDone());
cf1 = supplyAsync(() -> 1);
cf2 = supplyAsync(() -> { throw new RuntimeException(); });
cf3 = cf1.applyToEitherAsync(cf2, x -> { check(x == 1); return x; });
try { check(cf3.join() == 1); } catch (CompletionException x) { pass(); }
check(cf3.isDone());
check(cf1.isDone() || cf2.isDone());
cf1 = supplyAsync(() -> { throw new RuntimeException(); });
cf2 = supplyAsync(() -> { throw new RuntimeException(); });
cf3 = cf1.applyToEitherAsync(cf2, x -> { fail(); return x; });
checkCompletedExceptionally(cf3);
check(cf1.isDone() || cf2.isDone());
final Phaser cf3Done = new Phaser(2);
cf1 = supplyAsync(() -> { cf3Done.arriveAndAwaitAdvance(); return 1; });
cf2 = supplyAsync(() -> 2);
cf3 = cf1.applyToEither(cf2, x -> { check(x == 2); return x; });
checkCompletedNormally(cf3, 2);
checkCompletedNormally(cf2, 2);
check(!cf1.isDone());
cf3Done.arrive();
checkCompletedNormally(cf1, 1);
checkCompletedNormally(cf3, 2);
cf1 = supplyAsync(() -> 1);
cf2 = supplyAsync(() -> { cf3Done.arriveAndAwaitAdvance(); return 2; });
cf3 = cf1.applyToEitherAsync(cf2, x -> { check(x == 1); return x; });
checkCompletedNormally(cf3, 1);
checkCompletedNormally(cf1, 1);
check(!cf2.isDone());
cf3Done.arrive();
checkCompletedNormally(cf2, 2);
checkCompletedNormally(cf3, 1);
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// acceptEitherXXX tests
//----------------------------------------------------------------
try {
CompletableFuture<Void> cf3;
int before = atomicInt.get();
CompletableFuture<Integer> cf1 = supplyAsync(() -> 1);
CompletableFuture<Integer> cf2 = supplyAsync(() -> 2);
cf3 = cf1.acceptEither(cf2, x -> { check(x == 1 || x == 2); atomicInt.incrementAndGet(); });
checkCompletedNormally(cf3, null);
check(cf1.isDone() || cf2.isDone());
check(atomicInt.get() == (before + 1));
before = atomicInt.get();
cf1 = supplyAsync(() -> 1);
cf2 = supplyAsync(() -> 2);
cf3 = cf1.acceptEitherAsync(cf2, x -> { check(x == 1 || x == 2); atomicInt.incrementAndGet(); });
checkCompletedNormally(cf3, null);
check(cf1.isDone() || cf2.isDone());
check(atomicInt.get() == (before + 1));
before = atomicInt.get();
cf1 = supplyAsync(() -> 1);
cf2 = supplyAsync(() -> 2);
cf3 = cf2.acceptEitherAsync(cf1, x -> { check(x == 1 || x == 2); atomicInt.incrementAndGet(); }, executor);
checkCompletedNormally(cf3, null);
check(cf1.isDone() || cf2.isDone());
check(atomicInt.get() == (before + 1));
cf1 = supplyAsync(() -> { throw new RuntimeException(); });
cf2 = supplyAsync(() -> 2);
cf3 = cf2.acceptEitherAsync(cf1, x -> { check(x == 2); }, executor);
try { check(cf3.join() == null); } catch (CompletionException x) { pass(); }
check(cf3.isDone());
check(cf1.isDone() || cf2.isDone());
cf1 = supplyAsync(() -> 1);
cf2 = supplyAsync(() -> { throw new RuntimeException(); });
cf3 = cf2.acceptEitherAsync(cf1, x -> { check(x == 1); });
try { check(cf3.join() == null); } catch (CompletionException x) { pass(); }
check(cf3.isDone());
check(cf1.isDone() || cf2.isDone());
cf1 = supplyAsync(() -> { throw new RuntimeException(); });
cf2 = supplyAsync(() -> { throw new RuntimeException(); });
cf3 = cf2.acceptEitherAsync(cf1, x -> { fail(); });
checkCompletedExceptionally(cf3);
check(cf1.isDone() || cf2.isDone());
final Phaser cf3Done = new Phaser(2);
cf1 = supplyAsync(() -> { cf3Done.arriveAndAwaitAdvance(); return 1; });
cf2 = supplyAsync(() -> 2);
cf3 = cf1.acceptEither(cf2, x -> { check(x == 2); });
checkCompletedNormally(cf3, null);
checkCompletedNormally(cf2, 2);
check(!cf1.isDone());
cf3Done.arrive();
checkCompletedNormally(cf1, 1);
checkCompletedNormally(cf3, null);
cf1 = supplyAsync(() -> 1);
cf2 = supplyAsync(() -> { cf3Done.arriveAndAwaitAdvance(); return 2; });
cf3 = cf1.acceptEitherAsync(cf2, x -> { check(x == 1); });
checkCompletedNormally(cf3, null);
checkCompletedNormally(cf1, 1);
check(!cf2.isDone());
cf3Done.arrive();
checkCompletedNormally(cf2, 2);
checkCompletedNormally(cf3, null);
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// runAfterEitherXXX tests
//----------------------------------------------------------------
try {
CompletableFuture<Void> cf3;
int before = atomicInt.get();
CompletableFuture<Void> cf1 = runAsync(() -> {});
CompletableFuture<Void> cf2 = runAsync(() -> {});
cf3 = cf1.runAfterEither(cf2, () -> atomicInt.incrementAndGet());
checkCompletedNormally(cf3, null);
check(cf1.isDone() || cf2.isDone());
check(atomicInt.get() == (before + 1));
before = atomicInt.get();
cf1 = runAsync(() -> {});
cf2 = runAsync(() -> {});
cf3 = cf1.runAfterEitherAsync(cf2, () -> atomicInt.incrementAndGet());
checkCompletedNormally(cf3, null);
check(cf1.isDone() || cf2.isDone());
check(atomicInt.get() == (before + 1));
before = atomicInt.get();
cf1 = runAsync(() -> {});
cf2 = runAsync(() -> {});
cf3 = cf2.runAfterEitherAsync(cf1, () -> atomicInt.incrementAndGet(), executor);
checkCompletedNormally(cf3, null);
check(cf1.isDone() || cf2.isDone());
check(atomicInt.get() == (before + 1));
before = atomicInt.get();
cf1 = runAsync(() -> { throw new RuntimeException(); });
cf2 = runAsync(() -> {});
cf3 = cf2.runAfterEither(cf1, () -> atomicInt.incrementAndGet());
try {
check(cf3.join() == null);
check(atomicInt.get() == (before + 1));
} catch (CompletionException x) { pass(); }
check(cf3.isDone());
check(cf1.isDone() || cf2.isDone());
before = atomicInt.get();
cf1 = runAsync(() -> {});
cf2 = runAsync(() -> { throw new RuntimeException(); });
cf3 = cf1.runAfterEitherAsync(cf2, () -> atomicInt.incrementAndGet());
try {
check(cf3.join() == null);
check(atomicInt.get() == (before + 1));
} catch (CompletionException x) { pass(); }
check(cf3.isDone());
check(cf1.isDone() || cf2.isDone());
before = atomicInt.get();
cf1 = runAsync(() -> { throw new RuntimeException(); });
cf2 = runAsync(() -> { throw new RuntimeException(); });
cf3 = cf2.runAfterEitherAsync(cf1, () -> atomicInt.incrementAndGet(), executor);
checkCompletedExceptionally(cf3);
check(cf1.isDone() || cf2.isDone());
check(atomicInt.get() == before);
final Phaser cf3Done = new Phaser(2);
before = atomicInt.get();
cf1 = runAsync(() -> cf3Done.arriveAndAwaitAdvance());
cf2 = runAsync(() -> {});
cf3 = cf1.runAfterEither(cf2, () -> atomicInt.incrementAndGet());
checkCompletedNormally(cf3, null);
checkCompletedNormally(cf2, null);
check(!cf1.isDone());
check(atomicInt.get() == (before + 1));
cf3Done.arrive();
checkCompletedNormally(cf1, null);
checkCompletedNormally(cf3, null);
before = atomicInt.get();
cf1 = runAsync(() -> {});
cf2 = runAsync(() -> cf3Done.arriveAndAwaitAdvance());
cf3 = cf1.runAfterEitherAsync(cf2, () -> atomicInt.incrementAndGet());
checkCompletedNormally(cf3, null);
checkCompletedNormally(cf1, null);
check(!cf2.isDone());
check(atomicInt.get() == (before + 1));
cf3Done.arrive();
checkCompletedNormally(cf2, null);
checkCompletedNormally(cf3, null);
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// thenComposeXXX tests
//----------------------------------------------------------------
try {
CompletableFuture<Integer> cf2;
CompletableFuture<Integer> cf1 = supplyAsync(() -> 1);
cf2 = cf1.thenCompose(x -> { check(x == 1); return CompletableFuture.completedFuture(2); });
checkCompletedNormally(cf1, 1);
checkCompletedNormally(cf2, 2);
cf1 = supplyAsync(() -> 1);
cf2 = cf1.thenComposeAsync(x -> { check(x == 1); return CompletableFuture.completedFuture(2); });
checkCompletedNormally(cf1, 1);
checkCompletedNormally(cf2, 2);
cf1 = supplyAsync(() -> 1);
cf2 = cf1.thenComposeAsync(x -> { check(x == 1); return CompletableFuture.completedFuture(2); }, executor);
checkCompletedNormally(cf1, 1);
checkCompletedNormally(cf2, 2);
int before = atomicInt.get();
cf1 = supplyAsync(() -> { throw new RuntimeException(); });
cf2 = cf1.thenCompose(x -> { atomicInt.incrementAndGet(); return CompletableFuture.completedFuture(2); });
checkCompletedExceptionally(cf1);
checkCompletedExceptionally(cf2);
check(atomicInt.get() == before);
cf1 = supplyAsync(() -> { throw new RuntimeException(); });
cf2 = cf1.thenComposeAsync(x -> { atomicInt.incrementAndGet(); return CompletableFuture.completedFuture(2); });
checkCompletedExceptionally(cf1);
checkCompletedExceptionally(cf2);
check(atomicInt.get() == before);
cf1 = supplyAsync(() -> 1);
cf2 = cf1.thenComposeAsync(x -> { throw new RuntimeException(); }, executor);
checkCompletedNormally(cf1, 1);
checkCompletedExceptionally(cf2);
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// anyOf tests
//----------------------------------------------------------------
try {
CompletableFuture<Object> cf3;
for (int k=0; k < 10; k++){
CompletableFuture<Integer> cf1 = supplyAsync(() -> 1);
CompletableFuture<Integer> cf2 = supplyAsync(() -> 2);
cf3 = CompletableFuture.anyOf(cf1, cf2);
checkCompletedNormally(cf3, new Object[] {1, 2});
check(cf1.isDone() || cf2.isDone());
}
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// allOf tests
//----------------------------------------------------------------
try {
CompletableFuture<?> cf3;
for (int k=0; k < 10; k++){
CompletableFuture<Integer>[] cfs = (CompletableFuture<Integer>[])
Array.newInstance(CompletableFuture.class, 10);
for (int j=0; j < 10; j++) {
final int v = j;
cfs[j] = supplyAsync(() -> v);
}
cf3 = CompletableFuture.allOf(cfs);
for (int j=0; j < 10; j++)
checkCompletedNormally(cfs[j], j);
checkCompletedNormally(cf3, null);
}
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// exceptionally tests
//----------------------------------------------------------------
try {
CompletableFuture<Integer> cf2;
CompletableFuture<Integer> cf1 = supplyAsync(() -> 1);
cf2 = cf1.exceptionally(t -> { fail("function should never be called"); return 2;});
checkCompletedNormally(cf1, 1);
checkCompletedNormally(cf2, 1);
final RuntimeException t = new RuntimeException();
cf1 = supplyAsync(() -> { throw t; });
cf2 = cf1.exceptionally(x -> { check(x.getCause() == t); return 2;});
checkCompletedExceptionally(cf1);
checkCompletedNormally(cf2, 2);
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// handle tests
//----------------------------------------------------------------
try {
CompletableFuture<Integer> cf2;
CompletableFuture<Integer> cf1 = supplyAsync(() -> 1);
cf2 = cf1.handle((x,t) -> x+1);
checkCompletedNormally(cf1, 1);
checkCompletedNormally(cf2, 2);
final RuntimeException ex = new RuntimeException();
cf1 = supplyAsync(() -> { throw ex; });
cf2 = cf1.handle((x,t) -> { check(t.getCause() == ex); return 2;});
checkCompletedExceptionally(cf1);
checkCompletedNormally(cf2, 2);
cf1 = supplyAsync(() -> 1);
cf2 = cf1.handleAsync((x,t) -> x+1);
checkCompletedNormally(cf1, 1);
checkCompletedNormally(cf2, 2);
cf1 = supplyAsync(() -> { throw ex; });
cf2 = cf1.handleAsync((x,t) -> { check(t.getCause() == ex); return 2;});
checkCompletedExceptionally(cf1);
checkCompletedNormally(cf2, 2);
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// whenComplete tests
//----------------------------------------------------------------
try {
AtomicInteger count = new AtomicInteger();
CompletableFuture<Integer> cf2;
CompletableFuture<Integer> cf1 = supplyAsync(() -> 1);
cf2 = cf1.whenComplete((x,t) -> count.getAndIncrement());
checkCompletedNormally(cf1, 1);
checkCompletedNormally(cf2, 1);
check(count.get() == 1, "action count should be incremented");
final RuntimeException ex = new RuntimeException();
cf1 = supplyAsync(() -> { throw ex; });
cf2 = cf1.whenComplete((x,t) -> count.getAndIncrement());
checkCompletedExceptionally(cf1);
checkCompletedExceptionally(cf2);
check(count.get() == 2, "action count should be incremented");
cf1 = supplyAsync(() -> 1);
cf2 = cf1.whenCompleteAsync((x,t) -> count.getAndIncrement());
checkCompletedNormally(cf1, 1);
checkCompletedNormally(cf2, 1);
check(count.get() == 3, "action count should be incremented");
cf1 = supplyAsync(() -> { throw ex; });
cf2 = cf1.whenCompleteAsync((x,t) -> count.getAndIncrement());
checkCompletedExceptionally(cf1);
checkCompletedExceptionally(cf2);
check(count.get() == 4, "action count should be incremented");
} catch (Throwable t) { unexpected(t); }
}
//--------------------- Infrastructure ---------------------------
static volatile int passed = 0, failed = 0;
static void pass() {passed++;}
static void fail() {failed++; Thread.dumpStack();}
static void fail(String msg) {System.out.println(msg); fail();}
static void unexpected(Throwable t) {failed++; t.printStackTrace();}
static void check(boolean cond) {if (cond) pass(); else fail();}
static void check(boolean cond, String msg) {if (cond) pass(); else fail(msg);}
static void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
static void equalAnyOf(Object x, Object[] y) {
if (x == null && y == null) { pass(); return; }
for (Object z : y) { if (x.equals(z)) { pass(); return; } }
StringBuilder sb = new StringBuilder();
for (Object o : y)
sb.append(o).append(" ");
fail(x + " not equal to one of [" + sb + "]");}
public static void main(String[] args) throws Throwable {
try {realMain(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}

View file

@ -0,0 +1,70 @@
/*
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8303742
* @summary CompletableFuture.orTimeout can leak memory if completed exceptionally
* @modules java.base/java.util.concurrent:open
* @run junit/othervm -Xmx128m CompletableFutureOrTimeoutExceptionallyTest
*/
import java.time.Duration;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
class CompletableFutureOrTimeoutExceptionallyTest {
// updated February 2025 to adapt to CompletableFuture DelayScheduler changes
/**
* Test that orTimeout task is cancelled if the CompletableFuture is completed Exceptionally
*/
@Test
void testOrTimeoutWithCompleteExceptionallyDoesNotLeak() throws InterruptedException {
ForkJoinPool delayer = ForkJoinPool.commonPool();
assertEquals(delayer.getDelayedTaskCount(), 0);
var future = new CompletableFuture<>().orTimeout(12, TimeUnit.HOURS);
future.completeExceptionally(new RuntimeException("This is fine"));
while (delayer.getDelayedTaskCount() > 0) {
Thread.sleep(100);
};
}
/**
* Test that the completeOnTimeout task is cancelled if the CompletableFuture is completed Exceptionally
*/
@Test
void testCompleteOnTimeoutWithCompleteExceptionallyDoesNotLeak() throws InterruptedException {
ForkJoinPool delayer = ForkJoinPool.commonPool();
assertEquals(delayer.getDelayedTaskCount(), 0);
var future = new CompletableFuture<>().completeOnTimeout(null, 12, TimeUnit.HOURS);
future.completeExceptionally(new RuntimeException("This is fine"));
while (delayer.getDelayedTaskCount() > 0) {
Thread.sleep(100);
};
}
}

View file

@ -0,0 +1,73 @@
/*
* Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ThreadLocalRandom;
import static java.util.concurrent.TimeUnit.DAYS;
/*
* @test
* @bug 8254350
* @run main LostInterrupt
* @summary CompletableFuture.get may swallow interrupted status
* @key randomness
*/
// TODO: Rewrite as a CompletableFuture tck test ?
/**
* Submits a task that completes immediately, then invokes CompletableFuture.get
* with the interrupted status set. CompletableFuture.get should either complete
* immediately with the interrupted status set, or else throw InterruptedException
* with the interrupted status cleared.
*/
public class LostInterrupt {
static final int ITERATIONS = 10_000;
public static void main(String[] args) throws Exception {
ThreadLocalRandom rnd = ThreadLocalRandom.current();
ForkJoinPool executor = new ForkJoinPool(1);
try {
for (int i = 0; i < ITERATIONS; i++) {
CompletableFuture<String> future = new CompletableFuture<>();
boolean timed = rnd.nextBoolean();
executor.execute(() -> future.complete("foo"));
Thread.currentThread().interrupt();
try {
String result = timed ? future.get(1, DAYS) : future.get();
if (!Thread.interrupted())
throw new AssertionError("lost interrupt, run=" + i);
} catch (InterruptedException expected) {
if (Thread.interrupted())
throw new AssertionError(
"interrupted status not cleared, run=" + i);
}
}
} finally {
executor.shutdown();
}
}
}

View file

@ -0,0 +1,89 @@
/*
* Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadLocalRandom;
import static java.util.concurrent.TimeUnit.DAYS;
import java.util.concurrent.atomic.AtomicReference;
/*
* @test
* @bug 8254350
* @run main SwallowedInterruptedException
* @key randomness
*/
// TODO: incorporate into CompletableFuture tck tests
public class SwallowedInterruptedException {
static final int ITERATIONS = 100;
public static void main(String[] args) throws Throwable {
ThreadLocalRandom rnd = ThreadLocalRandom.current();
for (int i = 1; i <= ITERATIONS; i++) {
boolean timed = rnd.nextBoolean();
long sleepMillis = rnd.nextLong(10);
CompletableFuture<Void> future = new CompletableFuture<>();
CountDownLatch threadRunning = new CountDownLatch(1);
AtomicReference<Throwable> fail = new AtomicReference<>();
Thread thread = new Thread(() -> {
threadRunning.countDown();
try {
Void result = (timed) ? future.get(1, DAYS) : future.get();
if (!Thread.currentThread().isInterrupted()) {
fail.set(new AssertionError(
"Future.get completed with interrupted status not set"));
}
} catch (InterruptedException ex) {
if (Thread.currentThread().isInterrupted()) {
fail.set(new AssertionError(
"InterruptedException with interrupted status set"));
}
} catch (Throwable ex) {
fail.set(ex);
}
});
thread.start();
threadRunning.await();
// interrupt thread, then set result after an optional (random) delay
thread.interrupt();
if (sleepMillis > 0)
Thread.sleep(sleepMillis);
future.complete(null);
thread.join();
if (fail.get() != null) {
throw new AssertionError(
String.format("Test failed at iteration %d with [timed=%s sleepMillis=%d]",
i, timed, sleepMillis),
fail.get());
}
}
}
}

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import org.testng.Assert;
import org.testng.annotations.Test;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
/**
* @test
* @bug 8029164
* @run testng ThenComposeAsyncTest
* @run testng/othervm -Djava.util.concurrent.ForkJoinPool.common.parallelism=0 ThenComposeAsyncTest
* @summary Test that CompletableFuture.thenCompose works correctly if the
* composing task is complete before composition
*/
@Test
public class ThenComposeAsyncTest {
public void testThenComposeAsync() throws Exception {
// Composing CompletableFuture is complete
CompletableFuture<String> cf1 = CompletableFuture.completedFuture("one");
// Composing function returns a CompletableFuture executed asynchronously
CountDownLatch cdl = new CountDownLatch(1);
CompletableFuture<String> cf2 = cf1.thenCompose(str -> CompletableFuture.supplyAsync(() -> {
while (true) {
try {
cdl.await();
break;
}
catch (InterruptedException e) {
}
}
return str + ", two";
}));
// Ensure returned CompletableFuture completes after call to thenCompose
// This guarantees that any premature internal completion will be
// detected
cdl.countDown();
String val = cf2.get();
Assert.assertNotNull(val);
Assert.assertEquals(val, "one, two");
}
}

View file

@ -0,0 +1,122 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiFunction;
import java.util.function.Consumer;
/**
* @test
* @bug 8068432 8072030
* @run testng ThenComposeExceptionTest
* @summary Test that CompletableFuture.thenCompose works correctly if the
* composing future completes exceptionally
*/
@Test
public class ThenComposeExceptionTest {
static final BiFunction<CompletableFuture<String>, CompletableFuture<String>, CompletableFuture<String>>
THEN_COMPOSE = (f, fe) -> f.thenCompose(s -> fe);
static final BiFunction<CompletableFuture<String>, CompletableFuture<String>, CompletableFuture<String>>
THEN_COMPOSE_ASYNC = (f, fe) -> f.thenComposeAsync(s -> fe);
static final Consumer<CompletableFuture<String>>
COMPLETE_EXCEPTIONALLY = f -> f.completeExceptionally(new RuntimeException());
static final Consumer<CompletableFuture<String>>
NOP = f -> { };
static Object[][] actionsDataProvider;
@DataProvider(name = "actions")
static Object[][] actionsDataProvider() {
if (actionsDataProvider != null) {
return actionsDataProvider;
}
List<Object[]> data = new ArrayList<>();
data.add(new Object[]{"thenCompose and completeExceptionally", NOP, THEN_COMPOSE, COMPLETE_EXCEPTIONALLY});
data.add(new Object[]{"thenComposeAsync and completeExceptionally", NOP, THEN_COMPOSE_ASYNC, COMPLETE_EXCEPTIONALLY});
data.add(new Object[]{"completeExceptionally and thenCompose", COMPLETE_EXCEPTIONALLY, THEN_COMPOSE, NOP});
data.add(new Object[]{"completeExceptionally and thenComposeAsync", COMPLETE_EXCEPTIONALLY, THEN_COMPOSE_ASYNC, NOP});
return actionsDataProvider = data.toArray(new Object[0][]);
}
@Test(dataProvider = "actions")
public void testThenCompose(
String description,
Consumer<CompletableFuture<String>> beforeAction,
BiFunction<CompletableFuture<String>, CompletableFuture<String>, CompletableFuture<String>> composeFunction,
Consumer<CompletableFuture<String>> afterAction) throws Exception {
CompletableFuture<String> f = new CompletableFuture<>();
CompletableFuture<String> fe = new CompletableFuture<>();
// Ensure pre-composed stage is completed to trigger
// processing the composing future
f.complete("");
beforeAction.accept(fe);
CompletableFuture<String> f_thenCompose = composeFunction.apply(f, fe);
Assert.assertNotSame(f_thenCompose, fe, "Composed CompletableFuture returned directly");
AtomicReference<Throwable> eOnWhenComplete = new AtomicReference<>();
CompletableFuture<String> f_whenComplete = f_thenCompose.
whenComplete((r, e) -> eOnWhenComplete.set(e));
afterAction.accept(fe);
Throwable eOnJoined = null;
try {
f_thenCompose.join();
}
catch (Throwable t) {
eOnJoined = t;
}
Assert.assertTrue(eOnJoined instanceof CompletionException,
"Incorrect exception reported when joined on thenCompose: " + eOnJoined);
// Need to wait for f_whenComplete to complete to avoid
// race condition when updating eOnWhenComplete
eOnJoined = null;
try {
f_whenComplete.join();
} catch (Throwable t) {
eOnJoined = t;
}
Assert.assertTrue(eOnJoined instanceof CompletionException,
"Incorrect exception reported when joined on whenComplete: " + eOnJoined);
Assert.assertTrue(eOnWhenComplete.get() instanceof CompletionException,
"Incorrect exception passed to whenComplete: " + eOnWhenComplete.get());
}
}

View file

@ -0,0 +1,182 @@
/*
* Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import org.testng.annotations.Test;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.BiConsumer;
import java.util.function.Supplier;
import java.util.stream.IntStream;
import java.util.stream.Stream;
/**
* @test
* @bug 8028564
* @run testng/timeout=1200 ConcurrentAssociateTest
* @summary Test that association operations, such as put and compute,
* place entries in the map
* @modules java.management
*/
@Test
public class ConcurrentAssociateTest {
/** Maximum time (in seconds) to wait for a test method to complete. */
private static final int TIMEOUT = Integer.getInteger("timeout", 200);
/** The number of entries for each thread to place in a map. */
private static final int N = Integer.getInteger("n", 128);
/** The number of iterations of the test. */
private static final int I = Integer.getInteger("i", 64);
/** Objects to be placed in the concurrent map. */
static class X {
// Limit the hash code to trigger collisions
final int hc = ThreadLocalRandom.current().nextInt(1, 9);
public int hashCode() { return hc; }
}
@Test
public void testPut() throws Throwable {
test("CHM.put", (m, o) -> m.put(o, o));
}
@Test
public void testCompute() throws Throwable {
test("CHM.compute", (m, o) -> m.compute(o, (k, v) -> o));
}
@Test
public void testComputeIfAbsent() throws Throwable {
test("CHM.computeIfAbsent", (m, o) -> m.computeIfAbsent(o, (k) -> o));
}
@Test
public void testMerge() throws Throwable {
test("CHM.merge", (m, o) -> m.merge(o, o, (v1, v2) -> v1));
}
@Test
public void testPutAll() throws Throwable {
test("CHM.putAll", (m, o) -> {
Map<Object, Object> hm = new HashMap<>();
hm.put(o, o);
m.putAll(hm);
});
}
private static void test(String desc, BiConsumer<ConcurrentMap<Object, Object>, Object> associator) throws Throwable {
for (int i = 0; i < I; i++) {
testOnce(desc, associator);
}
}
static class AssociationFailure extends RuntimeException {
AssociationFailure(String message) {
super(message);
}
}
private static void testOnce(String desc, BiConsumer<ConcurrentMap<Object, Object>, Object> associator) throws Throwable {
ConcurrentHashMap<Object, Object> m = new ConcurrentHashMap<>();
CountDownLatch s = new CountDownLatch(1);
Supplier<Runnable> sr = () -> () -> {
try {
if (!s.await(TIMEOUT, TimeUnit.SECONDS)) {
dumpTestThreads();
throw new AssertionError("timed out");
}
}
catch (InterruptedException e) {
}
for (int i = 0; i < N; i++) {
Object o = new X();
associator.accept(m, o);
if (!m.containsKey(o)) {
throw new AssociationFailure(desc + " failed: entry does not exist");
}
}
};
// Bound concurrency to avoid degenerate performance
int ps = Math.min(Runtime.getRuntime().availableProcessors(), 8);
Stream<CompletableFuture> runners = IntStream.range(0, ps)
.mapToObj(i -> sr.get())
.map(CompletableFuture::runAsync);
CompletableFuture all = CompletableFuture.allOf(
runners.toArray(CompletableFuture[]::new));
// Trigger the runners to start associating
s.countDown();
try {
all.get(TIMEOUT, TimeUnit.SECONDS);
} catch (TimeoutException e) {
dumpTestThreads();
throw e;
} catch (Throwable e) {
dumpTestThreads();
Throwable cause = e.getCause();
if (cause instanceof AssociationFailure) {
throw cause;
}
throw e;
}
}
/**
* A debugging tool to print stack traces of most threads, as jstack does.
* Uninteresting threads are filtered out.
*/
static void dumpTestThreads() {
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
System.err.println("------ stacktrace dump start ------");
for (ThreadInfo info : threadMXBean.dumpAllThreads(true, true)) {
final String name = info.getThreadName();
String lockName;
if ("Signal Dispatcher".equals(name))
continue;
if ("Reference Handler".equals(name))
continue;
if ("Finalizer".equals(name))
continue;
System.err.print(info);
}
System.err.println("------ stacktrace dump end ------");
}
}

View file

@ -0,0 +1,136 @@
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import org.testng.annotations.Test;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.function.Supplier;
import java.util.stream.IntStream;
import java.util.stream.Stream;
/**
* @test
* @bug 8028564
* @run testng ConcurrentContainsKeyTest
* @summary Test that entries are always present in the map,
* when entries are held within one bin that is a tree
*/
@Test
public class ConcurrentContainsKeyTest {
// The number of entries for each thread to place in a map
// Should be > ConcurrentHashMap.TREEIFY_THRESHOLD but small
// enough to allow for enough iteration overlap by multiple threads
private static final int N = Integer.getInteger("n", 16);
// The number of rounds each thread performs per entry
private static final int R = Integer.getInteger("r", 32);
// The number of iterations of the test
private static final int I = Integer.getInteger("i", 256);
// Object to be placed in the concurrent map
static class X implements Comparable<X> {
private final int a;
X(int a) {
this.a = a;
}
public int compareTo(X o) {
return this.a - o.a;
}
public int hashCode() {
// Return the same hash code to guarantee collisions
return 0;
}
}
@Test
public void testContainsKey() {
X[] content = IntStream.range(0, N).mapToObj(i -> new X(i)).toArray(X[]::new);
// Create map with an initial size >= ConcurrentHashMap.TREEIFY_THRESHOLD
// ensuring tree'ification will occur for a small number of entries
// with the same hash code
ConcurrentHashMap<Object, Object> m = new ConcurrentHashMap<>(64);
Stream.of(content).forEach(x -> m.put(x, x));
test(content, m);
}
private static void test(X[] content, ConcurrentHashMap<Object, Object> m) {
for (int i = 0; i < I; i++) {
testOnce(content, m);
}
}
static class AssociationFailure extends RuntimeException {
AssociationFailure(String message) {
super(message);
}
}
private static void testOnce(Object[] content, ConcurrentHashMap<Object, Object> m) {
CountDownLatch s = new CountDownLatch(1);
Supplier<Runnable> sr = () -> () -> {
try {
s.await();
}
catch (InterruptedException e) {
}
for (int i = 0; i < R * N; i++) {
Object o = content[i % content.length];
if (!m.containsKey(o)) {
throw new AssociationFailure("CHM.containsKey failed: entry does not exist");
}
}
};
int ps = Runtime.getRuntime().availableProcessors();
Stream<CompletableFuture> runners = IntStream.range(0, ps)
.mapToObj(i -> sr.get())
.map(CompletableFuture::runAsync);
CompletableFuture all = CompletableFuture.allOf(
runners.toArray(CompletableFuture[]::new));
// Trigger the runners to start checking key membership
s.countDown();
try {
all.join();
}
catch (CompletionException e) {
Throwable t = e.getCause();
if (t instanceof AssociationFailure) {
throw (AssociationFailure) t;
}
else {
throw e;
}
}
}
}

View file

@ -0,0 +1,59 @@
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* Portions Copyright (c) 2011 IBM Corporation
*/
/*
* @test
* @bug 6312706
* @summary Sets from Map.entrySet() return distinct objects for each Entry
* @author Neil Richards <neil.richards@ngmr.net>, <neil_richards@uk.ibm.com>
*/
import java.util.concurrent.ConcurrentHashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class DistinctEntrySetElements {
public static void main(String[] args) throws Exception {
final ConcurrentHashMap<String, String> concurrentHashMap =
new ConcurrentHashMap<>();
concurrentHashMap.put("One", "Un");
concurrentHashMap.put("Two", "Deux");
concurrentHashMap.put("Three", "Trois");
Set<Map.Entry<String, String>> entrySet = concurrentHashMap.entrySet();
HashSet<Map.Entry<String, String>> hashSet = new HashSet<>(entrySet);
if (false == hashSet.equals(entrySet)) {
throw new RuntimeException("Test FAILED: Sets are not equal.");
}
if (hashSet.hashCode() != entrySet.hashCode()) {
throw new RuntimeException("Test FAILED: Set's hashcodes are not equal.");
}
}
}

View file

@ -0,0 +1,103 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/**
* Misc utilities in JSR166 performance tests
*/
class LoopHelpers {
// Some mindless computation to do between synchronizations...
/**
* generates 32 bit pseudo-random numbers.
* Adapted from http://www.snippets.org
*/
public static int compute1(int x) {
int lo = 16807 * (x & 0xFFFF);
int hi = 16807 * (x >>> 16);
lo += (hi & 0x7FFF) << 16;
if ((lo & 0x80000000) != 0) {
lo &= 0x7fffffff;
++lo;
}
lo += hi >>> 15;
if (lo == 0 || (lo & 0x80000000) != 0) {
lo &= 0x7fffffff;
++lo;
}
return lo;
}
/**
* Computes a linear congruential random number a random number
* of times.
*/
public static int compute2(int x) {
int loops = (x >>> 4) & 7;
while (loops-- > 0) {
x = (x * 2147483647) % 16807;
}
return x;
}
public static class BarrierTimer implements Runnable {
public volatile long startTime;
public volatile long endTime;
public void run() {
long t = System.nanoTime();
if (startTime == 0)
startTime = t;
else
endTime = t;
}
public void clear() {
startTime = 0;
endTime = 0;
}
public long getTime() {
return endTime - startTime;
}
}
public static String rightJustify(long n) {
// There's probably a better way to do this...
String field = " ";
String num = Long.toString(n);
if (num.length() >= field.length())
return num;
StringBuilder b = new StringBuilder(field);
b.replace(b.length()-num.length(), b.length(), num);
return b.toString();
}
}

View file

@ -0,0 +1,622 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* @test
* @bug 4486658
* @run main/timeout=240 MapCheck
* @summary Times and checks basic map operations
*/
import java.io.Serializable;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
public class MapCheck {
static final int absentSize = 1 << 17;
static final int absentMask = absentSize - 1;
static Object[] absent = new Object[absentSize];
static final Object MISSING = new Object();
static TestTimer timer = new TestTimer();
static void reallyAssert(boolean b) {
if (!b) throw new Error("Failed Assertion");
}
public static void main(String[] args) throws Exception {
Class mapClass = java.util.concurrent.ConcurrentHashMap.class;
int numTests = 8;
int size = 50000;
if (args.length > 0) {
try {
mapClass = Class.forName(args[0]);
} catch (ClassNotFoundException e) {
throw new RuntimeException("Class " + args[0] + " not found.");
}
}
if (args.length > 1)
numTests = Integer.parseInt(args[1]);
if (args.length > 2)
size = Integer.parseInt(args[2]);
boolean doSerializeTest = args.length > 3;
System.out.println("Testing " + mapClass.getName() + " trials: " + numTests + " size: " + size);
for (int i = 0; i < absentSize; ++i) absent[i] = new Object();
Object[] key = new Object[size];
for (int i = 0; i < size; ++i) key[i] = new Object();
forceMem(size * 8);
for (int rep = 0; rep < numTests; ++rep) {
runTest(newMap(mapClass), key);
}
TestTimer.printStats();
if (doSerializeTest)
stest(newMap(mapClass), size);
}
static Map newMap(Class cl) {
try {
return (Map)cl.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new RuntimeException("Can't instantiate " + cl + ": " + e);
}
}
static void runTest(Map s, Object[] key) {
shuffle(key);
int size = key.length;
long startTime = System.currentTimeMillis();
test(s, key);
long time = System.currentTimeMillis() - startTime;
}
static void forceMem(int n) {
// force enough memory
Long[] junk = new Long[n];
for (int i = 0; i < junk.length; ++i) junk[i] = new Long(i);
int sum = 0;
for (int i = 0; i < junk.length; ++i)
sum += (int)(junk[i].longValue() + i);
if (sum == 0) System.out.println("Useless number = " + sum);
junk = null;
// System.gc();
}
static void t1(String nm, int n, Map s, Object[] key, int expect) {
int sum = 0;
int iters = 4;
timer.start(nm, n * iters);
for (int j = 0; j < iters; ++j) {
for (int i = 0; i < n; i++) {
if (s.get(key[i]) != null) ++sum;
}
}
timer.finish();
reallyAssert(sum == expect * iters);
}
static void t2(String nm, int n, Map s, Object[] key, int expect) {
int sum = 0;
timer.start(nm, n);
for (int i = 0; i < n; i++) {
if (s.remove(key[i]) != null) ++sum;
}
timer.finish();
reallyAssert(sum == expect);
}
static void t3(String nm, int n, Map s, Object[] key, int expect) {
int sum = 0;
timer.start(nm, n);
for (int i = 0; i < n; i++) {
if (s.put(key[i], absent[i & absentMask]) == null) ++sum;
}
timer.finish();
reallyAssert(sum == expect);
}
static void t4(String nm, int n, Map s, Object[] key, int expect) {
int sum = 0;
timer.start(nm, n);
for (int i = 0; i < n; i++) {
if (s.containsKey(key[i])) ++sum;
}
timer.finish();
reallyAssert(sum == expect);
}
static void t5(String nm, int n, Map s, Object[] key, int expect) {
int sum = 0;
timer.start(nm, n/2);
for (int i = n-2; i >= 0; i-=2) {
if (s.remove(key[i]) != null) ++sum;
}
timer.finish();
reallyAssert(sum == expect);
}
static void t6(String nm, int n, Map s, Object[] k1, Object[] k2) {
int sum = 0;
timer.start(nm, n * 2);
for (int i = 0; i < n; i++) {
if (s.get(k1[i]) != null) ++sum;
if (s.get(k2[i & absentMask]) != null) ++sum;
}
timer.finish();
reallyAssert(sum == n);
}
static void t7(String nm, int n, Map s, Object[] k1, Object[] k2) {
int sum = 0;
timer.start(nm, n * 2);
for (int i = 0; i < n; i++) {
if (s.containsKey(k1[i])) ++sum;
if (s.containsKey(k2[i & absentMask])) ++sum;
}
timer.finish();
reallyAssert(sum == n);
}
static void t8(String nm, int n, Map s, Object[] key, int expect) {
int sum = 0;
timer.start(nm, n);
for (int i = 0; i < n; i++) {
if (s.get(key[i]) != null) ++sum;
}
timer.finish();
reallyAssert(sum == expect);
}
static void t9(Map s) {
int sum = 0;
int iters = 20;
timer.start("ContainsValue (/n) ", iters * s.size());
int step = absentSize / iters;
for (int i = 0; i < absentSize; i += step)
if (s.containsValue(absent[i])) ++sum;
timer.finish();
reallyAssert(sum != 0);
}
static void ktest(Map s, int size, Object[] key) {
timer.start("ContainsKey ", size);
Set ks = s.keySet();
int sum = 0;
for (int i = 0; i < size; i++) {
if (ks.contains(key[i])) ++sum;
}
timer.finish();
reallyAssert(sum == size);
}
static void ittest1(Map s, int size) {
int sum = 0;
timer.start("Iter Key ", size);
for (Iterator it = s.keySet().iterator(); it.hasNext(); ) {
if (it.next() != MISSING)
++sum;
}
timer.finish();
reallyAssert(sum == size);
}
static void ittest2(Map s, int size) {
int sum = 0;
timer.start("Iter Value ", size);
for (Iterator it = s.values().iterator(); it.hasNext(); ) {
if (it.next() != MISSING)
++sum;
}
timer.finish();
reallyAssert(sum == size);
}
static void ittest3(Map s, int size) {
int sum = 0;
timer.start("Iter Entry ", size);
for (Iterator it = s.entrySet().iterator(); it.hasNext(); ) {
if (it.next() != MISSING)
++sum;
}
timer.finish();
reallyAssert(sum == size);
}
static void ittest4(Map s, int size, int pos) {
IdentityHashMap seen = new IdentityHashMap(size);
reallyAssert(s.size() == size);
int sum = 0;
timer.start("Iter XEntry ", size);
Iterator it = s.entrySet().iterator();
Object k = null;
Object v = null;
for (int i = 0; i < size-pos; ++i) {
Map.Entry x = (Map.Entry)(it.next());
k = x.getKey();
v = x.getValue();
seen.put(k, k);
if (x != MISSING)
++sum;
}
reallyAssert(s.containsKey(k));
it.remove();
reallyAssert(!s.containsKey(k));
while (it.hasNext()) {
Map.Entry x = (Map.Entry)(it.next());
Object k2 = x.getKey();
seen.put(k2, k2);
if (x != MISSING)
++sum;
}
reallyAssert(s.size() == size-1);
s.put(k, v);
reallyAssert(seen.size() == size);
timer.finish();
reallyAssert(sum == size);
reallyAssert(s.size() == size);
}
static void ittest(Map s, int size) {
ittest1(s, size);
ittest2(s, size);
ittest3(s, size);
// for (int i = 0; i < size-1; ++i)
// ittest4(s, size, i);
}
static void entest1(Hashtable ht, int size) {
int sum = 0;
timer.start("Iter Enumeration Key ", size);
for (Enumeration en = ht.keys(); en.hasMoreElements(); ) {
if (en.nextElement() != MISSING)
++sum;
}
timer.finish();
reallyAssert(sum == size);
}
static void entest2(Hashtable ht, int size) {
int sum = 0;
timer.start("Iter Enumeration Value ", size);
for (Enumeration en = ht.elements(); en.hasMoreElements(); ) {
if (en.nextElement() != MISSING)
++sum;
}
timer.finish();
reallyAssert(sum == size);
}
static void entest3(Hashtable ht, int size) {
int sum = 0;
timer.start("Iterf Enumeration Key ", size);
Enumeration en = ht.keys();
for (int i = 0; i < size; ++i) {
if (en.nextElement() != MISSING)
++sum;
}
timer.finish();
reallyAssert(sum == size);
}
static void entest4(Hashtable ht, int size) {
int sum = 0;
timer.start("Iterf Enumeration Value", size);
Enumeration en = ht.elements();
for (int i = 0; i < size; ++i) {
if (en.nextElement() != MISSING)
++sum;
}
timer.finish();
reallyAssert(sum == size);
}
static void entest(Map s, int size) {
if (s instanceof Hashtable) {
Hashtable ht = (Hashtable)s;
// entest3(ht, size);
// entest4(ht, size);
entest1(ht, size);
entest2(ht, size);
entest1(ht, size);
entest2(ht, size);
entest1(ht, size);
entest2(ht, size);
}
}
static void rtest(Map s, int size) {
timer.start("Remove (iterator) ", size);
for (Iterator it = s.keySet().iterator(); it.hasNext(); ) {
it.next();
it.remove();
}
timer.finish();
}
static void rvtest(Map s, int size) {
timer.start("Remove (iterator) ", size);
for (Iterator it = s.values().iterator(); it.hasNext(); ) {
it.next();
it.remove();
}
timer.finish();
}
static void dtest(Map s, int size, Object[] key) {
timer.start("Put (putAll) ", size * 2);
Map s2 = null;
try {
s2 = (Map) s.getClass().getDeclaredConstructor().newInstance();
s2.putAll(s);
}
catch (Exception e) { e.printStackTrace(); return; }
timer.finish();
timer.start("Iter Equals ", size * 2);
boolean eqt = s2.equals(s) && s.equals(s2);
reallyAssert(eqt);
timer.finish();
timer.start("Iter HashCode ", size * 2);
int shc = s.hashCode();
int s2hc = s2.hashCode();
reallyAssert(shc == s2hc);
timer.finish();
timer.start("Put (present) ", size);
s2.putAll(s);
timer.finish();
timer.start("Iter EntrySet contains ", size * 2);
Set es2 = s2.entrySet();
int sum = 0;
for (Iterator i1 = s.entrySet().iterator(); i1.hasNext(); ) {
Object entry = i1.next();
if (es2.contains(entry)) ++sum;
}
timer.finish();
reallyAssert(sum == size);
t6("Get ", size, s2, key, absent);
Object hold = s2.get(key[size-1]);
s2.put(key[size-1], absent[0]);
timer.start("Iter Equals ", size * 2);
eqt = s2.equals(s) && s.equals(s2);
reallyAssert(!eqt);
timer.finish();
timer.start("Iter HashCode ", size * 2);
int s1h = s.hashCode();
int s2h = s2.hashCode();
reallyAssert(s1h != s2h);
timer.finish();
s2.put(key[size-1], hold);
timer.start("Remove (iterator) ", size * 2);
Iterator s2i = s2.entrySet().iterator();
Set es = s.entrySet();
while (s2i.hasNext())
es.remove(s2i.next());
timer.finish();
reallyAssert(s.isEmpty());
timer.start("Clear ", size);
s2.clear();
timer.finish();
reallyAssert(s2.isEmpty() && s.isEmpty());
}
static void stest(Map s, int size) throws Exception {
if (!(s instanceof Serializable))
return;
System.out.print("Serialize : ");
for (int i = 0; i < size; i++) {
s.put(new Integer(i), Boolean.TRUE);
}
long startTime = System.currentTimeMillis();
FileOutputStream fs = new FileOutputStream("MapCheck.dat");
ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(fs));
out.writeObject(s);
out.close();
FileInputStream is = new FileInputStream("MapCheck.dat");
ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(is));
Map m = (Map)in.readObject();
long endTime = System.currentTimeMillis();
long time = endTime - startTime;
System.out.print(time + "ms");
if (s instanceof IdentityHashMap) return;
reallyAssert(s.equals(m));
}
static void test(Map s, Object[] key) {
int size = key.length;
t3("Put (absent) ", size, s, key, size);
t3("Put (present) ", size, s, key, 0);
t7("ContainsKey ", size, s, key, absent);
t4("ContainsKey ", size, s, key, size);
ktest(s, size, key);
t4("ContainsKey ", absentSize, s, absent, 0);
t6("Get ", size, s, key, absent);
t1("Get (present) ", size, s, key, size);
t1("Get (absent) ", absentSize, s, absent, 0);
t2("Remove (absent) ", absentSize, s, absent, 0);
t5("Remove (present) ", size, s, key, size / 2);
t3("Put (half present) ", size, s, key, size / 2);
ittest(s, size);
entest(s, size);
t9(s);
rtest(s, size);
t4("ContainsKey ", size, s, key, 0);
t2("Remove (absent) ", size, s, key, 0);
t3("Put (presized) ", size, s, key, size);
dtest(s, size, key);
}
static class TestTimer {
private String name;
private long numOps;
private long startTime;
private String cname;
static final java.util.TreeMap accum = new java.util.TreeMap();
static void printStats() {
for (Iterator it = accum.entrySet().iterator(); it.hasNext(); ) {
Map.Entry e = (Map.Entry)(it.next());
Stats stats = (Stats)(e.getValue());
int n = stats.number;
double t;
if (n > 0)
t = stats.sum / n;
else
t = stats.least;
long nano = Math.round(1000000.0 * t);
System.out.println(e.getKey() + ": " + nano);
}
}
void start(String name, long numOps) {
this.name = name;
this.cname = classify();
this.numOps = numOps;
startTime = System.currentTimeMillis();
}
String classify() {
if (name.startsWith("Get"))
return "Get ";
else if (name.startsWith("Put"))
return "Put ";
else if (name.startsWith("Remove"))
return "Remove ";
else if (name.startsWith("Iter"))
return "Iter ";
else
return null;
}
void finish() {
long endTime = System.currentTimeMillis();
long time = endTime - startTime;
double timePerOp = ((double)time)/numOps;
Object st = accum.get(name);
if (st == null)
accum.put(name, new Stats(timePerOp));
else {
Stats stats = (Stats) st;
stats.sum += timePerOp;
stats.number++;
if (timePerOp < stats.least) stats.least = timePerOp;
}
if (cname != null) {
st = accum.get(cname);
if (st == null)
accum.put(cname, new Stats(timePerOp));
else {
Stats stats = (Stats) st;
stats.sum += timePerOp;
stats.number++;
if (timePerOp < stats.least) stats.least = timePerOp;
}
}
}
}
static class Stats {
double sum = 0;
double least;
int number = 0;
Stats(double t) { least = t; }
}
static void shuffle(Object[] keys) {
ThreadLocalRandom rnd = ThreadLocalRandom.current();
int size = keys.length;
for (int i=size; i>1; i--) {
int r = rnd.nextInt(i);
Object t = keys[i-1];
keys[i-1] = keys[r];
keys[r] = t;
}
}
}

View file

@ -0,0 +1,249 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* @test
* @bug 4486658
* @summary Exercise multithreaded maps, by default ConcurrentHashMap.
* Multithreaded hash table test. Each thread does a random walk
* though elements of "key" array. On each iteration, it checks if
* table includes key. If absent, with probability pinsert it
* inserts it, and if present, with probability premove it removes
* it. (pinsert and premove are expressed as percentages to simplify
* parsing from command line.)
* @library /test/lib
* @run main/timeout=1600 MapLoops
*/
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import java.util.List;
import java.util.Map;
import java.util.SplittableRandom;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import jdk.test.lib.Utils;
public class MapLoops {
static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
static int nkeys = 1000; // 10_000
static int pinsert = 60;
static int premove = 2;
static int maxThreads = 100;
static int nops = 10000; // 100_000
static int removesPerMaxRandom;
static int insertsPerMaxRandom;
static final ExecutorService pool = Executors.newCachedThreadPool();
static final List<Throwable> throwables = new CopyOnWriteArrayList<>();
public static void main(String[] args) throws Exception {
Class mapClass = null;
if (args.length > 0) {
try {
mapClass = Class.forName(args[0]);
} catch (ClassNotFoundException e) {
throw new RuntimeException("Class " + args[0] + " not found.");
}
}
else
mapClass = java.util.concurrent.ConcurrentHashMap.class;
if (args.length > 1)
maxThreads = Integer.parseInt(args[1]);
if (args.length > 2)
nkeys = Integer.parseInt(args[2]);
if (args.length > 3)
pinsert = Integer.parseInt(args[3]);
if (args.length > 4)
premove = Integer.parseInt(args[4]);
if (args.length > 5)
nops = Integer.parseInt(args[5]);
// normalize probabilities wrt random number generator
removesPerMaxRandom = (int)((double)premove/100.0 * 0x7FFFFFFFL);
insertsPerMaxRandom = (int)((double)pinsert/100.0 * 0x7FFFFFFFL);
System.out.print("Class: " + mapClass.getName());
System.out.print(" threads: " + maxThreads);
System.out.print(" size: " + nkeys);
System.out.print(" ins: " + pinsert);
System.out.print(" rem: " + premove);
System.out.print(" ops: " + nops);
System.out.println();
int k = 1;
int warmups = 2;
for (int i = 1; i <= maxThreads;) {
test(i, nkeys, mapClass);
if (warmups > 0)
--warmups;
else if (i == k) {
k = i << 1;
i = i + (i >>> 1);
}
else if (i == 1 && k == 2) {
i = k;
warmups = 1;
}
else
i = k;
}
pool.shutdown();
if (! pool.awaitTermination(LONG_DELAY_MS, MILLISECONDS))
throw new Error();
if (! throwables.isEmpty())
throw new Error
(throwables.size() + " thread(s) terminated abruptly.");
}
static Integer[] makeKeys(int n) {
SplittableRandom rnd = new SplittableRandom();
Integer[] key = new Integer[n];
for (int i = 0; i < key.length; ++i)
key[i] = new Integer(rnd.nextInt());
return key;
}
static void shuffleKeys(Integer[] key) {
SplittableRandom rnd = new SplittableRandom();
for (int i = key.length; i > 1; --i) {
int j = rnd.nextInt(i);
Integer tmp = key[j];
key[j] = key[i-1];
key[i-1] = tmp;
}
}
static void test(int i, int nkeys, Class mapClass) throws Exception {
System.out.print("Threads: " + i + "\t:");
Map<Integer, Integer> map = (Map<Integer, Integer>)
mapClass.getDeclaredConstructor().newInstance();
Integer[] key = makeKeys(nkeys);
// Uncomment to start with a non-empty table
// for (int j = 0; j < nkeys; j += 4) // start 1/4 occupied
// map.put(key[j], key[j]);
LoopHelpers.BarrierTimer timer = new LoopHelpers.BarrierTimer();
CyclicBarrier barrier = new CyclicBarrier(i+1, timer);
SplittableRandom rnd = new SplittableRandom();
for (int t = 0; t < i; ++t)
pool.execute(new Runner(map, key, barrier, rnd.split()));
barrier.await();
barrier.await();
long time = timer.getTime();
long tpo = time / (i * (long)nops);
System.out.print(LoopHelpers.rightJustify(tpo) + " ns per op");
double secs = (double)time / 1000000000.0;
System.out.println("\t " + secs + "s run time");
map.clear();
}
static class Runner implements Runnable {
final Map<Integer,Integer> map;
final Integer[] key;
final CyclicBarrier barrier;
final SplittableRandom rnd;
int position;
int total;
Runner(Map<Integer,Integer> map,
Integer[] key,
CyclicBarrier barrier,
SplittableRandom rnd) {
this.map = map;
this.key = key;
this.barrier = barrier;
this.rnd = rnd;
position = key.length / 2;
}
int step() {
// random-walk around key positions, bunching accesses
int r = rnd.nextInt(Integer.MAX_VALUE);
position += (r & 7) - 3;
while (position >= key.length) position -= key.length;
while (position < 0) position += key.length;
Integer k = key[position];
Integer x = map.get(k);
if (x != null) {
if (x.intValue() != k.intValue())
throw new Error("bad mapping: " + x + " to " + k);
if (r < removesPerMaxRandom) {
if (map.remove(k) != null) {
position = total % key.length; // move from position
return 2;
}
}
}
else if (r < insertsPerMaxRandom) {
++position;
map.put(k, k);
return 2;
}
// Uncomment to add a little computation between accesses
// total += LoopHelpers.compute1(k.intValue());
total += r;
return 1;
}
public void run() {
try {
barrier.await();
int ops = nops;
while (ops > 0)
ops -= step();
barrier.await();
}
catch (Throwable throwable) {
synchronized (System.err) {
System.err.println("--------------------------------");
throwable.printStackTrace();
}
throwables.add(throwable);
}
}
}
}

View file

@ -0,0 +1,104 @@
/*
* Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4486658 8010293
* @summary thread safety of toArray methods of collection views
* @author Martin Buchholz
*/
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class ToArray {
public static void main(String[] args) throws Throwable {
final int runsPerTest = Integer.getInteger("jsr166.runsPerTest", 1);
final int reps = 10 * runsPerTest;
for (int i = reps; i--> 0; )
executeTest();
}
static void executeTest() throws Throwable {
try (var executor = Executors.newCachedThreadPool()) {
final ConcurrentHashMap<Integer, Integer> m = new ConcurrentHashMap<>();
final ThreadLocalRandom rnd = ThreadLocalRandom.current();
final int nCPU = Runtime.getRuntime().availableProcessors();
final int minWorkers = 2;
final int maxWorkers = Math.max(minWorkers, Math.min(32, nCPU));
final int nWorkers = rnd.nextInt(minWorkers, maxWorkers + 1);
final int sizePerWorker = 1024;
final int maxSize = nWorkers * sizePerWorker;
// The foreman busy-checks that the size of the arrays obtained
// from the keys and values views grows monotonically until it
// reaches the maximum size.
// NOTE: these size constraints are not specific to toArray and are
// applicable to any form of traversal of the collection views
CompletableFuture<?> foreman = CompletableFuture.runAsync(new Runnable() {
private int prevSize = 0;
private boolean checkProgress(Object[] a) {
int size = a.length;
if (size < prevSize || size > maxSize)
throw new AssertionError(
String.format("prevSize=%d size=%d maxSize=%d",
prevSize, size, maxSize));
prevSize = size;
return size == maxSize;
}
public void run() {
Integer[] empty = new Integer[0];
for (; ; )
if (checkProgress(m.values().toArray())
& checkProgress(m.keySet().toArray())
& checkProgress(m.values().toArray(empty))
& checkProgress(m.keySet().toArray(empty)))
return;
}
}, executor);
// Each worker puts globally unique keys into the map
List<CompletableFuture<?>> workers =
IntStream.range(0, nWorkers)
.mapToObj(w -> (Runnable) () -> {
for (int i = 0, o = w * sizePerWorker; i < sizePerWorker; i++)
m.put(o + i, i);
})
.map(r -> CompletableFuture.runAsync(r, executor))
.collect(Collectors.toList());
// Wait for workers and foreman to complete
workers.forEach(CompletableFuture<?>::join);
foreman.join();
}
}
}

View file

@ -0,0 +1,210 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Martin Buchholz with assistance from members of JCP
* JSR-166 Expert Group and released to the public domain, as
* explained at http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* @test
* @modules java.base/java.util.concurrent:open
* @run testng WhiteBox
* @summary White box tests of implementation details
*/
import static org.testng.Assert.*;
import org.testng.annotations.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.VarHandle;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Supplier;
@Test
public class WhiteBox {
final ThreadLocalRandom rnd = ThreadLocalRandom.current();
final VarHandle TABLE, NEXTTABLE, SIZECTL;
final MethodHandle TABLE_SIZE_FOR;
WhiteBox() throws ReflectiveOperationException {
Class<?> mClass = ConcurrentHashMap.class;
String nodeClassName = mClass.getName() + "$Node";
Class<?> nodeClass = Class.forName(nodeClassName);
Class<?> nodeArrayClass = Class.forName("[L" + nodeClassName + ";");
MethodHandles.Lookup lookup
= MethodHandles.privateLookupIn(mClass, MethodHandles.lookup());
TABLE = lookup.findVarHandle(mClass, "table", nodeArrayClass);
NEXTTABLE = lookup.findVarHandle(mClass, "nextTable", nodeArrayClass);
SIZECTL = lookup.findVarHandle(mClass, "sizeCtl", int.class);
TABLE_SIZE_FOR = lookup.findStatic(
mClass, "tableSizeFor",
MethodType.methodType(int.class, int.class));
}
Object[] table(ConcurrentHashMap m) { return (Object[]) TABLE.getVolatile(m); }
Object[] nextTable(ConcurrentHashMap m) { return (Object[]) NEXTTABLE.getVolatile(m); }
int sizeCtl(ConcurrentHashMap m) { return (int) SIZECTL.getVolatile(m); }
int tableSizeFor(int n) {
try {
return (int) TABLE_SIZE_FOR.invoke(n);
} catch (Throwable t) { throw new AssertionError(t); }
}
List<Supplier<ConcurrentHashMap>> newConcurrentHashMapSuppliers(
int initialCapacity) {
return List.of(
() -> new ConcurrentHashMap(initialCapacity),
() -> new ConcurrentHashMap(initialCapacity, 0.75f),
() -> new ConcurrentHashMap(initialCapacity, 0.75f, 1));
}
ConcurrentHashMap newConcurrentHashMap(int initialCapacity) {
List<Supplier<ConcurrentHashMap>> suppliers
= newConcurrentHashMapSuppliers(initialCapacity);
return suppliers.get(rnd.nextInt(suppliers.size())).get();
}
@Test
public void defaultConstructor() {
ConcurrentHashMap m = new ConcurrentHashMap();
assertNull(table(m));
assertEquals(sizeCtl(m), 0);
assertResizeNotInProgress(m);
}
@Test
public void shouldNotResizeWhenInitialCapacityProvided() {
int initialCapacity = rnd.nextInt(1, 100);
Object[] initialTable = null;
ConcurrentHashMap m = newConcurrentHashMap(initialCapacity);
// table is lazily initialized
assertNull(table(m));
int expectedInitialTableLength = sizeCtl(m);
assertInvariants(m);
for (int i = 0; i < initialCapacity; i++) {
m.put(i * 100 + rnd.nextInt(100), i);
if (i == 0)
initialTable = table(m);
else
assertSame(table(m), initialTable);
assertInvariants(m);
}
assertEquals(initialTable.length, expectedInitialTableLength);
}
@Test
public void constructorsShouldGiveSameInitialCapacity() {
int initialCapacity = rnd.nextInt(1, 256);
long distinctTableLengths
= newConcurrentHashMapSuppliers(initialCapacity).stream()
.map(Supplier::get)
.mapToInt(map -> { map.put(42, 42); return table(map).length; })
.distinct()
.count();
assertEquals(1L, distinctTableLengths);
}
@Test
public void testTableSizeFor() {
assertEquals(1, tableSizeFor(0));
assertEquals(1, tableSizeFor(1));
assertEquals(2, tableSizeFor(2));
assertEquals(4, tableSizeFor(3));
assertEquals(16, tableSizeFor(15));
assertEquals(16, tableSizeFor(16));
assertEquals(32, tableSizeFor(17));
int maxSize = 1 << 30;
assertEquals(maxSize, tableSizeFor(maxSize - 1));
assertEquals(maxSize, tableSizeFor(maxSize));
assertEquals(maxSize, tableSizeFor(maxSize + 1));
assertEquals(maxSize, tableSizeFor(Integer.MAX_VALUE));
}
byte[] serialBytes(Object o) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(o);
oos.flush();
oos.close();
return bos.toByteArray();
} catch (Exception fail) {
throw new AssertionError(fail);
}
}
@SuppressWarnings("unchecked")
<T> T serialClone(T o) {
try {
ObjectInputStream ois = new ObjectInputStream
(new ByteArrayInputStream(serialBytes(o)));
T clone = (T) ois.readObject();
assertNotSame(o, clone);
assertSame(o.getClass(), clone.getClass());
return clone;
} catch (Exception fail) {
throw new AssertionError(fail);
}
}
@Test
public void testSerialization() {
assertInvariants(serialClone(new ConcurrentHashMap()));
ConcurrentHashMap m = newConcurrentHashMap(rnd.nextInt(100));
m.put(1, 1);
ConcurrentHashMap clone = serialClone(m);
assertInvariants(clone);
assertNotSame(table(m), table(clone));
assertEquals(m, clone);
assertResizeNotInProgress(m);
assertResizeNotInProgress(clone);
}
/** Checks conditions which should always be true. */
void assertInvariants(ConcurrentHashMap m) {
if (!m.isEmpty())
assertNotNull(table(m));
}
void assertResizeNotInProgress(ConcurrentHashMap m) {
assertTrue(sizeCtl(m) >= 0);
assertNull(nextTable(m));
}
}

View file

@ -0,0 +1,156 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Martin Buchholz with assistance from members of JCP
* JSR-166 Expert Group and released to the public domain, as
* explained at http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* @test
* @bug 8054446 8137184 8137185
* @modules java.base/java.util.concurrent:open
* java.base/java.util.concurrent.locks:open
* @summary Regression test for memory leak in remove(Object)
*/
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.PriorityBlockingQueue;
public class RemoveLeak {
public static void main(String[] args) throws Throwable {
new RemoveLeak().main();
}
void main() throws Throwable {
test(new ConcurrentLinkedDeque());
test(new ConcurrentLinkedQueue());
test(new LinkedBlockingDeque(10));
test(new LinkedBlockingQueue(10));
test(new LinkedTransferQueue());
test(new ArrayBlockingQueue(10));
test(new PriorityBlockingQueue());
}
void test(Collection c) throws Throwable {
assertNoLeak(c, () -> addRemove(c));
// A demo that the leak detection infrastructure works
// assertNoLeak(c, () -> c.add(1));
// printRetainedObjects(c);
}
static void addRemove(Collection c) {
c.add(1);
c.remove(1);
}
// -------- leak detection infrastructure ---------------
void assertNoLeak(Object root, Runnable r) {
int prev = retainedObjects(root).size();
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) r.run();
int next = retainedObjects(root).size();
if (next <= prev)
return;
prev = next;
}
throw new AssertionError(
String.format("probable memory leak in %s: %s",
root.getClass().getSimpleName(), root));
}
ConcurrentHashMap<Class<?>, Collection<Field>> classFields
= new ConcurrentHashMap<>();
Collection<Field> referenceFieldsOf(Class<?> k) {
Collection<Field> fields = classFields.get(k);
if (fields == null) {
fields = new ArrayDeque<Field>();
ArrayDeque<Field> allFields = new ArrayDeque<>();
for (Class<?> c = k; c != null; c = c.getSuperclass())
for (Field field : c.getDeclaredFields())
if (!Modifier.isStatic(field.getModifiers())
&& !field.getType().isPrimitive())
fields.add(field);
AccessibleObject.setAccessible(
fields.toArray(new AccessibleObject[0]), true);
classFields.put(k, fields);
}
return fields;
}
static Object get(Field field, Object x) {
try { return field.get(x); }
catch (IllegalAccessException ex) { throw new AssertionError(ex); }
}
Set<Object> retainedObjects(Object x) {
ArrayDeque<Object> todo = new ArrayDeque<>() {
public void push(Object x) { if (x != null) super.push(x); }};
Set<Object> uniqueObjects = Collections.newSetFromMap(
new IdentityHashMap<Object, Boolean>());
todo.push(x);
while (!todo.isEmpty()) {
Object y = todo.pop();
if (uniqueObjects.contains(y))
continue;
uniqueObjects.add(y);
Class<?> k = y.getClass();
if (k.isArray() && !k.getComponentType().isPrimitive()) {
for (int i = 0, len = Array.getLength(y); i < len; i++)
todo.push(Array.get(y, i));
} else {
for (Field field : referenceFieldsOf(k))
todo.push(get(field, y));
}
}
return uniqueObjects;
}
/** for debugging the retained object graph */
void printRetainedObjects(Object x) {
for (Object y : retainedObjects(x))
System.out.printf("%s : %s%n", y.getClass().getSimpleName(), y);
}
}

View file

@ -0,0 +1,325 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Martin Buchholz with assistance from members of JCP
* JSR-166 Expert Group and released to the public domain, as
* explained at http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* @test
* @modules java.base/java.util.concurrent:open
* @run testng WhiteBox
* @summary White box tests of implementation details
*/
import static org.testng.Assert.*;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ThreadLocalRandom;
import static java.util.stream.Collectors.toList;
import java.util.function.Consumer;
@Test
public class WhiteBox {
final ThreadLocalRandom rnd = ThreadLocalRandom.current();
final VarHandle HEAD, TAIL, ITEM, NEXT;
WhiteBox() throws ReflectiveOperationException {
Class<?> qClass = ConcurrentLinkedQueue.class;
Class<?> nodeClass = Class.forName(qClass.getName() + "$Node");
MethodHandles.Lookup lookup
= MethodHandles.privateLookupIn(qClass, MethodHandles.lookup());
HEAD = lookup.findVarHandle(qClass, "head", nodeClass);
TAIL = lookup.findVarHandle(qClass, "tail", nodeClass);
NEXT = lookup.findVarHandle(nodeClass, "next", nodeClass);
ITEM = lookup.findVarHandle(nodeClass, "item", Object.class);
}
Object head(ConcurrentLinkedQueue q) { return HEAD.getVolatile(q); }
Object tail(ConcurrentLinkedQueue q) { return TAIL.getVolatile(q); }
Object item(Object node) { return ITEM.getVolatile(node); }
Object next(Object node) { return NEXT.getVolatile(node); }
int nodeCount(ConcurrentLinkedQueue q) {
int i = 0;
for (Object p = head(q); p != null; ) {
i++;
if (p == (p = next(p))) p = head(q);
}
return i;
}
void assertIsSelfLinked(Object node) {
assertSame(next(node), node);
assertNull(item(node));
}
void assertIsNotSelfLinked(Object node) {
assertNotSame(node, next(node));
}
@Test
public void addRemove() {
ConcurrentLinkedQueue q = new ConcurrentLinkedQueue();
assertInvariants(q);
assertNull(item(head(q)));
assertEquals(nodeCount(q), 1);
q.add(1);
assertEquals(nodeCount(q), 2);
assertInvariants(q);
q.remove(1);
assertEquals(nodeCount(q), 1);
assertInvariants(q);
}
/**
* Traversal actions that visit every node and do nothing, but
* have side effect of squeezing out dead nodes.
*/
@DataProvider
public Object[][] traversalActions() {
return List.<Consumer<ConcurrentLinkedQueue>>of(
q -> q.forEach(e -> {}),
q -> assertFalse(q.contains(new Object())),
q -> assertFalse(q.remove(new Object())),
q -> q.spliterator().forEachRemaining(e -> {}),
q -> q.stream().collect(toList()),
q -> assertFalse(q.removeIf(e -> false)),
q -> assertFalse(q.removeAll(List.of())))
.stream().map(x -> new Object[]{ x }).toArray(Object[][]::new);
}
@Test(dataProvider = "traversalActions")
public void traversalOperationsCollapseNodes(
Consumer<ConcurrentLinkedQueue> traversalAction) {
ConcurrentLinkedQueue q = new ConcurrentLinkedQueue();
Object oldHead;
int n = 1 + rnd.nextInt(5);
for (int i = 0; i < n; i++) q.add(i);
assertInvariants(q);
assertEquals(nodeCount(q), n + 1);
oldHead = head(q);
traversalAction.accept(q); // collapses head node
assertIsSelfLinked(oldHead);
assertInvariants(q);
assertEquals(nodeCount(q), n);
// Iterator.remove does not currently try to collapse dead nodes
for (Iterator it = q.iterator(); it.hasNext(); ) {
it.next();
it.remove();
}
assertEquals(nodeCount(q), n);
assertInvariants(q);
oldHead = head(q);
traversalAction.accept(q); // collapses all nodes
if (n > 1) assertIsSelfLinked(oldHead);
assertEquals(nodeCount(q), 1);
assertInvariants(q);
for (int i = 0; i < n + 1; i++) q.add(i);
assertEquals(nodeCount(q), n + 2);
oldHead = head(q);
assertEquals(0, q.poll()); // 2 leading nodes collapsed
assertIsSelfLinked(oldHead);
assertEquals(nodeCount(q), n);
assertTrue(q.remove(n));
assertEquals(nodeCount(q), n);
traversalAction.accept(q); // trailing node is never collapsed
}
@Test(dataProvider = "traversalActions")
public void traversalOperationsCollapseLeadingNodes(
Consumer<ConcurrentLinkedQueue> traversalAction) {
ConcurrentLinkedQueue q = new ConcurrentLinkedQueue();
Object oldHead;
int n = 1 + rnd.nextInt(5);
for (int i = 0; i < n; i++) q.add(i);
assertEquals(nodeCount(q), n + 1);
oldHead = head(q);
traversalAction.accept(q);
assertInvariants(q);
assertEquals(nodeCount(q), n);
assertIsSelfLinked(oldHead);
}
@Test(dataProvider = "traversalActions")
public void traversalOperationsDoNotSelfLinkInteriorNodes(
Consumer<ConcurrentLinkedQueue> traversalAction) {
ConcurrentLinkedQueue q = new ConcurrentLinkedQueue();
int c;
int n = 3 + rnd.nextInt(3);
for (int i = 0; i < n; i++) q.add(i);
Object oneNode;
for (oneNode = head(q);
! (item(oneNode) != null && item(oneNode).equals(1));
oneNode = next(oneNode))
;
Object next = next(oneNode);
c = nodeCount(q);
for (Iterator it = q.iterator(); it.hasNext(); )
if (it.next().equals(1)) it.remove();
assertEquals(nodeCount(q), c - 1); // iterator detached head!
assertNull(item(oneNode));
assertSame(next, next(oneNode));
assertInvariants(q);
c = nodeCount(q);
traversalAction.accept(q);
assertEquals(nodeCount(q), c - 1);
assertSame(next, next(oneNode)); // un-linked, but not self-linked
}
/**
* Checks that traversal operations collapse a random pattern of
* dead nodes as could normally only occur with a race.
*/
@Test(dataProvider = "traversalActions")
public void traversalOperationsCollapseRandomNodes(
Consumer<ConcurrentLinkedQueue> traversalAction) {
ConcurrentLinkedQueue q = new ConcurrentLinkedQueue();
int n = rnd.nextInt(6);
for (int i = 0; i < n; i++) q.add(i);
ArrayList nulledOut = new ArrayList();
for (Object p = head(q); p != null; p = next(p))
if (item(p) != null && rnd.nextBoolean()) {
nulledOut.add(item(p));
ITEM.setVolatile(p, null);
}
traversalAction.accept(q);
int c = nodeCount(q);
assertEquals(q.size(), c - (q.contains(n - 1) ? 0 : 1));
for (int i = 0; i < n; i++)
assertTrue(nulledOut.contains(i) ^ q.contains(i));
}
/**
* Traversal actions that remove every element, and are also
* expected to squeeze out dead nodes.
*/
@DataProvider
public Object[][] bulkRemovalActions() {
return List.<Consumer<ConcurrentLinkedQueue>>of(
q -> q.clear(),
q -> assertTrue(q.removeIf(e -> true)),
q -> assertTrue(q.retainAll(List.of())))
.stream().map(x -> new Object[]{ x }).toArray(Object[][]::new);
}
@Test(dataProvider = "bulkRemovalActions")
public void bulkRemovalOperationsCollapseNodes(
Consumer<ConcurrentLinkedQueue> bulkRemovalAction) {
ConcurrentLinkedQueue q = new ConcurrentLinkedQueue();
int n = 1 + rnd.nextInt(5);
for (int i = 0; i < n; i++) q.add(i);
bulkRemovalAction.accept(q);
assertEquals(nodeCount(q), 1);
assertInvariants(q);
}
/**
* Actions that remove the first element, and are expected to
* leave at most one slack dead node at head.
*/
@DataProvider
public Object[][] pollActions() {
return List.<Consumer<ConcurrentLinkedQueue>>of(
q -> assertNotNull(q.poll()),
q -> assertNotNull(q.remove()))
.stream().map(x -> new Object[]{ x }).toArray(Object[][]::new);
}
@Test(dataProvider = "pollActions")
public void pollActionsOneNodeSlack(
Consumer<ConcurrentLinkedQueue> pollAction) {
ConcurrentLinkedQueue q = new ConcurrentLinkedQueue();
int n = 1 + rnd.nextInt(5);
for (int i = 0; i < n; i++) q.add(i);
assertEquals(nodeCount(q), n + 1);
for (int i = 0; i < n; i++) {
int c = nodeCount(q);
boolean slack = item(head(q)) == null;
if (slack) assertNotNull(item(next(head(q))));
pollAction.accept(q);
assertEquals(nodeCount(q), q.isEmpty() ? 1 : c - (slack ? 2 : 0));
}
assertInvariants(q);
}
byte[] serialBytes(Object o) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(o);
oos.flush();
oos.close();
return bos.toByteArray();
} catch (Exception fail) {
throw new AssertionError(fail);
}
}
@SuppressWarnings("unchecked")
<T> T serialClone(T o) {
try {
ObjectInputStream ois = new ObjectInputStream
(new ByteArrayInputStream(serialBytes(o)));
T clone = (T) ois.readObject();
assertNotSame(o, clone);
assertSame(o.getClass(), clone.getClass());
return clone;
} catch (Exception fail) {
throw new AssertionError(fail);
}
}
@Test
public void testSerialization() {
ConcurrentLinkedQueue q = serialClone(new ConcurrentLinkedQueue());
assertInvariants(q);
}
/** Checks conditions which should always be true. */
void assertInvariants(ConcurrentLinkedQueue q) {
assertNotNull(head(q));
assertNotNull(tail(q));
// head is never self-linked (but tail may!)
for (Object h; next(h = head(q)) == h; )
assertNotSame(h, head(q)); // must be update race
}
}

View file

@ -0,0 +1,101 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6312056 4155650 4294891 4904074
* @summary Reasonable things should happen if mutating while iterating.
*/
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentSkipListMap;
public class ConcurrentModification {
static volatile int passed = 0, failed = 0;
static void fail(String msg) {
failed++;
new AssertionError(msg).printStackTrace();
}
static void unexpected(Throwable t) {
failed++;
t.printStackTrace();
}
static void check(boolean condition, String msg) {
if (condition)
passed++;
else
fail(msg);
}
static void check(boolean condition) {
check(condition, "Assertion failed");
}
private static void test(ConcurrentMap<Integer, Integer> m)
{
try {
m.clear();
check(m.isEmpty());
m.put(1,2);
Iterator<Map.Entry<Integer,Integer>> it = m.entrySet().iterator();
if (it.hasNext()) {
m.remove(1); // sneaky
Map.Entry<Integer, Integer> e = it.next();
check(m.isEmpty());
check(e.getKey() == 1);
check(e.getValue() == 2);
}
} catch (Throwable t) {unexpected(t);}
try {
m.clear();
check(m.isEmpty());
m.put(1,2);
Iterator<Map.Entry<Integer,Integer>> it = m.entrySet().iterator();
if (it.hasNext()) {
m.put(1,3); // sneaky
Map.Entry<Integer, Integer> e = it.next();
check(e.getKey() == 1);
check(e.getValue() == 2 || e.getValue() == 3);
if (m instanceof ConcurrentHashMap) {
e.setValue(4);
check(m.get(1) == 4);
}
}
} catch (Throwable t) {unexpected(t);}
}
public static void main(String[] args) {
test(new ConcurrentHashMap<Integer,Integer>());
test(new ConcurrentSkipListMap<Integer,Integer>());
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new Error("Some tests failed");
}
}

View file

@ -0,0 +1,170 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @run testng ConcurrentRemoveIf
* @bug 8078645
* @summary Test removeIf on views of concurrent maps
*/
import static org.testng.Assert.assertEquals;
import org.testng.annotations.AfterClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentNavigableMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Consumer;
import java.util.function.Supplier;
@Test
public class ConcurrentRemoveIf {
static final int K = 100;
static final int SIZE = 1000;
static final int HALF_SIZE = SIZE / 2;
@DataProvider()
public static Object[][] concurrentMapViewRemoveIfActions() {
List<Object[]> rows = new ArrayList<>();
// ConcurrentMap classes to test
Map<String, Supplier<ConcurrentMap<Integer, Integer>>> maps = new HashMap<>();
maps.put("ConcurrentHashMap", ConcurrentHashMap::new);
maps.put("ConcurrentSkipListMap", ConcurrentSkipListMap::new);
// ConcurrentMap actions
Map<String, Consumer<ConcurrentMap<Integer, Integer>>> actions = new HashMap<>();
actions.put(".entrySet().removeIf()", m -> m.entrySet().removeIf(e -> e.getValue() == 0));
actions.put(".values().removeIf()", m -> m.values().removeIf(v -> v == 0));
// ConcurrentNavigableMap actions
Map<String, Consumer<ConcurrentNavigableMap<Integer, Integer>>> navActions = new HashMap<>();
navActions.put(".headMap()/tailMap().entrySet().removeIf()",
m -> {
ConcurrentMap<Integer, Integer> left = m.headMap(HALF_SIZE, false);
ConcurrentMap<Integer, Integer> right = m.tailMap(HALF_SIZE, true);
left.entrySet().removeIf(e -> e.getValue() == 0);
right.entrySet().removeIf(e -> e.getValue() == 0);
});
navActions.put(".headMap()/tailMap().values().removeIf()",
m -> {
ConcurrentMap<Integer, Integer> left = m.headMap(HALF_SIZE, false);
ConcurrentMap<Integer, Integer> right = m.tailMap(HALF_SIZE, true);
left.values().removeIf(v -> v == 0);
right.values().removeIf(v -> v == 0);
});
navActions.put(".descendingMap().entrySet().removeIf()",
m -> {
ConcurrentMap<Integer, Integer> dm = m.descendingMap();
dm.entrySet().removeIf(e -> e.getValue() == 0);
});
navActions.put(".descendingMap().values().removeIf()",
m -> {
ConcurrentMap<Integer, Integer> dm = m.descendingMap();
dm.values().removeIf(v -> v == 0);
});
maps.forEach((mapDescription, sm) -> {
actions.forEach((actionDescription, action) -> {
rows.add(new Object[] {mapDescription + actionDescription, sm, action});
});
if (sm.get() instanceof ConcurrentNavigableMap) {
navActions.forEach((actionDescription, action) -> {
rows.add(new Object[] {mapDescription + actionDescription, sm, action});
});
}
});
return rows.toArray(new Object[0][]);
}
ExecutorService executorService = Executors.newCachedThreadPool();
@AfterClass
public void after() {
executorService.shutdown();
}
@Test(dataProvider = "concurrentMapViewRemoveIfActions")
public void testMap(String desc, Supplier<ConcurrentMap<Integer, Integer>> ms, Consumer<ConcurrentMap<Integer, Integer>> action)
throws InterruptedException {
for (int i = 0; i < K; i++) {
testMap(ms.get(), action);
}
}
private void testMap(ConcurrentMap<Integer, Integer> map, Consumer<ConcurrentMap<Integer, Integer>> action)
throws InterruptedException {
// put 0's
fillMap(map, 0);
// To start working simultaneously
CyclicBarrier threadStarted = new CyclicBarrier(2);
// This task puts 1's into map
CompletableFuture<Void> putter = CompletableFuture.runAsync(
awaitOn(threadStarted, () -> fillMap(map, 1)),
executorService);
// This task performs the map action to remove all 0's from map
CompletableFuture<Void> remover = CompletableFuture.runAsync(
awaitOn(threadStarted, () -> action.accept(map)),
executorService);
// Wait for both tasks to complete
CompletableFuture.allOf(putter, remover).join();
assertEquals(map.size(), SIZE, "Map size incorrect");
map.forEach((k, v) -> assertEquals(v, (Integer)1));
}
static void fillMap(ConcurrentMap<Integer, Integer> map, int value) {
for (int i = 0; i < SIZE; i++) {
map.put(i, value);
}
}
static Runnable awaitOn(CyclicBarrier threadStarted, Runnable r) {
return () -> {
try {
threadStarted.await();
}
catch (Exception e) {
throw new RuntimeException(e);
}
r.run();
};
}
}

View file

@ -0,0 +1,206 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* @test
* @bug 4486658 6785442
* @summary Checks that a set of threads can repeatedly get and modify items
* @library /test/lib
* @run main ConcurrentQueueLoops 8 123456
*/
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.atomic.AtomicInteger;
import jdk.test.lib.Utils;
public class ConcurrentQueueLoops {
static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
ExecutorService pool;
AtomicInteger totalItems;
boolean print;
// Suitable for benchmarking. Overridden by args[0] for testing.
int maxStages = 20;
// Suitable for benchmarking. Overridden by args[1] for testing.
int items = 1024 * 1024;
Collection<Queue<Integer>> concurrentQueues() {
List<Queue<Integer>> queues = new ArrayList<>();
queues.add(new ConcurrentLinkedDeque<Integer>());
queues.add(new ConcurrentLinkedQueue<Integer>());
queues.add(new ArrayBlockingQueue<Integer>(items, false));
//queues.add(new ArrayBlockingQueue<Integer>(count, true));
queues.add(new LinkedBlockingQueue<Integer>());
queues.add(new LinkedBlockingDeque<Integer>());
queues.add(new LinkedTransferQueue<Integer>());
// Following additional implementations are available from:
// http://gee.cs.oswego.edu/dl/concurrency-interest/index.html
// queues.add(new SynchronizedLinkedListQueue<Integer>());
// Avoid "first fast, second slow" benchmark effect.
Collections.shuffle(queues);
return queues;
}
void test(String[] args) throws Throwable {
if (args.length > 0)
maxStages = Integer.parseInt(args[0]);
if (args.length > 1)
items = Integer.parseInt(args[1]);
for (Queue<Integer> queue : concurrentQueues())
test(queue);
}
void test(final Queue<Integer> q) throws Throwable {
System.out.println(q.getClass().getSimpleName());
pool = Executors.newCachedThreadPool();
print = false;
print = false;
System.out.println("Warmup...");
oneRun(1, items, q);
oneRun(3, items, q);
print = true;
for (int i = 1; i <= maxStages; i += (i+1) >>> 1) {
oneRun(i, items, q);
}
pool.shutdown();
check(pool.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
}
class Stage implements Callable<Integer> {
final Queue<Integer> queue;
final CyclicBarrier barrier;
int items;
Stage(Queue<Integer> q, CyclicBarrier b, int items) {
queue = q;
barrier = b;
this.items = items;
}
public Integer call() {
// Repeatedly take something from queue if possible,
// transform it, and put back in.
try {
barrier.await();
int l = 4321;
int takes = 0;
for (;;) {
Integer item = queue.poll();
if (item != null) {
++takes;
l = LoopHelpers.compute2(item.intValue());
}
else if (takes != 0) {
totalItems.getAndAdd(-takes);
takes = 0;
}
else if (totalItems.get() <= 0)
break;
l = LoopHelpers.compute1(l);
if (items > 0) {
--items;
queue.offer(new Integer(l));
}
else if ( (l & (3 << 5)) == 0) // spinwait
Thread.sleep(1);
}
return new Integer(l);
}
catch (Throwable t) { unexpected(t); return null; }
}
}
void oneRun(int n, int items, final Queue<Integer> q) throws Exception {
LoopHelpers.BarrierTimer timer = new LoopHelpers.BarrierTimer();
CyclicBarrier barrier = new CyclicBarrier(n + 1, timer);
totalItems = new AtomicInteger(n * items);
ArrayList<Future<Integer>> results = new ArrayList<>(n);
for (int i = 0; i < n; ++i)
results.add(pool.submit(new Stage(q, barrier, items)));
if (print)
System.out.print("Threads: " + n + "\t:");
barrier.await();
int total = 0;
for (int i = 0; i < n; ++i) {
Future<Integer> f = results.get(i);
Integer r = f.get();
total += r.intValue();
}
long endTime = System.nanoTime();
long time = endTime - timer.startTime;
if (print)
System.out.println(LoopHelpers.rightJustify(time / (items * n)) + " ns per item");
if (total == 0) // avoid overoptimization
System.out.println("useless result: " + total);
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
new ConcurrentQueueLoops().instanceMain(args);}
public void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}

View file

@ -0,0 +1,189 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* @test
* @bug 6785442
* @summary Benchmark that tries to GC-tenure head, followed by
* many add/remove operations.
* @run main GCRetention just-testing
*/
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Queue;
import java.util.Map;
public class GCRetention {
boolean benchmarkMode;
int count;
/** No guarantees, but effective in practice. */
static void forceFullGc() {
long timeoutMillis = 1000L;
CountDownLatch finalized = new CountDownLatch(1);
ReferenceQueue<Object> queue = new ReferenceQueue<>();
WeakReference<Object> ref = new WeakReference<>(
new Object() { protected void finalize() { finalized.countDown(); }},
queue);
try {
for (int tries = 3; tries--> 0; ) {
System.gc();
if (finalized.await(timeoutMillis, MILLISECONDS)
&& queue.remove(timeoutMillis) != null
&& ref.get() == null) {
System.runFinalization(); // try to pick up stragglers
return;
}
timeoutMillis *= 4;
}
} catch (InterruptedException unexpected) {
throw new AssertionError("unexpected InterruptedException");
}
throw new AssertionError("failed to do a \"full\" gc");
}
final Map<String,String> results = new ConcurrentHashMap<>();
Collection<Queue<Boolean>> queues() {
List<Queue<Boolean>> queues = new ArrayList<>();
queues.add(new ConcurrentLinkedDeque<Boolean>());
queues.add(new ConcurrentLinkedQueue<Boolean>());
queues.add(new ArrayBlockingQueue<Boolean>(count, false));
queues.add(new ArrayBlockingQueue<Boolean>(count, true));
queues.add(new LinkedBlockingQueue<Boolean>());
queues.add(new LinkedBlockingDeque<Boolean>());
queues.add(new PriorityBlockingQueue<Boolean>());
queues.add(new PriorityQueue<Boolean>());
queues.add(new LinkedList<Boolean>());
queues.add(new LinkedTransferQueue<Boolean>());
// Following additional implementations are available from:
// http://gee.cs.oswego.edu/dl/concurrency-interest/index.html
// queues.add(new SynchronizedLinkedListQueue<Boolean>());
// Avoid "first fast, second slow" benchmark effect.
Collections.shuffle(queues);
return queues;
}
void prettyPrintResults() {
List<String> classNames = new ArrayList<>(results.keySet());
Collections.sort(classNames);
int maxClassNameLength = 0;
int maxNanosLength = 0;
for (String name : classNames) {
if (maxClassNameLength < name.length())
maxClassNameLength = name.length();
if (maxNanosLength < results.get(name).length())
maxNanosLength = results.get(name).length();
}
String format = String.format("%%%ds %%%ds nanos/item%%n",
maxClassNameLength, maxNanosLength);
for (String name : classNames)
System.out.printf(format, name, results.get(name));
}
void test(String[] args) {
benchmarkMode = ! (args.length > 0 && args[0].equals("just-testing"));
count = benchmarkMode ? 1024 * 1024 : 30;
// Warmup
for (Queue<Boolean> queue : queues())
test(queue);
results.clear();
for (Queue<Boolean> queue : queues())
test(queue);
prettyPrintResults();
}
void test(Queue<Boolean> q) {
long t0 = System.nanoTime();
for (int i = 0; i < count; i++)
check(q.add(Boolean.TRUE));
if (benchmarkMode) forceFullGc();
// forceFullGc();
Boolean x;
while ((x = q.poll()) != null)
equal(x, Boolean.TRUE);
check(q.isEmpty());
for (int i = 0; i < 10 * count; i++) {
for (int k = 0; k < 3; k++)
check(q.add(Boolean.TRUE));
for (int k = 0; k < 3; k++)
if (q.poll() != Boolean.TRUE)
fail();
}
check(q.isEmpty());
String className = q.getClass().getSimpleName();
long elapsed = System.nanoTime() - t0;
int nanos = (int) ((double) elapsed / (10 * 3 * count));
results.put(className, String.valueOf(nanos));
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
new GCRetention().instanceMain(args);}
public void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}

View file

@ -0,0 +1,278 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* @test
* @bug 6805775 6815766
* @summary Check weak consistency of concurrent queue iterators
*/
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.ThreadLocalRandom;
@SuppressWarnings({"unchecked", "rawtypes"})
public class IteratorWeakConsistency {
final ThreadLocalRandom rnd = ThreadLocalRandom.current();
void test(String[] args) throws Throwable {
test(new LinkedBlockingQueue());
test(new LinkedBlockingQueue(20));
test(new LinkedBlockingDeque());
test(new LinkedBlockingDeque(20));
test(new ConcurrentLinkedDeque());
test(new ConcurrentLinkedQueue());
test(new LinkedTransferQueue());
test(new ArrayBlockingQueue(20));
}
void checkExhausted(Iterator it) {
if (rnd.nextBoolean()) {
check(!it.hasNext());
}
if (rnd.nextBoolean()) {
it.forEachRemaining(e -> { throw new AssertionError(); });
}
if (rnd.nextBoolean())
try { it.next(); fail("should throw"); }
catch (NoSuchElementException success) {}
}
void checkRemoveThrowsISE(Iterator it) {
if (rnd.nextBoolean()) {
try { it.remove(); fail("should throw"); }
catch (IllegalStateException success) {}
}
}
void checkRemoveHasNoEffect(Iterator it, Collection c) {
if (rnd.nextBoolean()) {
int size = c.size();
it.remove(); // no effect
equal(c.size(), size);
checkRemoveThrowsISE(it);
}
}
void test(Queue q) {
//----------------------------------------------------------------
// Check iterators on an empty q
//----------------------------------------------------------------
try {
for (int i = 0; i < 4; i++) {
Iterator it = q.iterator();
if (rnd.nextBoolean()) checkExhausted(it);
checkRemoveThrowsISE(it);
}
} catch (Throwable t) { unexpected(t); }
// TODO: make this more general
try {
for (int i = 0; i < 10; i++)
q.add(i);
Iterator it = q.iterator();
q.poll();
q.poll();
q.poll();
q.remove(7);
List list = new ArrayList();
while (it.hasNext())
list.add(it.next());
equal(list, Arrays.asList(0, 3, 4, 5, 6, 8, 9));
check(! list.contains(null));
System.err.printf("%s: %s%n",
q.getClass().getSimpleName(),
list);
} catch (Throwable t) { unexpected(t); }
try {
q.clear();
q.add(1);
q.add(2);
q.add(3);
q.add(4);
Iterator it = q.iterator();
it.next();
q.remove(2);
q.remove(1);
q.remove(3);
boolean found4 = false;
while (it.hasNext()) {
found4 |= it.next().equals(4);
}
check(found4);
} catch (Throwable t) { unexpected(t); }
try {
q.clear();
Object x = new Object();
for (int i = 0; i < 20; i++)
q.add(x);
equal(20, q.size());
Iterator it1 = q.iterator();
Iterator it2 = q.iterator();
try { it1.remove(); fail(); }
catch (IllegalStateException success) {}
try { it2.remove(); fail(); }
catch (IllegalStateException success) {}
check(it1.next() == x);
check(it2.hasNext());
check(it2.next() == x);
it1.remove();
it2.remove();
equal(19, q.size());
try { it1.remove(); fail(); }
catch (IllegalStateException success) {}
try { it2.remove(); fail(); }
catch (IllegalStateException success) {}
equal(19, q.size());
it1.next();
check(it2.hasNext());
it2.next();
it2.remove();
it1.remove();
equal(18, q.size());
it1.next();
it2.next();
check(q.remove() == x);
equal(17, q.size());
it1.remove();
it2.remove();
equal(17, q.size());
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// Check "interior" removal of alternating elements
//----------------------------------------------------------------
try {
q.clear();
final int remainingCapacity = (q instanceof BlockingQueue) ?
((BlockingQueue)q).remainingCapacity() :
Integer.MAX_VALUE;
final int capacity = Math.min(20, remainingCapacity);
List<Iterator> its = new ArrayList<>();
// Move to "middle"
for (int i = 0; i < capacity/2; i++) {
check(q.add(i));
equal(q.poll(), i);
}
for (int i = 0; i < capacity; i++)
check(q.add(i));
for (int i = 0; i < capacity; i++) {
Iterator it = q.iterator();
its.add(it);
for (int j = 0; j < i; j++)
equal(j, it.next());
}
// Remove all even elements, in either direction using
// q.remove(), or iterator.remove()
switch (rnd.nextInt(3)) {
case 0:
for (int i = 0; i < capacity; i+=2)
check(q.remove(i));
break;
case 1:
for (int i = capacity - 2; i >= 0; i-=2)
check(q.remove(i));
break;
case 2:
Iterator it = q.iterator();
while (it.hasNext()) {
int i = (Integer) it.next();
if ((i & 1) == 0)
it.remove();
}
break;
default: throw new AssertionError();
}
for (int i = 0; i < capacity; i++) {
Iterator it = its.get(i);
boolean even = ((i & 1) == 0);
if (even) {
if (rnd.nextBoolean()) check(it.hasNext());
equal(i, it.next());
for (int j = i+1; j < capacity; j += 2)
equal(j, it.next());
check(!it.hasNext());
} else { /* odd */
if (rnd.nextBoolean()) check(it.hasNext());
checkRemoveHasNoEffect(it, q);
equal(i, it.next());
for (int j = i+2; j < capacity; j += 2)
equal(j, it.next());
check(!it.hasNext());
}
}
// q only contains odd elements
for (int i = 0; i < capacity; i++)
check(q.contains(i) ^ ((i & 1) == 0));
} catch (Throwable t) { unexpected(t); }
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
new IteratorWeakConsistency().instanceMain(args);}
public void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.err.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}

View file

@ -0,0 +1,103 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/**
* Misc utilities in JSR166 performance tests
*/
class LoopHelpers {
// Some mindless computation to do between synchronizations...
/**
* generates 32 bit pseudo-random numbers.
* Adapted from http://www.snippets.org
*/
public static int compute1(int x) {
int lo = 16807 * (x & 0xFFFF);
int hi = 16807 * (x >>> 16);
lo += (hi & 0x7FFF) << 16;
if ((lo & 0x80000000) != 0) {
lo &= 0x7fffffff;
++lo;
}
lo += hi >>> 15;
if (lo == 0 || (lo & 0x80000000) != 0) {
lo &= 0x7fffffff;
++lo;
}
return lo;
}
/**
* Computes a linear congruential random number a random number
* of times.
*/
public static int compute2(int x) {
int loops = (x >>> 4) & 7;
while (loops-- > 0) {
x = (x * 2147483647) % 16807;
}
return x;
}
public static class BarrierTimer implements Runnable {
public volatile long startTime;
public volatile long endTime;
public void run() {
long t = System.nanoTime();
if (startTime == 0)
startTime = t;
else
endTime = t;
}
public void clear() {
startTime = 0;
endTime = 0;
}
public long getTime() {
return endTime - startTime;
}
}
public static String rightJustify(long n) {
// There's probably a better way to do this...
String field = " ";
String num = Long.toString(n);
if (num.length() >= field.length())
return num;
StringBuilder b = new StringBuilder(field);
b.replace(b.length()-num.length(), b.length(), num);
return b.toString();
}
}

View file

@ -0,0 +1,190 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6316155 6595669 6871697 6868712
* @summary Test concurrent offer vs. remove
* @library /test/lib
* @run main OfferRemoveLoops 100
* @author Martin Buchholz
*/
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import java.util.Arrays;
import java.util.Queue;
import java.util.SplittableRandom;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.Semaphore;
import jdk.test.lib.Utils;
@SuppressWarnings({"unchecked", "rawtypes", "deprecation"})
public class OfferRemoveLoops {
static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
final long testDurationMillisDefault = 10_000L;
final long testDurationMillis;
OfferRemoveLoops(String[] args) {
testDurationMillis = (args.length > 0) ?
Long.valueOf(args[0]) : testDurationMillisDefault;
}
void checkNotContainsNull(Iterable it) {
for (Object x : it)
check(x != null);
}
void test(String[] args) throws Throwable {
testQueue(new LinkedBlockingQueue(10));
testQueue(new LinkedBlockingQueue());
testQueue(new LinkedBlockingDeque(10));
testQueue(new LinkedBlockingDeque());
testQueue(new ArrayBlockingQueue(10));
testQueue(new PriorityBlockingQueue(10));
testQueue(new ConcurrentLinkedDeque());
testQueue(new ConcurrentLinkedQueue());
testQueue(new LinkedTransferQueue());
}
void testQueue(final Queue q) throws Throwable {
System.err.println(q.getClass().getSimpleName());
final long testDurationNanos = testDurationMillis * 1000L * 1000L;
final long quittingTimeNanos = System.nanoTime() + testDurationNanos;
final int maxChunkSize = 1042;
final int maxQueueSize = 10 * maxChunkSize;
final CountDownLatch done = new CountDownLatch(3);
final SplittableRandom rnd = new SplittableRandom();
// Poor man's bounded buffer; prevents unbounded queue expansion.
final Semaphore offers = new Semaphore(maxQueueSize);
abstract class CheckedThread extends Thread {
final SplittableRandom rnd;
CheckedThread(String name, SplittableRandom rnd) {
super(name);
this.rnd = rnd;
setDaemon(true);
start();
}
/** Polls for quitting time. */
protected boolean quittingTime() {
return System.nanoTime() - quittingTimeNanos > 0;
}
/** Polls occasionally for quitting time. */
protected boolean quittingTime(long i) {
return (i % 1024) == 0 && quittingTime();
}
protected abstract void realRun() throws Exception;
public void run() {
try { realRun(); } catch (Throwable t) { unexpected(t); }
}
}
Thread offerer = new CheckedThread("offerer", rnd.split()) {
protected void realRun() throws InterruptedException {
final int chunkSize = rnd.nextInt(maxChunkSize) + 20;
long c = 0;
while (! quittingTime()) {
if (q.offer(Long.valueOf(c))) {
if ((++c % chunkSize) == 0) {
offers.acquire(chunkSize);
}
} else {
Thread.yield();
}
}
done.countDown();
}};
Thread remover = new CheckedThread("remover", rnd.split()) {
protected void realRun() {
final int chunkSize = rnd.nextInt(maxChunkSize) + 20;
long c = 0;
while (! quittingTime()) {
if (q.remove(Long.valueOf(c))) {
if ((++c % chunkSize) == 0) {
offers.release(chunkSize);
}
} else {
Thread.yield();
}
}
q.clear();
offers.release(1<<30); // Releases waiting offerer thread
done.countDown();
}};
Thread scanner = new CheckedThread("scanner", rnd.split()) {
protected void realRun() {
while (! quittingTime()) {
switch (rnd.nextInt(3)) {
case 0: checkNotContainsNull(q); break;
case 1: q.size(); break;
case 2: checkNotContainsNull
(Arrays.asList(q.toArray(new Long[0])));
break;
}
Thread.yield();
}
done.countDown();
}};
if (! done.await(LONG_DELAY_MS + testDurationMillis, MILLISECONDS)) {
for (Thread thread : new Thread[] { offerer, remover, scanner }) {
if (thread.isAlive()) {
System.err.printf("Hung thread: %s%n", thread.getName());
failed++;
for (StackTraceElement e : thread.getStackTrace())
System.err.println(e);
thread.interrupt();
}
}
}
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
new OfferRemoveLoops(args).instanceMain(args);}
public void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}

View file

@ -0,0 +1,228 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* @test
* @bug 6785442
* @summary Checks race between poll and remove(Object), while
* occasionally moonlighting as a microbenchmark.
* @run main RemovePollRace 1234
*/
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.atomic.AtomicLong;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Queue;
import java.util.Map;
public class RemovePollRace {
// Suitable for benchmarking. Overridden by args[0] for testing.
int count = 1024 * 1024;
final Map<String,String> results = new ConcurrentHashMap<>();
Collection<Queue<Boolean>> concurrentQueues() {
List<Queue<Boolean>> queues = new ArrayList<>();
queues.add(new ConcurrentLinkedDeque<Boolean>());
queues.add(new ConcurrentLinkedQueue<Boolean>());
queues.add(new ArrayBlockingQueue<Boolean>(count, false));
queues.add(new ArrayBlockingQueue<Boolean>(count, true));
queues.add(new LinkedBlockingQueue<Boolean>());
queues.add(new LinkedBlockingDeque<Boolean>());
queues.add(new LinkedTransferQueue<Boolean>());
// Following additional implementations are available from:
// http://gee.cs.oswego.edu/dl/concurrency-interest/index.html
// queues.add(new SynchronizedLinkedListQueue<Boolean>());
// Avoid "first fast, second slow" benchmark effect.
Collections.shuffle(queues);
return queues;
}
void prettyPrintResults() {
List<String> classNames = new ArrayList<>(results.keySet());
Collections.sort(classNames);
int maxClassNameLength = 0;
int maxNanosLength = 0;
for (String name : classNames) {
if (maxClassNameLength < name.length())
maxClassNameLength = name.length();
if (maxNanosLength < results.get(name).length())
maxNanosLength = results.get(name).length();
}
String format = String.format("%%%ds %%%ds nanos/item%%n",
maxClassNameLength, maxNanosLength);
for (String name : classNames)
System.out.printf(format, name, results.get(name));
}
void test(String[] args) throws Throwable {
if (args.length > 0)
count = Integer.valueOf(args[0]);
// Warmup
for (Queue<Boolean> queue : concurrentQueues())
test(queue);
results.clear();
for (Queue<Boolean> queue : concurrentQueues())
test(queue);
prettyPrintResults();
}
void await(CountDownLatch latch) {
try { latch.await(); }
catch (InterruptedException e) { unexpected(e); }
}
void test(final Queue<Boolean> q) throws Throwable {
long t0 = System.nanoTime();
final int SPINS = 5;
final AtomicLong removes = new AtomicLong(0);
final AtomicLong polls = new AtomicLong(0);
// We need at least 3 threads, but we don't want to use too
// many on massively multi-core systems.
final int cpus = Runtime.getRuntime().availableProcessors();
final int threadsToUse = Math.max(3, Math.min(cpus, 16));
final int adderCount = threadsToUse / 3;
final int removerCount = adderCount;
final int pollerCount = removerCount;
final int threadCount = adderCount + removerCount + pollerCount;
final CountDownLatch startingGate = new CountDownLatch(1);
final CountDownLatch addersDone = new CountDownLatch(adderCount);
final Runnable remover = new Runnable() {
public void run() {
await(startingGate);
int spins = 0;
for (;;) {
boolean quittingTime = (addersDone.getCount() == 0);
if (q.remove(Boolean.TRUE))
removes.getAndIncrement();
else if (quittingTime)
break;
else if (++spins > SPINS) {
Thread.yield();
spins = 0;
}}}};
final Runnable poller = new Runnable() {
public void run() {
await(startingGate);
int spins = 0;
for (;;) {
boolean quittingTime = (addersDone.getCount() == 0);
if (q.poll() == Boolean.TRUE)
polls.getAndIncrement();
else if (quittingTime)
break;
else if (++spins > SPINS) {
Thread.yield();
spins = 0;
}}}};
final Runnable adder = new Runnable() {
public void run() {
await(startingGate);
for (int i = 0; i < count; i++) {
for (;;) {
try { q.add(Boolean.TRUE); break; }
catch (IllegalStateException e) { Thread.yield(); }
}
}
addersDone.countDown();
}};
final List<Thread> adders = new ArrayList<>();
final List<Thread> removers = new ArrayList<>();
final List<Thread> pollers = new ArrayList<>();
for (int i = 0; i < adderCount; i++)
adders.add(checkedThread(adder));
for (int i = 0; i < removerCount; i++)
removers.add(checkedThread(remover));
for (int i = 0; i < pollerCount; i++)
pollers.add(checkedThread(poller));
final List<Thread> allThreads = new ArrayList<>();
allThreads.addAll(removers);
allThreads.addAll(pollers);
allThreads.addAll(adders);
for (Thread t : allThreads)
t.start();
startingGate.countDown();
for (Thread t : allThreads)
t.join();
String className = q.getClass().getSimpleName();
long elapsed = System.nanoTime() - t0;
int nanos = (int) ((double) elapsed / (adderCount * count));
results.put(className, String.valueOf(nanos));
if (removes.get() + polls.get() != adderCount * count) {
String msg = String.format
("class=%s removes=%s polls=%d count=%d",
className, removes.get(), polls.get(), count);
fail(msg);
}
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
new RemovePollRace().instanceMain(args);}
public void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
Thread checkedThread(final Runnable r) {
return new Thread() {public void run() {
try {r.run();} catch (Throwable t) {unexpected(t);}}};}
}

View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8011645
* @summary CopyOnWriteArrayList.COWSubList.subList does not validate range properly
*/
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class COWSubList {
public static void main(String[] args) {
List<String> list = new CopyOnWriteArrayList<>();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
list.add("E");
expectThrow(() -> list.subList(-1, 5));
expectThrow(() -> list.subList(0, 6));
expectThrow(() -> list.subList(4, 3));
expectThrow(() -> list.subList(0, 5).subList(-1, 5));
expectThrow(() -> list.subList(0, 5).subList(0, 6));
expectThrow(() -> list.subList(0, 5).subList(4, 3));
}
static void expectThrow(Runnable r) {
try {
r.run();
throw new RuntimeException("Failed: expected IOOBE to be thrown");
} catch (IndexOutOfBoundsException x) {
// ok, expected
}
}
}

View file

@ -0,0 +1,75 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6318638 6325166 6330307
* @summary CopyOnWriteArrayList.equals should be thread-safe
* @author Martin Buchholz
*/
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class EqualsRace {
private static void realMain(String[] args) throws Throwable {
final int iterations = 100000;
final List<Integer> list = new CopyOnWriteArrayList<>();
final Integer one = Integer.valueOf(1);
final List<Integer> oneElementList = Arrays.asList(one);
final Thread t = new CheckedThread() { public void realRun() {
for (int i = 0; i < iterations; i++) {
list.add(one);
list.remove(one);
}}};
t.start();
for (int i = 0; i < iterations; i++) {
list.equals(oneElementList);
list.equals(Collections.EMPTY_LIST);
}
t.join();
check(list.size() == 0);
}
//--------------------- Infrastructure ---------------------------
static volatile int passed = 0, failed = 0;
static void pass() {passed++;}
static void fail() {failed++; Thread.dumpStack();}
static void fail(String msg) {System.out.println(msg); fail();}
static void unexpected(Throwable t) {failed++; t.printStackTrace();}
static void check(boolean cond) {if (cond) pass(); else fail();}
static void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
try {realMain(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
private abstract static class CheckedThread extends Thread {
public abstract void realRun() throws Throwable;
public void run() {
try { realRun(); } catch (Throwable t) { unexpected(t); }}}
}

View file

@ -0,0 +1,134 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6330307 6355645
* @summary Check for race conditions in COWArray classes
* @author Martin Buchholz
*/
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
public class RacingCows {
private static void realMain(String[] args) throws Throwable {
final int iterations = 100000;
final Integer two = Integer.valueOf(2);
final Integer three = Integer.valueOf(3);
//------------ CopyOnWriteArraySet -------------------------------
final Set<Integer> s1 = new CopyOnWriteArraySet<>();
final Set<Integer> s2 = new CopyOnWriteArraySet<>();
s1.add(1);
final Thread t1 = new CheckedThread() { public void realRun() {
for (int i = 0; i < iterations; i++) {
s2.add(two);
s2.remove(two);
}}};
t1.start();
for (int i = 0; i < iterations; i++) {
check(! s1.equals(s2));
check(! s2.equals(s1));
}
t1.join();
//------------ CopyOnWriteArrayList ------------------------------
final List<Integer> l1 = new CopyOnWriteArrayList<>();
final List<Integer> l2 = new CopyOnWriteArrayList<>();
final List<Integer> l3 = new CopyOnWriteArrayList<>();
l1.add(1);
final Thread t2 = new CheckedThread() { public void realRun() {
for (int i = 0; i < iterations; i++) {
switch (i%2) {
case 0: l2.add(two); break;
case 1: l2.add(0, two); break;
}
switch (i%3) {
case 0: l2.remove(two); break;
case 1: l2.remove(0); break;
case 2: l2.clear(); break;
}}}};
t2.start();
final Thread t3 = new CheckedThread() { public void realRun() {
l3.add(three);
for (int i = 0; i < iterations; i++) {
switch (i%2) {
case 0: l3.add(two); break;
case 1: l3.add(0, two); break;
}
switch (i%2) {
case 0: l3.remove(two); break;
case 1: l3.remove(0); break;
}}}};
t3.start();
for (int i = 0; i < iterations; i++) {
check(! l1.equals(l2));
check(! l2.equals(l1));
// CopyOnWriteArrayList(mutatingCollection)
try { new CopyOnWriteArrayList<Integer>(l2); }
catch (Throwable t) { unexpected(t); }
// addAllAbsent(mutatingCollection)
try { new CopyOnWriteArrayList<Integer>().addAllAbsent(l3); }
catch (Throwable t) { unexpected(t); }
// addAll(mutatingCollection)
try { new CopyOnWriteArrayList<Integer>().addAll(l3); }
catch (Throwable t) { unexpected(t); }
// addAll(int, mutatingCollection)
try { new CopyOnWriteArrayList<Integer>().addAll(0,l3); }
catch (Throwable t) { unexpected(t); }
}
t2.join();
t3.join();
}
//--------------------- Infrastructure ---------------------------
static volatile int passed = 0, failed = 0;
static void pass() {passed++;}
static void fail() {failed++; Thread.dumpStack();}
static void fail(String msg) {System.out.println(msg); fail();}
static void unexpected(Throwable t) {failed++; t.printStackTrace();}
static void check(boolean cond) {if (cond) pass(); else fail();}
static void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
try {realMain(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
private abstract static class CheckedThread extends Thread {
public abstract void realRun() throws Throwable;
public void run() {
try { realRun(); } catch (Throwable t) { unexpected(t); }}}
}

View file

@ -0,0 +1,84 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8365058
* @summary Check basic correctness of de-serialization
* @run junit SerializationTest
*/
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class SerializationTest {
// Ensure basic serialization round trip correctness
@ParameterizedTest
@MethodSource
void roundTripTest(CopyOnWriteArraySet<?> expected) {
var bytes = ser(expected);
var actual = deSer(bytes);
assertEquals(CopyOnWriteArraySet.class, actual.getClass());
assertEquals(expected, actual);
}
private static Stream<CopyOnWriteArraySet<?>> roundTripTest() {
return Stream.of(
new CopyOnWriteArraySet<>(),
new CopyOnWriteArraySet<>(List.of(1, 2, 3)),
new CopyOnWriteArraySet<>(Set.of("Foo", "Bar", "Baz"))
);
}
private static byte[] ser(Object obj) {
return assertDoesNotThrow(() -> {
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(byteArrayOutputStream)) {
oos.writeObject(obj);
return byteArrayOutputStream.toByteArray();
}
}, "Unexpected error during serialization");
}
private static Object deSer(byte[] bytes) {
return assertDoesNotThrow(() -> {
try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(byteArrayInputStream)) {
return ois.readObject();
}
}, "Unexpected error during de-serialization");
}
}

View file

@ -0,0 +1,200 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6332435 8221168
* @summary Basic tests for CountDownLatch
* @library /test/lib
* @author Seetharam Avadhanam, Martin Buchholz
*/
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
import jdk.test.lib.Utils;
public class Basic {
static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
abstract static class Awaiter extends Thread {
volatile Throwable exception;
volatile boolean interrupted;
abstract void realRun() throws Exception;
public final void run() {
try { realRun(); }
catch (Throwable ex) { exception = ex; }
interrupted = Thread.interrupted();
};
}
static Awaiter awaiter(CountDownLatch latch,
CountDownLatch gate) {
return new Awaiter() {
public void realRun() throws InterruptedException {
gate.countDown();
latch.await();
}};
}
static Awaiter awaiter(CountDownLatch latch,
CountDownLatch gate,
long timeoutMillis) {
return new Awaiter() {
public void realRun() throws InterruptedException {
gate.countDown();
latch.await(timeoutMillis, TimeUnit.MILLISECONDS);
}};
}
static Supplier<Awaiter> randomAwaiterSupplier(
CountDownLatch latch, CountDownLatch gate) {
return () -> (ThreadLocalRandom.current().nextBoolean())
? awaiter(latch, gate)
: awaiter(latch, gate, LONG_DELAY_MS);
}
//----------------------------------------------------------------
// Normal use
//----------------------------------------------------------------
public static void normalUse() throws Throwable {
int count = 0;
CountDownLatch latch = new CountDownLatch(3);
Awaiter[] a = new Awaiter[12];
for (int i = 0; i < 3; i++) {
CountDownLatch gate = new CountDownLatch(4);
Supplier<Awaiter> s = randomAwaiterSupplier(latch, gate);
a[count] = s.get(); a[count++].start();
a[count] = s.get(); a[count++].start();
a[count] = s.get(); a[count++].start();
a[count] = s.get(); a[count++].start();
gate.await();
latch.countDown();
checkCount(latch, 2-i);
}
for (Awaiter awaiter : a)
awaiter.join();
for (Awaiter awaiter : a)
checkException(awaiter, null);
}
//----------------------------------------------------------------
// One thread interrupted
//----------------------------------------------------------------
public static void threadInterrupted() throws Throwable {
int count = 0;
CountDownLatch latch = new CountDownLatch(3);
Awaiter[] a = new Awaiter[12];
for (int i = 0; i < 3; i++) {
CountDownLatch gate = new CountDownLatch(4);
Supplier<Awaiter> s = randomAwaiterSupplier(latch, gate);
a[count] = s.get(); a[count++].start();
a[count] = s.get(); a[count++].start();
a[count] = s.get(); a[count++].start();
a[count] = s.get(); a[count++].start();
gate.await();
a[count-1].interrupt();
latch.countDown();
checkCount(latch, 2-i);
}
for (Awaiter awaiter : a)
awaiter.join();
for (int i = 0; i < a.length; i++) {
Awaiter awaiter = a[i];
Throwable ex = awaiter.exception;
if ((i % 4) == 3 && !awaiter.interrupted)
checkException(awaiter, InterruptedException.class);
else
checkException(awaiter, null);
}
}
//----------------------------------------------------------------
// One thread timed out
//----------------------------------------------------------------
public static void timeOut() throws Throwable {
int count = 0;
CountDownLatch latch = new CountDownLatch(3);
Awaiter[] a = new Awaiter[12];
long[] timeout = { 0L, 5L, 10L };
for (int i = 0; i < 3; i++) {
CountDownLatch gate = new CountDownLatch(4);
Supplier<Awaiter> s = randomAwaiterSupplier(latch, gate);
a[count] = awaiter(latch, gate, timeout[i]); a[count++].start();
a[count] = s.get(); a[count++].start();
a[count] = s.get(); a[count++].start();
a[count] = s.get(); a[count++].start();
gate.await();
latch.countDown();
checkCount(latch, 2-i);
}
for (Awaiter awaiter : a)
awaiter.join();
for (Awaiter awaiter : a)
checkException(awaiter, null);
}
public static void main(String[] args) throws Throwable {
try {
normalUse();
} catch (Throwable ex) { fail(ex); }
try {
threadInterrupted();
} catch (Throwable ex) { fail(ex); }
try {
timeOut();
} catch (Throwable ex) { fail(ex); }
if (failures.get() > 0L)
throw new AssertionError(failures.get() + " failures");
}
static final AtomicInteger failures = new AtomicInteger(0);
static void fail(String msg) {
fail(new AssertionError(msg));
}
static void fail(Throwable t) {
t.printStackTrace();
failures.getAndIncrement();
}
static void checkCount(CountDownLatch b, int expected) {
if (b.getCount() != expected)
fail("Count = " + b.getCount() +
", expected = " + expected);
}
static void checkException(Awaiter awaiter, Class<? extends Throwable> c) {
Throwable ex = awaiter.exception;
if (! ((ex == null && c == null) || c.isInstance(ex)))
fail("Expected: " + c + ", got: " + ex);
}
}

View file

@ -0,0 +1,444 @@
/*
* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6253848 6366811
* @summary Basic tests for CyclicBarrier
* @library /test/lib
* @author Martin Buchholz, David Holmes
*/
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import jdk.test.lib.Utils;
public class Basic {
static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
private static void checkBroken(final CyclicBarrier barrier) {
check(barrier.isBroken());
equal(barrier.getNumberWaiting(), 0);
THROWS(BrokenBarrierException.class,
() -> barrier.await(),
() -> barrier.await(100, MILLISECONDS));
}
private static void reset(CyclicBarrier barrier) {
barrier.reset();
check(! barrier.isBroken());
equal(barrier.getNumberWaiting(), 0);
}
private static void checkResult(Awaiter a, Class<? extends Throwable> c) {
Throwable t = a.result();
if (! ((t == null && c == null) || (c != null && c.isInstance(t)))) {
// t.printStackTrace();
fail("Mismatch in thread " +
a.getName() + ": " +
t + ", " +
(c == null ? "<null>" : c.getName()));
} else {
pass();
}
}
//----------------------------------------------------------------
// Mechanism to get all victim threads into "running" mode.
// The fact that this also uses CyclicBarrier is entirely coincidental.
//----------------------------------------------------------------
private static final CyclicBarrier atTheStartingGate = new CyclicBarrier(3);
private static void toTheStartingGate() {
try { atTheStartingGate.await(LONG_DELAY_MS, MILLISECONDS); pass(); }
catch (Throwable t) {
unexpected(t);
reset(atTheStartingGate);
throw new Error(t);
}
}
//----------------------------------------------------------------
// Convenience methods for creating threads that call CyclicBarrier.await
//----------------------------------------------------------------
private abstract static class Awaiter extends Thread {
static AtomicInteger count = new AtomicInteger(1);
{
this.setName("Awaiter:"+count.getAndIncrement());
this.setDaemon(true);
}
private volatile Throwable result = null;
protected void result(Throwable result) { this.result = result; }
public Throwable result() { return this.result; }
}
private static Awaiter awaiter(final CyclicBarrier barrier) {
return new Awaiter() { public void run() {
toTheStartingGate();
try { barrier.await(); }
catch (Throwable result) { result(result); }}};
}
private static Awaiter awaiter(final CyclicBarrier barrier,
final long millis) {
return new Awaiter() { public void run() {
toTheStartingGate();
try { barrier.await(millis, MILLISECONDS); }
catch (Throwable result) { result(result); }}};
}
// Returns an infinite lazy list of all possible awaiter pair combinations.
private static Iterator<Awaiter> awaiterIterator(final CyclicBarrier barrier) {
return new Iterator<Awaiter>() {
int i = 0;
public boolean hasNext() { return true; }
public Awaiter next() {
switch ((i++)&7) {
case 0: case 2: case 4: case 5:
return awaiter(barrier);
default:
return awaiter(barrier, 10 * 1000); }}
public void remove() {throw new UnsupportedOperationException();}};
}
private static void realMain(String[] args) throws Throwable {
Thread.currentThread().setName("mainThread");
//----------------------------------------------------------------
// Normal use
//----------------------------------------------------------------
try {
CyclicBarrier barrier = new CyclicBarrier(3);
equal(barrier.getParties(), 3);
Iterator<Awaiter> awaiters = awaiterIterator(barrier);
for (boolean doReset : new boolean[] {false, true})
for (int i = 0; i < 4; i++) {
Awaiter a1 = awaiters.next(); a1.start();
Awaiter a2 = awaiters.next(); a2.start();
toTheStartingGate();
barrier.await();
a1.join();
a2.join();
checkResult(a1, null);
checkResult(a2, null);
check(! barrier.isBroken());
equal(barrier.getParties(), 3);
equal(barrier.getNumberWaiting(), 0);
if (doReset) reset(barrier);
}
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// One thread interrupted
//----------------------------------------------------------------
try {
CyclicBarrier barrier = new CyclicBarrier(3);
Iterator<Awaiter> awaiters = awaiterIterator(barrier);
for (int i = 0; i < 4; i++) {
Awaiter a1 = awaiters.next(); a1.start();
Awaiter a2 = awaiters.next(); a2.start();
toTheStartingGate();
a1.interrupt();
a1.join();
a2.join();
checkResult(a1, InterruptedException.class);
checkResult(a2, BrokenBarrierException.class);
checkBroken(barrier);
reset(barrier);
}
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// Barrier is reset while threads are waiting
//----------------------------------------------------------------
try {
CyclicBarrier barrier = new CyclicBarrier(3);
Iterator<Awaiter> awaiters = awaiterIterator(barrier);
for (int i = 0; i < 4; i++) {
Awaiter a1 = awaiters.next(); a1.start();
Awaiter a2 = awaiters.next(); a2.start();
toTheStartingGate();
while (barrier.getNumberWaiting() < 2) Thread.yield();
barrier.reset();
a1.join();
a2.join();
checkResult(a1, BrokenBarrierException.class);
checkResult(a2, BrokenBarrierException.class);
check(! barrier.isBroken());
equal(barrier.getParties(), 3);
equal(barrier.getNumberWaiting(), 0);
}
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// One thread timed out
//----------------------------------------------------------------
try {
CyclicBarrier barrier = new CyclicBarrier(3);
Iterator<Awaiter> awaiters = awaiterIterator(barrier);
for (long timeout : new long[] { 0L, 10L }) {
for (int i = 0; i < 2; i++) {
Awaiter a1 = awaiter(barrier, timeout); a1.start();
Awaiter a2 = awaiters.next(); a2.start();
toTheStartingGate();
a1.join();
a2.join();
checkResult(a1, TimeoutException.class);
checkResult(a2, BrokenBarrierException.class);
checkBroken(barrier);
equal(barrier.getParties(), 3);
reset(barrier);
}
}
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// Barrier action completed normally
//----------------------------------------------------------------
try {
final AtomicInteger count = new AtomicInteger(0);
final CyclicBarrier[] kludge = new CyclicBarrier[1];
Runnable action = new Runnable() { public void run() {
count.incrementAndGet();
equal(kludge[0].getNumberWaiting(),
kludge[0].getParties());
System.out.println("OK!"); }};
CyclicBarrier barrier = new CyclicBarrier(3, action);
kludge[0] = barrier;
equal(barrier.getParties(), 3);
Iterator<Awaiter> awaiters = awaiterIterator(barrier);
for (int i = 0; i < 4; i++) {
Awaiter a1 = awaiters.next(); a1.start();
Awaiter a2 = awaiters.next(); a2.start();
toTheStartingGate();
while (barrier.getNumberWaiting() < 2) Thread.yield();
try { barrier.await(); }
catch (Throwable t) { unexpected(t); }
a1.join();
a2.join();
checkResult(a1, null);
checkResult(a2, null);
check(! barrier.isBroken());
equal(barrier.getNumberWaiting(), 0);
reset(barrier);
equal(count.get(), i+1);
}
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// Barrier action threw exception
//----------------------------------------------------------------
try {
Runnable action = new Runnable() {
public void run() { throw new Error(); }};
CyclicBarrier barrier = new CyclicBarrier(3, action);
Iterator<Awaiter> awaiters = awaiterIterator(barrier);
for (int i = 0; i < 4; i++) {
Awaiter a1 = awaiters.next(); a1.start();
Awaiter a2 = awaiters.next(); a2.start();
toTheStartingGate();
while (barrier.getNumberWaiting() < 2) Thread.yield();
try {
barrier.await();
fail("Expected Error not thrown"); }
catch (Error e) { pass(); }
catch (Throwable t) { unexpected(t); }
a1.join();
a2.join();
checkResult(a1, BrokenBarrierException.class);
checkResult(a2, BrokenBarrierException.class);
checkBroken(barrier);
reset(barrier);
}
} catch (Throwable t) { unexpected(t); }
testInterrupts();
}
/**
* Handling of extra interrupts while waiting - tests for bug 6366811
*/
private static void testInterrupts() {
final int N = ThreadLocalRandom.current().nextInt(2, 10);
final CyclicBarrier startingGate = new CyclicBarrier(N+1);
/**
* A version of Awaiter that also records interrupted state.
*/
class Waiter extends CheckedThread {
private final boolean timed;
private final CyclicBarrier barrier;
private final CountDownLatch doneSignal;
volatile Throwable throwable;
volatile boolean interruptStatusSetAfterAwait;
public Waiter(CountDownLatch doneSignal, CyclicBarrier barrier) {
this.timed = ThreadLocalRandom.current().nextBoolean();
this.doneSignal = doneSignal;
this.barrier = barrier;
}
void realRun() throws Throwable {
startingGate.await(LONG_DELAY_MS, MILLISECONDS);
try {
if (timed) barrier.await(LONG_DELAY_MS, MILLISECONDS);
else barrier.await();
} catch (Throwable throwable) {
this.throwable = throwable;
}
try {
check(doneSignal.await(LONG_DELAY_MS, MILLISECONDS));
if (Thread.interrupted())
interruptStatusSetAfterAwait = true;
} catch (InterruptedException e) {
interruptStatusSetAfterAwait = true;
}
}
}
//----------------------------------------------------------------
// Interrupt occurs during barrier trip
//----------------------------------------------------------------
try {
final CountDownLatch doneSignal = new CountDownLatch(1);
final List<Waiter> waiters = new ArrayList<>(N);
// work around finality of closed-over variables
final Runnable[] realAction = new Runnable[1];
final Runnable delegateAction =
new Runnable() {public void run() {realAction[0].run();}};
final CyclicBarrier barrier = new CyclicBarrier(N+1, delegateAction);
realAction[0] = new Runnable() { public void run() {
try {
for (int i = 0; i < N/2; i++)
waiters.get(i).interrupt();
// we need to try and ensure that the waiters get
// to process their interruption before we do the
// signalAll that trips the barrier. Using sleep
// seems to work reliably while yield does not.
Thread.sleep(100);
} catch (Throwable t) { unexpected(t); }
}};
for (int i = 0; i < N; i++) {
Waiter waiter = new Waiter(doneSignal, barrier);
waiter.start();
waiters.add(waiter);
}
startingGate.await(LONG_DELAY_MS, MILLISECONDS);
while (barrier.getNumberWaiting() < N) Thread.yield();
barrier.await();
doneSignal.countDown();
int countInterruptStatusSetAfterAwait = 0;
for (Waiter waiter : waiters) {
waiter.join();
equal(waiter.throwable, null);
if (waiter.interruptStatusSetAfterAwait)
countInterruptStatusSetAfterAwait++;
}
equal(countInterruptStatusSetAfterAwait, N/2);
check(! barrier.isBroken());
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// Multiple interrupts occur during barrier await
//----------------------------------------------------------------
try {
final CountDownLatch doneSignal = new CountDownLatch(1);
final CyclicBarrier barrier = new CyclicBarrier(N+1);
final List<Waiter> waiters = new ArrayList<>(N);
for (int i = 0; i < N; i++) {
Waiter waiter = new Waiter(doneSignal, barrier);
waiter.start();
waiters.add(waiter);
}
startingGate.await(LONG_DELAY_MS, MILLISECONDS);
while (barrier.getNumberWaiting() < N) Thread.yield();
for (int i = 0; i < N/2; i++) {
Thread waiter = waiters.get(i);
waiter.interrupt();
}
doneSignal.countDown();
int countInterruptedException = 0;
int countBrokenBarrierException = 0;
int countInterruptStatusSetAfterAwait = 0;
for (Waiter waiter : waiters) {
waiter.join();
if (waiter.throwable instanceof InterruptedException)
countInterruptedException++;
if (waiter.throwable instanceof BrokenBarrierException)
countBrokenBarrierException++;
if (waiter.interruptStatusSetAfterAwait)
countInterruptStatusSetAfterAwait++;
}
equal(countInterruptedException, 1);
equal(countBrokenBarrierException, N-1);
checkBroken(barrier);
equal(countInterruptStatusSetAfterAwait, N/2-1);
reset(barrier);
} catch (Throwable t) { unexpected(t); }
}
//--------------------- Infrastructure ---------------------------
static volatile int passed = 0, failed = 0;
static void pass() {passed++;}
static void fail() {failed++; Thread.dumpStack();}
static void fail(String msg) {System.out.println(msg); fail();}
static void unexpected(Throwable t) {failed++; t.printStackTrace();}
static void check(boolean cond) {if (cond) pass(); else fail();}
static void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
try {realMain(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
interface Fun {void f() throws Throwable;}
private static void THROWS(Class<? extends Throwable> k, Fun... fs) {
for (Fun f : fs)
try { f.f(); fail("Expected " + k.getName() + " not thrown"); }
catch (Throwable t) {
if (k.isAssignableFrom(t.getClass())) pass();
else unexpected(t);}}
private abstract static class CheckedThread extends Thread {
abstract void realRun() throws Throwable;
public void run() {
try {realRun();} catch (Throwable t) {unexpected(t);}}}
}

View file

@ -0,0 +1,78 @@
/*
* Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6355327
* @summary DelayQueue iterators should support concurrent modification
* @author Martin Buchholz
*/
import java.util.Arrays;
import java.util.Iterator;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
public class Iterate {
private static class Godot implements Delayed {
public long getDelay(TimeUnit unit) {return Long.MAX_VALUE;}
public int compareTo(Delayed other) {return 0;}
}
private static void realMain(String[] args) throws Throwable {
Godot[] godots = new Godot[] { new Godot(), new Godot(), new Godot() };
DelayQueue<Godot> q = new DelayQueue<>(Arrays.asList(godots));
Iterator<Godot> it = q.iterator();
q.clear();
check(it.hasNext());
equal(it.next(), godots[0]);
it.remove();
check(q.isEmpty());
q.addAll(Arrays.asList(godots));
it = q.iterator();
check(it.hasNext());
it.next();
equal(it.next(), godots[1]);
it.remove();
equal(q.size(), 2);
check(q.contains(godots[0]));
check(q.contains(godots[2]));
}
//--------------------- Infrastructure ---------------------------
static volatile int passed = 0, failed = 0;
static void pass() {passed++;}
static void fail() {failed++; Thread.dumpStack();}
static void fail(String msg) {System.out.println(msg); fail();}
static void unexpected(Throwable t) {failed++; t.printStackTrace();}
static void check(boolean cond) {if (cond) pass(); else fail();}
static void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
try {realMain(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}

View file

@ -0,0 +1,67 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6327342
* @summary Try to poll a DelayQueue with only unexpired elements
* @author Martin Buchholz
*/
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
public class PollUnexpired {
private static class Godot implements Delayed {
public long getDelay(TimeUnit unit) {return Long.MAX_VALUE;}
public int compareTo(Delayed other) {return 0;}
}
private static void realMain(String[] args) throws Throwable {
DelayQueue<Godot> q = new DelayQueue<>();
for (int i = 0; i < 3; i++) {
equal(q.size(), i);
equal(q.poll(), null);
equal(q.size(), i);
equal(q.poll(100, TimeUnit.MILLISECONDS), null);
equal(q.size(), i);
q.add(new Godot());
}
}
//--------------------- Infrastructure ---------------------------
static volatile int passed = 0, failed = 0;
static void pass() {passed++;}
static void fail() {failed++; Thread.dumpStack();}
static void fail(String msg) {System.out.println(msg); fail();}
static void unexpected(Throwable t) {failed++; t.printStackTrace();}
static void check(boolean cond) {if (cond) pass(); else fail();}
static void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
try {realMain(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}

View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
/**
* This is not a regression test, but a stress benchmark test for
* 6609775: Reduce context switches in DelayQueue due to signalAll
*
* This runs in the same wall clock time, but much reduced cpu time,
* with the changes for 6609775.
*/
public class Stress {
public static void main(String[] args) throws Throwable {
final DelayQueue<Delayed> q = new DelayQueue<>();
final long t0 = System.nanoTime();
for (long i = 0; i < 1000; i++) {
final long expiry = t0 + i*10L*1000L*1000L;
q.add(new Delayed() {
public long getDelay(TimeUnit unit) {
return unit.convert(expiry - System.nanoTime(),
NANOSECONDS);
}
public int compareTo(Delayed x) {
long d = getDelay(NANOSECONDS)
- x.getDelay(NANOSECONDS);
return d < 0 ? -1 : d > 0 ? 1 : 0; }});
}
for (int i = 0; i < 300; i++)
new Thread() { public void run() {
try {
while (!q.isEmpty())
q.poll(10L, TimeUnit.SECONDS);
} catch (Throwable t) { t.printStackTrace(); }
}}.start();
}
}

View file

@ -0,0 +1,140 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8370887
* @summary Test that cancelling a delayed task doesn't impact the ordering that other
* delayed tasks execute
*/
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedTransferQueue;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
public class AscendingOrderAfterReplace {
private static final int[] DELAYS_IN_MS = { 3000, 3400, 3900, 3800, 3700, 3600, 3430, 3420, 3310, 3500, 3200 };
public static void main(String[] args) throws Exception {
for (int i = 1; i < DELAYS_IN_MS.length; i++) {
System.out.println("=== Test " + i + " ===");
while (!testCancel(DELAYS_IN_MS, i)) { }
}
}
/**
* Schedule the delayed tasks, cancel one of them, and check that the remaining tasks
* execute in the ascending order of delay.
* @return true if the test passed, false if a retry is needed
* @throws RuntimeException if the test fails
*/
private static boolean testCancel(int[] delays, int indexToCancel) throws Exception {
log("Delayed tasks: " + toString(delays));
// delayed tasks add to this queue when they execute
var queue = new LinkedTransferQueue<Integer>();
// pool with one thread to ensure that delayed tasks don't execute concurrently
try (var pool = new ForkJoinPool(1)) {
long startNanos = System.nanoTime();
Future<?>[] futures = Arrays.stream(delays)
.mapToObj(d -> pool.schedule(() -> {
log("Triggered " + d);
queue.add(d);
}, d, MILLISECONDS))
.toArray(Future[]::new);
long endNanos = System.nanoTime();
log("Delayed tasks submitted");
// check submit took < min diffs between two delays
long submitTime = Duration.ofNanos(endNanos - startNanos).toMillis();
long minDiff = minDifference(delays);
if (submitTime >= minDiff) {
log("Submit took >= " + minDiff + " ms, need to retry");
pool.shutdownNow();
return false;
}
// give a bit of time for -delayScheduler thread to process pending tasks
Thread.sleep(minValue(delays) / 2);
log("Cancel " + delays[indexToCancel]);
futures[indexToCancel].cancel(true);
}
// delayed tasks should have executed in ascending order of their delay
int[] executed = queue.stream().mapToInt(Integer::intValue).toArray();
log("Executed: " + toString(executed));
if (!isAscendingOrder(executed)) {
throw new RuntimeException("Not in ascending order!");
}
return true;
}
/**
* Return the minimum element.
*/
private static int minValue(int[] array) {
return IntStream.of(array).min().orElseThrow();
}
/**
* Return the minimum difference between any two elements.
*/
private static int minDifference(int[] array) {
int[] sorted = array.clone();
Arrays.sort(sorted);
return IntStream.range(1, sorted.length)
.map(i -> sorted[i] - sorted[i - 1])
.min()
.orElse(0);
}
/**
* Return true if the array is in ascending order.
*/
private static boolean isAscendingOrder(int[] array) {
return IntStream.range(1, array.length)
.allMatch(i -> array[i - 1] <= array[i]);
}
/**
* Returns a String containing the elements of an array in index order.
*/
private static String toString(int[] array) {
return IntStream.of(array)
.mapToObj(Integer::toString)
.collect(Collectors.joining(", ", "[", "]"));
}
private static void log(String message) {
System.out.println(Instant.now() + " " + message);
}
}

View file

@ -0,0 +1,143 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* @test
* @bug 4486658
* @summary checks to make sure a pipeline of exchangers passes data.
* @library /test/lib
*/
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import jdk.test.lib.Utils;
public class ExchangeLoops {
static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
static final ExecutorService pool = Executors.newCachedThreadPool();
static boolean print = false;
static class Int {
public int value;
Int(int i) { value = i; }
}
public static void main(String[] args) throws Exception {
int maxStages = 5;
int iters = 2000;
if (args.length > 0)
maxStages = Integer.parseInt(args[0]);
print = false;
System.out.println("Warmup...");
oneRun(2, iters);
print = true;
for (int i = 2; i <= maxStages; i += (i+1) >>> 1) {
System.out.print("Threads: " + i + "\t: ");
oneRun(i, iters);
}
pool.shutdown();
if (! pool.awaitTermination(LONG_DELAY_MS, MILLISECONDS))
throw new Error();
}
static class Stage implements Runnable {
final int iters;
final Exchanger<Int> left;
final Exchanger<Int> right;
final CyclicBarrier barrier;
volatile int result;
Stage(Exchanger<Int> left,
Exchanger<Int> right,
CyclicBarrier b, int iters) {
this.left = left;
this.right = right;
barrier = b;
this.iters = iters;
}
public void run() {
try {
barrier.await();
Int item = new Int(hashCode());
for (int i = 0; i < iters; ++i) {
if (left != null) {
item.value = LoopHelpers.compute1(item.value);
Int other = left.exchange(item);
if (other == item || other == null)
throw new Error("Failed Exchange");
item = other;
}
if (right != null) {
item.value = LoopHelpers.compute2(item.value);
Int other = right.exchange(item);
if (other == item || other == null)
throw new Error("Failed Exchange");
item = other;
}
}
barrier.await();
}
catch (Exception ex) {
ex.printStackTrace();
return;
}
}
}
static void oneRun(int nthreads, int iters) throws Exception {
LoopHelpers.BarrierTimer timer = new LoopHelpers.BarrierTimer();
CyclicBarrier barrier = new CyclicBarrier(nthreads + 1, timer);
Exchanger<Int> l = null;
Exchanger<Int> r = new Exchanger<>();
for (int i = 0; i < nthreads; ++i) {
pool.execute(new Stage(l, r, barrier, iters));
l = r;
r = (i+2 < nthreads) ? new Exchanger<Int>() : null;
}
barrier.await();
barrier.await();
long time = timer.getTime();
if (print)
System.out.println(LoopHelpers.rightJustify(time / (iters * nthreads + iters * (nthreads-2))) + " ns per transfer");
}
}

View file

@ -0,0 +1,103 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/**
* Misc utilities in JSR166 performance tests
*/
class LoopHelpers {
// Some mindless computation to do between synchronizations...
/**
* generates 32 bit pseudo-random numbers.
* Adapted from http://www.snippets.org
*/
public static int compute1(int x) {
int lo = 16807 * (x & 0xFFFF);
int hi = 16807 * (x >>> 16);
lo += (hi & 0x7FFF) << 16;
if ((lo & 0x80000000) != 0) {
lo &= 0x7fffffff;
++lo;
}
lo += hi >>> 15;
if (lo == 0 || (lo & 0x80000000) != 0) {
lo &= 0x7fffffff;
++lo;
}
return lo;
}
/**
* Computes a linear congruential random number a random number
* of times.
*/
public static int compute2(int x) {
int loops = (x >>> 4) & 7;
while (loops-- > 0) {
x = (x * 2147483647) % 16807;
}
return x;
}
public static class BarrierTimer implements Runnable {
public volatile long startTime;
public volatile long endTime;
public void run() {
long t = System.nanoTime();
if (startTime == 0)
startTime = t;
else
endTime = t;
}
public void clear() {
startTime = 0;
endTime = 0;
}
public long getTime() {
return endTime - startTime;
}
}
public static String rightJustify(long n) {
// There's probably a better way to do this...
String field = " ";
String num = Long.toString(n);
if (num.length() >= field.length())
return num;
StringBuilder b = new StringBuilder(field);
b.replace(b.length()-num.length(), b.length(), num);
return b.toString();
}
}

View file

@ -0,0 +1,121 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* @test
* @bug 4965960
* @summary Exercise ExecutorCompletionService
* @library /test/lib
*/
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import jdk.test.lib.Utils;
public class ExecutorCompletionServiceLoops {
static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
static final int POOLSIZE = 10;
static final ExecutorService pool =
Executors.newFixedThreadPool(POOLSIZE);
static final ExecutorCompletionService<Integer> ecs =
new ExecutorCompletionService<>(pool);
static boolean print = false;
public static void main(String[] args) throws Exception {
int max = 8;
int base = 2000;
if (args.length > 0)
max = Integer.parseInt(args[0]);
System.out.println("Warmup...");
oneTest(base);
print = true;
for (int i = 1; i <= max; i += (i+1) >>> 1) {
System.out.print("n: " + i * base);
oneTest(i * base);
}
pool.shutdown();
if (! pool.awaitTermination(LONG_DELAY_MS, MILLISECONDS))
throw new Error();
}
static class Task implements Callable<Integer> {
public Integer call() {
int s = 0;
int l = System.identityHashCode(this);
for (int i = 0; i < 5; ++i) {
l = LoopHelpers.compute2(l);
s += LoopHelpers.compute1(l);
}
return new Integer(s);
}
}
static class Producer implements Runnable {
final ExecutorCompletionService cs;
final int iters;
Producer(ExecutorCompletionService ecs, int i) {
cs = ecs;
iters = i;
}
public void run() {
for (int i = 0; i < iters; ++i)
ecs.submit(new Task());
}
}
static void oneTest(int iters) throws Exception {
long startTime = System.nanoTime();
new Thread(new Producer(ecs, iters)).start();
int r = 0;
for (int i = 0; i < iters; ++i)
r += ecs.take().get().intValue();
long elapsed = System.nanoTime() - startTime;
long tpi = elapsed/ iters;
if (print)
System.out.println("\t: " + LoopHelpers.rightJustify(tpi) + " ns per task");
if (r == 0) // avoid overoptimization
System.out.println("useless result: " + r);
}
}

View file

@ -0,0 +1,103 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/**
* Misc utilities in JSR166 performance tests
*/
class LoopHelpers {
// Some mindless computation to do between synchronizations...
/**
* generates 32 bit pseudo-random numbers.
* Adapted from http://www.snippets.org
*/
public static int compute1(int x) {
int lo = 16807 * (x & 0xFFFF);
int hi = 16807 * (x >>> 16);
lo += (hi & 0x7FFF) << 16;
if ((lo & 0x80000000) != 0) {
lo &= 0x7fffffff;
++lo;
}
lo += hi >>> 15;
if (lo == 0 || (lo & 0x80000000) != 0) {
lo &= 0x7fffffff;
++lo;
}
return lo;
}
/**
* Computes a linear congruential random number a random number
* of times.
*/
public static int compute2(int x) {
int loops = (x >>> 4) & 7;
while (loops-- > 0) {
x = (x * 2147483647) % 16807;
}
return x;
}
public static class BarrierTimer implements Runnable {
public volatile long startTime;
public volatile long endTime;
public void run() {
long t = System.nanoTime();
if (startTime == 0)
startTime = t;
else
endTime = t;
}
public void clear() {
startTime = 0;
endTime = 0;
}
public long getTime() {
return endTime - startTime;
}
}
public static String rightJustify(long n) {
// There's probably a better way to do this...
String field = " ";
String num = Long.toString(n);
if (num.length() >= field.length())
return num;
StringBuilder b = new StringBuilder(field);
b.replace(b.length()-num.length(), b.length(), num);
return b.toString();
}
}

View file

@ -0,0 +1,269 @@
/*
* Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary Test implementations of ExecutorService.close
* @library ../lib
* @run junit CloseTest
*/
import java.time.Duration;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.Phaser;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import static org.junit.jupiter.api.Assertions.*;
class CloseTest {
static Stream<ExecutorService> executors() {
return Stream.of(
// ensures that default close method is tested
new DelegatingExecutorService(Executors.newCachedThreadPool()),
// implementations that may override close
Executors.newCachedThreadPool(),
Executors.newVirtualThreadPerTaskExecutor(),
new ForkJoinPool()
);
}
/**
* Test close with no tasks running.
*/
@ParameterizedTest
@MethodSource("executors")
void testCloseWithNoTasks(ExecutorService executor) throws Exception {
executor.close();
assertTrue(executor.isShutdown());
assertTrue(executor.isTerminated());
assertTrue(executor.awaitTermination(10, TimeUnit.MILLISECONDS));
}
/**
* Test close with tasks running.
*/
@ParameterizedTest
@MethodSource("executors")
void testCloseWithRunningTasks(ExecutorService executor) throws Exception {
Phaser phaser = new Phaser(2);
Future<?> future = executor.submit(() -> {
phaser.arriveAndAwaitAdvance();
Thread.sleep(Duration.ofMillis(100));
return "foo";
});
phaser.arriveAndAwaitAdvance(); // wait for task to start
executor.close(); // waits for task to complete
assertFalse(Thread.interrupted());
assertTrue(executor.isShutdown());
assertTrue(executor.isTerminated());
assertTrue(executor.awaitTermination(10, TimeUnit.MILLISECONDS));
assertEquals("foo", future.resultNow());
}
/**
* Test shutdown with tasks running.
*/
@ParameterizedTest
@MethodSource("executors")
void testShutdownWithRunningTasks(ExecutorService executor) throws Exception {
Phaser phaser = new Phaser(2);
Future<?> future = executor.submit(() -> {
phaser.arriveAndAwaitAdvance();
Thread.sleep(Duration.ofMillis(100));
return "foo";
});
phaser.arriveAndAwaitAdvance(); // wait for task to start
executor.shutdown();
assertFalse(Thread.interrupted());
assertTrue(executor.isShutdown());
assertTrue(executor.awaitTermination(1, TimeUnit.MINUTES));
assertTrue(executor.isTerminated());
assertEquals("foo", future.resultNow());
}
/**
* Test close with multiple tasks running
*/
@ParameterizedTest
@MethodSource("executors")
void testCloseWith2RunningTasks(ExecutorService executor) throws Exception {
Phaser phaser = new Phaser(3);
Future<?> f1 = executor.submit(() -> {
phaser.arriveAndAwaitAdvance();
Thread.sleep(Duration.ofMillis(100));
return "foo";
});
Future<?> f2 = executor.submit(() -> {
phaser.arriveAndAwaitAdvance();
Thread.sleep(Duration.ofMillis(100));
return "bar";
});
phaser.arriveAndAwaitAdvance(); // wait for tasks to start
executor.close(); // waits for task to complete
assertFalse(Thread.interrupted());
assertTrue(executor.isShutdown());
assertTrue(executor.isTerminated());
assertTrue(executor.awaitTermination(10, TimeUnit.MILLISECONDS));
assertEquals("foo", f1.resultNow());
assertEquals("bar", f2.resultNow());
}
/**
* Test shutdown with multiple tasks running
*/
@ParameterizedTest
@MethodSource("executors")
void testShutdownWith2RunningTasks(ExecutorService executor) throws Exception {
Phaser phaser = new Phaser(3);
Future<?> f1 = executor.submit(() -> {
phaser.arriveAndAwaitAdvance();
Thread.sleep(Duration.ofMillis(100));
return "foo";
});
Future<?> f2 = executor.submit(() -> {
phaser.arriveAndAwaitAdvance();
Thread.sleep(Duration.ofMillis(100));
return "bar";
});
phaser.arriveAndAwaitAdvance(); // wait for tasks to start
executor.shutdown();
assertFalse(Thread.interrupted());
assertTrue(executor.isShutdown());
assertTrue(executor.awaitTermination(1, TimeUnit.MINUTES));
assertTrue(executor.isTerminated());
assertEquals("foo", f1.resultNow());
assertEquals("bar", f2.resultNow());
}
/**
* Test close when executor is shutdown but not terminated.
*/
@ParameterizedTest
@MethodSource("executors")
void testShutdownBeforeClose(ExecutorService executor) throws Exception {
Phaser phaser = new Phaser(2);
Future<?> future = executor.submit(() -> {
phaser.arriveAndAwaitAdvance();
Thread.sleep(Duration.ofMillis(100));
return "foo";
});
phaser.arriveAndAwaitAdvance(); // wait for task to start
executor.shutdown(); // shutdown, will not immediately terminate
executor.close();
assertTrue(executor.isShutdown());
assertTrue(executor.isTerminated());
assertTrue(executor.awaitTermination(10, TimeUnit.MILLISECONDS));
Object s = future.resultNow();
assertEquals("foo", s);
}
/**
* Test close when terminated.
*/
@ParameterizedTest
@MethodSource("executors")
void testTerminateBeforeClose(ExecutorService executor) throws Exception {
executor.shutdown();
assertTrue(executor.isTerminated());
executor.close();
assertTrue(executor.isShutdown());
assertTrue(executor.isTerminated());
assertTrue(executor.awaitTermination(10, TimeUnit.MILLISECONDS));
}
/**
* Test invoking close with interrupted status set.
*/
@ParameterizedTest
@MethodSource("executors")
void testInterruptBeforeClose(ExecutorService executor) throws Exception {
Phaser phaser = new Phaser(2);
Future<?> future = executor.submit(() -> {
phaser.arriveAndAwaitAdvance();
Thread.sleep(Duration.ofDays(1));
return null;
});
phaser.arriveAndAwaitAdvance(); // wait for task to start
Thread.currentThread().interrupt();
try {
executor.close();
assertTrue(Thread.currentThread().isInterrupted());
} finally {
Thread.interrupted(); // clear interrupted status
}
assertTrue(executor.isShutdown());
assertTrue(executor.isTerminated());
assertTrue(executor.awaitTermination(10, TimeUnit.MILLISECONDS));
assertThrows(ExecutionException.class, future::get);
}
/**
* Test interrupting thread blocked in close.
*/
@ParameterizedTest
@MethodSource("executors")
void testInterruptDuringClose(ExecutorService executor) throws Exception {
Phaser phaser = new Phaser(2);
Future<?> future = executor.submit(() -> {
phaser.arriveAndAwaitAdvance();
Thread.sleep(Duration.ofDays(1));
return null;
});
phaser.arriveAndAwaitAdvance(); // wait for task to start
// schedule main thread to be interrupted
Thread thread = Thread.currentThread();
new Thread(() -> {
try {
Thread.sleep( Duration.ofMillis(100));
} catch (Exception ignore) { }
thread.interrupt();
}).start();
try {
executor.close();
assertTrue(Thread.currentThread().isInterrupted());
} finally {
Thread.interrupted(); // clear interrupted status
}
assertTrue(executor.isShutdown());
assertTrue(executor.isTerminated());
assertTrue(executor.awaitTermination(10, TimeUnit.MILLISECONDS));
assertThrows(ExecutionException.class, future::get);
}
}

View file

@ -0,0 +1,235 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6267833
* @summary Tests for invokeAny, invokeAll
* @author Martin Buchholz
*/
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicLong;
public class Invoke {
static volatile int passed = 0, failed = 0;
static void fail(String msg) {
failed++;
new AssertionError(msg).printStackTrace();
}
static void pass() {
passed++;
}
static void unexpected(Throwable t) {
failed++;
t.printStackTrace();
}
static void check(boolean condition, String msg) {
if (condition) pass(); else fail(msg);
}
static void check(boolean condition) {
check(condition, "Assertion failure");
}
static long secondsElapsedSince(long startTime) {
return NANOSECONDS.toSeconds(System.nanoTime() - startTime);
}
static void awaitInterrupt(long timeoutSeconds) {
long startTime = System.nanoTime();
try {
Thread.sleep(SECONDS.toMillis(timeoutSeconds));
fail("timed out waiting for interrupt");
} catch (InterruptedException expected) {
check(secondsElapsedSince(startTime) < timeoutSeconds);
}
}
public static void main(String[] args) {
try {
for (int nThreads = 1; nThreads <= 6; ++nThreads) {
// untimed
testInvokeAll(nThreads, false);
testInvokeAny(nThreads, false);
testInvokeAny_cancellationInterrupt(nThreads, false);
// timed
testInvokeAll(nThreads, true);
testInvokeAny(nThreads, true);
testInvokeAny_cancellationInterrupt(nThreads, true);
}
} catch (Throwable t) { unexpected(t); }
if (failed > 0)
throw new Error(
String.format("Passed = %d, failed = %d", passed, failed));
}
static final long timeoutSeconds = 10L;
static void testInvokeAll(int nThreads, boolean timed) throws Throwable {
final ThreadLocalRandom rnd = ThreadLocalRandom.current();
final ExecutorService pool = Executors.newFixedThreadPool(nThreads);
final AtomicLong count = new AtomicLong(0);
class Task implements Callable<Long> {
public Long call() throws Exception {
return count.incrementAndGet();
}
}
try {
final List<Task> tasks =
IntStream.range(0, nThreads)
.mapToObj(i -> new Task())
.collect(Collectors.toList());
List<Future<Long>> futures;
if (timed) {
long startTime = System.nanoTime();
futures = pool.invokeAll(tasks, timeoutSeconds, SECONDS);
check(secondsElapsedSince(startTime) < timeoutSeconds);
}
else
futures = pool.invokeAll(tasks);
check(futures.size() == tasks.size());
check(count.get() == tasks.size());
long gauss = 0;
for (Future<Long> future : futures) gauss += future.get();
check(gauss == (tasks.size()+1)*tasks.size()/2);
pool.shutdown();
check(pool.awaitTermination(10L, SECONDS));
} finally {
pool.shutdownNow();
}
}
static void testInvokeAny(int nThreads, boolean timed) throws Throwable {
final ThreadLocalRandom rnd = ThreadLocalRandom.current();
final ExecutorService pool = Executors.newFixedThreadPool(nThreads);
final AtomicLong count = new AtomicLong(0);
final CountDownLatch invokeAnyDone = new CountDownLatch(1);
class Task implements Callable<Long> {
public Long call() throws Exception {
long x = count.incrementAndGet();
if (x > 1) {
// wait for main thread to interrupt us ...
awaitInterrupt(timeoutSeconds);
// ... and then for invokeAny to return
check(invokeAnyDone.await(timeoutSeconds, SECONDS));
}
return x;
}
}
try {
final List<Task> tasks =
IntStream.range(0, rnd.nextInt(1, 7))
.mapToObj(i -> new Task())
.collect(Collectors.toList());
long val;
if (timed) {
long startTime = System.nanoTime();
val = pool.invokeAny(tasks, timeoutSeconds, SECONDS);
check(secondsElapsedSince(startTime) < timeoutSeconds);
}
else
val = pool.invokeAny(tasks);
check(val == 1);
invokeAnyDone.countDown();
pool.shutdown();
check(pool.awaitTermination(timeoutSeconds, SECONDS));
long c = count.get();
check(c >= 1 && c <= tasks.size());
} finally {
pool.shutdownNow();
}
}
/**
* Every remaining running task is sent an interrupt for cancellation.
*/
static void testInvokeAny_cancellationInterrupt(int nThreads, boolean timed) throws Throwable {
final ThreadLocalRandom rnd = ThreadLocalRandom.current();
final ExecutorService pool = Executors.newFixedThreadPool(nThreads);
final AtomicLong count = new AtomicLong(0);
final AtomicLong interruptedCount = new AtomicLong(0);
final CyclicBarrier allStarted = new CyclicBarrier(nThreads);
class Task implements Callable<Long> {
public Long call() throws Exception {
long x = count.incrementAndGet();
allStarted.await();
if (x > 1)
// main thread will interrupt us
awaitInterrupt(timeoutSeconds);
return x;
}
}
try {
final List<Task> tasks =
IntStream.range(0, nThreads)
.mapToObj(i -> new Task())
.collect(Collectors.toList());
long val;
if (timed) {
long startTime = System.nanoTime();
val = pool.invokeAny(tasks, timeoutSeconds, SECONDS);
check(secondsElapsedSince(startTime) < timeoutSeconds);
}
else
val = pool.invokeAny(tasks);
check(val == 1);
pool.shutdown();
check(pool.awaitTermination(timeoutSeconds, SECONDS));
// Check after shutdown to avoid race
check(count.get() == nThreads);
} finally {
pool.shutdownNow();
}
}
}

View file

@ -0,0 +1,787 @@
/*
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @summary Test implementations of ExecutorService.invokeAll/invokeAny
* @run junit InvokeTest
*/
import java.time.Duration;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Stream;
import static java.lang.Thread.State.*;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import static org.junit.jupiter.api.Assertions.*;
class InvokeTest {
private static ScheduledExecutorService scheduler;
@BeforeAll
static void setup() throws Exception {
scheduler = Executors.newSingleThreadScheduledExecutor();
}
@AfterAll
static void shutdown() {
scheduler.shutdown();
}
private static Stream<ExecutorService> executors() {
return Stream.of(
Executors.newCachedThreadPool(),
Executors.newVirtualThreadPerTaskExecutor(),
new ForkJoinPool()
);
}
/**
* Test invokeAny where all tasks complete normally.
*/
@ParameterizedTest
@MethodSource("executors")
void testInvokeAny1(ExecutorService executor) throws Exception {
try (executor) {
Callable<String> task1 = () -> "foo";
Callable<String> task2 = () -> "bar";
String result = executor.invokeAny(List.of(task1, task2));
assertTrue(Set.of("foo", "bar").contains(result));
}
}
/**
* Test invokeAny where all tasks complete normally. The completion of the
* first task should cancel remaining tasks.
*/
@ParameterizedTest
@MethodSource("executors")
void testInvokeAny2(ExecutorService executor) throws Exception {
try (executor) {
Callable<String> task1 = () -> "foo";
var task2Started = new AtomicBoolean();
var task2Interrupted = new CountDownLatch(1);
Callable<String> task2 = () -> {
task2Started.set(true);
try {
Thread.sleep(Duration.ofDays(1));
} catch (InterruptedException e) {
task2Interrupted.countDown();
}
return null;
};
String result = executor.invokeAny(List.of(task1, task2));
assertEquals("foo", result);
// if task2 started then it should have been interrupted
if (task2Started.get()) {
task2Interrupted.await();
}
}
}
/**
* Test invokeAny where all tasks complete with exception.
*/
@ParameterizedTest
@MethodSource("executors")
void testInvokeAny3(ExecutorService executor) throws Exception {
try (executor) {
class FooException extends Exception { }
Callable<String> task1 = () -> { throw new FooException(); };
Callable<String> task2 = () -> { throw new FooException(); };
try {
executor.invokeAny(List.of(task1, task2));
fail("invokeAny did not throw");
} catch (ExecutionException e) {
Throwable cause = e.getCause();
assertTrue(cause instanceof FooException);
}
}
}
/**
* Test invokeAny where all tasks complete with exception. The completion
* of the last task is delayed.
*/
@ParameterizedTest
@MethodSource("executors")
void testInvokeAny4(ExecutorService executor) throws Exception {
try (executor) {
class FooException extends Exception { }
Callable<String> task1 = () -> { throw new FooException(); };
Callable<String> task2 = () -> {
Thread.sleep(Duration.ofMillis(50));
throw new FooException();
};
try {
executor.invokeAny(List.of(task1, task2));
fail("invokeAny did not throw");
} catch (ExecutionException e) {
Throwable cause = e.getCause();
assertTrue(cause instanceof FooException);
}
}
}
/**
* Test invokeAny where some, not all, tasks complete normally.
*/
@ParameterizedTest
@MethodSource("executors")
void testInvokeAny5(ExecutorService executor) throws Exception {
try (executor) {
class FooException extends Exception { }
Callable<String> task1 = () -> "foo";
Callable<String> task2 = () -> { throw new FooException(); };
String result = executor.invokeAny(List.of(task1, task2));
assertEquals("foo", result);
}
}
/**
* Test invokeAny where some, not all, tasks complete normally. The first
* task to complete normally is delayed.
*/
@ParameterizedTest
@MethodSource("executors")
void testInvokeAny6(ExecutorService executor) throws Exception {
try (executor) {
class FooException extends Exception { }
Callable<String> task1 = () -> {
Thread.sleep(Duration.ofMillis(50));
return "foo";
};
Callable<String> task2 = () -> { throw new FooException(); };
String result = executor.invokeAny(List.of(task1, task2));
assertEquals("foo", result);
}
}
/**
* Test timed-invokeAny where all tasks complete normally before the timeout.
*/
@ParameterizedTest
@MethodSource("executors")
void testInvokeAnyWithTimeout1(ExecutorService executor) throws Exception {
try (executor) {
Callable<String> task1 = () -> "foo";
Callable<String> task2 = () -> "bar";
String result = executor.invokeAny(List.of(task1, task2), 1, TimeUnit.MINUTES);
assertTrue(Set.of("foo", "bar").contains(result));
}
}
/**
* Test timed-invokeAny where one task completes normally before the timeout.
* The remaining tests should be cancelled.
*/
@ParameterizedTest
@MethodSource("executors")
void testInvokeAnyWithTimeout2(ExecutorService executor) throws Exception {
try (executor) {
Callable<String> task1 = () -> "foo";
var task2Started = new AtomicBoolean();
var task2Interrupted = new CountDownLatch(1);
Callable<String> task2 = () -> {
task2Started.set(true);
try {
Thread.sleep(Duration.ofDays(1));
} catch (InterruptedException e) {
task2Interrupted.countDown();
}
return null;
};
String result = executor.invokeAny(List.of(task1, task2), 1, TimeUnit.MINUTES);
assertEquals("foo", result);
// if task2 started then it should have been interrupted
if (task2Started.get()) {
task2Interrupted.await();
}
}
}
/**
* Test timed-invokeAny where timeout expires before any task completes.
*/
@ParameterizedTest
@MethodSource("executors")
void testInvokeAnyWithTimeout3(ExecutorService executor) throws Exception {
try (executor) {
var task1Started = new AtomicBoolean();
var task1Interrupted = new CountDownLatch(1);
Callable<String> task1 = () -> {
task1Started.set(true);
try {
Thread.sleep(Duration.ofDays(1));
} catch (InterruptedException e) {
task1Interrupted.countDown();
}
return null;
};
var task2Started = new AtomicBoolean();
var task2Interrupted = new CountDownLatch(1);
Callable<String> task2 = () -> {
task2Started.set(true);
try {
Thread.sleep(Duration.ofDays(1));
} catch (InterruptedException e) {
task2Interrupted.countDown();
}
return null;
};
// invokeAny should throw TimeoutException
assertThrows(TimeoutException.class,
() -> executor.invokeAny(List.of(task1, task2), 100, TimeUnit.MILLISECONDS));
// tasks that started should be interrupted
if (task1Started.get()) {
task1Interrupted.await();
}
if (task2Started.get()) {
task2Interrupted.await();
}
}
}
/**
* Test invokeAny with interrupted status set.
*/
@ParameterizedTest
@MethodSource("executors")
void testInvokeAnyWithInterruptSet(ExecutorService executor) throws Exception {
try (executor) {
Callable<String> task1 = () -> {
Thread.sleep(Duration.ofMinutes(1));
return "foo";
};
Callable<String> task2 = () -> {
Thread.sleep(Duration.ofMinutes(1));
return "bar";
};
Thread.currentThread().interrupt();
try {
executor.invokeAny(List.of(task1, task2));
fail("invokeAny did not throw");
} catch (InterruptedException expected) {
assertFalse(Thread.currentThread().isInterrupted());
} finally {
Thread.interrupted(); // clear interrupt
}
}
}
/**
* Test interrupting a thread blocked in invokeAny.
*/
@ParameterizedTest
@MethodSource("executors")
void testInterruptInvokeAny(ExecutorService executor) throws Exception {
try (executor) {
var task1Started = new AtomicBoolean();
var task1Interrupted = new CountDownLatch(1);
Callable<String> task1 = () -> {
task1Started.set(true);
try {
Thread.sleep(Duration.ofDays(1));
} catch (InterruptedException e) {
task1Interrupted.countDown();
}
return null;
};
var task2Started = new AtomicBoolean();
var task2Interrupted = new CountDownLatch(1);
Callable<String> task2 = () -> {
task2Started.set(true);
try {
Thread.sleep(Duration.ofDays(1));
} catch (InterruptedException e) {
task2Interrupted.countDown();
}
return null;
};
scheduleInterruptAt("invokeAny");
try {
executor.invokeAny(List.of(task1, task2));
fail("invokeAny did not throw");
} catch (InterruptedException expected) {
assertFalse(Thread.currentThread().isInterrupted());
} finally {
Thread.interrupted(); // clear interrupt
}
// tasks that started should be interrupted
if (task1Started.get()) {
task1Interrupted.await();
}
if (task2Started.get()) {
task2Interrupted.await();
}
}
}
/**
* Test invokeAny after ExecutorService has been shutdown.
*/
@ParameterizedTest
@MethodSource("executors")
void testInvokeAnyAfterShutdown(ExecutorService executor) throws Exception {
executor.shutdown();
Callable<String> task1 = () -> "foo";
Callable<String> task2 = () -> "bar";
assertThrows(RejectedExecutionException.class,
() -> executor.invokeAny(List.of(task1, task2)));
}
/**
* Test invokeAny with empty collection.
*/
@ParameterizedTest
@MethodSource("executors")
void testInvokeAnyEmpty1(ExecutorService executor) throws Exception {
try (executor) {
assertThrows(IllegalArgumentException.class, () -> executor.invokeAny(List.of()));
}
}
/**
* Test timed-invokeAny with empty collection.
*/
@ParameterizedTest
@MethodSource("executors")
void testInvokeAnyEmpty2(ExecutorService executor) throws Exception {
try (executor) {
assertThrows(IllegalArgumentException.class,
() -> executor.invokeAny(List.of(), 1, TimeUnit.MINUTES));
}
}
/**
* Test invokeAny with null.
*/
@ParameterizedTest
@MethodSource("executors")
void testInvokeAnyNull1(ExecutorService executor)throws Exception {
try (executor) {
assertThrows(NullPointerException.class, () -> executor.invokeAny(null));
}
}
/**
* Test invokeAny with null element
*/
@ParameterizedTest
@MethodSource("executors")
void testInvokeAnyNull2(ExecutorService executor)throws Exception {
try (executor) {
List<Callable<String>> list = new ArrayList<>();
list.add(() -> "foo");
list.add(null);
assertThrows(NullPointerException.class, () -> executor.invokeAny(null));
}
}
/**
* Test invokeAll where all tasks complete normally.
*/
@ParameterizedTest
@MethodSource("executors")
void testInvokeAll1(ExecutorService executor) throws Exception {
try (executor) {
Callable<String> task1 = () -> "foo";
Callable<String> task2 = () -> {
Thread.sleep(Duration.ofMillis(50));
return "bar";
};
List<Future<String>> futures = executor.invokeAll(List.of(task1, task2));
assertTrue(futures.size() == 2);
// check results
List<String> results = futures.stream().map(Future::resultNow).toList();
assertEquals(results, List.of("foo", "bar"));
}
}
/**
* Test invokeAll where all tasks complete with exception.
*/
@ParameterizedTest
@MethodSource("executors")
void testInvokeAll2(ExecutorService executor) throws Exception {
try (executor) {
class FooException extends Exception { }
class BarException extends Exception { }
Callable<String> task1 = () -> { throw new FooException(); };
Callable<String> task2 = () -> {
Thread.sleep(Duration.ofMillis(50));
throw new BarException();
};
List<Future<String>> futures = executor.invokeAll(List.of(task1, task2));
assertTrue(futures.size() == 2);
// check results
Throwable e1 = assertThrows(ExecutionException.class, () -> futures.get(0).get());
assertTrue(e1.getCause() instanceof FooException);
Throwable e2 = assertThrows(ExecutionException.class, () -> futures.get(1).get());
assertTrue(e2.getCause() instanceof BarException);
}
}
/**
* Test invokeAll where all tasks complete normally before the timeout expires.
*/
@ParameterizedTest
@MethodSource("executors")
void testInvokeAll3(ExecutorService executor) throws Exception {
try (executor) {
Callable<String> task1 = () -> "foo";
Callable<String> task2 = () -> {
Thread.sleep(Duration.ofMillis(50));
return "bar";
};
List<Future<String>> futures = executor.invokeAll(List.of(task1, task2), 1, TimeUnit.MINUTES);
assertTrue(futures.size() == 2);
// check results
List<String> results = futures.stream().map(Future::resultNow).toList();
assertEquals(results, List.of("foo", "bar"));
}
}
/**
* Test invokeAll where some tasks do not complete before the timeout expires.
*/
@ParameterizedTest
@MethodSource("executors")
void testInvokeAll4(ExecutorService executor) throws Exception {
try (executor) {
Callable<String> task1 = () -> "foo";
var task2Started = new AtomicBoolean();
var task2Interrupted = new CountDownLatch(1);
Callable<String> task2 = () -> {
task2Started.set(true);
try {
Thread.sleep(Duration.ofDays(1));
} catch (InterruptedException e) {
task2Interrupted.countDown();
}
return null;
};
List<Future<String>> futures = executor.invokeAll(List.of(task1, task2), 1, TimeUnit.SECONDS);
assertTrue(futures.size() == 2);
// task1 should be done
assertTrue(futures.get(0).isDone());
// task2 should be cancelled and interrupted
assertTrue(futures.get(1).isCancelled());
// if task2 started then it should have been interrupted
if (task2Started.get()) {
task2Interrupted.await();
}
}
}
/**
* Test invokeAll with interrupted status set.
*/
@ParameterizedTest
@MethodSource("executors")
void testInvokeAllInterrupt1(ExecutorService executor) throws Exception {
try (executor) {
Callable<String> task1 = () -> "foo";
Callable<String> task2 = () -> {
Thread.sleep(Duration.ofMinutes(1));
return "bar";
};
Thread.currentThread().interrupt();
try {
executor.invokeAll(List.of(task1, task2));
fail("invokeAll did not throw");
} catch (InterruptedException expected) {
assertFalse(Thread.currentThread().isInterrupted());
} finally {
Thread.interrupted(); // clear interrupt
}
}
}
/**
* Test timed-invokeAll with interrupted status set.
*/
@ParameterizedTest
@MethodSource("executors")
void testInvokeAllInterrupt3(ExecutorService executor) throws Exception {
try (executor) {
Callable<String> task1 = () -> "foo";
Callable<String> task2 = () -> {
Thread.sleep(Duration.ofMinutes(1));
return "bar";
};
Thread.currentThread().interrupt();
try {
executor.invokeAll(List.of(task1, task2), 1, TimeUnit.MINUTES);
fail("invokeAll did not throw");
} catch (InterruptedException expected) {
assertFalse(Thread.currentThread().isInterrupted());
} finally {
Thread.interrupted(); // clear interrupt
}
}
}
/**
* Test interrupt with thread blocked in invokeAll.
*/
@ParameterizedTest
@MethodSource("executors")
void testInvokeAllInterrupt4(ExecutorService executor) throws Exception {
try (executor) {
Callable<String> task1 = () -> "foo";
var task2Started = new AtomicBoolean();
var task2Interrupted = new CountDownLatch(1);
Callable<String> task2 = () -> {
task2Started.set(true);
try {
Thread.sleep(Duration.ofDays(1));
} catch (InterruptedException e) {
task2Interrupted.countDown();
}
return null;
};
scheduleInterruptAt("invokeAll");
try {
executor.invokeAll(List.of(task1, task2));
fail("invokeAll did not throw");
} catch (InterruptedException expected) {
assertFalse(Thread.currentThread().isInterrupted());
} finally {
Thread.interrupted(); // clear interrupt
}
// if task2 started then it should have been interrupted
if (task2Started.get()) {
task2Interrupted.await();
}
}
}
/**
* Test interrupt with thread blocked in timed-invokeAll.
*/
@ParameterizedTest
@MethodSource("executors")
void testInvokeAllInterrupt6(ExecutorService executor) throws Exception {
try (executor) {
Callable<String> task1 = () -> "foo";
var task2Started = new AtomicBoolean();
var task2Interrupted = new CountDownLatch(1);
Callable<String> task2 = () -> {
task2Started.set(true);
try {
Thread.sleep(Duration.ofDays(1));
} catch (InterruptedException e) {
task2Interrupted.countDown();
}
return null;
};
scheduleInterruptAt("invokeAll");
try {
executor.invokeAll(List.of(task1, task2), 1, TimeUnit.MINUTES);
fail("invokeAll did not throw");
} catch (InterruptedException expected) {
assertFalse(Thread.currentThread().isInterrupted());
} finally {
Thread.interrupted(); // clear interrupt
}
// if task2 started then it should have been interrupted
if (task2Started.get()) {
task2Interrupted.await();
}
}
}
/**
* Test invokeAll after ExecutorService has been shutdown.
*/
@ParameterizedTest
@MethodSource("executors")
void testInvokeAllAfterShutdown1(ExecutorService executor) throws Exception {
executor.shutdown();
Callable<String> task1 = () -> "foo";
Callable<String> task2 = () -> "bar";
assertThrows(RejectedExecutionException.class,
() -> executor.invokeAll(List.of(task1, task2)));
}
@ParameterizedTest
@MethodSource("executors")
void testInvokeAllAfterShutdown2(ExecutorService executor) throws Exception {
executor.shutdown();
Callable<String> task1 = () -> "foo";
Callable<String> task2 = () -> "bar";
assertThrows(RejectedExecutionException.class,
() -> executor.invokeAll(List.of(task1, task2), 1, TimeUnit.SECONDS));
}
/**
* Test invokeAll with empty collection.
*/
@ParameterizedTest
@MethodSource("executors")
void testInvokeAllEmpty1(ExecutorService executor) throws Exception {
try (executor) {
List<Future<Object>> list = executor.invokeAll(List.of());
assertTrue(list.size() == 0);
}
}
@ParameterizedTest
@MethodSource("executors")
void testInvokeAllEmpty2(ExecutorService executor) throws Exception {
try (executor) {
List<Future<Object>> list = executor.invokeAll(List.of(), 1, TimeUnit.SECONDS);
assertTrue(list.size() == 0);
}
}
@ParameterizedTest
@MethodSource("executors")
void testInvokeAllNull1(ExecutorService executor)throws Exception {
try (executor) {
assertThrows(NullPointerException.class, () -> executor.invokeAll(null));
}
}
@ParameterizedTest
@MethodSource("executors")
void testInvokeAllNull2(ExecutorService executor)throws Exception {
try (executor) {
List<Callable<String>> tasks = new ArrayList<>();
tasks.add(() -> "foo");
tasks.add(null);
assertThrows(NullPointerException.class, () -> executor.invokeAll(tasks));
}
}
@ParameterizedTest
@MethodSource("executors")
void testInvokeAllNull3(ExecutorService executor)throws Exception {
try (executor) {
assertThrows(NullPointerException.class,
() -> executor.invokeAll(null, 1, TimeUnit.SECONDS));
}
}
@ParameterizedTest
@MethodSource("executors")
void testInvokeAllNull4(ExecutorService executor)throws Exception {
try (executor) {
Callable<String> task = () -> "foo";
assertThrows(NullPointerException.class,
() -> executor.invokeAll(List.of(task), 1, null));
}
}
@ParameterizedTest
@MethodSource("executors")
void testInvokeAllNull5(ExecutorService executor)throws Exception {
try (executor) {
List<Callable<String>> tasks = new ArrayList<>();
tasks.add(() -> "foo");
tasks.add(null);
assertThrows(NullPointerException.class,
() -> executor.invokeAll(tasks, 1, TimeUnit.SECONDS));
}
}
/**
* Schedules the current thread to be interrupted when it waits (timed or untimed)
* at the given method name.
*/
private void scheduleInterruptAt(String methodName) {
Thread target = Thread.currentThread();
scheduler.submit(() -> {
try {
boolean found = false;
while (!found) {
Thread.State state = target.getState();
assertTrue(state != TERMINATED);
if ((state == WAITING || state == TIMED_WAITING)
&& contains(target.getStackTrace(), methodName)) {
found = true;
} else {
Thread.sleep(20);
}
}
target.interrupt();
} catch (Exception e) {
e.printStackTrace();
}
});
}
/**
* Returns true if the given stack trace contains an element for the given method name.
*/
private boolean contains(StackTraceElement[] stack, String methodName) {
return Arrays.stream(stack)
.anyMatch(e -> methodName.equals(e.getMethodName()));
}
}

View file

@ -0,0 +1,370 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @summary Test implementations of ExecutorService.submit/execute
* @run junit SubmitTest
*/
import java.time.Duration;
import java.util.concurrent.*;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import static org.junit.jupiter.api.Assertions.*;
class SubmitTest {
private static Stream<ExecutorService> executors() {
return Stream.of(
Executors.newCachedThreadPool(),
Executors.newVirtualThreadPerTaskExecutor(),
new ForkJoinPool()
);
}
/**
* Test submit(Runnable) executes the task.
*/
@ParameterizedTest
@MethodSource("executors")
void testSubmitRunnable(ExecutorService executor) throws Exception {
try (executor) {
var latch = new CountDownLatch(1);
Future<?> future = executor.submit(latch::countDown);
latch.await();
assertNull(future.get());
}
}
/**
* Test submit(Runnable) throws if executor is shutdown.
*/
@ParameterizedTest
@MethodSource("executors")
void testSubmitRunnableAfterShutdown(ExecutorService executor) {
executor.shutdown();
assertThrows(RejectedExecutionException.class, () -> executor.submit(() -> { }));
}
/**
* Test task submitted with submit(Runnable) is not interrupted by cancel(false).
*/
@ParameterizedTest
@MethodSource("executors")
void testSubmitRunnableWithCancelFalse(ExecutorService executor) throws Exception {
try (executor) {
var started = new CountDownLatch(1);
var stop = new CountDownLatch(1);
var done = new CountDownLatch(1);
Future<?> future = executor.submit(() -> {
started.countDown();
try {
stop.await();
} catch (InterruptedException e) {
// ignore
} finally {
done.countDown();
}
});
// wait for task to start
started.await();
// cancel(false), task should not be interrupted
future.cancel(false);
assertFalse(done.await(500, TimeUnit.MILLISECONDS));
// let task finish
stop.countDown();
}
}
/**
* Test task submitted with submit(Runnable) is interrupted by cancel(true).
*/
@ParameterizedTest
@MethodSource("executors")
void testSubmitRunnableWithCancelTrue(ExecutorService executor) throws Exception {
try (executor) {
var started = new CountDownLatch(1);
var interrupted = new CountDownLatch(1);
Future<?> future = executor.submit(() -> {
started.countDown();
try {
Thread.sleep(Duration.ofDays(1));
} catch (InterruptedException e) {
interrupted.countDown();
}
});
// wait for task to start
started.await();
// cancel(true), task should be interrupted
future.cancel(true);
interrupted.await();
}
}
/**
* Test task submitted with submit(Runnable) is interrupted if executor is
* stopped with shutdownNow.
*/
@ParameterizedTest
@MethodSource("executors")
void testSubmitRunnableWithShutdownNow(ExecutorService executor) throws Exception {
try (executor) {
var started = new CountDownLatch(1);
var interrupted = new CountDownLatch(1);
Future<?> future = executor.submit(() -> {
started.countDown();
try {
Thread.sleep(Duration.ofDays(1));
} catch (InterruptedException e) {
interrupted.countDown();
}
});
// wait for task to start
started.await();
// shutdown forcefully, task should be interrupted
executor.shutdownNow();
interrupted.await();
}
}
/**
* Test submit(Runnable) throws if task is null.
*/
@ParameterizedTest
@MethodSource("executors")
void testSubmitRunnableNull(ExecutorService executor) {
try (executor) {
Runnable nullTask = null;
assertThrows(NullPointerException.class, () -> executor.submit(nullTask));
assertThrows(NullPointerException.class, () -> executor.submit(nullTask, Void.class));
}
}
//
/**
* Test submit(Callable) executes the task.
*/
@ParameterizedTest
@MethodSource("executors")
void testSubmitCallable(ExecutorService executor) throws Exception {
try (executor) {
var latch = new CountDownLatch(1);
Future<String> future = executor.submit(() -> {
latch.countDown();
return "foo";
});
latch.await();
assertEquals("foo", future.get());
}
}
/**
* Test submit(Callable) throws if executor is shutdown.
*/
@ParameterizedTest
@MethodSource("executors")
void testSubmitCallableAfterShutdown(ExecutorService executor) {
executor.shutdown();
assertThrows(RejectedExecutionException.class, () -> executor.submit(() -> null));
}
/**
* Test task submitted with submit(Callable) is not interrupted by cancel(false).
*/
@ParameterizedTest
@MethodSource("executors")
void testSubmitCallableWithCancelFalse(ExecutorService executor) throws Exception {
try (executor) {
var started = new CountDownLatch(1);
var stop = new CountDownLatch(1);
var done = new CountDownLatch(1);
Future<Void> future = executor.submit(() -> {
started.countDown();
try {
stop.await();
} finally {
done.countDown();
}
return null;
});
// wait for task to start
started.await();
// cancel(false), task should not be interrupted
future.cancel(false);
assertFalse(done.await(500, TimeUnit.MILLISECONDS));
// let task finish
stop.countDown();
}
}
/**
* Test task submitted with submit(Callable) is interrupted by cancel(true).
*/
@ParameterizedTest
@MethodSource("executors")
void testSubmitCallableWithCancelTrue(ExecutorService executor) throws Exception {
try (executor) {
var started = new CountDownLatch(1);
var interrupted = new CountDownLatch(1);
Future<Void> future = executor.submit(() -> {
started.countDown();
try {
Thread.sleep(Duration.ofDays(1));
} catch (InterruptedException e) {
interrupted.countDown();
}
return null;
});
// wait for task to start
started.await();
// cancel(true), task should be interrupted
future.cancel(true);
interrupted.await();
}
}
/**
* Test task submitted with submit(Callable) is interrupted if executor is
* stopped with shutdownNow.
*/
@ParameterizedTest
@MethodSource("executors")
void testSubmitCallableWithShutdownNow(ExecutorService executor) throws Exception {
try (executor) {
var started = new CountDownLatch(1);
var interrupted = new CountDownLatch(1);
Future<Void> future = executor.submit(() -> {
started.countDown();
try {
Thread.sleep(Duration.ofDays(1));
} catch (InterruptedException e) {
interrupted.countDown();
}
return null;
});
// wait for task to start
started.await();
// shutdown forcefully, task should be interrupted
executor.shutdownNow();
interrupted.await();
}
}
/**
* Test submit(Callable) throws if task is null.
*/
@ParameterizedTest
@MethodSource("executors")
void testSubmitCallableNull(ExecutorService executor) {
try (executor) {
Callable<Void> nullTask = null;
assertThrows(NullPointerException.class, () -> executor.submit(nullTask));
}
}
//
/**
* Test execute(Runnable) executes the task.
*/
@ParameterizedTest
@MethodSource("executors")
void testExecute(ExecutorService executor) throws Exception {
try (executor) {
var latch = new CountDownLatch(1);
executor.execute(latch::countDown);
latch.await();
}
}
/**
* Test execute(Runnable) throws if executor is shutdown.
*/
@ParameterizedTest
@MethodSource("executors")
void testExecuteAfterShutdown(ExecutorService executor) {
executor.shutdown();
assertThrows(RejectedExecutionException.class, () -> executor.execute(() -> { }));
}
/**
* Test task submitted with execute(Runnable) is interrupted if executor is
* stopped with shutdownNow.
*/
@ParameterizedTest
@MethodSource("executors")
void testExecuteWithShutdownNow(ExecutorService executor) throws Exception {
try (executor) {
var started = new CountDownLatch(1);
var interrupted = new CountDownLatch(1);
executor.execute(() -> {
started.countDown();
try {
Thread.sleep(Duration.ofDays(1));
} catch (InterruptedException e) {
interrupted.countDown();
}
});
// wait for task to start
started.await();
// shutdown forcefully, task should be interrupted
executor.shutdownNow();
interrupted.await();
}
}
/**
* Test execute(Runnable) throws if task is null.
*/
@ParameterizedTest
@MethodSource("executors")
void testExecuteNull(ExecutorService executor) {
try (executor) {
Runnable nullTask = null;
assertThrows(NullPointerException.class, () -> executor.execute(nullTask));
}
}
}

View file

@ -0,0 +1,191 @@
/*
* Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6399443 8302899 8362123
* @summary Test that Executors.newSingleThreadExecutor wraps an ExecutorService that
* automatically shuts down and terminates when the wrapper is GC'ed
* @library /test/lib/
* @modules java.base/java.util.concurrent:+open
* @run junit AutoShutdown
*/
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.reflect.Field;
import java.time.Duration;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Stream;
import java.util.stream.IntStream;
import jdk.test.lib.Utils;
import jdk.test.lib.util.ForceGC;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.Arguments;
import static org.junit.jupiter.api.Assertions.*;
class AutoShutdown {
private static Stream<Supplier<ExecutorService>> executors() {
return Stream.of(
() -> Executors.newSingleThreadExecutor(),
() -> Executors.newSingleThreadExecutor(Executors.defaultThreadFactory())
);
}
private static Stream<Arguments> executorAndQueuedTaskCounts() {
int[] queuedTaskCounts = { 0, 1, 2 };
return executors().flatMap(s -> IntStream.of(queuedTaskCounts)
.mapToObj(i -> Arguments.of(s, i)));
}
private static Stream<Arguments> shutdownMethods() {
return Stream.<Consumer<ExecutorService>>of(
e -> e.shutdown(),
e -> e.shutdownNow()
).map(Arguments::of);
}
/**
* SingleThreadExecutor with no worker threads.
*/
@ParameterizedTest
@MethodSource("executors")
void testNoWorker(Supplier<ExecutorService> supplier) throws Exception {
ExecutorService executor = supplier.get();
ExecutorService delegate = getDelegate(executor);
executor = null;
gcAndAwaitTermination(delegate);
}
/**
* SingleThreadExecutor with an idle worker thread.
*/
@ParameterizedTest
@MethodSource("executors")
void testIdleWorker(Supplier<ExecutorService> supplier) throws Exception {
ExecutorService executor = supplier.get();
// submit a task to get a worker to start
executor.submit(() -> null).get();
ExecutorService delegate = getDelegate(executor);
executor = null;
gcAndAwaitTermination(delegate);
}
/**
* SingleThreadExecutor with an active worker and queued tasks.
*/
@ParameterizedTest
@MethodSource("executorAndQueuedTaskCounts")
void testActiveWorker(Supplier<ExecutorService> supplier,int queuedTaskCount) throws Exception {
ExecutorService executor = supplier.get();
// the worker will execute one task, the other tasks will be queued
int ntasks = 1 + queuedTaskCount;
AtomicInteger completedTaskCount = new AtomicInteger();
for (int i = 0; i < ntasks; i++) {
executor.submit(() -> {
Thread.sleep(Duration.ofMillis(500));
completedTaskCount.incrementAndGet();
return null;
});
}
ExecutorService delegate = getDelegate(executor);
executor = null;
gcAndAwaitTermination(delegate);
assertEquals(ntasks, completedTaskCount.get());
}
@ParameterizedTest
@MethodSource("shutdownMethods")
void testShutdownUnlinksCleaner(Consumer<ExecutorService> shutdown) throws Exception {
ClassLoader classLoader =
Utils.getTestClassPathURLClassLoader(ClassLoader.getPlatformClassLoader());
ReferenceQueue<?> queue = new ReferenceQueue<>();
Reference<?> reference = new PhantomReference(classLoader, queue);
try {
Class<?> isolatedClass = classLoader.loadClass("AutoShutdown$IsolatedClass");
assertSame(isolatedClass.getClassLoader(), classLoader);
isolatedClass.getDeclaredMethod("shutdown", Consumer.class).invoke(null, shutdown);
isolatedClass = null;
classLoader = null;
assertTrue(ForceGC.wait(() -> queue.poll() != null));
} finally {
Reference.reachabilityFence(reference);
}
}
/**
* Returns the delegate for the given ExecutorService. The given ExecutorService
* must be a Executors$DelegatedExecutorService.
*/
private ExecutorService getDelegate(ExecutorService executor) throws Exception {
Field eField = Class.forName("java.util.concurrent.Executors$DelegatedExecutorService")
.getDeclaredField("e");
eField.setAccessible(true);
return (ExecutorService) eField.get(executor);
}
/**
* Invokes System.gc and waits for the given ExecutorService to terminate.
*/
private void gcAndAwaitTermination(ExecutorService executor) throws Exception {
System.err.println(executor);
boolean terminated = false;
while (!terminated) {
System.gc();
terminated = executor.awaitTermination(100, TimeUnit.MILLISECONDS);
}
}
public static class IsolatedClass {
private static final ExecutorService executor =
Executors.newSingleThreadExecutor(new IsolatedThreadFactory());
public static void shutdown(Consumer<ExecutorService> shutdown) {
shutdown.accept(executor);
}
}
public static class IsolatedThreadFactory implements ThreadFactory {
@Override
public Thread newThread(Runnable r) {
return new Thread(r);
}
}
}

View file

@ -0,0 +1,117 @@
/*
* Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6552961 6558429
* @summary Test privilegedCallable, privilegedCallableUsingCurrentClassLoader
* @run main PrivilegedCallables
* @author Martin Buchholz
*/
import static java.util.concurrent.Executors.privilegedCallable;
import static java.util.concurrent.Executors.privilegedCallableUsingCurrentClassLoader;
import static java.util.concurrent.Executors.privilegedThreadFactory;
import java.util.Random;
import java.util.concurrent.Callable;
public class PrivilegedCallables {
Callable<Integer> real;
final Callable<Integer> realCaller = new Callable<>() {
public Integer call() throws Exception {
return real.call(); }};
final Random rnd = new Random();
@SuppressWarnings("serial")
final Throwable[] throwables = {
new Exception() {},
new RuntimeException() {},
new Error() {}
};
Throwable randomThrowable() {
return throwables[rnd.nextInt(throwables.length)];
}
void throwThrowable(Throwable t) throws Exception {
if (t instanceof Error) throw (Error) t;
if (t instanceof RuntimeException) throw (RuntimeException) t;
throw (Exception) t;
}
void test(String[] args) {
try { test(privilegedCallable(realCaller)); }
catch (Throwable t) { unexpected(t); }
try { test(privilegedCallableUsingCurrentClassLoader(realCaller)); }
catch (Throwable t) { unexpected(t); }
try { privilegedThreadFactory(); }
catch (Throwable t) { unexpected(t); }
}
void test(final Callable<Integer> c) throws Throwable {
for (int i = 0; i < 20; i++)
if (rnd.nextBoolean()) {
final Throwable t = randomThrowable();
real = new Callable<>() {
public Integer call() throws Exception {
throwThrowable(t);
return null; }};
try {
c.call();
fail("Expected exception not thrown");
} catch (Throwable tt) { check(t == tt); }
} else {
final int n = rnd.nextInt();
real = new Callable<>() {
public Integer call() { return n; }};
equal(c.call(), n);
}
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
new PrivilegedCallables().instanceMain(args);}
void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
abstract class F {abstract void f() throws Throwable;}
void THROWS(Class<? extends Throwable> k, F... fs) {
for (F f : fs)
try {f.f(); fail("Expected " + k.getName() + " not thrown");}
catch (Throwable t) {
if (k.isAssignableFrom(t.getClass())) pass();
else unexpected(t);}}
}

View file

@ -0,0 +1,142 @@
/*
* Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6398290
* @summary Check Executors/STPE Exception specifications
* @author Martin Buchholz
*/
import static java.util.concurrent.Executors.callable;
import static java.util.concurrent.Executors.defaultThreadFactory;
import static java.util.concurrent.Executors.newCachedThreadPool;
import static java.util.concurrent.Executors.newFixedThreadPool;
import static java.util.concurrent.Executors.newScheduledThreadPool;
import static java.util.concurrent.Executors.newSingleThreadExecutor;
import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
import static java.util.concurrent.Executors.privilegedCallable;
import static java.util.concurrent.Executors.unconfigurableExecutorService;
import static java.util.concurrent.Executors.unconfigurableScheduledExecutorService;
import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
import java.util.concurrent.Callable;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
public class Throws {
private static void realMain(String[] args) throws Throwable {
final ThreadFactory fac = defaultThreadFactory();
final ThreadFactory nullFactory = null;
final RejectedExecutionHandler reh
= new RejectedExecutionHandler() {
public void rejectedExecution(Runnable r,
ThreadPoolExecutor executor) {}};
final RejectedExecutionHandler nullHandler = null;
THROWS(NullPointerException.class,
() -> newFixedThreadPool(3, null),
() -> newCachedThreadPool(null),
() -> newSingleThreadScheduledExecutor(null),
() -> newScheduledThreadPool(0, null),
() -> unconfigurableExecutorService(null),
() -> unconfigurableScheduledExecutorService(null),
() -> callable(null, "foo"),
() -> callable((Runnable) null),
() -> callable((PrivilegedAction<?>) null),
() -> callable((PrivilegedExceptionAction<?>) null),
() -> privilegedCallable((Callable<?>) null),
() -> new ScheduledThreadPoolExecutor(0, nullFactory),
() -> new ScheduledThreadPoolExecutor(0, nullFactory, reh),
() -> new ScheduledThreadPoolExecutor(0, fac, nullHandler));
THROWS(IllegalArgumentException.class,
() -> newFixedThreadPool(-42),
() -> newFixedThreadPool(0),
() -> newFixedThreadPool(-42, fac),
() -> newFixedThreadPool(0, fac),
() -> newScheduledThreadPool(-42),
() -> new ScheduledThreadPoolExecutor(-42),
() -> new ScheduledThreadPoolExecutor(-42, reh),
() -> new ScheduledThreadPoolExecutor(-42, fac, reh));
try { newFixedThreadPool(1).shutdownNow(); pass(); }
catch (Throwable t) { unexpected(t); }
try { newFixedThreadPool(1, fac).shutdownNow(); pass(); }
catch (Throwable t) { unexpected(t); }
try { newSingleThreadExecutor().shutdownNow(); pass(); }
catch (Throwable t) { unexpected(t); }
try { newCachedThreadPool().shutdownNow(); pass(); }
catch (Throwable t) { unexpected(t); }
try { newSingleThreadScheduledExecutor().shutdownNow(); pass(); }
catch (Throwable t) { unexpected(t); }
try { newSingleThreadScheduledExecutor(fac).shutdownNow(); pass(); }
catch (Throwable t) { unexpected(t); }
try { newScheduledThreadPool(0).shutdownNow(); pass(); }
catch (Throwable t) { unexpected(t); }
try { newScheduledThreadPool(0, fac).shutdownNow(); pass(); }
catch (Throwable t) { unexpected(t); }
try { new ScheduledThreadPoolExecutor(0).shutdownNow(); pass(); }
catch (Throwable t) { unexpected(t); }
try { new ScheduledThreadPoolExecutor(0, fac).shutdownNow(); pass(); }
catch (Throwable t) { unexpected(t); }
try { new ScheduledThreadPoolExecutor(0, fac, reh).shutdownNow(); pass(); }
catch (Throwable t) { unexpected(t); }
}
//--------------------- Infrastructure ---------------------------
static volatile int passed = 0, failed = 0;
static void pass() {passed++;}
static void fail() {failed++; Thread.dumpStack();}
static void fail(String msg) {System.out.println(msg); fail();}
static void unexpected(Throwable t) {failed++; t.printStackTrace();}
static void check(boolean cond) {if (cond) pass(); else fail();}
static void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
try {realMain(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
interface Fun {void f() throws Throwable;}
static void THROWS(Class<? extends Throwable> k, Fun... fs) {
for (Fun f : fs)
try { f.f(); fail("Expected " + k.getName() + " not thrown"); }
catch (Throwable t) {
if (k.isAssignableFrom(t.getClass())) pass();
else unexpected(t);}}
}

View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8308235
* @summary Unreference ExecutorService objects returned by the Executors without shutdown
* and termination, this should not leak memory
* @run main/othervm -Xmx32m UnreferencedExecutor
*/
import java.time.Duration;
import java.util.concurrent.Executors;
public class UnreferencedExecutor {
private static final int DURATION_IN_SECONDS = 5;
public static void main(String[] args) throws Exception {
int ncores = Runtime.getRuntime().availableProcessors();
long durationNanos = Duration.ofSeconds(DURATION_IN_SECONDS).toNanos();
long start = System.nanoTime();
while (System.nanoTime() - start < durationNanos) {
Executors.newFixedThreadPool(ncores);
Executors.newCachedThreadPool();
Executors.newVirtualThreadPerTaskExecutor();
Executors.newWorkStealingPool(ncores);
}
}
}

View file

@ -0,0 +1,240 @@
/*
* Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary Test Future's default methods
* @library ../lib
* @run junit DefaultMethods
*/
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.stream.Stream;
import static java.util.concurrent.Future.State.*;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import static org.junit.jupiter.api.Assertions.*;
class DefaultMethods {
static Stream<ExecutorService> executors() {
return Stream.of(
// ensures that default close method is tested
new DelegatingExecutorService(Executors.newCachedThreadPool()),
// executors that may return a Future that overrides the methods
Executors.newCachedThreadPool(),
Executors.newVirtualThreadPerTaskExecutor(),
new ForkJoinPool()
);
}
/**
* Test methods when the task has not completed.
*/
@ParameterizedTest
@MethodSource("executors")
void testRunningTask(ExecutorService executor) {
try (executor) {
var latch = new CountDownLatch(1);
Future<?> future = executor.submit(() -> { latch.await(); return null; });
try {
assertTrue(future.state() == RUNNING);
assertThrows(IllegalStateException.class, future::resultNow);
assertThrows(IllegalStateException.class, future::exceptionNow);
} finally {
latch.countDown();
}
}
}
/**
* Test methods when the task has already completed with a result.
*/
@ParameterizedTest
@MethodSource("executors")
void testCompletedTask1(ExecutorService executor) {
try (executor) {
Future<String> future = executor.submit(() -> "foo");
awaitDone(future);
assertTrue(future.state() == SUCCESS);
assertEquals("foo", future.resultNow());
assertThrows(IllegalStateException.class, future::exceptionNow);
}
}
/**
* Test methods when the task has already completed with null.
*/
@ParameterizedTest
@MethodSource("executors")
void testCompletedTask2(ExecutorService executor) {
try (executor) {
Future<String> future = executor.submit(() -> null);
awaitDone(future);
assertTrue(future.state() == SUCCESS);
assertNull(future.resultNow());
assertThrows(IllegalStateException.class, future::exceptionNow);
}
}
/**
* Test methods when the task has completed with an exception.
*/
@ParameterizedTest
@MethodSource("executors")
void testFailedTask(ExecutorService executor) {
try (executor) {
Future<?> future = executor.submit(() -> { throw new ArithmeticException(); });
awaitDone(future);
assertTrue(future.state() == FAILED);
assertThrows(IllegalStateException.class, future::resultNow);
Throwable ex = future.exceptionNow();
assertTrue(ex instanceof ArithmeticException);
}
}
/**
* Test methods when the task has been cancelled (mayInterruptIfRunning=false)
*/
@ParameterizedTest
@MethodSource("executors")
void testCancelledTask1(ExecutorService executor) {
try (executor) {
var latch = new CountDownLatch(1);
Future<?> future = executor.submit(() -> { latch.await(); return null; });
future.cancel(false);
try {
assertTrue(future.state() == CANCELLED);
assertThrows(IllegalStateException.class, future::resultNow);
assertThrows(IllegalStateException.class, future::exceptionNow);
} finally {
latch.countDown();
}
}
}
/**
* Test methods when the task has been cancelled (mayInterruptIfRunning=true)
*/
@ParameterizedTest
@MethodSource("executors")
void testCancelledTask2(ExecutorService executor) {
try (executor) {
var latch = new CountDownLatch(1);
Future<?> future = executor.submit(() -> { latch.await(); return null; });
future.cancel(true);
try {
assertTrue(future.state() == CANCELLED);
assertThrows(IllegalStateException.class, future::resultNow);
assertThrows(IllegalStateException.class, future::exceptionNow);
} finally {
latch.countDown();
}
}
}
/**
* Test CompletableFuture with the task has not completed.
*/
@Test
void testCompletableFuture1() {
var future = new CompletableFuture<String>();
assertTrue(future.state() == RUNNING);
assertThrows(IllegalStateException.class, future::resultNow);
assertThrows(IllegalStateException.class, future::exceptionNow);
}
/**
* Test CompletableFuture with the task that completed with result.
*/
@Test
void testCompletableFuture2() {
var future = new CompletableFuture<String>();
future.complete("foo");
assertTrue(future.state() == SUCCESS);
assertEquals("foo", future.resultNow());
assertThrows(IllegalStateException.class, future::exceptionNow);
}
/**
* Test CompletableFuture with the task that completed with null.
*/
@Test
void testCompletableFuture3() {
var future = new CompletableFuture<String>();
future.complete(null);
assertTrue(future.state() == SUCCESS);
assertNull(future.resultNow());
assertThrows(IllegalStateException.class, future::exceptionNow);
}
/**
* Test CompletableFuture with the task that completed with exception.
*/
@Test
void testCompletableFuture4() {
var future = new CompletableFuture<String>();
future.completeExceptionally(new ArithmeticException());
assertTrue(future.state() == FAILED);
assertThrows(IllegalStateException.class, future::resultNow);
Throwable ex = future.exceptionNow();
assertTrue(ex instanceof ArithmeticException);
}
/**
* Test CompletableFuture with the task that was cancelled.
*/
@Test
void testCompletableFuture5() {
var future = new CompletableFuture<String>();
future.cancel(false);
assertTrue(future.state() == CANCELLED);
assertThrows(IllegalStateException.class, future::resultNow);
assertThrows(IllegalStateException.class, future::exceptionNow);
}
/**
* Waits for the future to be done.
*/
private static void awaitDone(Future<?> future) {
boolean interrupted = false;
while (!future.isDone()) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
interrupted = true;
}
}
if (interrupted) {
Thread.currentThread().interrupt();
}
}
}

View file

@ -0,0 +1,175 @@
/*
* Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6431315
* @summary ExecutorService.invokeAll might hang
* @author Martin Buchholz
* @library /test/lib
*/
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
import jdk.test.lib.Utils;
/**
* Adapted from Doug Lea, which was...
* adapted from a posting by Tom Sugden tom at epcc.ed.ac.uk
*/
public class BlockingTaskExecutor {
static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
static void realMain(String[] args) throws Throwable {
for (int i = 1; i <= 100; i++) {
System.out.print(".");
test();
}
}
static void test() throws Throwable {
final ExecutorService executor = Executors.newCachedThreadPool();
final NotificationReceiver notifiee1 = new NotificationReceiver();
final NotificationReceiver notifiee2 = new NotificationReceiver();
final Collection<Callable<Object>> tasks = new ArrayList<>();
tasks.add(new BlockingTask(notifiee1));
tasks.add(new BlockingTask(notifiee2));
tasks.add(new NonBlockingTask());
// start a thread to invoke the tasks
Thread thread = new Thread() { public void run() {
try { executor.invokeAll(tasks); }
catch (RejectedExecutionException t) {/* OK */}
catch (Throwable t) { unexpected(t); }}};
thread.start();
// Wait until tasks begin execution
notifiee1.waitForNotification();
notifiee2.waitForNotification();
// Now try to shutdown the executor service while tasks
// are blocked. This should cause the tasks to be
// interrupted.
executor.shutdownNow();
if (! executor.awaitTermination(LONG_DELAY_MS, MILLISECONDS))
throw new Error(
String.format("Executor termination timed out after %d ms",
LONG_DELAY_MS));
// Wait for the invocation thread to complete.
thread.join(LONG_DELAY_MS);
if (thread.isAlive()) {
thread.interrupt();
thread.join(LONG_DELAY_MS);
throw new Error(
String.format("invokeAll timed out after %d ms",
LONG_DELAY_MS));
}
}
/**
* A helper class with a method to wait for a notification.
*
* The notification is received via the
* {@code sendNotification} method.
*/
static class NotificationReceiver {
/** Has the notifiee been notified? */
boolean notified;
/**
* Notify the notification receiver.
*/
public synchronized void sendNotification() {
notified = true;
notifyAll();
}
/**
* Waits until a notification has been received.
*
* @throws InterruptedException if the wait is interrupted
*/
public synchronized void waitForNotification()
throws InterruptedException {
while (! notified)
wait();
}
}
/**
* A callable task that blocks until it is interrupted.
* This task sends a notification to a notification receiver when
* it is first called.
*/
static class BlockingTask implements Callable<Object> {
private final NotificationReceiver notifiee;
BlockingTask(NotificationReceiver notifiee) {
this.notifiee = notifiee;
}
public Object call() throws InterruptedException {
notifiee.sendNotification();
// wait indefinitely until task is interrupted
while (true) {
synchronized (this) {
wait();
}
}
}
}
/**
* A callable task that simply returns a string result.
*/
static class NonBlockingTask implements Callable<Object> {
public Object call() {
return "NonBlockingTaskResult";
}
}
//--------------------- Infrastructure ---------------------------
static volatile int passed = 0, failed = 0;
static void pass() {passed++;}
static void fail() {failed++; Thread.dumpStack();}
static void fail(String msg) {System.out.println(msg); fail();}
static void unexpected(Throwable t) {failed++; t.printStackTrace();}
static void check(boolean cond) {if (cond) pass(); else fail();}
static void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
try {realMain(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}

View file

@ -0,0 +1,158 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* @test
* @bug 4486658
* @summary Checks for responsiveness of futures to cancellation.
* Runs under the assumption that ITERS computations require more than
* TIMEOUT msecs to complete.
* @library /test/lib
* @run main/timeout=2000 CancelledFutureLoops
*/
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import java.util.SplittableRandom;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.Callable;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.locks.ReentrantLock;
import jdk.test.lib.Utils;
public final class CancelledFutureLoops {
static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
static final ExecutorService pool = Executors.newCachedThreadPool();
static final SplittableRandom rnd = new SplittableRandom();
static boolean print = false;
static final int ITERS = 1000000;
static final long TIMEOUT = 100;
public static void main(String[] args) throws Exception {
int maxThreads = 5;
if (args.length > 0)
maxThreads = Integer.parseInt(args[0]);
print = true;
for (int i = 2; i <= maxThreads; i += (i+1) >>> 1) {
System.out.print("Threads: " + i);
try {
new FutureLoop(i, rnd.split()).test();
}
catch (BrokenBarrierException bb) {
// OK; ignore
}
catch (ExecutionException ee) {
// OK; ignore
}
Thread.sleep(TIMEOUT);
}
pool.shutdown();
if (! pool.awaitTermination(6 * LONG_DELAY_MS, MILLISECONDS))
throw new Error();
}
static final class FutureLoop implements Callable {
private final int nthreads;
private final SplittableRandom rnd;
private final ReentrantLock lock = new ReentrantLock();
private final LoopHelpers.BarrierTimer timer = new LoopHelpers.BarrierTimer();
private final CyclicBarrier barrier;
private int v;
FutureLoop(int nthreads, SplittableRandom rnd) {
this.nthreads = nthreads;
this.rnd = rnd;
barrier = new CyclicBarrier(nthreads+1, timer);
v = rnd.nextInt();
}
final void test() throws Exception {
Future[] futures = new Future[nthreads];
for (int i = 0; i < nthreads; ++i)
futures[i] = pool.submit(this);
barrier.await();
Thread.sleep(TIMEOUT);
boolean tooLate = false;
for (int i = 1; i < nthreads; ++i) {
if (!futures[i].cancel(true))
tooLate = true;
// Unbunch some of the cancels
if ( (i & 3) == 0)
Thread.sleep(1 + rnd.nextInt(5));
}
Object f0 = futures[0].get();
if (!tooLate) {
for (int i = 1; i < nthreads; ++i) {
if (!futures[i].isDone() || !futures[i].isCancelled())
throw new Error("Only one thread should complete");
}
}
else
System.out.print("(cancelled too late) ");
long endTime = System.nanoTime();
long time = endTime - timer.startTime;
if (print) {
double secs = (double)time / 1000000000.0;
System.out.println("\t " + secs + "s run time");
}
}
public final Object call() throws Exception {
barrier.await();
int sum = v;
int x = 0;
int n = ITERS;
while (n-- > 0) {
lock.lockInterruptibly();
try {
v = x = LoopHelpers.compute1(v);
}
finally {
lock.unlock();
}
sum += LoopHelpers.compute2(LoopHelpers.compute2(x));
}
return new Integer(sum);
}
}
}

View file

@ -0,0 +1,211 @@
/*
* Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6464365
* @summary Test state transitions; check protected methods are called
* @author Martin Buchholz
*/
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicLong;
public class Customized {
static final AtomicLong doneCount = new AtomicLong(0);
static final AtomicLong setCount = new AtomicLong(0);
static final AtomicLong setExceptionCount = new AtomicLong(0);
static void equal(long expected, AtomicLong actual) {
equal(expected, actual.get());
}
static void equalCounts(long x, long y, long z) {
equal(x, doneCount);
equal(y, setCount);
equal(z, setExceptionCount);
}
static class MyFutureTask<V> extends FutureTask<V> {
MyFutureTask(Runnable r, V result) { super(r, result); }
protected void done() {
doneCount.getAndIncrement();
super.done();
}
protected void set(V v) {
setCount.getAndIncrement();
super.set(v);
}
protected void setException(Throwable t) {
setExceptionCount.getAndIncrement();
super.setException(t);
}
public boolean runAndReset() {
return super.runAndReset();
}
}
static <V> void checkReady(final FutureTask<V> task) {
check(! task.isDone());
check(! task.isCancelled());
THROWS(TimeoutException.class,
() -> task.get(0L, TimeUnit.SECONDS));
}
static <V> void checkDone(final FutureTask<V> task) {
try {
check(task.isDone());
check(! task.isCancelled());
check(task.get() != null);
} catch (Throwable t) { unexpected(t); }
}
static <V> void checkCancelled(final FutureTask<V> task) {
check(task.isDone());
check(task.isCancelled());
THROWS(CancellationException.class,
() -> task.get(0L, TimeUnit.SECONDS),
() -> task.get());
}
static <V> void checkThrew(final FutureTask<V> task) {
check(task.isDone());
check(! task.isCancelled());
THROWS(ExecutionException.class,
() -> task.get(0L, TimeUnit.SECONDS),
() -> task.get());
}
static <V> void cancel(FutureTask<V> task, boolean mayInterruptIfRunning) {
task.cancel(mayInterruptIfRunning);
checkCancelled(task);
}
static <V> void run(FutureTask<V> task) {
boolean isCancelled = task.isCancelled();
task.run();
check(task.isDone());
equal(isCancelled, task.isCancelled());
}
static void realMain(String[] args) throws Throwable {
final Runnable nop = new Runnable() {
public void run() {}};
final Runnable bad = new Runnable() {
public void run() { throw new Error(); }};
try {
final MyFutureTask<Long> task = new MyFutureTask<>(nop, 42L);
checkReady(task);
equalCounts(0,0,0);
check(task.runAndReset());
checkReady(task);
equalCounts(0,0,0);
run(task);
checkDone(task);
equalCounts(1,1,0);
equal(42L, task.get());
run(task);
checkDone(task);
equalCounts(1,1,0);
equal(42L, task.get());
} catch (Throwable t) { unexpected(t); }
try {
final MyFutureTask<Long> task = new MyFutureTask<>(nop, 42L);
cancel(task, false);
equalCounts(2,1,0);
cancel(task, false);
equalCounts(2,1,0);
run(task);
equalCounts(2,1,0);
check(! task.runAndReset());
} catch (Throwable t) { unexpected(t); }
try {
final MyFutureTask<Long> task = new MyFutureTask<>(bad, 42L);
checkReady(task);
run(task);
checkThrew(task);
equalCounts(3,1,1);
run(task);
equalCounts(3,1,1);
} catch (Throwable t) { unexpected(t); }
try {
final MyFutureTask<Long> task = new MyFutureTask<>(nop, 42L);
checkReady(task);
task.set(99L);
checkDone(task);
equalCounts(4,2,1);
run(task);
equalCounts(4,2,1);
task.setException(new Throwable());
checkDone(task);
equalCounts(4,2,2);
} catch (Throwable t) { unexpected(t); }
try {
final MyFutureTask<Long> task = new MyFutureTask<>(nop, 42L);
checkReady(task);
task.setException(new Throwable());
checkThrew(task);
equalCounts(5,2,3);
run(task);
equalCounts(5,2,3);
task.set(99L);
checkThrew(task);
equalCounts(5,3,3);
} catch (Throwable t) { unexpected(t); }
System.out.printf("doneCount=%d%n", doneCount.get());
System.out.printf("setCount=%d%n", setCount.get());
System.out.printf("setExceptionCount=%d%n", setExceptionCount.get());
}
//--------------------- Infrastructure ---------------------------
static volatile int passed = 0, failed = 0;
static void pass() {passed++;}
static void fail() {failed++; Thread.dumpStack();}
static void fail(String msg) {System.out.println(msg); fail();}
static void unexpected(Throwable t) {failed++; t.printStackTrace();}
static void check(boolean cond) {if (cond) pass(); else fail();}
static void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
try {realMain(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
interface Fun {void f() throws Throwable;}
static void THROWS(Class<? extends Throwable> k, Fun... fs) {
for (Fun f : fs)
try { f.f(); fail("Expected " + k.getName() + " not thrown"); }
catch (Throwable t) {
if (k.isAssignableFrom(t.getClass())) pass();
else unexpected(t);}}
}

View file

@ -0,0 +1,106 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Martin Buchholz with assistance from members of JCP
* JSR-166 Expert Group and released to the public domain, as
* explained at http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* @test
* @bug 8073704
* @summary Checks that once isDone() returns true,
* get() never throws InterruptedException or TimeoutException
* @library /test/lib
*/
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import jdk.test.lib.Utils;
public class DoneMeansDone {
static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
public static void main(String[] args) throws Throwable {
final int iters = 1000;
final int nThreads = 2;
final AtomicBoolean done = new AtomicBoolean(false);
final AtomicReference<FutureTask<Boolean>> a = new AtomicReference<>();
final CountDownLatch threadsStarted = new CountDownLatch(nThreads);
final Callable<Boolean> alwaysTrue = new Callable<>() {
public Boolean call() {
return true;
}};
final Runnable observer = new Runnable() { public void run() {
threadsStarted.countDown();
final ThreadLocalRandom rnd = ThreadLocalRandom.current();
try {
for (FutureTask<Boolean> f; !done.get();) {
f = a.get();
if (f != null) {
do {} while (!f.isDone());
Thread.currentThread().interrupt();
if (!(rnd.nextBoolean()
? f.get()
: f.get(-1L, TimeUnit.DAYS)))
throw new AssertionError();
}
}
} catch (Exception t) { throw new AssertionError(t); }
}};
final ArrayList<Future<?>> futures = new ArrayList<>(nThreads);
final ExecutorService pool = Executors.newCachedThreadPool();
for (int i = 0; i < nThreads; i++)
futures.add(pool.submit(observer));
threadsStarted.await();
for (int i = 0; i < iters; i++) {
FutureTask<Boolean> f = new FutureTask<>(alwaysTrue);
a.set(f);
f.run();
}
done.set(true);
pool.shutdown();
if (!pool.awaitTermination(LONG_DELAY_MS, MILLISECONDS))
throw new AssertionError();
for (Future<?> future : futures)
future.get();
}
}

View file

@ -0,0 +1,168 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Martin Buchholz with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* @test
* @library /test/lib
* @run main DoneTimedGetLoops 300
* @summary isDone returning true guarantees that subsequent timed get
* will never throw TimeoutException.
*/
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import jdk.test.lib.Utils;
@SuppressWarnings({"unchecked", "rawtypes", "deprecation"})
public class DoneTimedGetLoops {
static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
final long testDurationMillisDefault = 10_000L;
final long testDurationMillis;
static class PublicFutureTask extends FutureTask<Boolean> {
static final Runnable noop = new Runnable() { public void run() {} };
PublicFutureTask() { super(noop, null); }
public void set(Boolean v) { super.set(v); }
public void setException(Throwable t) { super.setException(t); }
}
DoneTimedGetLoops(String[] args) {
testDurationMillis = (args.length > 0) ?
Long.valueOf(args[0]) : testDurationMillisDefault;
}
void test(String[] args) throws Throwable {
final long testDurationNanos = testDurationMillis * 1000L * 1000L;
final long quittingTimeNanos = System.nanoTime() + testDurationNanos;
final AtomicReference<PublicFutureTask> normalRef
= new AtomicReference<>();
final AtomicReference<PublicFutureTask> abnormalRef
= new AtomicReference<>();
final Throwable throwable = new Throwable();
abstract class CheckedThread extends Thread {
CheckedThread(String name) {
super(name);
setDaemon(true);
start();
}
/** Polls for quitting time. */
protected boolean quittingTime() {
return System.nanoTime() - quittingTimeNanos > 0;
}
/** Polls occasionally for quitting time. */
protected boolean quittingTime(long i) {
return (i % 1024) == 0 && quittingTime();
}
protected abstract void realRun() throws Exception;
public void run() {
try { realRun(); } catch (Throwable t) { unexpected(t); }
}
}
Thread setter = new CheckedThread("setter") {
protected void realRun() {
while (! quittingTime()) {
PublicFutureTask future = new PublicFutureTask();
normalRef.set(future);
future.set(Boolean.TRUE);
}}};
Thread setterException = new CheckedThread("setterException") {
protected void realRun() {
while (! quittingTime()) {
PublicFutureTask future = new PublicFutureTask();
abnormalRef.set(future);
future.setException(throwable);
}}};
Thread doneTimedGetNormal = new CheckedThread("doneTimedGetNormal") {
protected void realRun() throws Exception {
while (! quittingTime()) {
PublicFutureTask future = normalRef.get();
if (future != null) {
while (!future.isDone())
;
check(future.get(0L, TimeUnit.HOURS) == Boolean.TRUE);
}}}};
Thread doneTimedGetAbnormal = new CheckedThread("doneTimedGetAbnormal") {
protected void realRun() throws Exception {
while (! quittingTime()) {
PublicFutureTask future = abnormalRef.get();
if (future != null) {
while (!future.isDone())
;
try { future.get(0L, TimeUnit.HOURS); fail(); }
catch (ExecutionException t) {
check(t.getCause() == throwable);
}
}}}};
for (Thread thread : new Thread[] {
setter,
setterException,
doneTimedGetNormal,
doneTimedGetAbnormal }) {
thread.join(LONG_DELAY_MS + testDurationMillis);
if (thread.isAlive()) {
System.err.printf("Hung thread: %s%n", thread.getName());
failed++;
for (StackTraceElement e : thread.getStackTrace())
System.err.println(e);
thread.join(LONG_DELAY_MS);
}
}
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
new DoneTimedGetLoops(args).instanceMain(args);}
public void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}

View file

@ -0,0 +1,87 @@
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 7132378
* @summary Race in FutureTask if used with explicit set ( not Runnable )
* @author Chris Hegarty
*/
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
public class ExplicitSet {
static void realMain(String[] args) throws Throwable {
for (int i = 1; i <= 10000; i++) {
//System.out.print(".");
test();
}
}
static void test() throws Throwable {
final SettableTask task = new SettableTask();
Thread thread = new Thread() { public void run() {
try {
check(task.get() != null);
} catch (Exception e) { unexpected(e); }
}};
thread.start();
task.set(Boolean.TRUE);
thread.join(5000);
}
static class SettableTask extends FutureTask<Boolean> {
SettableTask() {
super(new Callable<Boolean>() {
public Boolean call() {
fail("The task should never be run!");
return null;
}
});
}
@Override
public void set(Boolean b) {
super.set(b);
}
}
//--------------------- Infrastructure ---------------------------
static volatile int passed = 0, failed = 0;
static void pass() {passed++;}
static void fail() {failed++; Thread.dumpStack();}
static void fail(String msg) {System.out.println(msg); fail();}
static void unexpected(Throwable t) {failed++; t.printStackTrace();}
static void check(boolean cond) {if (cond) pass(); else fail();}
static void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
try {realMain(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}

View file

@ -0,0 +1,103 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/**
* Misc utilities in JSR166 performance tests
*/
class LoopHelpers {
// Some mindless computation to do between synchronizations...
/**
* generates 32 bit pseudo-random numbers.
* Adapted from http://www.snippets.org
*/
public static int compute1(int x) {
int lo = 16807 * (x & 0xFFFF);
int hi = 16807 * (x >>> 16);
lo += (hi & 0x7FFF) << 16;
if ((lo & 0x80000000) != 0) {
lo &= 0x7fffffff;
++lo;
}
lo += hi >>> 15;
if (lo == 0 || (lo & 0x80000000) != 0) {
lo &= 0x7fffffff;
++lo;
}
return lo;
}
/**
* Computes a linear congruential random number a random number
* of times.
*/
public static int compute2(int x) {
int loops = (x >>> 4) & 7;
while (loops-- > 0) {
x = (x * 2147483647) % 16807;
}
return x;
}
public static class BarrierTimer implements Runnable {
public volatile long startTime;
public volatile long endTime;
public void run() {
long t = System.nanoTime();
if (startTime == 0)
startTime = t;
else
endTime = t;
}
public void clear() {
startTime = 0;
endTime = 0;
}
public long getTime() {
return endTime - startTime;
}
}
public static String rightJustify(long n) {
// There's probably a better way to do this...
String field = " ";
String num = Long.toString(n);
if (num.length() >= field.length())
return num;
StringBuilder b = new StringBuilder(field);
b.replace(b.length()-num.length(), b.length(), num);
return b.toString();
}
}

View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8060052
* @summary FutureTask; fix underflow when timeout = Long.MIN_VALUE
* @author Chris Hegarty
*/
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.TimeUnit;
// If the bug exists the test will eventually be interrupted by the
// test harness and fail with an InterruptedException, otherwise it
// will throw a TimeoutException almost immediately and return silently.
public class NegativeTimeout {
public static void main(String[] args) throws Exception {
FutureTask<Void> task = new FutureTask<>(() -> null);
try {
task.get(Long.MIN_VALUE, TimeUnit.NANOSECONDS);
} catch (TimeoutException success) {}
}
}

View file

@ -0,0 +1,147 @@
/*
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6415572
* @summary Check exceptional behavior in run and done methods
*/
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class Throw {
static void THROW(final Throwable t) {
if (t != null)
Throw.<RuntimeException>uncheckedThrow(t);
}
Callable<Void> thrower(final Throwable t) {
return new Callable<Void>() { public Void call() {
THROW(t); return null; }};
}
@SuppressWarnings("serial")
private static class DoneError extends Error {}
@SuppressWarnings("serial")
private static class DoneException extends RuntimeException {}
static class MyFutureTask extends FutureTask<Void> {
MyFutureTask(Callable<Void> task) { super(task); }
public boolean runAndReset() { return super.runAndReset(); }
}
MyFutureTask checkTask(final MyFutureTask task) {
check(! task.isCancelled());
check(! task.isDone());
return task;
}
MyFutureTask taskFor(final Throwable callableThrowable,
final Throwable doneThrowable) {
return checkTask(
new MyFutureTask(thrower(callableThrowable)) {
protected void done() { THROW(doneThrowable); }});
}
void test(String[] args) throws Throwable {
final Throwable[] callableThrowables = {
null, new Exception(), new Error(), new RuntimeException() };
final Throwable[] doneThrowables = {
new DoneError(), new DoneException() };
for (final Throwable c : callableThrowables) {
for (final Throwable d : doneThrowables) {
THROWS(d.getClass(),
new F(){void f(){
taskFor(c, d).cancel(false);}},
new F(){void f(){
taskFor(c, d).run();}});
if (c != null)
THROWS(d.getClass(),
new F(){void f(){
taskFor(c, d).runAndReset();}});
}
try {
final MyFutureTask task = taskFor(c, null);
check(task.cancel(false));
THROWS(CancellationException.class,
new F(){void f() throws Throwable { task.get(); }});
} catch (Throwable t) { unexpected(t); }
if (c != null) {
final MyFutureTask task = taskFor(c, null);
task.run();
try {
task.get();
fail("Expected ExecutionException");
} catch (ExecutionException ee) {
equal(c.getClass(), ee.getCause().getClass());
} catch (Throwable t) { unexpected(t); }
}
if (c != null) {
final MyFutureTask task = taskFor(c, null);
task.runAndReset();
try {
task.get();
fail("Expected ExecutionException");
} catch (ExecutionException ee) {
check(c.getClass().isInstance(ee.getCause()));
} catch (Throwable t) { unexpected(t); }
}
}
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
new Throw().instanceMain(args);}
void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
abstract class F {abstract void f() throws Throwable;}
void THROWS(Class<? extends Throwable> k, F... fs) {
for (F f : fs)
try {f.f(); fail("Expected " + k.getName() + " not thrown");}
catch (Throwable t) {
if (k.isAssignableFrom(t.getClass())) pass();
else unexpected(t);}}
@SuppressWarnings("unchecked")
static <T extends Throwable> void uncheckedThrow(Throwable t) throws T {
throw (T)t; // rely on vacuous cast
}
}

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6307455
* @summary toArray(a) must set "after-end" element to null
* @author Martin Buchholz
*/
import java.util.Collection;
import java.util.concurrent.LinkedBlockingQueue;
public class ToArray {
public static void main(String[] args) throws Throwable {
Collection<Integer> c = new LinkedBlockingQueue<>();
if (c.toArray(new Integer[]{42})[0] != null)
throw new Error("should be null");
}
}

View file

@ -0,0 +1,114 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @run testng SpliteratorTraverseAddRemoveTest
* @bug 8085978
* @summary repeatedly traverse the queue using the spliterator while
* concurrently adding and removing an element to test that self-linked
* nodes are never erroneously reported on traversal
*/
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.Spliterator;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
@Test
public class SpliteratorTraverseAddRemoveTest {
static Object[] of(String desc, Consumer<Queue<?>> c) {
return new Object[]{desc, c};
}
static void assertIsString(Object e) {
Assert.assertTrue(e instanceof String,
String.format("Object instanceof %s (actual: instanceof %s)",
String.class.getName(),
e.getClass().getName()));
}
@DataProvider()
public static Object[][] spliteratorTraversers() {
return new Object[][]{
of("forEachRemaining", q -> {
q.spliterator().forEachRemaining(SpliteratorTraverseAddRemoveTest::assertIsString);
}),
of("tryAdvance", q -> {
Spliterator<?> s = q.spliterator();
while (s.tryAdvance(SpliteratorTraverseAddRemoveTest::assertIsString))
;
}),
of("trySplit then forEachRemaining", q -> {
Spliterator<?> r = q.spliterator();
List<Spliterator<?>> ss = new ArrayList<>();
Spliterator<?> l;
while ((l = r.trySplit()) != null) {
ss.add(l);
}
ss.add(r);
ss.forEach(s -> s.forEachRemaining(SpliteratorTraverseAddRemoveTest::assertIsString));
}),
};
}
@Test(dataProvider = "spliteratorTraversers")
public void testQueue(String desc, Consumer<Queue<String>> c)
throws InterruptedException {
AtomicBoolean done = new AtomicBoolean(false);
Queue<String> msgs = new LinkedTransferQueue<>();
CompletableFuture<Void> traversalTask = CompletableFuture.runAsync(() -> {
while (!done.get()) {
// Traversal will fail if self-linked nodes of
// LinkedTransferQueue are erroneously reported
c.accept(msgs);
}
});
CompletableFuture<Void> addAndRemoveTask = CompletableFuture.runAsync(() -> {
while (!traversalTask.isDone()) {
msgs.add("msg");
msgs.remove("msg");
}
});
Thread.sleep(TimeUnit.SECONDS.toMillis(1));
done.set(true);
addAndRemoveTask.join();
Assert.assertTrue(traversalTask.isDone());
traversalTask.join();
}
}

View file

@ -0,0 +1,67 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8323659
* @summary Ensures that the implementation of LTQ add and put methods does
* not call overridable offer. This test specifically asserts implementation
* details of LTQ. It's not that such impl details cannot change, just that
* such a change should be deliberately done with suitable consideration
* to compatibility.
* @run testng SubclassTest
*/
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.TimeUnit;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
@Test
public class SubclassTest {
public void testPut() {
var queue = new TestLinkedTransferQueue();
queue.put(new Object());
assertEquals(queue.size(), 1);
}
public void testAdd() {
var queue = new TestLinkedTransferQueue();
queue.add(new Object());
assertEquals(queue.size(), 1);
}
public void testTimedOffer() {
var queue = new TestLinkedTransferQueue();
queue.offer(new Object(), 60, TimeUnit.SECONDS);
assertEquals(queue.size(), 1);
}
static class TestLinkedTransferQueue extends LinkedTransferQueue<Object> {
@Override
public boolean offer(Object obj) {
return false; // simulate fails to add the given obj
}
}
}

View file

@ -0,0 +1,392 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Martin Buchholz with assistance from members of JCP
* JSR-166 Expert Group and released to the public domain, as
* explained at http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* @test
* @modules java.base/java.util.concurrent:open
* @run testng WhiteBox
* @summary White box tests of implementation details
*/
import static org.testng.Assert.*;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import static java.util.stream.Collectors.toList;
import java.util.function.Consumer;
@Test
public class WhiteBox {
final ThreadLocalRandom rnd = ThreadLocalRandom.current();
final VarHandle HEAD, TAIL, ITEM, NEXT;
public WhiteBox() throws Throwable { // throws ReflectiveOperationException {
try {
Class<?> qClass = LinkedTransferQueue.class;
Class<?> nodeClass = Class.forName(qClass.getName() + "$DualNode");
MethodHandles.Lookup lookup
= MethodHandles.privateLookupIn(qClass, MethodHandles.lookup());
HEAD = lookup.findVarHandle(qClass, "head", nodeClass);
TAIL = lookup.findVarHandle(qClass, "tail", nodeClass);
NEXT = lookup.findVarHandle(nodeClass, "next", nodeClass);
ITEM = lookup.findVarHandle(nodeClass, "item", Object.class);
} catch (Throwable ex) {
ex.printStackTrace();
throw ex;
}
}
Object head(LinkedTransferQueue q) { return HEAD.getVolatile(q); }
Object tail(LinkedTransferQueue q) { return TAIL.getVolatile(q); }
Object item(Object node) { return ITEM.getVolatile(node); }
Object next(Object node) { return NEXT.getVolatile(node); }
/*
* Modified for jdk22: Accommodate lazy initialization, so counts
* may vary by 1, and some nodes become headers vs unlinked,
* compared to previous versions.
*/
static void checkCount(int val, int expect) {
assertTrue(val == expect || val == expect - 1);
}
int nodeCount(LinkedTransferQueue q) {
int i = 0;
for (Object p = head(q); p != null; ) {
i++;
if (p == (p = next(p))) p = head(q);
}
return i;
}
int tailCount(LinkedTransferQueue q) {
int i = 0;
for (Object p = tail(q); p != null; ) {
i++;
if (p == (p = next(p))) p = head(q);
}
return i;
}
Object findNode(LinkedTransferQueue q, Object e) {
for (Object p = head(q); p != null; ) {
if (item(p) != null && e.equals(item(p)))
return p;
if (p == (p = next(p))) p = head(q);
}
throw new AssertionError("not found");
}
Iterator iteratorAt(LinkedTransferQueue q, Object e) {
for (Iterator it = q.iterator(); it.hasNext(); )
if (it.next().equals(e))
return it;
throw new AssertionError("not found");
}
void assertIsSelfLinked(Object node) {
assertSame(next(node), node);
assertNull(item(node));
}
void assertIsNotSelfLinked(Object node) {
assertNotSame(node, next(node));
}
@Test
public void addRemove() {
LinkedTransferQueue q = new LinkedTransferQueue();
assertInvariants(q);
if (head(q) != null) {
assertNull(next(head(q)));
assertNull(item(head(q)));
}
q.add(1);
checkCount(nodeCount(q), 2);
assertInvariants(q);
q.remove(1);
checkCount(nodeCount(q), 1);
assertInvariants(q);
}
/**
* Traversal actions that visit every node and do nothing, but
* have side effect of squeezing out dead nodes.
*/
@DataProvider
public Object[][] traversalActions() {
return List.<Consumer<LinkedTransferQueue>>of(
q -> q.forEach(e -> {}),
q -> assertFalse(q.contains(new Object())),
q -> assertFalse(q.remove(new Object())),
q -> q.spliterator().forEachRemaining(e -> {}),
q -> q.stream().collect(toList()),
q -> assertFalse(q.removeIf(e -> false)),
q -> assertFalse(q.removeAll(List.of())))
.stream().map(x -> new Object[]{ x }).toArray(Object[][]::new);
}
@Test(dataProvider = "traversalActions")
public void traversalOperationsCollapseLeadingNodes(
Consumer<LinkedTransferQueue> traversalAction) {
LinkedTransferQueue q = new LinkedTransferQueue();
Object oldHead;
int n = 1 + rnd.nextInt(5);
for (int i = 0; i < n; i++) q.add(i);
checkCount(nodeCount(q), n + 1);
oldHead = head(q);
traversalAction.accept(q);
assertInvariants(q);
checkCount(nodeCount(q), n);
// assertIsSelfLinked(oldHead);
}
@Test(dataProvider = "traversalActions")
public void traversalOperationsCollapseInteriorNodes(
Consumer<LinkedTransferQueue> traversalAction) {
LinkedTransferQueue q = new LinkedTransferQueue();
int n = 6;
for (int i = 0; i < n; i++) q.add(i);
// We must be quite devious to reliably create an interior dead node
Object p0 = findNode(q, 0);
Object p1 = findNode(q, 1);
Object p2 = findNode(q, 2);
Object p3 = findNode(q, 3);
Object p4 = findNode(q, 4);
Object p5 = findNode(q, 5);
Iterator it1 = iteratorAt(q, 1);
Iterator it2 = iteratorAt(q, 2);
it2.remove(); // causes it2's ancestor to advance to 1
assertSame(next(p1), p3);
assertSame(next(p2), p3);
assertNull(item(p2));
it1.remove(); // removes it2's ancestor
assertSame(next(p0), p3);
assertSame(next(p1), p3);
assertSame(next(p2), p3);
assertNull(item(p1));
assertEquals(it2.next(), 3);
it2.remove(); // it2's ancestor can't unlink
assertSame(next(p0), p3); // p3 is now interior dead node
assertSame(next(p1), p4); // it2 uselessly CASed p1.next
assertSame(next(p2), p3);
assertSame(next(p3), p4);
assertInvariants(q);
int c = nodeCount(q);
traversalAction.accept(q);
checkCount(nodeCount(q), c - 1);
assertSame(next(p0), p4);
assertSame(next(p1), p4);
assertSame(next(p2), p3);
assertSame(next(p3), p4);
assertInvariants(q);
// trailing nodes are not unlinked
Iterator it5 = iteratorAt(q, 5); it5.remove();
traversalAction.accept(q);
assertSame(next(p4), p5);
assertNull(next(p5));
checkCount(nodeCount(q), c - 1);
}
/**
* Checks that traversal operations collapse a random pattern of
* dead nodes as could normally only occur with a race.
*/
@Test(dataProvider = "traversalActions")
public void traversalOperationsCollapseRandomNodes(
Consumer<LinkedTransferQueue> traversalAction) {
LinkedTransferQueue q = new LinkedTransferQueue();
int n = 1 + rnd.nextInt(6);
for (int i = 0; i < n; i++) q.add(i);
ArrayList nulledOut = new ArrayList();
for (Object p = head(q); p != null; p = next(p))
if (rnd.nextBoolean()) {
nulledOut.add(item(p));
ITEM.setVolatile(p, null);
}
traversalAction.accept(q);
int c = nodeCount(q);
checkCount(c - (q.contains(n - 1) ? 0 : 1), q.size() + 1);
for (int i = 0; i < n; i++)
assertTrue(nulledOut.contains(i) ^ q.contains(i));
}
/**
* Traversal actions that remove every element, and are also
* expected to squeeze out dead nodes.
*/
@DataProvider
public Object[][] bulkRemovalActions() {
return List.<Consumer<LinkedTransferQueue>>of(
q -> q.clear(),
q -> assertTrue(q.removeIf(e -> true)),
q -> assertTrue(q.retainAll(List.of())))
.stream().map(x -> new Object[]{ x }).toArray(Object[][]::new);
}
@Test(dataProvider = "bulkRemovalActions")
public void bulkRemovalOperationsCollapseNodes(
Consumer<LinkedTransferQueue> bulkRemovalAction) {
LinkedTransferQueue q = new LinkedTransferQueue();
int n = 1 + rnd.nextInt(5);
for (int i = 0; i < n; i++) q.add(i);
bulkRemovalAction.accept(q);
checkCount(nodeCount(q), 1);
assertInvariants(q);
}
/**
* Actions that remove the first element, and are expected to
* leave at most one slack dead node at head.
*/
@DataProvider
public Object[][] pollActions() {
return List.<Consumer<LinkedTransferQueue>>of(
q -> assertNotNull(q.poll()),
q -> { try { assertNotNull(q.poll(1L, TimeUnit.DAYS)); }
catch (Throwable x) { throw new AssertionError(x); }},
q -> { try { assertNotNull(q.take()); }
catch (Throwable x) { throw new AssertionError(x); }},
q -> assertNotNull(q.remove()))
.stream().map(x -> new Object[]{ x }).toArray(Object[][]::new);
}
@Test(dataProvider = "pollActions")
public void pollActionsOneNodeSlack(
Consumer<LinkedTransferQueue> pollAction) {
LinkedTransferQueue q = new LinkedTransferQueue();
int n = 1 + rnd.nextInt(5);
for (int i = 0; i < n; i++) q.add(i);
checkCount(nodeCount(q), n + 1);
for (int i = 0; i < n; i++) {
int c = nodeCount(q);
boolean slack = item(head(q)) == null;
if (slack) assertNotNull(item(next(head(q))));
pollAction.accept(q);
checkCount(nodeCount(q), q.isEmpty() ? 1 : c - (slack ? 2 : 0));
}
assertInvariants(q);
}
/**
* Actions that append an element, and are expected to
* leave at most one slack node at tail.
*/
@DataProvider
public Object[][] addActions() {
return List.<Consumer<LinkedTransferQueue>>of(
q -> q.add(1),
q -> q.offer(1))
.stream().map(x -> new Object[]{ x }).toArray(Object[][]::new);
}
@Test(dataProvider = "addActions")
public void addActionsOneNodeSlack(
Consumer<LinkedTransferQueue> addAction) {
LinkedTransferQueue q = new LinkedTransferQueue();
int n = 1 + rnd.nextInt(9);
for (int i = 0; i < n; i++) {
boolean empty = (tail(q) == null);
boolean slack = !empty && (next(tail(q)) != null);
addAction.accept(q);
if (slack)
assertNull(next(tail(q)));
else if (!empty) {
assertNotNull(next(tail(q)));
assertNull(next(next(tail(q))));
}
assertInvariants(q);
}
}
byte[] serialBytes(Object o) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(o);
oos.flush();
oos.close();
return bos.toByteArray();
} catch (Exception fail) {
throw new AssertionError(fail);
}
}
@SuppressWarnings("unchecked")
<T> T serialClone(T o) {
try {
ObjectInputStream ois = new ObjectInputStream
(new ByteArrayInputStream(serialBytes(o)));
T clone = (T) ois.readObject();
assertNotSame(o, clone);
assertSame(o.getClass(), clone.getClass());
return clone;
} catch (Exception fail) {
throw new AssertionError(fail);
}
}
@Test
public void testSerialization() {
LinkedTransferQueue q = serialClone(new LinkedTransferQueue());
assertInvariants(q);
}
/** Checks conditions which should always be true. */
void assertInvariants(LinkedTransferQueue q) {
// head is never self-linked (but tail may!)
Object h;
if ((h = head(q)) != null)
assertNotSame(h, next(h));
}
}

View file

@ -0,0 +1,97 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* @test
* @bug 6445158
* @summary tests for Phaser.arrive()
*/
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Phaser;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicInteger;
public class Arrive {
void test(String[] args) throws Throwable {
for (int i = 0; i < 100; ++i)
doTest(args);
}
void doTest(String[] args) throws Throwable {
final int n = ThreadLocalRandom.current().nextInt(1, 10);
final Phaser startingGate = new Phaser(n);
final Phaser phaser = new Phaser(n);
final List<Thread> threads = new ArrayList<>();
final AtomicInteger count0 = new AtomicInteger(0);
final AtomicInteger count1 = new AtomicInteger(0);
final Runnable task = new Runnable() { public void run() {
equal(startingGate.getPhase(), 0);
startingGate.arriveAndAwaitAdvance();
equal(startingGate.getPhase(), 1);
int phase = phaser.arrive();
if (phase == 0)
count0.getAndIncrement();
else if (phase == 1)
count1.getAndIncrement();
else
fail();
}};
for (int i = 0; i < n; i++)
threads.add(new Thread(task));
for (Thread thread : threads)
thread.start();
for (Thread thread : threads)
thread.join();
equal(count0.get(), n);
equal(count1.get(), 0);
equal(phaser.getPhase(), 1);
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
new Arrive().instanceMain(args);}
public void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}

View file

@ -0,0 +1,463 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* @test
* @bug 6445158
* @summary Basic tests for Phaser
* @author Chris Hegarty
* @modules java.management
*/
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.concurrent.Phaser;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
public class Basic {
private static void checkTerminated(final Phaser phaser) {
check(phaser.isTerminated());
int unarriverParties = phaser.getUnarrivedParties();
int registeredParties = phaser.getRegisteredParties();
int phase = phaser.getPhase();
check(phase < 0);
equal(phase, phaser.arrive());
equal(phase, phaser.arriveAndDeregister());
equal(phase, phaser.arriveAndAwaitAdvance());
equal(phase, phaser.bulkRegister(10));
equal(phase, phaser.register());
try {
equal(phase, phaser.awaitAdvanceInterruptibly(0));
equal(phase, phaser.awaitAdvanceInterruptibly(0, 10, SECONDS));
} catch (Exception ex) {
unexpected(ex);
}
equal(phaser.getUnarrivedParties(), unarriverParties);
equal(phaser.getRegisteredParties(), registeredParties);
}
private static void checkResult(Arriver a, Class<? extends Throwable> c) {
Throwable t = a.result();
if (! ((t == null && c == null) || (c != null && c.isInstance(t)))) {
// t.printStackTrace();
fail("Mismatch in thread " +
a.getName() + ": " +
t + ", " +
(c == null ? "<null>" : c.getName()));
} else {
pass();
}
}
//----------------------------------------------------------------
// Mechanism to get all test threads into "running" mode.
//----------------------------------------------------------------
private static Phaser startingGate = new Phaser(3);
private static void toTheStartingGate() {
try {
boolean expectNextPhase = (startingGate.getUnarrivedParties() == 1);
int phase = startingGate.getPhase();
equal(phase, startingGate.arrive());
int awaitPhase;
for (boolean interrupted = false;;) {
try {
awaitPhase = startingGate.awaitAdvanceInterruptibly
(phase, 30, SECONDS);
if (interrupted) Thread.currentThread().interrupt();
break;
} catch (InterruptedException ie) {
interrupted = true;
}
}
if (expectNextPhase) check(awaitPhase == phase + 1);
else check(awaitPhase == phase || awaitPhase == phase + 1);
pass();
} catch (Throwable t) {
unexpected(t);
// reset(startingGate);
throw new Error(t);
}
}
//----------------------------------------------------------------
// Convenience methods for creating threads that call arrive,
// awaitAdvance, arriveAndAwaitAdvance, awaitAdvanceInterruptibly
//----------------------------------------------------------------
private abstract static class Arriver extends Thread {
static AtomicInteger count = new AtomicInteger(1);
Arriver() {
this("Arriver");
}
Arriver(String name) {
this.setName(name + ":" + count.getAndIncrement());
this.setDaemon(true);
}
private volatile Throwable result;
private volatile int phase;
protected void result(Throwable result) { this.result = result; }
public Throwable result() { return this.result; }
protected void phase(int phase) { this.phase = phase; }
public int phase() { return this.phase; }
}
private abstract static class Awaiter extends Arriver {
Awaiter() { super("Awaiter"); }
Awaiter(String name) { super(name); }
}
private static Arriver arriver(final Phaser phaser) {
return new Arriver() { public void run() {
toTheStartingGate();
try { phase(phaser.arrive()); }
catch (Throwable result) { result(result); }}};
}
private static AtomicInteger cycleArriveAwaitAdvance = new AtomicInteger(1);
private static Awaiter awaiter(final Phaser phaser) {
return new Awaiter() { public void run() {
toTheStartingGate();
try {
if (cycleArriveAwaitAdvance.getAndIncrement() % 2 == 0)
phase(phaser.awaitAdvance(phaser.arrive()));
else
phase(phaser.arriveAndAwaitAdvance());
} catch (Throwable result) { result(result); }}};
}
private static Awaiter awaiter(final Phaser phaser,
final long timeout,
final TimeUnit unit) {
return new Awaiter("InterruptibleWaiter") { public void run() {
toTheStartingGate();
try {
if (timeout < 0)
phase(phaser.awaitAdvanceInterruptibly(phaser.arrive()));
else
phase(phaser.awaitAdvanceInterruptibly(phaser.arrive(),
timeout,
unit));
} catch (Throwable result) { result(result); }}};
}
// Returns an infinite lazy list of all possible arriver/awaiter combinations.
private static Iterator<Arriver> arriverIterator(final Phaser phaser) {
return new Iterator<Arriver>() {
int i = 0;
public boolean hasNext() { return true; }
public Arriver next() {
switch ((i++)&7) {
case 0: case 4:
return arriver(phaser);
case 1: case 5:
return awaiter(phaser);
case 2: case 6: case 7:
return awaiter(phaser, -1, SECONDS);
default:
return awaiter(phaser, 30, SECONDS); }}
public void remove() {throw new UnsupportedOperationException();}};
}
// Returns an infinite lazy list of all possible awaiter only combinations.
private static Iterator<Awaiter> awaiterIterator(final Phaser phaser) {
return new Iterator<Awaiter>() {
int i = 0;
public boolean hasNext() { return true; }
public Awaiter next() {
switch ((i++)&7) {
case 1: case 4: case 7:
return awaiter(phaser);
case 2: case 5:
return awaiter(phaser, -1, SECONDS);
default:
return awaiter(phaser, 30, SECONDS); }}
public void remove() {throw new UnsupportedOperationException();}};
}
static class SimpleTimer {
long startTime = System.nanoTime();
long elapsedMillis() {
long now = System.nanoTime();
long elapsed = NANOSECONDS.toMillis(now - startTime);
startTime = now;
return elapsed;
}
void printElapsed() { System.out.println(elapsedMillis() + " ms"); }
}
private static void realMain(String[] args) throws Throwable {
SimpleTimer timer = new SimpleTimer();
Thread.currentThread().setName("mainThread");
//----------------------------------------------------------------
System.out.print("Normal use: ");
//----------------------------------------------------------------
try {
Phaser phaser = new Phaser(3);
equal(phaser.getRegisteredParties(), 3);
equal(phaser.getArrivedParties(), 0);
equal(phaser.getPhase(), 0);
check(phaser.getRoot().equals(phaser));
equal(phaser.getParent(), null);
check(!phaser.isTerminated());
Iterator<Arriver> arrivers = arriverIterator(phaser);
int phase = 0;
for (int i = 0; i < 10; i++) {
equal(phaser.getPhase(), phase++);
Arriver a1 = arrivers.next(); a1.start();
Arriver a2 = arrivers.next(); a2.start();
toTheStartingGate();
phaser.arriveAndAwaitAdvance();
a1.join();
a2.join();
checkResult(a1, null);
checkResult(a2, null);
check(!phaser.isTerminated());
equal(phaser.getRegisteredParties(), 3);
equal(phaser.getArrivedParties(), 0);
}
} catch (Throwable t) { unexpected(t); }
timer.printElapsed();
//----------------------------------------------------------------
System.out.print("One thread interrupted: ");
//----------------------------------------------------------------
try {
Phaser phaser = new Phaser(3);
Iterator<Arriver> arrivers = arriverIterator(phaser);
int phase = phaser.getPhase();
for (int i = 0; i < 10; i++) {
check(phaser.getPhase() == phase);
Awaiter a1 = awaiter(phaser, 30, SECONDS); a1.start();
Arriver a2 = arrivers.next(); a2.start();
toTheStartingGate();
a1.interrupt();
a1.join();
phaser.arriveAndAwaitAdvance();
a2.join();
checkResult(a1, InterruptedException.class);
checkResult(a2, null);
check(!phaser.isTerminated());
equal(phaser.getRegisteredParties(), 3);
equal(phaser.getArrivedParties(), 0);
phase++;
}
} catch (Throwable t) { unexpected(t); }
timer.printElapsed();
//----------------------------------------------------------------
System.out.print("Phaser is terminated while threads are waiting: ");
//----------------------------------------------------------------
try {
for (int i = 0; i < 10; i++) {
Phaser phaser = new Phaser(3);
Iterator<Awaiter> awaiters = awaiterIterator(phaser);
Arriver a1 = awaiters.next(); a1.start();
Arriver a2 = awaiters.next(); a2.start();
toTheStartingGate();
while (phaser.getArrivedParties() < 2) Thread.yield();
equal(0, phaser.getPhase());
phaser.forceTermination();
a1.join();
a2.join();
equal(0 + Integer.MIN_VALUE, a1.phase);
equal(0 + Integer.MIN_VALUE, a2.phase);
int arrivedParties = phaser.getArrivedParties();
checkTerminated(phaser);
equal(phaser.getArrivedParties(), arrivedParties);
}
} catch (Throwable t) { unexpected(t); }
timer.printElapsed();
//----------------------------------------------------------------
System.out.print("Adds new unarrived parties to this phaser: ");
//----------------------------------------------------------------
try {
Phaser phaser = new Phaser(1);
Iterator<Arriver> arrivers = arriverIterator(phaser);
LinkedList<Arriver> arriverList = new LinkedList<>();
int phase = phaser.getPhase();
for (int i = 1; i < 5; i++) {
startingGate = new Phaser(1+(3*i));
check(phaser.getPhase() == phase);
// register 3 more
phaser.register(); phaser.register(); phaser.register();
for (int z=0; z<(3*i); z++) {
arriverList.add(arrivers.next());
}
for (Arriver arriver : arriverList)
arriver.start();
toTheStartingGate();
phaser.arriveAndAwaitAdvance();
for (Arriver arriver : arriverList) {
arriver.join();
checkResult(arriver, null);
}
equal(phaser.getRegisteredParties(), 1 + (3*i));
equal(phaser.getArrivedParties(), 0);
arriverList.clear();
phase++;
}
startingGate = new Phaser(3);
} catch (Throwable t) { unexpected(t); }
timer.printElapsed();
//----------------------------------------------------------------
System.out.print("One thread timed out: ");
//----------------------------------------------------------------
try {
Phaser phaser = new Phaser(3);
Iterator<Arriver> arrivers = arriverIterator(phaser);
for (long timeout : new long[] { 0L, 12L }) {
Awaiter a1 = awaiter(phaser, timeout, MILLISECONDS);
a1.start();
Arriver a2 = arrivers.next();
a2.start();
toTheStartingGate();
a1.join();
checkResult(a1, TimeoutException.class);
phaser.arrive();
a2.join();
checkResult(a2, null);
check(!phaser.isTerminated());
}
} catch (Throwable t) { unexpected(t); }
timer.printElapsed();
//----------------------------------------------------------------
System.out.print("Barrier action completed normally: ");
//----------------------------------------------------------------
try {
final AtomicInteger count = new AtomicInteger(0);
final Phaser[] kludge = new Phaser[1];
Phaser phaser = new Phaser(3) {
@Override
protected boolean onAdvance(int phase, int registeredParties) {
int countPhase = count.getAndIncrement();
equal(countPhase, phase);
equal(kludge[0].getPhase(), phase);
equal(kludge[0].getRegisteredParties(), registeredParties);
if (phase >= 3)
return true; // terminate
return false;
}
};
kludge[0] = phaser;
equal(phaser.getRegisteredParties(), 3);
Iterator<Awaiter> awaiters = awaiterIterator(phaser);
for (int i = 0; i < 4; i++) {
Awaiter a1 = awaiters.next(); a1.start();
Awaiter a2 = awaiters.next(); a2.start();
toTheStartingGate();
while (phaser.getArrivedParties() < 2) Thread.yield();
phaser.arrive();
a1.join();
a2.join();
checkResult(a1, null);
checkResult(a2, null);
equal(count.get(), i+1);
if (i < 3) {
check(!phaser.isTerminated());
equal(phaser.getRegisteredParties(), 3);
equal(phaser.getArrivedParties(), 0);
equal(phaser.getUnarrivedParties(), 3);
equal(phaser.getPhase(), count.get());
} else
checkTerminated(phaser);
}
} catch (Throwable t) { unexpected(t); }
timer.printElapsed();
}
//--------------------- Infrastructure ---------------------------
/**
* A debugging tool to print stack traces of most threads, as jstack does.
* Uninteresting threads are filtered out.
*/
static void dumpTestThreads() {
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
System.err.println("------ stacktrace dump start ------");
for (ThreadInfo info : threadMXBean.dumpAllThreads(true, true)) {
String name = info.getThreadName();
if ("Signal Dispatcher".equals(name))
continue;
if ("Reference Handler".equals(name))
continue;
if ("Finalizer".equals(name))
continue;
if (name.startsWith("process reaper"))
continue;
if (name != null && name.startsWith("ForkJoinPool.commonPool-worker"))
continue;
System.err.print(info);
}
System.err.println("------ stacktrace dump end ------");
}
static volatile int passed = 0, failed = 0;
static void pass() {passed++;}
static void fail() {failed++; Thread.dumpStack();}
static void fail(String msg) {System.out.println(msg); fail();}
static void unexpected(Throwable t) {failed++; t.printStackTrace(); dumpTestThreads();}
static void check(boolean cond) {if (cond) pass(); else fail();}
static void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
try {realMain(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}

View file

@ -0,0 +1,150 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* @test
* @summary stress test for register/arriveAndDeregister
* @run main FickleRegister 300
*/
import java.util.ArrayList;
import java.util.concurrent.Phaser;
import java.util.concurrent.atomic.AtomicLong;
public class FickleRegister {
final AtomicLong count = new AtomicLong(0);
final long testDurationMillisDefault = 10_000L;
final long testDurationMillis;
final long quittingTimeNanos;
final int chunkSize = 1000;
FickleRegister(String[] args) {
testDurationMillis = (args.length > 0) ?
Long.valueOf(args[0]) : testDurationMillisDefault;
quittingTimeNanos = System.nanoTime() +
testDurationMillis * 1000L * 1000L;
}
class Runner extends CheckedRunnable {
final Phaser p;
Runner(Phaser phaser) { p = phaser; }
public void realRun() {
int prevPhase = -1;
for (int k = 1;; k++) {
for (int i = 0; i < chunkSize; i++) {
int phase = p.register();
if (phase < 0) break;
check(phase > prevPhase);
prevPhase = phase;
equal(phase, p.arriveAndDeregister());
check(phase < p.awaitAdvance(phase));
}
if (System.nanoTime() - quittingTimeNanos > 0) {
count.getAndAdd(k * chunkSize);
break;
}
}
}
}
void test(String[] args) throws Throwable {
final Phaser parent = new Phaser() {
protected boolean onAdvance(int phase, int parties) {
return false;
}
};
final Phaser child1 = new Phaser(parent);
final Phaser child2 = new Phaser(parent);
final Phaser subchild1 = new Phaser(child1);
final Phaser subchild2 = new Phaser(child2);
final Phaser[] phasers = {
parent, child1, child2, subchild1, subchild2
};
int reps = 4;
ArrayList<Thread> threads = new ArrayList<>();
for (int j = 0; j < reps; ++j) {
threads.add(new Thread(new Runner(subchild1)));
threads.add(new Thread(new Runner(child1)));
threads.add(new Thread(new Runner(parent)));
threads.add(new Thread(new Runner(child2)));
threads.add(new Thread(new Runner(subchild2)));
}
for (Thread thread : threads)
thread.start();
for (Thread thread : threads)
thread.join();
System.out.println("Parent: " + parent);
System.out.println("Child1: " + child1);
System.out.println("Child2: " + child2);
System.out.println("Subchild1: " + subchild1);
System.out.println("Subchild2: " + subchild2);
System.out.println("Iterations:" + count.get());
for (Phaser phaser : phasers) {
check(phaser.getPhase() > 0);
equal(0, phaser.getRegisteredParties());
equal(0, phaser.getUnarrivedParties());
equal(parent.getPhase(), phaser.getPhase());
}
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
new FickleRegister(args).instanceMain(args);}
public void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
abstract class CheckedRunnable implements Runnable {
protected abstract void realRun() throws Throwable;
public final void run() {
try {realRun();} catch (Throwable t) {unexpected(t);}
}
}
}

View file

@ -0,0 +1,159 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Martin Buchholz and Doug Lea with assistance from
* members of JCP JSR-166 Expert Group and released to the public
* domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* @test
* @modules java.base/java.util.concurrent:open
* @summary Test Phaser phase integer overflow behavior
*/
import java.util.concurrent.Phaser;
import java.lang.reflect.Field;
public class PhaseOverflow {
Field stateField;
void checkState(Phaser phaser,
int phase, int parties, int unarrived) {
equal(phase, phaser.getPhase());
equal(parties, phaser.getRegisteredParties());
equal(unarrived, phaser.getUnarrivedParties());
}
void test(String[] args) throws Throwable {
stateField = Phaser.class.getDeclaredField("state");
stateField.setAccessible(true);
testLeaf();
testTiered();
}
void testLeaf() throws Throwable {
Phaser phaser = new Phaser();
// this is extremely dependent on internal representation
stateField.setLong(phaser, ((Integer.MAX_VALUE - 1L) << 32) | 1L);
checkState(phaser, Integer.MAX_VALUE - 1, 0, 0);
phaser.register();
checkState(phaser, Integer.MAX_VALUE - 1, 1, 1);
phaser.arrive();
checkState(phaser, Integer.MAX_VALUE, 1, 1);
phaser.arrive();
checkState(phaser, 0, 1, 1);
phaser.arrive();
checkState(phaser, 1, 1, 1);
}
int phaseInc(int phase) { return (phase + 1) & Integer.MAX_VALUE; }
void testTiered() throws Throwable {
Phaser root = new Phaser();
// this is extremely dependent on internal representation
stateField.setLong(root, ((Integer.MAX_VALUE - 1L) << 32) | 1L);
checkState(root, Integer.MAX_VALUE - 1, 0, 0);
Phaser p1 = new Phaser(root, 1);
checkState(root, Integer.MAX_VALUE - 1, 1, 1);
checkState(p1, Integer.MAX_VALUE - 1, 1, 1);
Phaser p2 = new Phaser(root, 2);
checkState(root, Integer.MAX_VALUE - 1, 2, 2);
checkState(p2, Integer.MAX_VALUE - 1, 2, 2);
int ph = Integer.MAX_VALUE - 1;
for (int k = 0; k < 5; k++) {
checkState(root, ph, 2, 2);
checkState(p1, ph, 1, 1);
checkState(p2, ph, 2, 2);
p1.arrive();
checkState(root, ph, 2, 1);
checkState(p1, ph, 1, 0);
checkState(p2, ph, 2, 2);
p2.arrive();
checkState(root, ph, 2, 1);
checkState(p1, ph, 1, 0);
checkState(p2, ph, 2, 1);
p2.arrive();
ph = phaseInc(ph);
checkState(root, ph, 2, 2);
checkState(p1, ph, 1, 1);
checkState(p2, ph, 2, 2);
}
equal(3, ph);
}
void xtestTiered() throws Throwable {
Phaser root = new Phaser();
stateField.setLong(root, ((Integer.MAX_VALUE - 1L) << 32) | 1L);
checkState(root, Integer.MAX_VALUE - 1, 0, 0);
Phaser p1 = new Phaser(root, 1);
checkState(root, Integer.MAX_VALUE - 1, 1, 1);
checkState(p1, Integer.MAX_VALUE - 1, 1, 1);
Phaser p2 = new Phaser(root, 2);
checkState(root, Integer.MAX_VALUE - 1, 2, 2);
checkState(p2, Integer.MAX_VALUE - 1, 2, 2);
int ph = Integer.MAX_VALUE - 1;
for (int k = 0; k < 5; k++) {
checkState(root, ph, 2, 2);
checkState(p1, ph, 1, 1);
checkState(p2, ph, 2, 2);
p1.arrive();
checkState(root, ph, 2, 1);
checkState(p1, ph, 1, 0);
checkState(p2, ph, 2, 2);
p2.arrive();
checkState(root, ph, 2, 1);
checkState(p1, ph, 1, 0);
checkState(p2, ph, 2, 1);
p2.arrive();
ph = phaseInc(ph);
checkState(root, ph, 2, 2);
checkState(p1, ph, 1, 1);
checkState(p2, ph, 2, 2);
}
equal(3, ph);
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
new PhaseOverflow().instanceMain(args);}
public void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}

View file

@ -0,0 +1,117 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* @test
* @summary stress test for arrivals in a tiered phaser
* @run main TieredArriveLoops 300
*/
import java.util.concurrent.Phaser;
public class TieredArriveLoops {
final long testDurationMillisDefault = 10_000L;
final long testDurationMillis;
final long quittingTimeNanos;
TieredArriveLoops(String[] args) {
testDurationMillis = (args.length > 0) ?
Long.valueOf(args[0]) : testDurationMillisDefault;
quittingTimeNanos = System.nanoTime() +
testDurationMillis * 1000L * 1000L;
}
Runnable runner(final Phaser p) {
return new CheckedRunnable() { public void realRun() {
int prevPhase = p.register();
while (!p.isTerminated()) {
int phase = p.awaitAdvance(p.arrive());
if (phase < 0)
return;
equal(phase, (prevPhase + 1) & Integer.MAX_VALUE);
int ph = p.getPhase();
check(ph < 0 || ph == phase);
prevPhase = phase;
}
}};
}
void test(String[] args) throws Throwable {
final Phaser parent = new Phaser();
final Phaser child1 = new Phaser(parent);
final Phaser child2 = new Phaser(parent);
Thread t1 = new Thread(runner(child1));
Thread t2 = new Thread(runner(child2));
t1.start();
t2.start();
for (int prevPhase = 0, phase; ; prevPhase = phase) {
phase = child2.getPhase();
check(phase >= prevPhase);
if (System.nanoTime() - quittingTimeNanos > 0) {
System.err.printf("phase=%d%n", phase);
child1.forceTermination();
break;
}
}
t1.join();
t2.join();
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
new TieredArriveLoops(args).instanceMain(args);}
public void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
abstract class CheckedRunnable implements Runnable {
protected abstract void realRun() throws Throwable;
public final void run() {
try {realRun();} catch (Throwable t) {unexpected(t);}
}
}
}

View file

@ -0,0 +1,270 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Martin Buchholz with assistance from members of JCP
* JSR-166 Expert Group and released to the public domain, as
* explained at http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* @test
* @modules java.base/java.util.concurrent:open
* java.base/java.util:open
* @run testng WhiteBox
* @summary White box tests of implementation details
*/
import static org.testng.Assert.*;
import org.testng.annotations.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Consumer;
import java.util.function.Supplier;
@Test
public class WhiteBox {
final ThreadLocalRandom rnd = ThreadLocalRandom.current();
final VarHandle PQ_QUEUE = queueVarHandle(PriorityQueue.class);
final VarHandle PBQ_QUEUE = queueVarHandle(PriorityBlockingQueue.class);
VarHandle queueVarHandle(Class klazz) {
return findVarHandle(klazz, "queue", Object[].class);
}
VarHandle findVarHandle(Class klazz, String fieldName, Class type) {
try {
return MethodHandles.privateLookupIn(klazz, MethodHandles.lookup())
.findVarHandle(klazz, fieldName, type);
} catch (ReflectiveOperationException ex) { throw new Error(ex); }
}
Object[] queue(PriorityQueue q) {
return (Object[]) PQ_QUEUE.getOpaque(q);
}
Object[] queue(PriorityBlockingQueue q) {
return (Object[]) PBQ_QUEUE.getOpaque(q);
}
/** PriorityQueue and PriorityBlockingQueue have identical heap management. */
@Test
public void randomLockstep() {
PriorityBlockingQueue pbq = new PriorityBlockingQueue();
PriorityQueue pq = new PriorityQueue();
List<Consumer<Queue>> frobbers = List.of(
q -> q.add(42),
q -> assertTrue(q.offer(86)),
q -> q.poll(),
q -> q.peek(),
q -> {
Iterator it = q.iterator();
if (it.hasNext()) {
it.next();
it.remove();
}});
for (int i = 0; i < 100; i++) {
Consumer<Queue> frobber = frobbers.get(rnd.nextInt(frobbers.size()));
frobber.accept(pq);
frobber.accept(pbq);
assertInvariants(pbq);
assertInvariants(pq);
assertTrue(Arrays.equals(pq.toArray(), pbq.toArray()));
}
}
@Test
public void forgetMeNot_PriorityQueue() {
forgetMeNot(() -> new PriorityQueue());
forgetMeNot(() -> new PriorityQueue(rnd.nextInt(1, 100)));
forgetMeNot(() -> new PriorityQueue(rnd.nextInt(1, 100), Collections.reverseOrder()));
}
@Test
public void forgetMeNot_PriorityBlockingQueue() {
forgetMeNot(() -> new PriorityBlockingQueue());
forgetMeNot(() -> new PriorityBlockingQueue(rnd.nextInt(1, 100)));
forgetMeNot(() -> new PriorityBlockingQueue(rnd.nextInt(1, 100), Collections.reverseOrder()));
}
void forgetMeNot(Supplier<Queue> qMaker) {
Queue q = qMaker.get();
Set replay = Collections.newSetFromMap(new IdentityHashMap());
int size = rnd.nextInt(64);
for (int i = 0; i < size; i++) {
Object e = new Integer(rnd.nextInt());
q.add(e);
replay.add(e);
}
Iterator it = q.iterator();
while (it.hasNext()) {
Object e = it.next();
assertTrue(replay.contains(e));
if (rnd.nextBoolean()) {
it.remove();
if (rnd.nextBoolean())
assertThrows(IllegalStateException.class,
() -> it.remove());
assertTrue(replay.remove(e));
}
assertInvariants(q);
}
for (Object e; (e = q.poll()) != null; )
assertTrue(replay.remove(e));
assertTrue(replay.isEmpty());
}
@Test
public void testRemoveIf_PriorityQueue() {
testRemoveIf(() -> new PriorityQueue());
testRemoveIf(() -> new PriorityQueue(rnd.nextInt(1, 100)));
testRemoveIf(() -> new PriorityQueue(rnd.nextInt(1, 100), Collections.reverseOrder()));
}
@Test
public void testRemoveIf_PriorityBlockingQueue() {
testRemoveIf(() -> new PriorityBlockingQueue());
testRemoveIf(() -> new PriorityBlockingQueue(rnd.nextInt(1, 100)));
testRemoveIf(() -> new PriorityBlockingQueue(rnd.nextInt(1, 100), Collections.reverseOrder()));
}
void testRemoveIf(Supplier<Queue> qMaker) {
Queue q = qMaker.get();
Set replay = Collections.newSetFromMap(new IdentityHashMap());
int size = rnd.nextInt(64);
for (int i = 0; i < size; i++) {
Object e = new Integer(rnd.nextInt());
q.add(e);
replay.add(e);
}
q.removeIf(
e -> {
if (rnd.nextBoolean())
return false;
assertTrue(replay.remove(e));
return true;
});
assertInvariants(q);
for (Object e; (e = q.poll()) != null; )
assertTrue(replay.remove(e));
assertTrue(replay.isEmpty());
}
byte[] serialBytes(Object o) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(o);
oos.flush();
oos.close();
return bos.toByteArray();
} catch (Exception fail) {
throw new AssertionError(fail);
}
}
@SuppressWarnings("unchecked")
<T> T serialClone(T o) {
try {
ObjectInputStream ois = new ObjectInputStream
(new ByteArrayInputStream(serialBytes(o)));
T clone = (T) ois.readObject();
assertNotSame(o, clone);
assertSame(o.getClass(), clone.getClass());
return clone;
} catch (Exception fail) {
throw new AssertionError(fail);
}
}
@Test
public void testSerialization() {
assertInvariants(serialClone(new PriorityQueue()));
assertInvariants(serialClone(new PriorityQueue(1)));
assertInvariants(serialClone(new PriorityQueue(new ArrayList())));
assertInvariants(serialClone(new PriorityBlockingQueue()));
assertInvariants(serialClone(new PriorityBlockingQueue(1)));
assertInvariants(serialClone(new PriorityBlockingQueue(new ArrayList())));
}
void assertInvariants(Queue q) {
if (q instanceof PriorityQueue)
assertInvariants((PriorityQueue) q);
else
assertInvariants((PriorityBlockingQueue) q);
}
void assertInvariants(PriorityBlockingQueue q) {
assertHeap(queue(q), q.size(), q.comparator());
}
void assertInvariants(PriorityQueue q) {
assertHeap(queue(q), q.size(), q.comparator());
}
void assertHeap(Object[] es, int size, Comparator cmp) {
assertTrue(es.length > 0);
assertTrue(size >= 0 && size <= es.length);
if (size < es.length)
assertNull(es[size]);
if (size > 0)
assertNotNull(es[size - 1]);
for (int i = 0; i <= size / 2; i++) {
int leftChild = 2 * i + 1;
int rightChild = leftChild + 1;
if (leftChild < size)
assertTrue(cmp(es[i], es[leftChild], cmp) <= 0);
if (rightChild < size)
assertTrue(cmp(es[i], es[rightChild], cmp) <= 0);
}
}
int cmp(Object x, Object y, Comparator cmp) {
return (cmp == null)
? ((Comparable) x).compareTo(y)
: cmp.compare(x, y);
}
}

View file

@ -0,0 +1,117 @@
/*
* Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6602600
* @run main/othervm/timeout=480 -Xmx64m BasicCancelTest
* @summary Check effectiveness of RemoveOnCancelPolicy
*/
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* Simple timer cancellation test. Submits tasks to a scheduled executor
* service and immediately cancels them.
*/
public class BasicCancelTest {
void checkShutdown(final ExecutorService es) {
final Runnable nop = new Runnable() {public void run() {}};
try {
if (new Random().nextBoolean()) {
check(es.isShutdown());
if (es instanceof ThreadPoolExecutor)
check(((ThreadPoolExecutor) es).isTerminating()
|| es.isTerminated());
THROWS(RejectedExecutionException.class,
new F(){void f(){es.execute(nop);}});
}
} catch (Throwable t) { unexpected(t); }
}
void checkTerminated(final ThreadPoolExecutor tpe) {
try {
checkShutdown(tpe);
check(tpe.getQueue().isEmpty());
check(tpe.isTerminated());
check(! tpe.isTerminating());
equal(tpe.getActiveCount(), 0);
equal(tpe.getPoolSize(), 0);
equal(tpe.getTaskCount(), tpe.getCompletedTaskCount());
check(tpe.awaitTermination(0L, TimeUnit.SECONDS));
} catch (Throwable t) { unexpected(t); }
}
void test(String[] args) throws Throwable {
final ScheduledThreadPoolExecutor pool =
new ScheduledThreadPoolExecutor(1);
// Needed to avoid OOME
pool.setRemoveOnCancelPolicy(true);
final long moreThanYouCanChew = Runtime.getRuntime().maxMemory() / 32;
System.out.printf("moreThanYouCanChew=%d%n", moreThanYouCanChew);
Runnable noopTask = new Runnable() { public void run() {}};
for (long i = 0; i < moreThanYouCanChew; i++)
pool.schedule(noopTask, 10, TimeUnit.MINUTES).cancel(true);
pool.shutdown();
check(pool.awaitTermination(1L, TimeUnit.DAYS));
checkTerminated(pool);
equal(pool.getTaskCount(), 0L);
equal(pool.getCompletedTaskCount(), 0L);
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
new BasicCancelTest().instanceMain(args);}
void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
abstract class F {abstract void f() throws Throwable;}
void THROWS(Class<? extends Throwable> k, F... fs) {
for (F f : fs)
try {f.f(); fail("Expected " + k.getName() + " not thrown");}
catch (Throwable t) {
if (k.isAssignableFrom(t.getClass())) pass();
else unexpected(t);}}
}

View file

@ -0,0 +1,113 @@
/*
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6560953
* @summary Test ScheduledThreadPoolExecutor.decorateTask
*/
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Delayed;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.RunnableScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
public class DecorateTask {
Runnable countDownTask(final CountDownLatch latch) {
return new Runnable() { public void run() {
latch.countDown();
if (latch.getCount() <= 0)
throw new RuntimeException("done");
}};}
void test(String[] args) throws Throwable {
final int jobs = 100;
final AtomicInteger decoratorCount = new AtomicInteger(0);
final ScheduledThreadPoolExecutor pool =
new ScheduledThreadPoolExecutor(10) {
protected <V> RunnableScheduledFuture<V> decorateTask(
final Runnable runnable,
final RunnableScheduledFuture<V> task) {
return new RunnableScheduledFuture<V>() {
public void run() {
decoratorCount.incrementAndGet();
task.run();
}
public boolean isPeriodic() {
return task.isPeriodic();
}
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 {
return task.get();
}
public V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
return task.get(timeout, unit);
}
public long getDelay(TimeUnit unit) {
return task.getDelay(unit);
}
public int compareTo(Delayed o) {
return task.compareTo(o);
}};}};
final CountDownLatch latch1 = new CountDownLatch(jobs);
final CountDownLatch latch2 = new CountDownLatch(jobs);
pool.scheduleAtFixedRate(countDownTask(latch1), 0L, 1L, TimeUnit.NANOSECONDS);
pool.scheduleWithFixedDelay(countDownTask(latch2), 0L, 1L, TimeUnit.NANOSECONDS);
latch1.await();
latch2.await();
pool.shutdown();
pool.awaitTermination(1L, TimeUnit.MINUTES);
equal(decoratorCount.get(), 2 * jobs);
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
new DecorateTask().instanceMain(args);}
void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}

View file

@ -0,0 +1,178 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* @test
* @bug 6725789
* @summary Check for long overflow in task time comparison.
* @library /test/lib
*/
import static java.util.concurrent.TimeUnit.DAYS;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import jdk.test.lib.Utils;
public class DelayOverflow {
static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
static void waitForNanoTimeTick() {
for (long t0 = System.nanoTime(); t0 == System.nanoTime(); )
;
}
void scheduleNow(ScheduledThreadPoolExecutor pool,
Runnable r, int how) {
switch (how) {
case 0:
pool.schedule(r, 0, MILLISECONDS);
break;
case 1:
pool.schedule(Executors.callable(r), 0, DAYS);
break;
case 2:
pool.scheduleWithFixedDelay(r, 0, 1000, NANOSECONDS);
break;
case 3:
pool.scheduleAtFixedRate(r, 0, 1000, MILLISECONDS);
break;
default:
fail(String.valueOf(how));
}
}
void scheduleAtTheEndOfTime(ScheduledThreadPoolExecutor pool,
Runnable r, int how) {
switch (how) {
case 0:
pool.schedule(r, Long.MAX_VALUE, MILLISECONDS);
break;
case 1:
pool.schedule(Executors.callable(r), Long.MAX_VALUE, DAYS);
break;
case 2:
pool.scheduleWithFixedDelay(r, Long.MAX_VALUE, 1000, NANOSECONDS);
break;
case 3:
pool.scheduleAtFixedRate(r, Long.MAX_VALUE, 1000, MILLISECONDS);
break;
default:
fail(String.valueOf(how));
}
}
/**
* Attempts to test exhaustively and deterministically, all 20
* possible ways that one task can be scheduled in the maximal
* distant future, while at the same time an existing task's time
* has already expired.
*/
void test(String[] args) throws Throwable {
for (int nowHow = 0; nowHow < 4; nowHow++) {
for (int thenHow = 0; thenHow < 4; thenHow++) {
final ScheduledThreadPoolExecutor pool
= new ScheduledThreadPoolExecutor(1);
final CountDownLatch runLatch = new CountDownLatch(1);
final CountDownLatch busyLatch = new CountDownLatch(1);
final CountDownLatch proceedLatch = new CountDownLatch(1);
final Runnable notifier = new Runnable() {
public void run() { runLatch.countDown(); }};
final Runnable neverRuns = new Runnable() {
public void run() { fail(); }};
final Runnable keepPoolBusy = new Runnable() {
public void run() {
try {
busyLatch.countDown();
proceedLatch.await();
} catch (Throwable t) { unexpected(t); }
}};
pool.schedule(keepPoolBusy, 0, DAYS);
busyLatch.await();
scheduleNow(pool, notifier, nowHow);
waitForNanoTimeTick();
scheduleAtTheEndOfTime(pool, neverRuns, thenHow);
proceedLatch.countDown();
check(runLatch.await(LONG_DELAY_MS, MILLISECONDS));
equal(runLatch.getCount(), 0L);
pool.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
pool.shutdown();
}
final int nowHowCopy = nowHow;
final ScheduledThreadPoolExecutor pool
= new ScheduledThreadPoolExecutor(1);
final CountDownLatch runLatch = new CountDownLatch(1);
final Runnable notifier = new Runnable() {
public void run() { runLatch.countDown(); }};
final Runnable scheduleNowScheduler = new Runnable() {
public void run() {
try {
scheduleNow(pool, notifier, nowHowCopy);
waitForNanoTimeTick();
} catch (Throwable t) { unexpected(t); }
}};
pool.scheduleWithFixedDelay(scheduleNowScheduler,
0, Long.MAX_VALUE, NANOSECONDS);
check(runLatch.await(LONG_DELAY_MS, MILLISECONDS));
equal(runLatch.getCount(), 0L);
pool.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
pool.shutdown();
}
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
new DelayOverflow().instanceMain(args);}
void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}

View file

@ -0,0 +1,141 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea 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/publicdomain/zero/1.0/
*/
/*
* @test
* @summary Ensure that waiting pool threads don't retain refs to tasks.
*/
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Delayed;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.RunnableScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class GCRetention {
/**
* A custom thread pool with a custom RunnableScheduledFuture, for the
* sole purpose of ensuring that the task retains a strong reference to
* the Runnable even after cancellation.
*/
static class CustomPool extends ScheduledThreadPoolExecutor {
CustomPool(int n) { super(n); }
protected <V> RunnableScheduledFuture<V> decorateTask(
final Runnable r,
final RunnableScheduledFuture<V> task) {
return new RunnableScheduledFuture<V>() {
public void run() { System.err.println(r); task.run(); }
public boolean isPeriodic() { return task.isPeriodic(); }
public V get()
throws InterruptedException,ExecutionException
{ return task.get(); }
public V get(long x, TimeUnit y)
throws InterruptedException,ExecutionException,TimeoutException
{ return task.get(x, y); }
public boolean isDone() { return task.isDone(); }
public boolean isCancelled() { return task.isCancelled(); }
public boolean cancel(boolean x) { return task.cancel(x); }
public long getDelay(TimeUnit x) { return task.getDelay(x); }
public int compareTo(Delayed x) { return task.compareTo(x); }
};
}
}
void removeAll(ReferenceQueue<?> q, int n) throws InterruptedException {
for (int j = n; j--> 0; ) {
if (q.poll() == null) {
for (;;) {
System.gc();
if (q.remove(1000) != null)
break;
System.out.printf(
"%d/%d unqueued references remaining%n", j + 1, n);
}
}
}
check(q.poll() == null);
}
void test(String[] args) throws Throwable {
final CustomPool pool = new CustomPool(10);
final int size = 100;
final ReferenceQueue<Object> q = new ReferenceQueue<>();
final List<WeakReference<?>> refs = new ArrayList<>(size);
final List<Future<?>> futures = new ArrayList<>(size);
// Schedule custom tasks with strong references.
class Task implements Runnable {
final Object x;
Task() { refs.add(new WeakReference<>(x = new Object(), q)); }
public void run() { System.out.println(x); }
}
// Give tasks added later earlier expiration, to ensure
// multiple residents of queue head.
for (int i = size; i--> 0; )
futures.add(pool.schedule(new Task(), i + 1, TimeUnit.MINUTES));
futures.forEach(future -> future.cancel(false));
futures.clear();
pool.purge();
removeAll(q, size);
for (WeakReference<?> ref : refs) check(ref.get() == null);
pool.shutdown();
// rely on test harness to handle timeout
pool.awaitTermination(1L, TimeUnit.DAYS);
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
new GCRetention().instanceMain(args);}
void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}

View file

@ -0,0 +1,54 @@
/*
* Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.concurrent.ScheduledThreadPoolExecutor;
/**
* This is not a regression test, but a stress benchmark test for
* 6602600: Fast removal of cancelled scheduled thread pool tasks
*
* This runs in the same wall clock time, but much reduced cpu time,
* with the changes for 6602600.
*/
public class Stress {
public static void main(String[] args) throws Throwable {
final CountDownLatch count = new CountDownLatch(1000);
final ScheduledThreadPoolExecutor pool =
new ScheduledThreadPoolExecutor(100);
pool.prestartAllCoreThreads();
final Runnable incTask = new Runnable() { public void run() {
count.countDown();
}};
pool.scheduleAtFixedRate(incTask, 0, 10, TimeUnit.MILLISECONDS);
count.await();
pool.shutdown();
pool.awaitTermination(1L, TimeUnit.DAYS);
}
}

View file

@ -0,0 +1,87 @@
/*
* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 7091003
* @summary ScheduledExecutorService never executes Runnable
* with corePoolSize of zero
* @library /test/lib
* @author Chris Hegarty
*/
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import jdk.test.lib.Utils;
/**
* Verify that tasks can be run even with a core pool size of 0.
*/
public class ZeroCorePoolSize {
static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
volatile boolean taskRun;
void test(String[] args) throws Throwable {
ScheduledThreadPoolExecutor pool = new ScheduledThreadPoolExecutor(0);
Runnable task = new Runnable() {
public void run() {
taskRun = true;
}
};
check(pool.getCorePoolSize() == 0);
pool.schedule(task, 12L, MILLISECONDS);
pool.shutdown();
check(pool.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
check(pool.getCorePoolSize() == 0);
check(taskRun);
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
new ZeroCorePoolSize().instanceMain(args);}
void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
abstract class F {abstract void f() throws Throwable;}
void THROWS(Class<? extends Throwable> k, F... fs) {
for (F f : fs)
try {f.f(); fail("Expected " + k.getName() + " not thrown");}
catch (Throwable t) {
if (k.isAssignableFrom(t.getClass())) pass();
else unexpected(t);}}
}

View file

@ -0,0 +1,142 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Martin Buchholz with assistance from members of JCP
* JSR-166 Expert Group and released to the public domain, as
* explained at http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* @test
* @bug 8022642 8065320 8129861
* @summary Ensure relative sanity when zero core threads
* @library /test/lib
* @modules java.base/java.util.concurrent:open
*/
import static java.util.concurrent.TimeUnit.HOURS;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import java.lang.reflect.Field;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.BooleanSupplier;
import jdk.test.lib.Utils;
public class ZeroCoreThreads {
static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
static long millisElapsedSince(long startTime) {
return (System.nanoTime() - startTime) / (1000L * 1000L);
}
static void spinWaitUntil(BooleanSupplier predicate, long timeoutMillis) {
long startTime = -1L;
while (!predicate.getAsBoolean()) {
if (startTime == -1L)
startTime = System.nanoTime();
else if (millisElapsedSince(startTime) > timeoutMillis)
throw new AssertionError(
String.format("timed out after %s ms", timeoutMillis));
Thread.yield();
}
}
static boolean hasWaiters(ReentrantLock lock, Condition condition) {
lock.lock();
try {
return lock.hasWaiters(condition);
} finally {
lock.unlock();
}
}
static void awaitHasWaiters(ReentrantLock lock, Condition condition,
long timeoutMillis) {
spinWaitUntil(() -> hasWaiters(lock, condition), timeoutMillis);
}
static <T> T getField(Object x, String fieldName) {
try {
Field field = x.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
return (T) field.get(x);
} catch (ReflectiveOperationException ex) {
throw new AssertionError(ex);
}
}
void test(String[] args) throws Throwable {
ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(0);
try {
test(p);
} finally {
p.shutdownNow();
check(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
}
}
void test(ScheduledThreadPoolExecutor p) throws Throwable {
Runnable dummy = new Runnable() { public void run() {
throw new AssertionError("shouldn't get here"); }};
BlockingQueue q = p.getQueue();
ReentrantLock lock = getField(q, "lock");
Condition available = getField(q, "available");
equal(0, p.getPoolSize());
equal(0, p.getLargestPoolSize());
equal(0L, p.getTaskCount());
equal(0L, p.getCompletedTaskCount());
p.schedule(dummy, 1L, HOURS);
// Ensure one pool thread actually waits in timed queue poll
awaitHasWaiters(lock, available, LONG_DELAY_MS);
equal(1, p.getPoolSize());
equal(1, p.getLargestPoolSize());
equal(1L, p.getTaskCount());
equal(0L, p.getCompletedTaskCount());
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
new ZeroCoreThreads().instanceMain(args);}
void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}

View file

@ -0,0 +1,102 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* @test
* @bug 6941130
* @summary Numeric overflow/underflow of permits causes Error throw
*/
import java.util.concurrent.Semaphore;
public class PermitOverflow {
public static void main(String[] args) throws Throwable {
for (boolean fair : new boolean[] { true, false }) {
Semaphore sem = new Semaphore(Integer.MAX_VALUE - 1, fair);
if (sem.availablePermits() != Integer.MAX_VALUE - 1)
throw new RuntimeException();
try {
sem.release(2);
throw new RuntimeException();
} catch (Error expected) {
}
sem.release(1);
if (sem.availablePermits() != Integer.MAX_VALUE)
throw new RuntimeException();
try {
sem.release(1);
throw new RuntimeException();
} catch (Error expected) {
}
try {
sem.release(Integer.MAX_VALUE);
throw new RuntimeException();
} catch (Error expected) {
}
}
class Sem extends Semaphore {
public Sem(int permits, boolean fair) {
super(permits, fair);
}
public void reducePermits(int reduction) {
super.reducePermits(reduction);
}
}
for (boolean fair : new boolean[] { true, false }) {
Sem sem = new Sem(Integer.MIN_VALUE + 1, fair);
if (sem.availablePermits() != Integer.MIN_VALUE + 1)
throw new RuntimeException();
try {
sem.reducePermits(2);
throw new RuntimeException();
} catch (Error expected) {
}
sem.reducePermits(1);
if (sem.availablePermits() != Integer.MIN_VALUE)
throw new RuntimeException();
try {
sem.reducePermits(1);
throw new RuntimeException();
} catch (Error expected) {
}
try {
sem.reducePermits(Integer.MAX_VALUE);
throw new RuntimeException();
} catch (Error expected) {
}
}
}
}

View file

@ -0,0 +1,116 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* @test
* @bug 6801020 6803402
* @summary Try to tickle race conditions in
* AbstractQueuedSynchronizer "shared" code
*/
import java.util.concurrent.Semaphore;
public class RacingReleases {
/** Increase this for better chance of tickling races */
static final int iterations = 1000;
public static void test(final boolean fair,
final boolean interruptibly)
throws Throwable {
for (int i = 0; i < iterations; i++) {
final Semaphore sem = new Semaphore(0, fair);
final Throwable[] badness = new Throwable[1];
Runnable blocker = interruptibly ?
new Runnable() {
public void run() {
try {
sem.acquire();
} catch (Throwable t) {
badness[0] = t;
throw new Error(t);
}}}
:
new Runnable() {
public void run() {
try {
sem.acquireUninterruptibly();
} catch (Throwable t) {
badness[0] = t;
throw new Error(t);
}}};
Thread b1 = new Thread(blocker);
Thread b2 = new Thread(blocker);
Runnable signaller = new Runnable() {
public void run() {
try {
sem.release();
} catch (Throwable t) {
badness[0] = t;
throw new Error(t);
}}};
Thread s1 = new Thread(signaller);
Thread s2 = new Thread(signaller);
Thread[] threads = { b1, b2, s1, s2 };
java.util.Collections.shuffle(java.util.Arrays.asList(threads));
for (Thread thread : threads)
thread.start();
for (Thread thread : threads) {
thread.join(60 * 1000);
if (thread.isAlive())
throw new Error
(String.format
("Semaphore stuck: permits %d, thread waiting %s%n",
sem.availablePermits(),
sem.hasQueuedThreads() ? "true" : "false"));
}
if (badness[0] != null)
throw new Error(badness[0]);
if (sem.availablePermits() != 0)
throw new Error(String.valueOf(sem.availablePermits()));
if (sem.hasQueuedThreads())
throw new Error(String.valueOf(sem.hasQueuedThreads()));
if (sem.getQueueLength() != 0)
throw new Error(String.valueOf(sem.getQueueLength()));
if (sem.isFair() != fair)
throw new Error(String.valueOf(sem.isFair()));
}
}
public static void main(String[] args) throws Throwable {
for (boolean fair : new boolean[] { true, false })
for (boolean interruptibly : new boolean[] { true, false })
test(fair, interruptibly);
}
}

View file

@ -0,0 +1,103 @@
/*
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary Stress test of StructuredTaskScope cancellation with running and starting threads
* @enablePreview
* @run junit StressCancellation
*/
import java.time.Duration;
import java.util.concurrent.StructuredTaskScope;
import java.util.concurrent.StructuredTaskScope.Joiner;
import java.util.concurrent.StructuredTaskScope.Subtask;
import java.util.concurrent.ThreadFactory;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import static org.junit.jupiter.api.Assertions.*;
class StressCancellation {
static Stream<Arguments> testCases() {
Stream<ThreadFactory> factories = Stream.of(
Thread.ofPlatform().factory(),
Thread.ofVirtual().factory()
);
// 0..15 forks before shutdown, 0..15 forks after shutdown
return factories.flatMap(f -> IntStream.range(0, 256)
.mapToObj(x -> Arguments.of(f, x & 0x0F, (x & 0xF0) >> 4)));
}
/**
* Test StructuredTaskScope cancellation with running threads and concurrently with
* threads that are starting. The cancellation should interrupt all running threads,
* join should wakeup, and close would complete quickly.
*
* @param factory the ThreadFactory to use
* @param beforeCancel the number of subtasks to fork before cancel
* @param afterCancel the number of subtasks to fork after cancel
*/
@ParameterizedTest
@MethodSource("testCases")
void test(ThreadFactory factory, int beforeCancel, int afterCancel) throws Exception {
var joiner = new Joiner<Boolean, Void>() {
@Override
public boolean onComplete(Subtask<Boolean> subtask) {
boolean cancel = subtask.get();
return cancel;
}
@Override
public Void result() {
return null;
}
};
try (var scope = StructuredTaskScope.open(joiner, cf -> cf.withThreadFactory(factory))) {
// fork subtasks
for (int i = 0; i < beforeCancel; i++) {
scope.fork(() -> {
Thread.sleep(Duration.ofDays(1));
return false;
});
}
// fork subtask to cancel
scope.fork(() -> true);
// fork after forking subtask to cancel
for (int i = 0; i < afterCancel; i++) {
scope.fork(() -> {
Thread.sleep(Duration.ofDays(1));
return false;
});
}
scope.join();
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,198 @@
/*
* Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8284199 8296779 8306647
* @summary Test thread dumps with StructuredTaskScope
* @enablePreview
* @library /test/lib
* @run junit/othervm StructuredThreadDumpTest
*/
import java.util.concurrent.StructuredTaskScope;
import java.util.concurrent.StructuredTaskScope.Joiner;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.LockSupport;
import java.util.stream.Stream;
import com.sun.management.HotSpotDiagnosticMXBean;
import com.sun.management.HotSpotDiagnosticMXBean.ThreadDumpFormat;
import jdk.test.lib.threaddump.ThreadDump;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class StructuredThreadDumpTest {
/**
* Test that a thread dump with a tree of task scopes contains a thread grouping for
* each task scope.
*/
@Test
void testTree() throws Exception {
try (var scope = StructuredTaskScope.open(Joiner.awaitAll(), cf -> cf.withName("scope"))) {
Thread thread1 = fork(scope, "child-scope-A");
Thread thread2 = fork(scope, "child-scope-B");
try {
ThreadDump threadDump = threadDump();
// thread dump should have a thread container for each scope
var rootContainer = threadDump.rootThreadContainer();
var container1 = threadDump.findThreadContainer("scope").orElseThrow();
var container2 = threadDump.findThreadContainer("child-scope-A").orElseThrow();
var container3 = threadDump.findThreadContainer("child-scope-B").orElseThrow();
// check parents
assertFalse(rootContainer.parent().isPresent());
assertTrue(container1.parent().get() == rootContainer);
assertTrue(container2.parent().get() == container1);
assertTrue(container3.parent().get() == container1);
// check owners
assertFalse(rootContainer.owner().isPresent());
assertTrue(container1.owner().getAsLong() == Thread.currentThread().threadId());
assertTrue(container2.owner().getAsLong() == thread1.threadId());
assertTrue(container3.owner().getAsLong() == thread2.threadId());
// thread1 and threads2 should be in threads array of "scope"
container1.findThread(thread1.threadId()).orElseThrow();
container1.findThread(thread2.threadId()).orElseThrow();
} finally {
LockSupport.unpark(thread1);
LockSupport.unpark(thread2);
scope.join();
}
}
}
/**
* Test that a thread dump with nested tasks scopes contains a thread grouping for
* each task scope.
*/
@Test
void testNested() throws Exception {
try (var scope1 = StructuredTaskScope.open(Joiner.awaitAll(), cf -> cf.withName("scope-A"))) {
Thread thread1 = fork(scope1);
try (var scope2 = StructuredTaskScope.open(Joiner.awaitAll(), cf -> cf.withName("scope-B"))) {
Thread thread2 = fork(scope2);
try {
ThreadDump threadDump = threadDump();
// thread dump should have a thread container for both scopes
var rootContainer = threadDump.rootThreadContainer();
var container1 = threadDump.findThreadContainer("scope-A").orElseThrow();
var container2 = threadDump.findThreadContainer("scope-B").orElseThrow();
// check parents
assertFalse(rootContainer.parent().isPresent());
assertTrue(container1.parent().get() == rootContainer);
assertTrue(container2.parent().get() == container1);
// check owners
long tid = Thread.currentThread().threadId();
assertFalse(rootContainer.owner().isPresent());
assertTrue(container1.owner().getAsLong() == tid);
assertTrue(container2.owner().getAsLong() == tid);
// thread1 should be in threads array of "scope-A"
container1.findThread(thread1.threadId()).orElseThrow();
// thread2 should be in threads array of "scope-B"
container2.findThread(thread2.threadId()).orElseThrow();
} finally {
LockSupport.unpark(thread2);
scope2.join();
}
} finally {
LockSupport.unpark(thread1);
scope1.join();
}
}
}
/**
* Generates a JSON formatted thread dump to a temporary file, prints it to standard
* output, parses the JSON text and returns a ThreadDump object for the thread dump.
*/
private static ThreadDump threadDump() throws IOException {
Path dir = Path.of(".").toAbsolutePath();
Path file = Files.createTempFile(dir, "threadump", "json");
Files.delete(file);
ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class)
.dumpThreads(file.toString(), ThreadDumpFormat.JSON);
try (Stream<String> stream = Files.lines(file)) {
stream.forEach(System.out::println);
}
String jsonText = Files.readString(file);
return ThreadDump.parse(jsonText);
}
/**
* Forks a subtask in the given scope that parks, returning the Thread that executes
* the subtask.
*/
private static Thread fork(StructuredTaskScope<Object, Void> scope) throws Exception {
var ref = new AtomicReference<Thread>();
scope.fork(() -> {
ref.set(Thread.currentThread());
LockSupport.park();
return null;
});
Thread thread;
while ((thread = ref.get()) == null) {
Thread.sleep(10);
}
return thread;
}
/**
* Forks a subtask in the given scope. The subtask creates a new child scope with
* the given name, then parks. This method returns Thread that executes the subtask.
*/
private static Thread fork(StructuredTaskScope<Object, Void> scope,
String childScopeName) throws Exception {
var ref = new AtomicReference<Thread>();
scope.fork(() -> {
try (var childScope = StructuredTaskScope.open(Joiner.awaitAll(),
cf -> cf.withName(childScopeName))) {
ref.set(Thread.currentThread());
LockSupport.park();
}
});
Thread thread;
while ((thread = ref.get()) == null) {
Thread.sleep(10);
}
return thread;
}
}

View file

@ -0,0 +1,224 @@
/*
* Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8284199 8296779 8306647
* @summary Basic tests for StructuredTaskScope with scoped values
* @enablePreview
* @run junit WithScopedValue
*/
import java.util.concurrent.StructuredTaskScope;
import java.util.concurrent.StructuredTaskScope.Subtask;
import java.util.concurrent.StructuredTaskScope.Joiner;
import java.util.concurrent.StructureViolationException;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import static org.junit.jupiter.api.Assertions.*;
class WithScopedValue {
private static Stream<ThreadFactory> factories() {
return Stream.of(Thread.ofPlatform().factory(), Thread.ofVirtual().factory());
}
/**
* Test that fork inherits a scoped value into a child thread.
*/
@ParameterizedTest
@MethodSource("factories")
void testForkInheritsScopedValue1(ThreadFactory factory) throws Exception {
ScopedValue<String> name = ScopedValue.newInstance();
String value = ScopedValue.where(name, "x").call(() -> {
try (var scope = StructuredTaskScope.open(Joiner.awaitAll(),
cf -> cf.withThreadFactory(factory))) {
Subtask<String> subtask = scope.fork(() -> {
return name.get(); // child should read "x"
});
scope.join();
return subtask.get();
}
});
assertEquals(value, "x");
}
/**
* Test that fork inherits a scoped value into a grandchild thread.
*/
@ParameterizedTest
@MethodSource("factories")
void testForkInheritsScopedValue2(ThreadFactory factory) throws Exception {
ScopedValue<String> name = ScopedValue.newInstance();
String value = ScopedValue.where(name, "x").call(() -> {
try (var scope1 = StructuredTaskScope.open(Joiner.awaitAll(),
cf -> cf.withThreadFactory(factory))) {
Subtask<String> subtask1 = scope1.fork(() -> {
try (var scope2 = StructuredTaskScope.open(Joiner.awaitAll(),
cf -> cf.withThreadFactory(factory))) {
Subtask<String> subtask2 = scope2.fork(() -> {
return name.get(); // grandchild should read "x"
});
scope2.join();
return subtask2.get();
}
});
scope1.join();
return subtask1.get();
}
});
assertEquals(value, "x");
}
/**
* Test that fork inherits a rebound scoped value into a grandchild thread.
*/
@ParameterizedTest
@MethodSource("factories")
void testForkInheritsScopedValue3(ThreadFactory factory) throws Exception {
ScopedValue<String> name = ScopedValue.newInstance();
String value = ScopedValue.where(name, "x").call(() -> {
try (var scope1 = StructuredTaskScope.open(Joiner.awaitAll(),
cf -> cf.withThreadFactory(factory))) {
Subtask<String> subtask1 = scope1.fork(() -> {
assertEquals(name.get(), "x"); // child should read "x"
// rebind name to "y"
String grandchildValue = ScopedValue.where(name, "y").call(() -> {
try (var scope2 = StructuredTaskScope.open(Joiner.awaitAll(),
cf -> cf.withThreadFactory(factory))) {
Subtask<String> subtask2 = scope2.fork(() -> {
return name.get(); // grandchild should read "y"
});
scope2.join();
return subtask2.get();
}
});
assertEquals(name.get(), "x"); // child should read "x"
return grandchildValue;
});
scope1.join();
return subtask1.get();
}
});
assertEquals(value, "y");
}
/**
* Test exiting a dynamic scope with an open task scope.
*/
@Test
void testStructureViolation1() throws Exception {
ScopedValue<String> name = ScopedValue.newInstance();
class Box {
StructuredTaskScope<Object, Void> scope;
}
var box = new Box();
try {
try {
ScopedValue.where(name, "x").run(() -> {
box.scope = StructuredTaskScope.open(Joiner.awaitAll());
});
fail();
} catch (StructureViolationException expected) { }
// underlying flock should be closed and fork should fail to start a thread
StructuredTaskScope<Object, Void> scope = box.scope;
AtomicBoolean ran = new AtomicBoolean();
Subtask<Object> subtask = scope.fork(() -> {
ran.set(true);
return null;
});
scope.join();
assertEquals(Subtask.State.UNAVAILABLE, subtask.state());
assertFalse(ran.get());
} finally {
StructuredTaskScope<Object, Void> scope = box.scope;
if (scope != null) {
scope.close();
}
}
}
/**
* Test closing a StructuredTaskScope while executing in a dynamic scope.
*/
@Test
void testStructureViolation2() throws Exception {
ScopedValue<String> name = ScopedValue.newInstance();
try (var scope = StructuredTaskScope.open(Joiner.awaitAll())) {
ScopedValue.where(name, "x").run(() -> {
assertThrows(StructureViolationException.class, scope::close);
});
}
}
/**
* Test fork when a scoped value is bound after a StructuredTaskScope is created.
*/
@Test
void testStructureViolation3() throws Exception {
ScopedValue<String> name = ScopedValue.newInstance();
try (var scope = StructuredTaskScope.open(Joiner.awaitAll())) {
ScopedValue.where(name, "x").run(() -> {
assertThrows(StructureViolationException.class,
() -> scope.fork(() -> "foo"));
});
}
}
/**
* Test fork when a scoped value is re-bound after a StructuredTaskScope is created.
*/
@Test
void testStructureViolation4() throws Exception {
ScopedValue<String> name1 = ScopedValue.newInstance();
ScopedValue<String> name2 = ScopedValue.newInstance();
// rebind
ScopedValue.where(name1, "x").run(() -> {
try (var scope = StructuredTaskScope.open(Joiner.awaitAll())) {
ScopedValue.where(name1, "y").run(() -> {
assertThrows(StructureViolationException.class,
() -> scope.fork(() -> "foo"));
});
}
});
// new binding
ScopedValue.where(name1, "x").run(() -> {
try (var scope = StructuredTaskScope.open(Joiner.awaitAll())) {
ScopedValue.where(name2, "y").run(() -> {
assertThrows(StructureViolationException.class,
() -> scope.fork(() -> "foo"));
});
}
});
}
}

View file

@ -0,0 +1,103 @@
/*
* Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @modules java.base/java.util.concurrent:open
* @bug 4992438 6633113
* @summary Checks that fairness setting is respected.
*/
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class Fairness {
private final static VarHandle underlyingTransferQueueAccess;
static {
try {
underlyingTransferQueueAccess =
MethodHandles.privateLookupIn(
SynchronousQueue.class,
MethodHandles.lookup()
).findVarHandle(
SynchronousQueue.class,
"transferer",
Class.forName(SynchronousQueue.class.getName() + "$Transferer")
);
} catch (Exception ex) {
throw new ExceptionInInitializerError(ex);
}
}
private static void testFairness(boolean fair, final SynchronousQueue<Integer> q)
throws Throwable
{
final LinkedTransferQueue<Integer> underlying =
(LinkedTransferQueue<Integer>)underlyingTransferQueueAccess.get(q);
final ReentrantLock lock = new ReentrantLock();
final Condition ready = lock.newCondition();
final int threadCount = 10;
final Throwable[] badness = new Throwable[1];
lock.lock();
for (int i = 0; i < threadCount; i++) {
final Integer I = i;
Thread t = new Thread() { public void run() {
try {
lock.lock();
ready.signal();
lock.unlock();
q.put(I);
} catch (Throwable t) { badness[0] = t; }}};
t.start();
ready.await();
// Wait until previous put:ing thread is provably parked
while (underlying.size() < (i + 1))
Thread.yield();
if (underlying.size() > (i + 1))
throw new Error("Unexpected number of waiting producers: " + i);
}
for (int i = 0; i < threadCount; i++) {
int j = q.take();
// Non-fair queues are lifo in our implementation
if (fair ? j != i : j != threadCount - 1 - i)
throw new Error(String.format("fair=%b i=%d j=%d%n",
fair, i, j));
}
if (badness[0] != null) throw new Error(badness[0]);
}
public static void main(String[] args) throws Throwable {
testFairness(false, new SynchronousQueue<>());
testFairness(false, new SynchronousQueue<>(false));
testFairness(true, new SynchronousQueue<>(true));
}
}

View file

@ -0,0 +1 @@
maxOutputSize=2000000

View file

@ -0,0 +1,287 @@
/*
* Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6450200
* @summary Test proper handling of pool state changes
* @library /test/lib
* @build jdk.test.lib.RandomFactory
* @run main ConfigChanges
* @key randomness
* @author Martin Buchholz
*/
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.function.Supplier;
import jdk.test.lib.RandomFactory;
public class ConfigChanges {
static final ThreadGroup tg = new ThreadGroup("pool");
static final Random rnd = RandomFactory.getRandom();
static void report(ThreadPoolExecutor tpe) {
try {
System.out.printf(
"active=%d submitted=%d completed=%d queued=%d sizes=%d/%d/%d%n",
tg.activeCount(),
tpe.getTaskCount(),
tpe.getCompletedTaskCount(),
tpe.getQueue().size(),
tpe.getPoolSize(),
tpe.getCorePoolSize(),
tpe.getMaximumPoolSize());
} catch (Throwable t) { unexpected(t); }
}
static void report(String label, ThreadPoolExecutor tpe) {
System.out.printf("%10s ", label);
report(tpe);
}
static void checkShutdown(final ExecutorService es) {
final Runnable nop = new Runnable() {public void run() {}};
try {
if (new Random().nextBoolean()) {
check(es.isShutdown());
if (es instanceof ThreadPoolExecutor)
check(((ThreadPoolExecutor) es).isTerminating()
|| es.isTerminated());
THROWS(RejectedExecutionException.class,
() -> es.execute(nop));
}
} catch (Throwable t) { unexpected(t); }
}
static void checkTerminated(final ThreadPoolExecutor tpe) {
try {
checkShutdown(tpe);
check(tpe.getQueue().isEmpty());
check(tpe.isTerminated());
check(! tpe.isTerminating());
equal(0, tpe.getActiveCount());
equal(0, tpe.getPoolSize());
equal(tpe.getTaskCount(), tpe.getCompletedTaskCount());
check(tpe.awaitTermination(0L, MINUTES));
} catch (Throwable t) { unexpected(t); }
}
static Runnable waiter(final CyclicBarrier barrier) {
return new Runnable() { public void run() {
try { barrier.await(); barrier.await(); }
catch (Throwable t) { unexpected(t); }}};
}
static volatile Runnable runnableDuJour;
static void awaitIdleness(ThreadPoolExecutor tpe, long taskCount) {
restart: for (;;) {
// check twice to make chance of race vanishingly small
for (int i = 0; i < 2; i++) {
if (tpe.getQueue().size() != 0 ||
tpe.getActiveCount() != 0 ||
tpe.getCompletedTaskCount() != taskCount) {
Thread.yield();
continue restart;
}
}
return;
}
}
/**
* Waits for condition to become true, first spin-polling, then sleep-polling.
*/
static void spinAwait(Supplier<Boolean> waitingForGodot) {
for (int spins = 0; !waitingForGodot.get(); ) {
if ((spins = (spins + 1) & 3) > 0) {
Thread.yield();
} else {
try { Thread.sleep(4); }
catch (InterruptedException unexpected) {
throw new AssertionError(unexpected);
}
}
}
}
private static void realMain(String[] args) throws Throwable {
final boolean prestart = rnd.nextBoolean();
final Thread.UncaughtExceptionHandler handler
= new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread t, Throwable e) {
check(! Thread.currentThread().isInterrupted());
unexpected(e);
}};
final int n = 3;
final ThreadPoolExecutor tpe
= new ThreadPoolExecutor(n, 3*n,
3L, MINUTES,
new ArrayBlockingQueue<Runnable>(3*n));
tpe.setThreadFactory(new ThreadFactory() {
public Thread newThread(Runnable r) {
Thread t = new Thread(tg, r);
t.setUncaughtExceptionHandler(handler);
return t;
}});
if (prestart) {
tpe.prestartAllCoreThreads();
equal(n, tg.activeCount());
equal(n, tpe.getCorePoolSize());
equal(n, tpe.getLargestPoolSize());
}
final Runnable runRunnableDuJour =
new Runnable() { public void run() {
// Delay choice of action till last possible moment.
runnableDuJour.run(); }};
final CyclicBarrier pumpedUp = new CyclicBarrier(3*n + 1);
runnableDuJour = waiter(pumpedUp);
if (prestart) {
for (int i = 0; i < 1*n; i++)
tpe.execute(runRunnableDuJour);
// Wait for prestarted threads to dequeue their initial tasks.
while (! tpe.getQueue().isEmpty())
Thread.sleep(1);
for (int i = 0; i < 5*n; i++)
tpe.execute(runRunnableDuJour);
} else {
for (int i = 0; i < 6*n; i++)
tpe.execute(runRunnableDuJour);
}
//report("submitted", tpe);
pumpedUp.await();
equal(3*n, tg.activeCount());
equal(3*n, tpe.getMaximumPoolSize());
equal(3*n, tpe.getLargestPoolSize());
equal(n, tpe.getCorePoolSize());
equal(3*n, tpe.getActiveCount());
equal(6L*n, tpe.getTaskCount());
equal(0L, tpe.getCompletedTaskCount());
//report("pumped up", tpe);
tpe.setMaximumPoolSize(4*n);
equal(4*n, tpe.getMaximumPoolSize());
//report("pumped up2", tpe);
final CyclicBarrier pumpedUp2 = new CyclicBarrier(n + 1);
runnableDuJour = waiter(pumpedUp2);
for (int i = 0; i < 1*n; i++)
tpe.execute(runRunnableDuJour);
pumpedUp2.await();
equal(4*n, tg.activeCount());
equal(4*n, tpe.getMaximumPoolSize());
equal(4*n, tpe.getLargestPoolSize());
equal(4*n, tpe.getActiveCount());
equal(7L*n, tpe.getTaskCount());
equal(0L, tpe.getCompletedTaskCount());
//report("pumped up2", tpe);
runnableDuJour = new Runnable() { public void run() {}};
tpe.setMaximumPoolSize(2*n);
//report("after setMaximumPoolSize", tpe);
pumpedUp2.await();
pumpedUp.await();
spinAwait(() -> tg.activeCount() == 2*n);
equal(2*n, tpe.getMaximumPoolSize());
equal(4*n, tpe.getLargestPoolSize());
//report("draining", tpe);
awaitIdleness(tpe, 7L*n);
equal(2*n, tg.activeCount());
equal(2*n, tpe.getMaximumPoolSize());
equal(4*n, tpe.getLargestPoolSize());
equal(7L*n, tpe.getTaskCount());
equal(7L*n, tpe.getCompletedTaskCount());
equal(0, tpe.getActiveCount());
equal(3L, tpe.getKeepAliveTime(MINUTES));
long t0 = System.nanoTime();
tpe.setKeepAliveTime(7L, MILLISECONDS);
equal(7L, tpe.getKeepAliveTime(MILLISECONDS));
spinAwait(() -> tg.activeCount() == n);
check(System.nanoTime() - t0 >= tpe.getKeepAliveTime(NANOSECONDS));
//report("idle", tpe);
check(! tpe.allowsCoreThreadTimeOut());
t0 = System.nanoTime();
tpe.allowCoreThreadTimeOut(true);
check(tpe.allowsCoreThreadTimeOut());
spinAwait(() -> tg.activeCount() == 0);
// The following assertion is almost always true, but may
// exceptionally not be during a transition from core count
// too high to allowCoreThreadTimeOut. Users will never
// notice, and we accept the small loss of testability.
//
// check(System.nanoTime() - t0 >= tpe.getKeepAliveTime(NANOSECONDS));
//report("idle", tpe);
tpe.shutdown();
checkShutdown(tpe);
check(tpe.awaitTermination(3L, MINUTES));
checkTerminated(tpe);
}
//--------------------- Infrastructure ---------------------------
static volatile int passed = 0, failed = 0;
static void pass() {passed++;}
static void fail() {failed++; Thread.dumpStack();}
static void fail(String msg) {System.out.println(msg); fail();}
static void unexpected(Throwable t) {failed++; t.printStackTrace();}
static void check(boolean cond) {if (cond) pass(); else fail();}
static void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
try {realMain(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
interface Fun {void f() throws Throwable;}
static void THROWS(Class<? extends Throwable> k, Fun... fs) {
for (Fun f : fs)
try { f.f(); fail("Expected " + k.getName() + " not thrown"); }
catch (Throwable t) {
if (k.isAssignableFrom(t.getClass())) pass();
else unexpected(t);}}
}

View file

@ -0,0 +1,121 @@
/*
* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6233235 6268386
* @summary Test allowsCoreThreadTimeOut
* @library /test/lib
* @author Martin Buchholz
*/
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import jdk.test.lib.Utils;
public class CoreThreadTimeOut {
static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
static class IdentifiableThreadFactory implements ThreadFactory {
static ThreadFactory defaultThreadFactory
= Executors.defaultThreadFactory();
public Thread newThread(Runnable r) {
Thread t = defaultThreadFactory.newThread(r);
t.setName("CoreThreadTimeOut-" + t.getName());
return t;
}
}
int countExecutorThreads() {
Thread[] threads = new Thread[Thread.activeCount()+100];
Thread.enumerate(threads);
int count = 0;
for (Thread t : threads)
if (t != null &&
t.getName().matches
("CoreThreadTimeOut-pool-[0-9]+-thread-[0-9]+"))
count++;
return count;
}
static long millisElapsedSince(long startTime) {
return (System.nanoTime() - startTime) / (1000L * 1000L);
}
void test(String[] args) throws Throwable {
final int threadCount = 10;
final int timeoutMillis = 30;
BlockingQueue<Runnable> q = new ArrayBlockingQueue<>(2*threadCount);
ThreadPoolExecutor tpe
= new ThreadPoolExecutor(threadCount, threadCount,
timeoutMillis, TimeUnit.MILLISECONDS,
q, new IdentifiableThreadFactory());
equal(tpe.getCorePoolSize(), threadCount);
check(! tpe.allowsCoreThreadTimeOut());
tpe.allowCoreThreadTimeOut(true);
check(tpe.allowsCoreThreadTimeOut());
equal(countExecutorThreads(), 0);
long startTime = System.nanoTime();
for (int i = 0; i < threadCount; i++) {
tpe.submit(() -> {});
int count = countExecutorThreads();
if (millisElapsedSince(startTime) < timeoutMillis)
equal(count, i + 1);
}
while (countExecutorThreads() > 0 &&
millisElapsedSince(startTime) < LONG_DELAY_MS)
Thread.yield();
equal(countExecutorThreads(), 0);
check(millisElapsedSince(startTime) >= timeoutMillis);
tpe.shutdown();
check(tpe.allowsCoreThreadTimeOut());
check(tpe.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new Exception("Some tests failed");
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
new CoreThreadTimeOut().instanceMain(args);}
public void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}

View file

@ -0,0 +1,146 @@
/*
* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6277663
* @summary Test TPE extensibility framework
* @library /test/lib
* @author Martin Buchholz
*/
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import java.util.concurrent.RunnableFuture;
import java.util.concurrent.RunnableScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BooleanSupplier;
import jdk.test.lib.Utils;
public class Custom {
static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
static volatile int passed = 0, failed = 0;
static void pass() { passed++; }
static void fail() { failed++; Thread.dumpStack(); }
static void unexpected(Throwable t) { failed++; t.printStackTrace(); }
static void check(boolean cond) { if (cond) pass(); else fail(); }
static void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else {System.out.println(x + " not equal to " + y); fail(); }}
private static class CustomTask<V> extends FutureTask<V> {
public static final AtomicInteger births = new AtomicInteger(0);
CustomTask(Callable<V> c) { super(c); births.getAndIncrement(); }
CustomTask(Runnable r, V v) { super(r, v); births.getAndIncrement(); }
}
private static class CustomTPE extends ThreadPoolExecutor {
CustomTPE() {
super(threadCount, threadCount,
30, TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<Runnable>(2*threadCount));
}
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);
}
}
private static class CustomSTPE extends ScheduledThreadPoolExecutor {
public static final AtomicInteger decorations = new AtomicInteger(0);
CustomSTPE() {
super(threadCount);
}
protected <V> RunnableScheduledFuture<V> decorateTask(
Runnable r, RunnableScheduledFuture<V> task) {
decorations.getAndIncrement();
return task;
}
protected <V> RunnableScheduledFuture<V> decorateTask(
Callable<V> c, RunnableScheduledFuture<V> task) {
decorations.getAndIncrement();
return task;
}
}
static int countExecutorThreads() {
Thread[] threads = new Thread[Thread.activeCount()+100];
Thread.enumerate(threads);
int count = 0;
for (Thread t : threads)
if (t != null && t.getName().matches("pool-[0-9]+-thread-[0-9]+"))
count++;
return count;
}
private static final int threadCount = 10;
static long millisElapsedSince(long startTime) {
return (System.nanoTime() - startTime) / (1000L * 1000L);
}
static void spinWaitUntil(BooleanSupplier predicate, long timeoutMillis) {
long startTime = -1L;
while (!predicate.getAsBoolean()) {
if (startTime == -1L)
startTime = System.nanoTime();
else if (millisElapsedSince(startTime) > timeoutMillis)
throw new AssertionError(
String.format("timed out after %s ms", timeoutMillis));
Thread.yield();
}
}
public static void main(String[] args) throws Throwable {
CustomTPE tpe = new CustomTPE();
equal(tpe.getCorePoolSize(), threadCount);
equal(countExecutorThreads(), 0);
for (int i = 0; i < threadCount; i++)
tpe.submit(new Runnable() { public void run() {}});
equal(countExecutorThreads(), threadCount);
equal(CustomTask.births.get(), threadCount);
tpe.shutdown();
tpe.awaitTermination(LONG_DELAY_MS, MILLISECONDS);
spinWaitUntil(() -> countExecutorThreads() == 0, LONG_DELAY_MS);
CustomSTPE stpe = new CustomSTPE();
for (int i = 0; i < threadCount; i++)
stpe.submit(new Runnable() { public void run() {}});
equal(CustomSTPE.decorations.get(), threadCount);
equal(countExecutorThreads(), threadCount);
stpe.shutdown();
stpe.awaitTermination(LONG_DELAY_MS, MILLISECONDS);
spinWaitUntil(() -> countExecutorThreads() == 0, LONG_DELAY_MS);
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new Exception("Some tests failed");
}
}

View file

@ -0,0 +1,119 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Martin Buchholz and Doug Lea with assistance from
* members of JCP JSR-166 Expert Group and released to the public
* domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* @test
* @summary Should be able to shutdown a pool when worker creation failed.
* @library /test/lib
*/
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import jdk.test.lib.Utils;
public class FlakyThreadFactory {
static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
void test(String[] args) throws Throwable {
test(NullPointerException.class,
new ThreadFactory() {
public Thread newThread(Runnable r) {
throw new NullPointerException();
}});
test(OutOfMemoryError.class,
new ThreadFactory() {
@SuppressWarnings("DeadThread")
public Thread newThread(Runnable r) {
// We expect this to throw OOME, but ...
new Thread(null, r, "a natural OOME", 1L << 60);
// """On some platforms, the value of the stackSize
// parameter may have no effect whatsoever."""
throw new OutOfMemoryError("artificial OOME");
}});
test(null,
new ThreadFactory() {
public Thread newThread(Runnable r) {
return null;
}});
}
void test(final Class<?> exceptionClass,
final ThreadFactory failingThreadFactory)
throws Throwable {
ThreadFactory flakyThreadFactory = new ThreadFactory() {
int seq = 0;
public Thread newThread(Runnable r) {
if (seq++ < 4)
return new Thread(r);
else
return failingThreadFactory.newThread(r);
}};
ThreadPoolExecutor pool =
new ThreadPoolExecutor(10, 10,
0L, TimeUnit.SECONDS,
new LinkedBlockingQueue(),
flakyThreadFactory);
try {
for (int i = 0; i < 8; i++)
pool.submit(new Runnable() { public void run() {} });
check(exceptionClass == null);
} catch (Throwable t) {
/* t.printStackTrace(); */
check(exceptionClass.isInstance(t));
}
pool.shutdown();
check(pool.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
new FlakyThreadFactory().instanceMain(args);}
public void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}

View file

@ -0,0 +1,77 @@
/*
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6522773
* @summary Test changes to STPE core pool size
* @author Martin Buchholz
*/
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ModifyCorePoolSize {
static void awaitPoolSize(ThreadPoolExecutor pool, int n) {
while (pool.getPoolSize() != n) Thread.yield();
pass();
}
static void setCorePoolSize(ThreadPoolExecutor pool, int n) {
pool.setCorePoolSize(n);
equal(pool.getCorePoolSize(), n);
awaitPoolSize(pool, n);
}
static void realMain(String[] args) throws Throwable {
final int size = 10;
final ScheduledThreadPoolExecutor pool
= new ScheduledThreadPoolExecutor(size);
final Runnable nop = new Runnable() { public void run() {}};
for (int i = 0; i < size; i++)
pool.scheduleAtFixedRate(nop, 100L * (i + 1),
1000L, TimeUnit.MILLISECONDS);
awaitPoolSize(pool, size);
setCorePoolSize(pool, size - 3);
setCorePoolSize(pool, size + 3);
pool.shutdownNow();
check(pool.awaitTermination(1L, TimeUnit.DAYS));
}
//--------------------- Infrastructure ---------------------------
static volatile int passed = 0, failed = 0;
static void pass() {passed++;}
static void fail() {failed++; Thread.dumpStack();}
static void fail(String msg) {System.out.println(msg); fail();}
static void unexpected(Throwable t) {failed++; t.printStackTrace();}
static void check(boolean cond) {if (cond) pass(); else fail();}
static void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
try {realMain(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}

View file

@ -0,0 +1,195 @@
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6362121
* @summary Test one ScheduledThreadPoolExecutor extension scenario
* @author Martin Buchholz
*/
// based on a test kindly provided by Holger Hoffstaette <holger@wizards.de>
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Delayed;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.RunnableScheduledFuture;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class ScheduledTickleService {
// We get intermittent ClassCastException if greater than 1
// because of calls to compareTo
private static final int concurrency = 2;
// Record when tasks are done
public static final CountDownLatch done = new CountDownLatch(concurrency);
public static void realMain(String... args) throws InterruptedException {
// our tickle service
ScheduledExecutorService tickleService =
new ScheduledThreadPoolExecutor(concurrency) {
// We override decorateTask() to return a custom
// RunnableScheduledFuture which explicitly removes
// itself from the queue after cancellation.
protected <V> RunnableScheduledFuture<V>
decorateTask(Runnable runnable,
RunnableScheduledFuture<V> task) {
final ScheduledThreadPoolExecutor exec = this;
return new CustomRunnableScheduledFuture<V>(task) {
// delegate to wrapped task, except for:
public boolean cancel(boolean b) {
// cancel wrapped task & remove myself from the queue
return (task().cancel(b)
&& exec.remove(this));}};}};
for (int i = 0; i < concurrency; i++)
new ScheduledTickle(i, tickleService)
.setUpdateInterval(25, MILLISECONDS);
done.await();
tickleService.shutdown();
pass();
}
// our Runnable
static class ScheduledTickle implements Runnable {
public volatile int failures = 0;
// my tickle service
private final ScheduledExecutorService service;
// remember my own scheduled ticket
private ScheduledFuture ticket = null;
// remember the number of times I've been tickled
private int numTickled = 0;
// my private name
private final String name;
public ScheduledTickle(int i, ScheduledExecutorService service) {
super();
this.name = "Tickler-"+i;
this.service = service;
}
// set my tickle interval; 0 to disable further tickling.
public synchronized void setUpdateInterval(long interval,
TimeUnit unit) {
// cancel & remove previously created ticket
if (ticket != null) {
ticket.cancel(false);
ticket = null;
}
if (interval > 0 && ! service.isShutdown()) {
// requeue with new interval
ticket = service.scheduleAtFixedRate(this, interval,
interval, unit);
}
}
public synchronized void run() {
try {
check(numTickled < 6);
numTickled++;
System.out.println(name + ": Run " + numTickled);
// tickle 3 times and then slow down
if (numTickled == 3) {
System.out.println(name + ": slower please!");
this.setUpdateInterval(100, MILLISECONDS);
}
// ..but only 5 times max.
else if (numTickled == 5) {
System.out.println(name + ": OK that's enough.");
this.setUpdateInterval(0, MILLISECONDS);
ScheduledTickleService.done.countDown();
}
} catch (Throwable t) { unexpected(t); }
}
}
// This is just a generic wrapper to make up for the private ScheduledFutureTask
static class CustomRunnableScheduledFuture<V>
implements RunnableScheduledFuture<V> {
// the wrapped future
private RunnableScheduledFuture<V> task;
public CustomRunnableScheduledFuture(RunnableScheduledFuture<V> task) {
super();
this.task = task;
}
public RunnableScheduledFuture<V> task() { return task; }
// Forwarding methods
public boolean isPeriodic() { return task.isPeriodic(); }
public boolean isCancelled() { return task.isCancelled(); }
public boolean isDone() { return task.isDone(); }
public boolean cancel(boolean b) { return task.cancel(b); }
public long getDelay(TimeUnit unit) { return task.getDelay(unit); }
public void run() { task.run(); }
public V get()
throws InterruptedException, ExecutionException {
return task.get();
}
public V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
return task.get(timeout, unit);
}
public int compareTo(Delayed other) {
if (this == other)
return 0;
else if (other instanceof CustomRunnableScheduledFuture)
return task.compareTo(((CustomRunnableScheduledFuture)other).task());
else
return task.compareTo(other);
}
}
//--------------------- Infrastructure ---------------------------
static volatile int passed = 0, failed = 0;
static void pass() {passed++;}
static void fail() {failed++; Thread.dumpStack();}
static void fail(String msg) {System.out.println(msg); fail();}
static void unexpected(Throwable t) {failed++; t.printStackTrace();}
static void check(boolean cond) {if (cond) pass(); else fail();}
static void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
try {realMain(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}

Some files were not shown because too many files have changed in this diff Show more