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 Doug Lea with assistance from members of JCP JSR-166 30 * Expert Group and released to the public domain, as explained at 31 * http://creativecommons.org/publicdomain/zero/1.0/ 32 */ 33 34 /* 35 * @test 36 * @bug 6805775 6815766 37 * @library /test/lib 38 * @run main OfferDrainToLoops 100 39 * @summary Test concurrent offer vs. drainTo 40 */ 41 42 import java.util.ArrayList; 43 import java.util.List; 44 import java.util.SplittableRandom; 45 import java.util.concurrent.ArrayBlockingQueue; 46 import java.util.concurrent.BlockingQueue; 47 import java.util.concurrent.LinkedBlockingDeque; 48 import java.util.concurrent.LinkedBlockingQueue; 49 import java.util.concurrent.LinkedTransferQueue; 50 import java.util.concurrent.atomic.AtomicLong; 51 import jdk.test.lib.Utils; 52 53 @SuppressWarnings({"unchecked", "rawtypes", "deprecation"}) 54 public class OfferDrainToLoops { 55 static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000); 56 final long testDurationMillisDefault = 10_000L; 57 final long testDurationMillis; 58 59 OfferDrainToLoops(String[] args) { 60 testDurationMillis = (args.length > 0) ? 61 Long.valueOf(args[0]) : testDurationMillisDefault; 62 } 63 64 void checkNotContainsNull(Iterable it) { 65 for (Object x : it) 66 check(x != null); 67 } 68 69 void test(String[] args) throws Throwable { 70 test(new LinkedBlockingQueue()); 71 test(new LinkedBlockingQueue(2000)); 72 test(new LinkedBlockingDeque()); 73 test(new LinkedBlockingDeque(2000)); 74 test(new ArrayBlockingQueue(2000)); 75 test(new LinkedTransferQueue()); 76 } 77 78 void test(final BlockingQueue q) throws Throwable { 79 System.out.println(q.getClass().getSimpleName()); 80 final long testDurationNanos = testDurationMillis * 1000L * 1000L; 81 final long quittingTimeNanos = System.nanoTime() + testDurationNanos; 82 final SplittableRandom rnd = new SplittableRandom(); 83 84 // Poor man's bounded buffer. 85 final AtomicLong approximateCount = new AtomicLong(0L); 86 87 abstract class CheckedThread extends Thread { 88 final SplittableRandom rnd; 89 90 CheckedThread(String name, SplittableRandom rnd) { 91 super(name); 92 this.rnd = rnd; 93 setDaemon(true); 94 start(); 95 } 96 /** Polls for quitting time. */ 97 protected boolean quittingTime() { 98 return System.nanoTime() - quittingTimeNanos > 0; 99 } 100 /** Polls occasionally for quitting time. */ 101 protected boolean quittingTime(long i) { 102 return (i % 1024) == 0 && quittingTime(); 103 } 104 protected abstract void realRun(); 105 public void run() { 106 try { realRun(); } catch (Throwable t) { unexpected(t); } 107 } 108 } 109 110 Thread offerer = new CheckedThread("offerer", rnd.split()) { 111 protected void realRun() { 112 long c = 0; 113 for (long i = 0; ! quittingTime(i); i++) { 114 if (q.offer(c)) { 115 if ((++c % 1024) == 0) { 116 approximateCount.getAndAdd(1024); 117 while (approximateCount.get() > 10000) 118 Thread.yield(); 119 } 120 } else { 121 Thread.yield(); 122 }}}}; 123 124 Thread drainer = new CheckedThread("drainer", rnd.split()) { 125 protected void realRun() { 126 while (! quittingTime()) { 127 List list = new ArrayList(); 128 int n = rnd.nextBoolean() ? 129 q.drainTo(list) : 130 q.drainTo(list, 100); 131 approximateCount.getAndAdd(-n); 132 equal(list.size(), n); 133 for (int j = 0; j < n - 1; j++) 134 equal((Long) list.get(j) + 1L, list.get(j + 1)); 135 Thread.yield(); 136 } 137 q.clear(); 138 approximateCount.set(0); // Releases waiting offerer thread 139 }}; 140 141 Thread scanner = new CheckedThread("scanner", rnd.split()) { 142 protected void realRun() { 143 while (! quittingTime()) { 144 switch (rnd.nextInt(3)) { 145 case 0: checkNotContainsNull(q); break; 146 case 1: q.size(); break; 147 case 2: 148 Long[] a = (Long[]) q.toArray(new Long[0]); 149 int n = a.length; 150 for (int j = 0; j < n - 1; j++) { 151 check(a[j] < a[j+1]); 152 check(a[j] != null); 153 } 154 break; 155 } 156 Thread.yield(); 157 }}}; 158 159 for (Thread thread : new Thread[] { offerer, drainer, scanner }) { 160 thread.join(LONG_DELAY_MS + testDurationMillis); 161 if (thread.isAlive()) { 162 System.err.printf("Hung thread: %s%n", thread.getName()); 163 failed++; 164 for (StackTraceElement e : thread.getStackTrace()) 165 System.err.println(e); 166 thread.join(LONG_DELAY_MS); 167 } 168 } 169 } 170 171 //--------------------- Infrastructure --------------------------- 172 volatile int passed = 0, failed = 0; 173 void pass() {passed++;} 174 void fail() {failed++; Thread.dumpStack();} 175 void fail(String msg) {System.err.println(msg); fail();} 176 void unexpected(Throwable t) {failed++; t.printStackTrace();} 177 void check(boolean cond) {if (cond) pass(); else fail();} 178 void equal(Object x, Object y) { 179 if (x == null ? y == null : x.equals(y)) pass(); 180 else fail(x + " not equal to " + y);} 181 public static void main(String[] args) throws Throwable { 182 new OfferDrainToLoops(args).instanceMain(args);} 183 public void instanceMain(String[] args) throws Throwable { 184 try {test(args);} catch (Throwable t) {unexpected(t);} 185 System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); 186 if (failed > 0) throw new AssertionError("Some tests failed");} 187 }