1 /* 2 * Copyright (c) 2006, 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 6362121 27 * @summary Test one ScheduledThreadPoolExecutor extension scenario 28 * @author Martin Buchholz 29 */ 30 31 // based on a test kindly provided by Holger Hoffstaette <holger@wizards.de> 32 33 import java.util.concurrent.*; 34 import static java.util.concurrent.TimeUnit.MILLISECONDS; 35 36 public class ScheduledTickleService { 37 38 // We get intermittent ClassCastException if greater than 1 39 // because of calls to compareTo 40 private final static int concurrency = 2; 41 42 // Record when tasks are done 43 public final static CountDownLatch done = new CountDownLatch(concurrency); 44 45 public static void realMain(String... args) throws InterruptedException { 46 // our tickle service 47 ScheduledExecutorService tickleService = 48 new ScheduledThreadPoolExecutor(concurrency) { 49 // We override decorateTask() to return a custom 50 // RunnableScheduledFuture which explicitly removes 51 // itself from the queue after cancellation. 52 protected <V> RunnableScheduledFuture<V> 53 decorateTask(Runnable runnable, 54 RunnableScheduledFuture<V> task) { 55 final ScheduledThreadPoolExecutor exec = this; 56 return new CustomRunnableScheduledFuture<V>(task) { 57 // delegate to wrapped task, except for: 58 public boolean cancel(boolean b) { 59 // cancel wrapped task & remove myself from the queue 60 return (task().cancel(b) 61 && exec.remove(this));}};}}; 62 63 for (int i = 0; i < concurrency; i++) 64 new ScheduledTickle(i, tickleService) 65 .setUpdateInterval(25, MILLISECONDS); 66 67 done.await(); 68 tickleService.shutdown(); 69 pass(); 70 } 71 72 // our Runnable 73 static class ScheduledTickle implements Runnable { 74 public volatile int failures = 0; 75 76 // my tickle service 77 private final ScheduledExecutorService service; 78 79 // remember my own scheduled ticket 80 private ScheduledFuture ticket = null; 81 82 // remember the number of times I've been tickled 83 private int numTickled = 0; 84 85 // my private name 86 private final String name; 87 88 public ScheduledTickle(int i, ScheduledExecutorService service) { 89 super(); 90 this.name = "Tickler-"+i; 91 this.service = service; 92 } 93 94 // set my tickle interval; 0 to disable further tickling. 95 public synchronized void setUpdateInterval(long interval, 96 TimeUnit unit) { 97 // cancel & remove previously created ticket 98 if (ticket != null) { 99 ticket.cancel(false); 100 ticket = null; 101 } 102 103 if (interval > 0 && ! service.isShutdown()) { 104 // requeue with new interval 105 ticket = service.scheduleAtFixedRate(this, interval, 106 interval, unit); 107 } 108 } 109 110 public synchronized void run() { 111 try { 112 check(numTickled < 6); 113 numTickled++; 114 System.out.println(name + ": Run " + numTickled); 115 116 // tickle 3 times and then slow down 117 if (numTickled == 3) { 118 System.out.println(name + ": slower please!"); 119 this.setUpdateInterval(100, MILLISECONDS); 120 } 121 // ..but only 5 times max. 122 else if (numTickled == 5) { 123 System.out.println(name + ": OK that's enough."); 124 this.setUpdateInterval(0, MILLISECONDS); 125 ScheduledTickleService.done.countDown(); 126 } 127 } catch (Throwable t) { unexpected(t); } 128 } 129 } 130 131 // This is just a generic wrapper to make up for the private ScheduledFutureTask 132 static class CustomRunnableScheduledFuture<V> 133 implements RunnableScheduledFuture<V> { 134 // the wrapped future 135 private RunnableScheduledFuture<V> task; 136 137 public CustomRunnableScheduledFuture(RunnableScheduledFuture<V> task) { 138 super(); 139 this.task = task; 140 } 141 142 public RunnableScheduledFuture<V> task() { return task; } 143 144 // Forwarding methods 145 public boolean isPeriodic() { return task.isPeriodic(); } 146 public boolean isCancelled() { return task.isCancelled(); } 147 public boolean isDone() { return task.isDone(); } 148 public boolean cancel(boolean b) { return task.cancel(b); } 149 public long getDelay(TimeUnit unit) { return task.getDelay(unit); } 150 public void run() { task.run(); } 151 152 public V get() 153 throws InterruptedException, ExecutionException { 154 return task.get(); 155 } 156 157 public V get(long timeout, TimeUnit unit) 158 throws InterruptedException, ExecutionException, TimeoutException { 159 return task.get(timeout, unit); 160 } 161 162 public int compareTo(Delayed other) { 163 if (this == other) 164 return 0; 165 else if (other instanceof CustomRunnableScheduledFuture) 166 return task.compareTo(((CustomRunnableScheduledFuture)other).task()); 167 else 168 return task.compareTo(other); 169 } 170 } 171 172 //--------------------- Infrastructure --------------------------- 173 static volatile int passed = 0, failed = 0; 174 static void pass() {passed++;} 175 static void fail() {failed++; Thread.dumpStack();} 176 static void fail(String msg) {System.out.println(msg); fail();} 177 static void unexpected(Throwable t) {failed++; t.printStackTrace();} 178 static void check(boolean cond) {if (cond) pass(); else fail();} 179 static void equal(Object x, Object y) { 180 if (x == null ? y == null : x.equals(y)) pass(); 181 else fail(x + " not equal to " + y);} 182 public static void main(String[] args) throws Throwable { 183 try {realMain(args);} catch (Throwable t) {unexpected(t);} 184 System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); 185 if (failed > 0) throw new AssertionError("Some tests failed");} 186 } --- EOF ---