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 6431315 27 * @summary ExecutorService.invokeAll might hang 28 * @author Martin Buchholz 29 */ 30 31 import java.util.*; 32 import java.util.concurrent.*; 33 34 /** 35 * Adapted from Doug Lea, which was... 36 * adapted from a posting by Tom Sugden tom at epcc.ed.ac.uk 37 */ 38 public class BlockingTaskExecutor { 39 40 static void realMain(String[] args) throws Throwable { 41 for (int i = 1; i <= 100; i++) { 42 System.out.print("."); 43 test(); 44 } 45 } 46 47 static void test() throws Throwable { 48 final ExecutorService executor = Executors.newCachedThreadPool(); 49 50 final NotificationReceiver notifiee1 = new NotificationReceiver(); 51 final NotificationReceiver notifiee2 = new NotificationReceiver(); 52 53 final Collection<Callable<Object>> tasks = 54 new ArrayList<Callable<Object>>(); 55 tasks.add(new BlockingTask(notifiee1)); 56 tasks.add(new BlockingTask(notifiee2)); 57 tasks.add(new NonBlockingTask()); 58 59 // start a thread to invoke the tasks 60 Thread thread = new Thread() { public void run() { 61 try { executor.invokeAll(tasks); } 62 catch (RejectedExecutionException t) {/* OK */} 63 catch (Throwable t) { unexpected(t); }}}; 64 thread.start(); 65 66 // Wait until tasks begin execution 67 notifiee1.waitForNotification(); 68 notifiee2.waitForNotification(); 69 70 // Now try to shutdown the executor service while tasks 71 // are blocked. This should cause the tasks to be 72 // interrupted. 73 executor.shutdownNow(); 74 if (! executor.awaitTermination(5, TimeUnit.SECONDS)) 75 throw new Error("Executor stuck"); 76 77 // Wait for the invocation thread to complete. 78 thread.join(1000); 79 if (thread.isAlive()) { 80 thread.interrupt(); 81 thread.join(1000); 82 throw new Error("invokeAll stuck"); 83 } 84 } 85 86 /** 87 * A helper class with a method to wait for a notification. 88 * 89 * The notification is received via the 90 * {@code sendNotification} method. 91 */ 92 static class NotificationReceiver { 93 /** Has the notifiee been notified? */ 94 boolean notified = false; 95 96 /** 97 * Notify the notification receiver. 98 */ 99 public synchronized void sendNotification() { 100 notified = true; 101 notifyAll(); 102 } 103 104 /** 105 * Waits until a notification has been received. 106 * 107 * @throws InterruptedException if the wait is interrupted 108 */ 109 public synchronized void waitForNotification() 110 throws InterruptedException { 111 while (! notified) 112 wait(); 113 } 114 } 115 116 /** 117 * A callable task that blocks until it is interrupted. 118 * This task sends a notification to a notification receiver when 119 * it is first called. 120 */ 121 static class BlockingTask implements Callable<Object> { 122 private final NotificationReceiver notifiee; 123 124 BlockingTask(NotificationReceiver notifiee) { 125 this.notifiee = notifiee; 126 } 127 128 public Object call() throws InterruptedException { 129 notifiee.sendNotification(); 130 131 // wait indefinitely until task is interrupted 132 while (true) { 133 synchronized (this) { 134 wait(); 135 } 136 } 137 } 138 } 139 140 /** 141 * A callable task that simply returns a string result. 142 */ 143 static class NonBlockingTask implements Callable<Object> { 144 public Object call() { 145 return "NonBlockingTaskResult"; 146 } 147 } 148 149 //--------------------- Infrastructure --------------------------- 150 static volatile int passed = 0, failed = 0; 151 static void pass() {passed++;} 152 static void fail() {failed++; Thread.dumpStack();} 153 static void fail(String msg) {System.out.println(msg); fail();} 154 static void unexpected(Throwable t) {failed++; t.printStackTrace();} 155 static void check(boolean cond) {if (cond) pass(); else fail();} 156 static void equal(Object x, Object y) { 157 if (x == null ? y == null : x.equals(y)) pass(); 158 else fail(x + " not equal to " + y);} 159 public static void main(String[] args) throws Throwable { 160 try {realMain(args);} catch (Throwable t) {unexpected(t);} 161 System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); 162 if (failed > 0) throw new AssertionError("Some tests failed");} 163 }