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:
commit
0a580b313d
70422 changed files with 17213626 additions and 0 deletions
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
218
test/jdk/java/util/concurrent/BlockingQueue/DrainToFails.java
Normal file
218
test/jdk/java/util/concurrent/BlockingQueue/DrainToFails.java
Normal 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");}
|
||||
}
|
||||
143
test/jdk/java/util/concurrent/BlockingQueue/Interrupt.java
Normal file
143
test/jdk/java/util/concurrent/BlockingQueue/Interrupt.java
Normal 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;}
|
||||
}
|
||||
121
test/jdk/java/util/concurrent/BlockingQueue/LastElement.java
Normal file
121
test/jdk/java/util/concurrent/BlockingQueue/LastElement.java
Normal 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");}
|
||||
}
|
||||
103
test/jdk/java/util/concurrent/BlockingQueue/LoopHelpers.java
Normal file
103
test/jdk/java/util/concurrent/BlockingQueue/LoopHelpers.java
Normal 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();
|
||||
}
|
||||
|
||||
}
|
||||
78
test/jdk/java/util/concurrent/BlockingQueue/MissedPoll.java
Normal file
78
test/jdk/java/util/concurrent/BlockingQueue/MissedPoll.java
Normal 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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");}
|
||||
}
|
||||
160
test/jdk/java/util/concurrent/BlockingQueue/PollMemoryLeak.java
Normal file
160
test/jdk/java/util/concurrent/BlockingQueue/PollMemoryLeak.java
Normal 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue