Print this page
Split |
Close |
Expand all |
Collapse all |
--- old/test/java/util/concurrent/CyclicBarrier/Basic.java
+++ new/test/java/util/concurrent/CyclicBarrier/Basic.java
1 1 /*
2 2 * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
3 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 4 *
5 5 * This code is free software; you can redistribute it and/or modify it
6 6 * under the terms of the GNU General Public License version 2 only, as
7 7 * published by the Free Software Foundation.
8 8 *
9 9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 12 * version 2 for more details (a copy is included in the LICENSE file that
13 13 * accompanied this code).
14 14 *
15 15 * You should have received a copy of the GNU General Public License version
16 16 * 2 along with this work; if not, write to the Free Software Foundation,
17 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 18 *
19 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 20 * or visit www.oracle.com if you need additional information or have any
21 21 * questions.
22 22 */
23 23
24 24 /*
25 25 * @test
26 26 * @bug 6253848 6366811
27 27 * @summary Basic tests for CyclicBarrier
28 28 * @author Martin Buchholz, David Holmes
29 29 */
30 30
31 31 import java.util.*;
32 32 import java.util.concurrent.*;
33 33 import java.util.concurrent.atomic.AtomicInteger;
34 34 import static java.util.concurrent.TimeUnit.*;
35 35
36 36 public class Basic {
37 37
38 38 private static void checkBroken(final CyclicBarrier barrier) {
39 39 check(barrier.isBroken());
40 40 equal(barrier.getNumberWaiting(), 0);
41 41
42 42 THROWS(BrokenBarrierException.class,
43 43 new Fun() { public void f() throws Throwable {
44 44 barrier.await(); }},
45 45 new Fun() { public void f() throws Throwable {
46 46 barrier.await(100, MILLISECONDS); }});
47 47 }
48 48
49 49 private static void reset(CyclicBarrier barrier) {
50 50 barrier.reset();
51 51 check(! barrier.isBroken());
52 52 equal(barrier.getNumberWaiting(), 0);
53 53 }
54 54
55 55 private static void checkResult(Awaiter a, Class<? extends Throwable> c) {
56 56 Throwable t = a.result();
57 57 if (! ((t == null && c == null) || (c != null && c.isInstance(t)))) {
58 58 // t.printStackTrace();
59 59 fail("Mismatch in thread " +
60 60 a.getName() + ": " +
61 61 t + ", " +
62 62 (c == null ? "<null>" : c.getName()));
63 63 } else {
64 64 pass();
65 65 }
66 66 }
67 67
68 68 //----------------------------------------------------------------
69 69 // Mechanism to get all victim threads into "running" mode.
70 70 // The fact that this also uses CyclicBarrier is entirely coincidental.
71 71 //----------------------------------------------------------------
72 72 private static final CyclicBarrier atTheStartingGate = new CyclicBarrier(3);
73 73
74 74 private static void toTheStartingGate() {
75 75 try { atTheStartingGate.await(10, SECONDS); pass(); }
↓ open down ↓ |
75 lines elided |
↑ open up ↑ |
76 76 catch (Throwable t) {
77 77 unexpected(t);
78 78 reset(atTheStartingGate);
79 79 throw new Error(t);
80 80 }
81 81 }
82 82
83 83 //----------------------------------------------------------------
84 84 // Convenience methods for creating threads that call CyclicBarrier.await
85 85 //----------------------------------------------------------------
86 - private static abstract class Awaiter extends Thread {
86 + private abstract static class Awaiter extends Thread {
87 87 static AtomicInteger count = new AtomicInteger(1);
88 88
89 89 {
90 90 this.setName("Awaiter:"+count.getAndIncrement());
91 91 this.setDaemon(true);
92 92 }
93 93
94 94 private volatile Throwable result = null;
95 95 protected void result(Throwable result) { this.result = result; }
96 96 public Throwable result() { return this.result; }
97 97 }
98 98
99 99 private static Awaiter awaiter(final CyclicBarrier barrier) {
100 100 return new Awaiter() { public void run() {
101 101 toTheStartingGate();
102 102
103 103 try { barrier.await(); }
104 104 catch (Throwable result) { result(result); }}};
105 105 }
106 106
107 107 private static Awaiter awaiter(final CyclicBarrier barrier,
108 108 final long millis) {
109 109 return new Awaiter() { public void run() {
110 110 toTheStartingGate();
111 111
112 112 try { barrier.await(millis, MILLISECONDS); }
113 113 catch (Throwable result) { result(result); }}};
114 114 }
115 115
116 116 // Returns an infinite lazy list of all possible awaiter pair combinations.
117 117 private static Iterator<Awaiter> awaiterIterator(final CyclicBarrier barrier) {
118 118 return new Iterator<Awaiter>() {
119 119 int i = 0;
120 120 public boolean hasNext() { return true; }
121 121 public Awaiter next() {
122 122 switch ((i++)&7) {
123 123 case 0: case 2: case 4: case 5:
124 124 return awaiter(barrier);
125 125 default:
126 126 return awaiter(barrier, 10 * 1000); }}
127 127 public void remove() {throw new UnsupportedOperationException();}};
128 128 }
129 129
130 130 private static void realMain(String[] args) throws Throwable {
131 131
132 132 Thread.currentThread().setName("mainThread");
133 133
134 134 //----------------------------------------------------------------
135 135 // Normal use
136 136 //----------------------------------------------------------------
137 137 try {
138 138 CyclicBarrier barrier = new CyclicBarrier(3);
139 139 equal(barrier.getParties(), 3);
140 140 Iterator<Awaiter> awaiters = awaiterIterator(barrier);
141 141 for (boolean doReset : new boolean[] {false, true})
142 142 for (int i = 0; i < 4; i++) {
143 143 Awaiter a1 = awaiters.next(); a1.start();
144 144 Awaiter a2 = awaiters.next(); a2.start();
145 145 toTheStartingGate();
146 146 barrier.await();
147 147 a1.join();
148 148 a2.join();
149 149 checkResult(a1, null);
150 150 checkResult(a2, null);
151 151 check(! barrier.isBroken());
152 152 equal(barrier.getParties(), 3);
153 153 equal(barrier.getNumberWaiting(), 0);
154 154 if (doReset) reset(barrier);
155 155 }
156 156 } catch (Throwable t) { unexpected(t); }
157 157
158 158 //----------------------------------------------------------------
159 159 // One thread interrupted
160 160 //----------------------------------------------------------------
161 161 try {
162 162 CyclicBarrier barrier = new CyclicBarrier(3);
163 163 Iterator<Awaiter> awaiters = awaiterIterator(barrier);
164 164 for (int i = 0; i < 4; i++) {
165 165 Awaiter a1 = awaiters.next(); a1.start();
166 166 Awaiter a2 = awaiters.next(); a2.start();
167 167 toTheStartingGate();
168 168 a1.interrupt();
169 169 a1.join();
170 170 a2.join();
171 171 checkResult(a1, InterruptedException.class);
172 172 checkResult(a2, BrokenBarrierException.class);
173 173 checkBroken(barrier);
174 174 reset(barrier);
175 175 }
176 176 } catch (Throwable t) { unexpected(t); }
177 177
178 178 //----------------------------------------------------------------
179 179 // Barrier is reset while threads are waiting
180 180 //----------------------------------------------------------------
181 181 try {
182 182 CyclicBarrier barrier = new CyclicBarrier(3);
183 183 Iterator<Awaiter> awaiters = awaiterIterator(barrier);
184 184 for (int i = 0; i < 4; i++) {
185 185 Awaiter a1 = awaiters.next(); a1.start();
186 186 Awaiter a2 = awaiters.next(); a2.start();
187 187 toTheStartingGate();
188 188 while (barrier.getNumberWaiting() < 2) Thread.yield();
189 189 barrier.reset();
190 190 a1.join();
191 191 a2.join();
192 192 checkResult(a1, BrokenBarrierException.class);
193 193 checkResult(a2, BrokenBarrierException.class);
194 194 check(! barrier.isBroken());
195 195 equal(barrier.getParties(), 3);
196 196 equal(barrier.getNumberWaiting(), 0);
197 197 }
198 198 } catch (Throwable t) { unexpected(t); }
199 199
200 200 //----------------------------------------------------------------
201 201 // One thread timed out
202 202 //----------------------------------------------------------------
203 203 try {
204 204 CyclicBarrier barrier = new CyclicBarrier(3);
205 205 Iterator<Awaiter> awaiters = awaiterIterator(barrier);
206 206 for (long timeout : new long[] { 0L, 10L }) {
207 207 for (int i = 0; i < 2; i++) {
208 208 Awaiter a1 = awaiter(barrier, timeout); a1.start();
209 209 Awaiter a2 = awaiters.next(); a2.start();
210 210 toTheStartingGate();
211 211 a1.join();
212 212 a2.join();
213 213 checkResult(a1, TimeoutException.class);
214 214 checkResult(a2, BrokenBarrierException.class);
215 215 checkBroken(barrier);
216 216 equal(barrier.getParties(), 3);
217 217 reset(barrier);
218 218 }
219 219 }
220 220 } catch (Throwable t) { unexpected(t); }
221 221
222 222 //----------------------------------------------------------------
223 223 // Barrier action completed normally
224 224 //----------------------------------------------------------------
225 225 try {
226 226 final AtomicInteger count = new AtomicInteger(0);
227 227 final CyclicBarrier[] kludge = new CyclicBarrier[1];
228 228 Runnable action = new Runnable() { public void run() {
229 229 count.incrementAndGet();
230 230 equal(kludge[0].getNumberWaiting(),
231 231 kludge[0].getParties());
232 232 System.out.println("OK!"); }};
233 233 CyclicBarrier barrier = new CyclicBarrier(3, action);
234 234 kludge[0] = barrier;
235 235 equal(barrier.getParties(), 3);
236 236 Iterator<Awaiter> awaiters = awaiterIterator(barrier);
237 237 for (int i = 0; i < 4; i++) {
238 238 Awaiter a1 = awaiters.next(); a1.start();
239 239 Awaiter a2 = awaiters.next(); a2.start();
240 240 toTheStartingGate();
241 241 while (barrier.getNumberWaiting() < 2) Thread.yield();
242 242 try { barrier.await(); }
243 243 catch (Throwable t) { unexpected(t); }
244 244 a1.join();
245 245 a2.join();
246 246 checkResult(a1, null);
247 247 checkResult(a2, null);
248 248 check(! barrier.isBroken());
249 249 equal(barrier.getNumberWaiting(), 0);
250 250 reset(barrier);
251 251 equal(count.get(), i+1);
252 252 }
253 253 } catch (Throwable t) { unexpected(t); }
254 254
255 255 //----------------------------------------------------------------
256 256 // Barrier action threw exception
257 257 //----------------------------------------------------------------
258 258 try {
259 259 Runnable action = new Runnable() {
260 260 public void run() { throw new Error(); }};
261 261 CyclicBarrier barrier = new CyclicBarrier(3, action);
262 262 Iterator<Awaiter> awaiters = awaiterIterator(barrier);
263 263 for (int i = 0; i < 4; i++) {
264 264 Awaiter a1 = awaiters.next(); a1.start();
265 265 Awaiter a2 = awaiters.next(); a2.start();
266 266 toTheStartingGate();
267 267 while (barrier.getNumberWaiting() < 2) Thread.yield();
268 268 try {
269 269 barrier.await();
270 270 fail("Expected Error not thrown"); }
271 271 catch (Error e) { pass(); }
272 272 catch (Throwable t) { unexpected(t); }
273 273 a1.join();
274 274 a2.join();
275 275 checkResult(a1, BrokenBarrierException.class);
276 276 checkResult(a2, BrokenBarrierException.class);
277 277 checkBroken(barrier);
278 278 reset(barrier);
279 279 }
280 280 } catch (Throwable t) { unexpected(t); }
281 281
282 282 testInterrupts();
283 283 }
284 284
285 285 /**
286 286 * Handling of extra interrupts while waiting - tests for bug 6366811
287 287 */
288 288 private static void testInterrupts() {
289 289 final int N = 10;
290 290 final CyclicBarrier startingGate = new CyclicBarrier(N+1);
291 291
292 292 /**
293 293 * A version of Awaiter that also records interrupted state.
294 294 */
295 295 class Waiter extends CheckedThread {
296 296 private boolean timed;
297 297 private CyclicBarrier barrier;
298 298 private CountDownLatch doneSignal;
299 299 private Throwable throwable;
300 300 private boolean interrupted;
301 301
302 302 public Waiter(boolean timed,
303 303 CountDownLatch doneSignal,
304 304 CyclicBarrier barrier) {
305 305 this.timed = timed;
306 306 this.doneSignal = doneSignal;
307 307 this.barrier = barrier;
308 308 }
309 309 Throwable throwable() { return this.throwable; }
310 310 boolean interruptBit() { return this.interrupted; }
311 311 void realRun() throws Throwable {
312 312 startingGate.await(10, SECONDS);
313 313 try {
314 314 if (timed) barrier.await(10, SECONDS);
315 315 else barrier.await(); }
316 316 catch (Throwable throwable) { this.throwable = throwable; }
317 317
318 318 try { doneSignal.await(10, SECONDS); }
319 319 catch (InterruptedException e) { interrupted = true; }
320 320 }
321 321 }
322 322
323 323 //----------------------------------------------------------------
324 324 // Interrupt occurs during barrier trip
325 325 //----------------------------------------------------------------
326 326 try {
327 327 final CountDownLatch doneSignal = new CountDownLatch(1);
328 328 final List<Waiter> waiters = new ArrayList<Waiter>(N);
329 329
330 330 // work around finality of closed-over variables
331 331 final Runnable[] realAction = new Runnable[1];
332 332 final Runnable delegateAction =
333 333 new Runnable() {public void run() {realAction[0].run();}};
334 334 final CyclicBarrier barrier = new CyclicBarrier(N+1, delegateAction);
335 335
336 336 realAction[0] = new Runnable() { public void run() {
337 337 try {
338 338 for (int i = 0; i < N/2; i++)
339 339 waiters.get(i).interrupt();
340 340 // we need to try and ensure that the waiters get
341 341 // to process their interruption before we do the
342 342 // signalAll that trips the barrier. Using sleep
343 343 // seems to work reliably while yield does not.
344 344 Thread.sleep(100);
345 345 } catch (Throwable t) { unexpected(t); }
346 346 }};
347 347 for (int i = 0; i < N; i++) {
348 348 Waiter waiter = new Waiter(i < N/2, doneSignal, barrier);
349 349 waiter.start();
350 350 waiters.add(waiter);
351 351 }
352 352 startingGate.await(10, SECONDS);
353 353 while (barrier.getNumberWaiting() < N) Thread.yield();
354 354 barrier.await();
355 355 doneSignal.countDown();
356 356 int countInterrupted = 0;
357 357 int countInterruptedException = 0;
358 358 int countBrokenBarrierException = 0;
359 359 for (Waiter waiter : waiters) {
360 360 waiter.join();
361 361 equal(waiter.throwable(), null);
362 362 if (waiter.interruptBit())
363 363 countInterrupted++;
364 364 }
365 365 equal(countInterrupted, N/2);
366 366 check(! barrier.isBroken());
367 367 } catch (Throwable t) { unexpected(t); }
368 368
369 369 //----------------------------------------------------------------
370 370 // Multiple interrupts occur during barrier await
371 371 //----------------------------------------------------------------
372 372 try {
373 373 final CountDownLatch doneSignal = new CountDownLatch(1);
374 374 final CyclicBarrier barrier = new CyclicBarrier(N+1);
375 375 final List<Waiter> waiters = new ArrayList<Waiter>(N);
376 376 for (int i = 0; i < N; i++) {
377 377 Waiter waiter = new Waiter(i < N/2, doneSignal, barrier);
378 378 waiter.start();
379 379 waiters.add(waiter);
380 380 }
381 381 startingGate.await(10, SECONDS);
382 382 while (barrier.getNumberWaiting() < N) Thread.yield();
383 383 for (int i = 0; i < N/2; i++)
384 384 waiters.get(i).interrupt();
385 385 doneSignal.countDown();
386 386 int countInterrupted = 0;
387 387 int countInterruptedException = 0;
388 388 int countBrokenBarrierException = 0;
389 389 for (Waiter waiter : waiters) {
390 390 waiter.join();
391 391 if (waiter.throwable() instanceof InterruptedException)
392 392 countInterruptedException++;
393 393 if (waiter.throwable() instanceof BrokenBarrierException)
394 394 countBrokenBarrierException++;
395 395 if (waiter.interruptBit())
396 396 countInterrupted++;
397 397 }
398 398 equal(countInterrupted, N/2-1);
399 399 equal(countInterruptedException, 1);
400 400 equal(countBrokenBarrierException, N-1);
401 401 checkBroken(barrier);
402 402 reset(barrier);
403 403 } catch (Throwable t) { unexpected(t); }
404 404 }
405 405
406 406 //--------------------- Infrastructure ---------------------------
407 407 static volatile int passed = 0, failed = 0;
408 408 static void pass() {passed++;}
409 409 static void fail() {failed++; Thread.dumpStack();}
↓ open down ↓ |
313 lines elided |
↑ open up ↑ |
410 410 static void fail(String msg) {System.out.println(msg); fail();}
411 411 static void unexpected(Throwable t) {failed++; t.printStackTrace();}
412 412 static void check(boolean cond) {if (cond) pass(); else fail();}
413 413 static void equal(Object x, Object y) {
414 414 if (x == null ? y == null : x.equals(y)) pass();
415 415 else fail(x + " not equal to " + y);}
416 416 public static void main(String[] args) throws Throwable {
417 417 try {realMain(args);} catch (Throwable t) {unexpected(t);}
418 418 System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
419 419 if (failed > 0) throw new AssertionError("Some tests failed");}
420 - static abstract class Fun { abstract void f() throws Throwable; }
420 + abstract static class Fun { abstract void f() throws Throwable; }
421 421 private static void THROWS(Class<? extends Throwable> k, Fun... fs) {
422 422 for (Fun f : fs)
423 423 try { f.f(); fail("Expected " + k.getName() + " not thrown"); }
424 424 catch (Throwable t) {
425 425 if (k.isAssignableFrom(t.getClass())) pass();
426 426 else unexpected(t);}}
427 - private static abstract class CheckedThread extends Thread {
427 + private abstract static class CheckedThread extends Thread {
428 428 abstract void realRun() throws Throwable;
429 429 public void run() {
430 430 try {realRun();} catch (Throwable t) {unexpected(t);}}}
431 431 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX