ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/tck/CyclicBarrierTest.java
(Generate patch)

Comparing jsr166/src/test/tck/CyclicBarrierTest.java (file contents):
Revision 1.5 by dl, Sun Oct 5 23:00:40 2003 UTC vs.
Revision 1.34 by jsr166, Mon Sep 9 00:46:44 2019 UTC

# Line 1 | Line 1
1   /*
2 < * Written by members of JCP JSR-166 Expert Group and released to the
3 < * public domain. Use, modify, and redistribute this code in any way
4 < * without acknowledgement. Other contributors include Andrew Wright,
5 < * Jeffrey Hayes, Pat Fischer, Mike Judd.
2 > * Written by Doug Lea with assistance from members of JCP JSR-166
3 > * Expert Group and released to the public domain, as explained at
4 > * http://creativecommons.org/publicdomain/zero/1.0/
5 > * Other contributors include Andrew Wright, Jeffrey Hayes,
6 > * Pat Fisher, Mike Judd.
7   */
8  
9 < import junit.framework.*;
9 < import java.util.*;
10 < import java.util.concurrent.*;
9 > import static java.util.concurrent.TimeUnit.MILLISECONDS;
10  
11 < public class CyclicBarrierTest extends JSR166TestCase{
11 > import java.util.concurrent.BrokenBarrierException;
12 > import java.util.concurrent.CountDownLatch;
13 > import java.util.concurrent.CyclicBarrier;
14 > import java.util.concurrent.ExecutorService;
15 > import java.util.concurrent.Executors;
16 > import java.util.concurrent.ThreadLocalRandom;
17 > import java.util.concurrent.TimeoutException;
18 > import java.util.concurrent.atomic.AtomicInteger;
19 >
20 > import junit.framework.Test;
21 > import junit.framework.TestSuite;
22 >
23 > public class CyclicBarrierTest extends JSR166TestCase {
24      public static void main(String[] args) {
25 <        junit.textui.TestRunner.run (suite());  
25 >        main(suite(), args);
26      }
27      public static Test suite() {
28 <        return new TestSuite(CyclicBarrierTest.class);
28 >        return new TestSuite(CyclicBarrierTest.class);
29      }
30  
31 <    private volatile int countAction;
32 <    private class MyAction implements Runnable {
33 <        public void run() { ++countAction; }
31 >    /**
32 >     * Spin-waits till the number of waiters == numberOfWaiters.
33 >     */
34 >    void awaitNumberWaiting(CyclicBarrier barrier, int numberOfWaiters) {
35 >        long startTime = System.nanoTime();
36 >        while (barrier.getNumberWaiting() != numberOfWaiters) {
37 >            if (millisElapsedSince(startTime) > LONG_DELAY_MS)
38 >                fail("timed out");
39 >            Thread.yield();
40 >        }
41      }
42 <    
42 >
43      /**
44 <     * Creating with negative parties throws IAE
44 >     * Creating with negative parties throws IllegalArgumentException
45       */
46      public void testConstructor1() {
47          try {
48              new CyclicBarrier(-1, (Runnable)null);
49              shouldThrow();
50 <        } catch(IllegalArgumentException e){}
50 >        } catch (IllegalArgumentException success) {}
51      }
52  
53      /**
54 <     * Creating with negative parties and no action throws IAE
54 >     * Creating with negative parties and no action throws
55 >     * IllegalArgumentException
56       */
57      public void testConstructor2() {
58          try {
59              new CyclicBarrier(-1);
60              shouldThrow();
61 <        } catch(IllegalArgumentException e){}
61 >        } catch (IllegalArgumentException success) {}
62      }
63  
64      /**
# Line 47 | Line 66 | public class CyclicBarrierTest extends J
66       */
67      public void testGetParties() {
68          CyclicBarrier b = new CyclicBarrier(2);
69 <        assertEquals(2, b.getParties());
69 >        assertEquals(2, b.getParties());
70          assertEquals(0, b.getNumberWaiting());
71      }
72  
73      /**
74       * A 1-party barrier triggers after single await
75       */
76 <    public void testSingleParty() {
77 <        try {
78 <            CyclicBarrier b = new CyclicBarrier(1);
79 <            assertEquals(1, b.getParties());
80 <            assertEquals(0, b.getNumberWaiting());
81 <            b.await();
82 <            b.await();
64 <            assertEquals(0, b.getNumberWaiting());
65 <        }
66 <        catch(Exception e) {
67 <            unexpectedException();
68 <        }
76 >    public void testSingleParty() throws Exception {
77 >        CyclicBarrier b = new CyclicBarrier(1);
78 >        assertEquals(1, b.getParties());
79 >        assertEquals(0, b.getNumberWaiting());
80 >        b.await();
81 >        b.await();
82 >        assertEquals(0, b.getNumberWaiting());
83      }
84 <    
84 >
85      /**
86       * The supplied barrier action is run at barrier
87       */
88 <    public void testBarrierAction() {
89 <        try {
90 <            countAction = 0;
91 <            CyclicBarrier b = new CyclicBarrier(1, new MyAction());
92 <            assertEquals(1, b.getParties());
93 <            assertEquals(0, b.getNumberWaiting());
94 <            b.await();
95 <            b.await();
96 <            assertEquals(0, b.getNumberWaiting());
97 <            assertEquals(countAction, 2);
98 <        }
85 <        catch(Exception e) {
86 <            unexpectedException();
87 <        }
88 >    public void testBarrierAction() throws Exception {
89 >        final AtomicInteger count = new AtomicInteger(0);
90 >        final Runnable incCount = new Runnable() { public void run() {
91 >            count.getAndIncrement(); }};
92 >        CyclicBarrier b = new CyclicBarrier(1, incCount);
93 >        assertEquals(1, b.getParties());
94 >        assertEquals(0, b.getNumberWaiting());
95 >        b.await();
96 >        b.await();
97 >        assertEquals(0, b.getNumberWaiting());
98 >        assertEquals(2, count.get());
99      }
100  
101      /**
102       * A 2-party/thread barrier triggers after both threads invoke await
103       */
104 <    public void testTwoParties() {
104 >    public void testTwoParties() throws Exception {
105          final CyclicBarrier b = new CyclicBarrier(2);
106 <        Thread t = new Thread(new Runnable() {
107 <                public void run() {
108 <                    try {
109 <                        b.await();
110 <                        b.await();
111 <                        b.await();
112 <                        b.await();
113 <                    } catch(Exception e){
114 <                        threadUnexpectedException();
115 <                    }}});
116 <
117 <        try {
118 <            t.start();
108 <            b.await();
109 <            b.await();
110 <            b.await();
111 <            b.await();
112 <            t.join();
113 <        } catch(Exception e){
114 <            unexpectedException();
115 <        }
106 >        Thread t = newStartedThread(new CheckedRunnable() {
107 >            public void realRun() throws Exception {
108 >                b.await();
109 >                b.await();
110 >                b.await();
111 >                b.await();
112 >            }});
113 >
114 >        b.await();
115 >        b.await();
116 >        b.await();
117 >        b.await();
118 >        awaitTermination(t);
119      }
120  
118
121      /**
122       * An interruption in one party causes others waiting in await to
123       * throw BrokenBarrierException
124       */
125      public void testAwait1_Interrupted_BrokenBarrier() {
126          final CyclicBarrier c = new CyclicBarrier(3);
127 <        Thread t1 = new Thread(new Runnable() {
128 <                public void run() {
129 <                    try {
130 <                        c.await();
131 <                        threadShouldThrow();
132 <                    } catch(InterruptedException success){}                
133 <                    catch(Exception b){
134 <                        threadUnexpectedException();
135 <                    }
136 <                }
137 <            });
138 <        Thread t2 = new Thread(new Runnable() {
139 <                public void run() {
140 <                    try {
141 <                        c.await();
142 <                        threadShouldThrow();                        
143 <                    } catch(BrokenBarrierException success){
144 <                    } catch(Exception i){
143 <                        threadUnexpectedException();
144 <                    }
145 <                }
146 <            });
147 <        try {
148 <            t1.start();
149 <            t2.start();
150 <            Thread.sleep(SHORT_DELAY_MS);
151 <            t1.interrupt();
152 <            t1.join();
153 <            t2.join();
154 <        } catch(InterruptedException e){
155 <            unexpectedException();
156 <        }
127 >        final CountDownLatch pleaseInterrupt = new CountDownLatch(2);
128 >        Thread t1 = new ThreadShouldThrow(InterruptedException.class) {
129 >            public void realRun() throws Exception {
130 >                pleaseInterrupt.countDown();
131 >                c.await();
132 >            }};
133 >        Thread t2 = new ThreadShouldThrow(BrokenBarrierException.class) {
134 >            public void realRun() throws Exception {
135 >                pleaseInterrupt.countDown();
136 >                c.await();
137 >            }};
138 >
139 >        t1.start();
140 >        t2.start();
141 >        await(pleaseInterrupt);
142 >        t1.interrupt();
143 >        awaitTermination(t1);
144 >        awaitTermination(t2);
145      }
146  
147      /**
148       * An interruption in one party causes others waiting in timed await to
149       * throw BrokenBarrierException
150       */
151 <    public void testAwait2_Interrupted_BrokenBarrier() {
152 <      final CyclicBarrier c = new CyclicBarrier(3);
153 <        Thread t1 = new Thread(new Runnable() {
154 <                public void run() {
155 <                    try {
156 <                        c.await(MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS);
157 <                        threadShouldThrow();
158 <                    } catch(InterruptedException success){
159 <                    } catch(Exception b){
160 <                        threadUnexpectedException();
161 <                    }
162 <                }
163 <            });
164 <        Thread t2 = new Thread(new Runnable() {
165 <                public void run() {
166 <                    try {
167 <                        c.await(MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS);
168 <                        threadShouldThrow();                        
169 <                    } catch(BrokenBarrierException success){
170 <                    } catch(Exception i){
183 <                        threadUnexpectedException();
184 <                    }
185 <                }
186 <            });
187 <        try {
188 <            t1.start();
189 <            t2.start();
190 <            Thread.sleep(SHORT_DELAY_MS);
191 <            t1.interrupt();
192 <            t1.join();
193 <            t2.join();
194 <        } catch(InterruptedException e){
195 <            unexpectedException();
196 <        }
151 >    public void testAwait2_Interrupted_BrokenBarrier() throws Exception {
152 >        final CyclicBarrier c = new CyclicBarrier(3);
153 >        final CountDownLatch pleaseInterrupt = new CountDownLatch(2);
154 >        Thread t1 = new ThreadShouldThrow(InterruptedException.class) {
155 >            public void realRun() throws Exception {
156 >                pleaseInterrupt.countDown();
157 >                c.await(LONG_DELAY_MS, MILLISECONDS);
158 >            }};
159 >        Thread t2 = new ThreadShouldThrow(BrokenBarrierException.class) {
160 >            public void realRun() throws Exception {
161 >                pleaseInterrupt.countDown();
162 >                c.await(LONG_DELAY_MS, MILLISECONDS);
163 >            }};
164 >
165 >        t1.start();
166 >        t2.start();
167 >        await(pleaseInterrupt);
168 >        t1.interrupt();
169 >        awaitTermination(t1);
170 >        awaitTermination(t2);
171      }
172 <    
172 >
173      /**
174       * A timeout in timed await throws TimeoutException
175       */
176 <    public void testAwait3_TimeOutException() {
176 >    public void testAwait3_TimeoutException() throws InterruptedException {
177          final CyclicBarrier c = new CyclicBarrier(2);
178 <        Thread t = new Thread(new Runnable() {
179 <                public void run() {
180 <                    try {
181 <                        c.await(SHORT_DELAY_MS, TimeUnit.MILLISECONDS);
182 <                        threadShouldThrow();
183 <                    } catch(TimeoutException success){
184 <                    } catch(Exception b){
185 <                        threadUnexpectedException();
186 <                        
187 <                    }
188 <                }
215 <            });
216 <        try {
217 <            t.start();
218 <            t.join();
219 <        } catch(InterruptedException e){
220 <            unexpectedException();
221 <        }
178 >        Thread t = newStartedThread(new CheckedRunnable() {
179 >            public void realRun() throws Exception {
180 >                long startTime = System.nanoTime();
181 >                try {
182 >                    c.await(timeoutMillis(), MILLISECONDS);
183 >                    shouldThrow();
184 >                } catch (TimeoutException success) {}
185 >                assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
186 >            }});
187 >
188 >        awaitTermination(t);
189      }
190  
191      /**
192       * A timeout in one party causes others waiting in timed await to
193       * throw BrokenBarrierException
194       */
195 <    public void testAwait4_Timeout_BrokenBarrier() {
196 <      final CyclicBarrier c = new CyclicBarrier(3);
197 <        Thread t1 = new Thread(new Runnable() {
198 <                public void run() {
199 <                    try {
200 <                        c.await(SHORT_DELAY_MS, TimeUnit.MILLISECONDS);
201 <                        threadShouldThrow();
202 <                    } catch(TimeoutException success){
203 <                    } catch(Exception b){
204 <                        threadUnexpectedException();
205 <                    }
206 <                }
207 <            });
208 <        Thread t2 = new Thread(new Runnable() {
209 <                public void run() {
210 <                    try {
211 <                        c.await(MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS);
212 <                        threadShouldThrow();                        
213 <                    } catch(BrokenBarrierException success){
214 <                    } catch(Exception i){
215 <                        threadUnexpectedException();
216 <                    }
250 <                }
251 <            });
252 <        try {
253 <            t1.start();
254 <            t2.start();
255 <            t1.join();
256 <            t2.join();
257 <        } catch(InterruptedException e){
258 <            unexpectedException();
259 <        }
195 >    public void testAwait4_Timeout_BrokenBarrier() throws InterruptedException {
196 >        final CyclicBarrier c = new CyclicBarrier(3);
197 >        Thread t1 = newStartedThread(new CheckedRunnable() {
198 >            public void realRun() throws Exception {
199 >                try {
200 >                    c.await(LONG_DELAY_MS, MILLISECONDS);
201 >                    shouldThrow();
202 >                } catch (BrokenBarrierException success) {}
203 >            }});
204 >        Thread t2 = newStartedThread(new CheckedRunnable() {
205 >            public void realRun() throws Exception {
206 >                awaitNumberWaiting(c, 1);
207 >                long startTime = System.nanoTime();
208 >                try {
209 >                    c.await(timeoutMillis(), MILLISECONDS);
210 >                    shouldThrow();
211 >                } catch (TimeoutException success) {}
212 >                assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
213 >            }});
214 >
215 >        awaitTermination(t1);
216 >        awaitTermination(t2);
217      }
218  
219      /**
220       * A timeout in one party causes others waiting in await to
221       * throw BrokenBarrierException
222       */
223 <    public void testAwait5_Timeout_BrokenBarrier() {
224 <      final CyclicBarrier c = new CyclicBarrier(3);
225 <        Thread t1 = new Thread(new Runnable() {
226 <                public void run() {
227 <                    try {
228 <                        c.await(SHORT_DELAY_MS, TimeUnit.MILLISECONDS);
229 <                        threadShouldThrow();
230 <                    } catch(TimeoutException success){
231 <                    } catch(Exception b){
232 <                        threadUnexpectedException();
233 <                    }
234 <                }
235 <            });
236 <        Thread t2 = new Thread(new Runnable() {
237 <                public void run() {
238 <                    try {
239 <                        c.await();
240 <                        threadShouldThrow();                        
241 <                    } catch(BrokenBarrierException success){
242 <                    } catch(Exception i){
243 <                        threadUnexpectedException();
244 <                    }
288 <                }
289 <            });
290 <        try {
291 <            t1.start();
292 <            t2.start();
293 <            t1.join();
294 <            t2.join();
295 <        } catch(InterruptedException e){
296 <            unexpectedException();
297 <        }
223 >    public void testAwait5_Timeout_BrokenBarrier() throws InterruptedException {
224 >        final CyclicBarrier c = new CyclicBarrier(3);
225 >        Thread t1 = newStartedThread(new CheckedRunnable() {
226 >            public void realRun() throws Exception {
227 >                try {
228 >                    c.await();
229 >                    shouldThrow();
230 >                } catch (BrokenBarrierException success) {}
231 >            }});
232 >        Thread t2 = newStartedThread(new CheckedRunnable() {
233 >            public void realRun() throws Exception {
234 >                awaitNumberWaiting(c, 1);
235 >                long startTime = System.nanoTime();
236 >                try {
237 >                    c.await(timeoutMillis(), MILLISECONDS);
238 >                    shouldThrow();
239 >                } catch (TimeoutException success) {}
240 >                assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
241 >            }});
242 >
243 >        awaitTermination(t1);
244 >        awaitTermination(t2);
245      }
246 <    
246 >
247      /**
248       * A reset of an active barrier causes waiting threads to throw
249       * BrokenBarrierException
250       */
251 <    public void testReset_BrokenBarrier() {
251 >    public void testReset_BrokenBarrier() throws InterruptedException {
252          final CyclicBarrier c = new CyclicBarrier(3);
253 <        Thread t1 = new Thread(new Runnable() {
254 <                public void run() {
255 <                    try {
256 <                        c.await();
257 <                        threadShouldThrow();
258 <                    } catch(BrokenBarrierException success){}                
259 <                    catch(Exception b){
260 <                        threadUnexpectedException();
261 <                    }
262 <                }
263 <            });
264 <        Thread t2 = new Thread(new Runnable() {
265 <                public void run() {
266 <                    try {
267 <                        c.await();
268 <                        threadShouldThrow();                        
269 <                    } catch(BrokenBarrierException success){
270 <                    } catch(Exception i){
271 <                        threadUnexpectedException();
272 <                    }
326 <                }
327 <            });
328 <        try {
329 <            t1.start();
330 <            t2.start();
331 <            Thread.sleep(SHORT_DELAY_MS);
332 <            c.reset();
333 <            t1.join();
334 <            t2.join();
335 <        } catch(InterruptedException e){
336 <            unexpectedException();
337 <        }
253 >        final CountDownLatch pleaseReset = new CountDownLatch(2);
254 >        Thread t1 = new ThreadShouldThrow(BrokenBarrierException.class) {
255 >            public void realRun() throws Exception {
256 >                pleaseReset.countDown();
257 >                c.await();
258 >            }};
259 >        Thread t2 = new ThreadShouldThrow(BrokenBarrierException.class) {
260 >            public void realRun() throws Exception {
261 >                pleaseReset.countDown();
262 >                c.await();
263 >            }};
264 >
265 >        t1.start();
266 >        t2.start();
267 >        await(pleaseReset);
268 >
269 >        awaitNumberWaiting(c, 2);
270 >        c.reset();
271 >        awaitTermination(t1);
272 >        awaitTermination(t2);
273      }
274  
275      /**
276       * A reset before threads enter barrier does not throw
277       * BrokenBarrierException
278       */
279 <    public void testReset_NoBrokenBarrier() {
279 >    public void testReset_NoBrokenBarrier() throws Exception {
280          final CyclicBarrier c = new CyclicBarrier(3);
281 <        Thread t1 = new Thread(new Runnable() {
282 <                public void run() {
283 <                    try {
284 <                        c.await();
285 <                    } catch(Exception b){
286 <                        threadUnexpectedException();
287 <                    }
288 <                }
289 <            });
290 <        Thread t2 = new Thread(new Runnable() {
291 <                public void run() {
292 <                    try {
293 <                        c.await();
294 <                    } catch(Exception i){
295 <                        threadUnexpectedException();
296 <                    }
297 <                }
298 <            });
299 <        try {
300 <            c.reset();
281 >        c.reset();
282 >
283 >        Thread t1 = newStartedThread(new CheckedRunnable() {
284 >            public void realRun() throws Exception {
285 >                c.await();
286 >            }});
287 >        Thread t2 = newStartedThread(new CheckedRunnable() {
288 >            public void realRun() throws Exception {
289 >                c.await();
290 >            }});
291 >
292 >        c.await();
293 >        awaitTermination(t1);
294 >        awaitTermination(t2);
295 >    }
296 >
297 >    /**
298 >     * Reset of a non-broken barrier does not break barrier
299 >     */
300 >    public void testResetWithoutBreakage() throws Exception {
301 >        final CyclicBarrier barrier = new CyclicBarrier(3);
302 >        for (int i = 0; i < 3; i++) {
303 >            final CyclicBarrier start = new CyclicBarrier(3);
304 >            Thread t1 = newStartedThread(new CheckedRunnable() {
305 >                public void realRun() throws Exception {
306 >                    start.await();
307 >                    barrier.await();
308 >                }});
309 >
310 >            Thread t2 = newStartedThread(new CheckedRunnable() {
311 >                public void realRun() throws Exception {
312 >                    start.await();
313 >                    barrier.await();
314 >                }});
315 >
316 >            start.await();
317 >            barrier.await();
318 >            awaitTermination(t1);
319 >            awaitTermination(t2);
320 >            assertFalse(barrier.isBroken());
321 >            assertEquals(0, barrier.getNumberWaiting());
322 >            if (i == 1) barrier.reset();
323 >            assertFalse(barrier.isBroken());
324 >            assertEquals(0, barrier.getNumberWaiting());
325 >        }
326 >    }
327 >
328 >    /**
329 >     * Reset of a barrier after interruption reinitializes it.
330 >     */
331 >    public void testResetAfterInterrupt() throws Exception {
332 >        final CyclicBarrier barrier = new CyclicBarrier(3);
333 >        for (int i = 0; i < 2; i++) {
334 >            final CyclicBarrier start = new CyclicBarrier(3);
335 >            Thread t1 = new ThreadShouldThrow(InterruptedException.class) {
336 >                public void realRun() throws Exception {
337 >                    start.await();
338 >                    barrier.await();
339 >                }};
340 >
341 >            Thread t2 = new ThreadShouldThrow(BrokenBarrierException.class) {
342 >                public void realRun() throws Exception {
343 >                    start.await();
344 >                    barrier.await();
345 >                }};
346 >
347              t1.start();
348              t2.start();
349 <            c.await();
350 <            t1.join();
351 <            t2.join();
352 <        } catch(Exception e){
353 <            unexpectedException();
349 >            start.await();
350 >            t1.interrupt();
351 >            awaitTermination(t1);
352 >            awaitTermination(t2);
353 >            assertTrue(barrier.isBroken());
354 >            assertEquals(0, barrier.getNumberWaiting());
355 >            barrier.reset();
356 >            assertFalse(barrier.isBroken());
357 >            assertEquals(0, barrier.getNumberWaiting());
358 >        }
359 >    }
360 >
361 >    /**
362 >     * Reset of a barrier after timeout reinitializes it.
363 >     */
364 >    public void testResetAfterTimeout() throws Exception {
365 >        final CyclicBarrier barrier = new CyclicBarrier(3);
366 >        for (int i = 0; i < 2; i++) {
367 >            assertEquals(0, barrier.getNumberWaiting());
368 >            Thread t1 = newStartedThread(new CheckedRunnable() {
369 >                public void realRun() throws Exception {
370 >                    try {
371 >                        barrier.await();
372 >                        shouldThrow();
373 >                    } catch (BrokenBarrierException success) {}
374 >                }});
375 >            Thread t2 = newStartedThread(new CheckedRunnable() {
376 >                public void realRun() throws Exception {
377 >                    awaitNumberWaiting(barrier, 1);
378 >                    long startTime = System.nanoTime();
379 >                    try {
380 >                        barrier.await(timeoutMillis(), MILLISECONDS);
381 >                        shouldThrow();
382 >                    } catch (TimeoutException success) {}
383 >                    assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
384 >                }});
385 >
386 >            awaitTermination(t1);
387 >            awaitTermination(t2);
388 >            assertEquals(0, barrier.getNumberWaiting());
389 >            assertTrue(barrier.isBroken());
390 >            assertEquals(0, barrier.getNumberWaiting());
391 >            barrier.reset();
392 >            assertFalse(barrier.isBroken());
393 >            assertEquals(0, barrier.getNumberWaiting());
394 >        }
395 >    }
396 >
397 >    /**
398 >     * Reset of a barrier after a failed command reinitializes it.
399 >     */
400 >    public void testResetAfterCommandException() throws Exception {
401 >        final CyclicBarrier barrier =
402 >            new CyclicBarrier(3, new Runnable() {
403 >                    public void run() {
404 >                        throw new NullPointerException(); }});
405 >        for (int i = 0; i < 2; i++) {
406 >            final CyclicBarrier start = new CyclicBarrier(3);
407 >            Thread t1 = new ThreadShouldThrow(BrokenBarrierException.class) {
408 >                public void realRun() throws Exception {
409 >                    start.await();
410 >                    barrier.await();
411 >                }};
412 >
413 >            Thread t2 = new ThreadShouldThrow(BrokenBarrierException.class) {
414 >                public void realRun() throws Exception {
415 >                    start.await();
416 >                    barrier.await();
417 >                }};
418 >
419 >            t1.start();
420 >            t2.start();
421 >            start.await();
422 >            awaitNumberWaiting(barrier, 2);
423 >            try {
424 >                barrier.await();
425 >                shouldThrow();
426 >            } catch (NullPointerException success) {}
427 >            awaitTermination(t1);
428 >            awaitTermination(t2);
429 >            assertTrue(barrier.isBroken());
430 >            assertEquals(0, barrier.getNumberWaiting());
431 >            barrier.reset();
432 >            assertFalse(barrier.isBroken());
433 >            assertEquals(0, barrier.getNumberWaiting());
434          }
435      }
436  
437 +    /**
438 +     * There can be more threads calling await() than parties, as long as each
439 +     * task only calls await once and the task count is a multiple of parties.
440 +     */
441 +    public void testMoreTasksThanParties() throws Exception {
442 +        final ThreadLocalRandom rnd = ThreadLocalRandom.current();
443 +        final int parties = rnd.nextInt(1, 5);
444 +        final int nTasks = rnd.nextInt(1, 5) * parties;
445 +        final AtomicInteger tripCount = new AtomicInteger(0);
446 +        final AtomicInteger awaitCount = new AtomicInteger(0);
447 +        final CyclicBarrier barrier =
448 +            new CyclicBarrier(parties, () -> tripCount.getAndIncrement());
449 +        final ExecutorService e = Executors.newFixedThreadPool(nTasks);
450 +        final Runnable awaiter = () -> {
451 +            try {
452 +                if (randomBoolean())
453 +                    barrier.await();
454 +                else
455 +                    barrier.await(LONG_DELAY_MS, MILLISECONDS);
456 +                awaitCount.getAndIncrement();
457 +            } catch (Throwable fail) { threadUnexpectedException(fail); }};
458 +        try (PoolCleaner cleaner = cleaner(e)) {
459 +            for (int i = nTasks; i--> 0; )
460 +                e.execute(awaiter);
461 +        }
462 +        assertEquals(nTasks / parties, tripCount.get());
463 +        assertEquals(nTasks, awaitCount.get());
464 +        assertEquals(0, barrier.getNumberWaiting());
465 +    }
466   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines