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</code> 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 }
--- EOF ---