1 /* 2 * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @bug 6277663 27 * @summary Test TPE extensibility framework 28 * @library /test/lib 29 * @author Martin Buchholz 30 */ 31 32 import static java.util.concurrent.TimeUnit.MILLISECONDS; 33 34 import java.util.concurrent.ArrayBlockingQueue; 35 import java.util.concurrent.Callable; 36 import java.util.concurrent.FutureTask; 37 import java.util.concurrent.RunnableFuture; 38 import java.util.concurrent.RunnableScheduledFuture; 39 import java.util.concurrent.ScheduledThreadPoolExecutor; 40 import java.util.concurrent.ThreadPoolExecutor; 41 import java.util.concurrent.TimeUnit; 42 import java.util.concurrent.atomic.AtomicInteger; 43 import java.util.function.BooleanSupplier; 44 import jdk.test.lib.Utils; 45 46 public class Custom { 47 static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000); 48 static volatile int passed = 0, failed = 0; 49 static void pass() { passed++; } 50 static void fail() { failed++; Thread.dumpStack(); } 51 static void unexpected(Throwable t) { failed++; t.printStackTrace(); } 52 static void check(boolean cond) { if (cond) pass(); else fail(); } 53 static void equal(Object x, Object y) { 54 if (x == null ? y == null : x.equals(y)) pass(); 55 else {System.out.println(x + " not equal to " + y); fail(); }} 56 57 private static class CustomTask<V> extends FutureTask<V> { 58 public static final AtomicInteger births = new AtomicInteger(0); 59 CustomTask(Callable<V> c) { super(c); births.getAndIncrement(); } 60 CustomTask(Runnable r, V v) { super(r, v); births.getAndIncrement(); } 61 } 62 63 private static class CustomTPE extends ThreadPoolExecutor { 64 CustomTPE() { 65 super(threadCount, threadCount, 66 30, TimeUnit.MILLISECONDS, 67 new ArrayBlockingQueue<Runnable>(2*threadCount)); 68 } 69 protected <V> RunnableFuture<V> newTaskFor(Callable<V> c) { 70 return new CustomTask<V>(c); 71 } 72 protected <V> RunnableFuture<V> newTaskFor(Runnable r, V v) { 73 return new CustomTask<V>(r, v); 74 } 75 } 76 77 private static class CustomSTPE extends ScheduledThreadPoolExecutor { 78 public static final AtomicInteger decorations = new AtomicInteger(0); 79 CustomSTPE() { 80 super(threadCount); 81 } 82 protected <V> RunnableScheduledFuture<V> decorateTask( 83 Runnable r, RunnableScheduledFuture<V> task) { 84 decorations.getAndIncrement(); 85 return task; 86 } 87 protected <V> RunnableScheduledFuture<V> decorateTask( 88 Callable<V> c, RunnableScheduledFuture<V> task) { 89 decorations.getAndIncrement(); 90 return task; 91 } 92 } 93 94 static int countExecutorThreads() { 95 Thread[] threads = new Thread[Thread.activeCount()+100]; 96 Thread.enumerate(threads); 97 int count = 0; 98 for (Thread t : threads) 99 if (t != null && t.getName().matches("pool-[0-9]+-thread-[0-9]+")) 100 count++; 101 return count; 102 } 103 104 private static final int threadCount = 10; 105 106 static long millisElapsedSince(long startTime) { 107 return (System.nanoTime() - startTime) / (1000L * 1000L); 108 } 109 110 static void spinWaitUntil(BooleanSupplier predicate, long timeoutMillis) { 111 long startTime = -1L; 112 while (!predicate.getAsBoolean()) { 113 if (startTime == -1L) 114 startTime = System.nanoTime(); 115 else if (millisElapsedSince(startTime) > timeoutMillis) 116 throw new AssertionError( 117 String.format("timed out after %s ms", timeoutMillis)); 118 Thread.yield(); 119 } 120 } 121 122 public static void main(String[] args) throws Throwable { 123 CustomTPE tpe = new CustomTPE(); 124 equal(tpe.getCorePoolSize(), threadCount); 125 equal(countExecutorThreads(), 0); 126 for (int i = 0; i < threadCount; i++) 127 tpe.submit(new Runnable() { public void run() {}}); 128 equal(countExecutorThreads(), threadCount); 129 equal(CustomTask.births.get(), threadCount); 130 tpe.shutdown(); 131 tpe.awaitTermination(LONG_DELAY_MS, MILLISECONDS); 132 spinWaitUntil(() -> countExecutorThreads() == 0, LONG_DELAY_MS); 133 134 CustomSTPE stpe = new CustomSTPE(); 135 for (int i = 0; i < threadCount; i++) 136 stpe.submit(new Runnable() { public void run() {}}); 137 equal(CustomSTPE.decorations.get(), threadCount); 138 equal(countExecutorThreads(), threadCount); 139 stpe.shutdown(); 140 stpe.awaitTermination(LONG_DELAY_MS, MILLISECONDS); 141 spinWaitUntil(() -> countExecutorThreads() == 0, LONG_DELAY_MS); 142 143 System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); 144 if (failed > 0) throw new Exception("Some tests failed"); 145 } 146 }