1/* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. 7 * 8 * This code is distributed in the hope that it will be useful, but WITHOUT 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 11 * version 2 for more details (a copy is included in the LICENSE file that 12 * accompanied this code). 13 * 14 * You should have received a copy of the GNU General Public License version 15 * 2 along with this work; if not, write to the Free Software Foundation, 16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 17 * 18 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 19 * or visit www.oracle.com if you need additional information or have any 20 * questions. 21 */ 22 23/* 24 * This file is available under and governed by the GNU General Public 25 * License version 2 only, as published by the Free Software Foundation. 26 * However, the following notice accompanied the original version of this 27 * file: 28 * 29 * Written by Martin Buchholz with assistance from members of JCP 30 * JSR-166 Expert Group and released to the public domain, as 31 * explained at http://creativecommons.org/publicdomain/zero/1.0/ 32 */ 33 34/* 35 * @test 36 * @bug 8074773 37 * @summary Stress test looks for lost unparks 38 */ 39 40import static java.util.concurrent.TimeUnit.SECONDS; 41 42import java.util.SplittableRandom; 43import java.util.concurrent.CountDownLatch; 44import java.util.concurrent.ExecutorService; 45import java.util.concurrent.Executors; 46import java.util.concurrent.atomic.AtomicReferenceArray; 47import java.util.concurrent.locks.LockSupport; 48 49public final class ParkLoops { 50 static final int THREADS = 4; 51 static final int ITERS = 30_000; 52 53 static class Parker implements Runnable { 54 static { 55 // Reduce the risk of rare disastrous classloading in first call to 56 // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773 57 Class<?> ensureLoaded = LockSupport.class; 58 } 59 60 private final AtomicReferenceArray<Thread> threads; 61 private final CountDownLatch done; 62 private final SplittableRandom rnd; 63 64 Parker(AtomicReferenceArray<Thread> threads, 65 CountDownLatch done, 66 SplittableRandom rnd) { 67 this.threads = threads; this.done = done; this.rnd = rnd; 68 } 69 70 public void run() { 71 final Thread current = Thread.currentThread(); 72 for (int k = ITERS, j; k > 0; k--) { 73 do { 74 j = rnd.nextInt(THREADS); 75 } while (!threads.compareAndSet(j, null, current)); 76 do { // handle spurious wakeups 77 LockSupport.park(); 78 } while (threads.get(j) == current); 79 } 80 done.countDown(); 81 } 82 } 83 84 static class Unparker implements Runnable { 85 static { 86 // Reduce the risk of rare disastrous classloading in first call to 87 // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773 88 Class<?> ensureLoaded = LockSupport.class; 89 } 90 91 private final AtomicReferenceArray<Thread> threads; 92 private final CountDownLatch done; 93 private final SplittableRandom rnd; 94 95 Unparker(AtomicReferenceArray<Thread> threads, 96 CountDownLatch done, 97 SplittableRandom rnd) { 98 this.threads = threads; this.done = done; this.rnd = rnd; 99 } 100 101 public void run() { 102 for (int n = 0; (n++ & 0xff) != 0 || done.getCount() > 0;) { 103 int j = rnd.nextInt(THREADS); 104 Thread parker = threads.get(j); 105 if (parker != null && 106 threads.compareAndSet(j, parker, null)) { 107 LockSupport.unpark(parker); 108 } 109 } 110 } 111 } 112 113 public static void main(String[] args) throws Exception { 114 final SplittableRandom rnd = new SplittableRandom(); 115 final ExecutorService pool = Executors.newCachedThreadPool(); 116 final AtomicReferenceArray<Thread> threads 117 = new AtomicReferenceArray<>(THREADS); 118 final CountDownLatch done = new CountDownLatch(THREADS); 119 for (int i = 0; i < THREADS; i++) { 120 pool.submit(new Parker(threads, done, rnd.split())); 121 pool.submit(new Unparker(threads, done, rnd.split())); 122 } 123 // Let test harness handle timeout 124 done.await(); 125 pool.shutdown(); 126 pool.awaitTermination(Long.MAX_VALUE, SECONDS); 127 } 128} 129