/* * 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 Checks for responsiveness of futures to cancellation. * Runs under * the assumption that ITERS computations require more than TIMEOUT * msecs to complete. */ /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain. Use, modify, and * redistribute this code in any way without acknowledgement. */ 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.locks.ReentrantLock; public final class CancelledFutureLoops { static final ExecutorService pool = Executors.newCachedThreadPool(); static final LoopHelpers.SimpleRandom rng = new LoopHelpers.SimpleRandom(); static boolean print = false; static final int ITERS = 10000000; static final long TIMEOUT = 100; public static void main(String[] args) throws Exception { int maxThreads = 100; 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); new FutureLoop(i).test(); Thread.sleep(TIMEOUT); } pool.shutdown(); } static final class FutureLoop implements Callable { private int v = rng.next(); private final ReentrantLock lock = new ReentrantLock(); private final LoopHelpers.BarrierTimer timer = new LoopHelpers.BarrierTimer(); private final CyclicBarrier barrier; private final int nthreads; FutureLoop(int nthreads) { this.nthreads = nthreads; barrier = new CyclicBarrier(nthreads+1, timer); } 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 + rng.next() % 10); } 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); } } }