OfferRemoveLoops.java revision 12745:f068a4ffddd2
1/*
2 * Copyright (c) 2005, 2010, 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 6316155 6595669 6871697 6868712
27 * @summary Test concurrent offer vs. remove
28 * @run main OfferRemoveLoops 300
29 * @author Martin Buchholz
30 */
31
32import java.util.*;
33import java.util.concurrent.*;
34import java.util.concurrent.atomic.*;
35
36@SuppressWarnings({"unchecked", "rawtypes", "deprecation"})
37public class OfferRemoveLoops {
38    final long testDurationMillisDefault = 10L * 1000L;
39    final long testDurationMillis;
40
41    OfferRemoveLoops(String[] args) {
42        testDurationMillis = (args.length > 0) ?
43            Long.valueOf(args[0]) : testDurationMillisDefault;
44    }
45
46    void checkNotContainsNull(Iterable it) {
47        for (Object x : it)
48            check(x != null);
49    }
50
51    void test(String[] args) throws Throwable {
52        testQueue(new LinkedBlockingQueue(10));
53        testQueue(new LinkedBlockingQueue());
54        testQueue(new LinkedBlockingDeque(10));
55        testQueue(new LinkedBlockingDeque());
56        testQueue(new ArrayBlockingQueue(10));
57        testQueue(new PriorityBlockingQueue(10));
58        testQueue(new ConcurrentLinkedDeque());
59        testQueue(new ConcurrentLinkedQueue());
60        testQueue(new LinkedTransferQueue());
61    }
62
63    Random getRandom() {
64        return ThreadLocalRandom.current();
65    }
66
67    void testQueue(final Queue q) throws Throwable {
68        System.out.println(q.getClass().getSimpleName());
69        final long testDurationNanos = testDurationMillis * 1000L * 1000L;
70        final long quittingTimeNanos = System.nanoTime() + testDurationNanos;
71        final long timeoutMillis = 10L * 1000L;
72        final int maxChunkSize = 1042;
73        final int maxQueueSize = 10 * maxChunkSize;
74
75        /** Poor man's bounded buffer. */
76        final AtomicLong approximateCount = new AtomicLong(0L);
77
78        abstract class CheckedThread extends Thread {
79            CheckedThread(String name) {
80                super(name);
81                setDaemon(true);
82                start();
83            }
84            /** Polls for quitting time. */
85            protected boolean quittingTime() {
86                return System.nanoTime() - quittingTimeNanos > 0;
87            }
88            /** Polls occasionally for quitting time. */
89            protected boolean quittingTime(long i) {
90                return (i % 1024) == 0 && quittingTime();
91            }
92            protected abstract void realRun();
93            public void run() {
94                try { realRun(); } catch (Throwable t) { unexpected(t); }
95            }
96        }
97
98        Thread offerer = new CheckedThread("offerer") {
99            protected void realRun() {
100                final long chunkSize = getRandom().nextInt(maxChunkSize) + 2;
101                long c = 0;
102                for (long i = 0; ! quittingTime(i); i++) {
103                    if (q.offer(Long.valueOf(c))) {
104                        if ((++c % chunkSize) == 0) {
105                            approximateCount.getAndAdd(chunkSize);
106                            while (approximateCount.get() > maxQueueSize)
107                                Thread.yield();
108                        }
109                    } else {
110                        Thread.yield();
111                    }}}};
112
113        Thread remover = new CheckedThread("remover") {
114            protected void realRun() {
115                final long chunkSize = getRandom().nextInt(maxChunkSize) + 2;
116                long c = 0;
117                for (long i = 0; ! quittingTime(i); i++) {
118                    if (q.remove(Long.valueOf(c))) {
119                        if ((++c % chunkSize) == 0) {
120                            approximateCount.getAndAdd(-chunkSize);
121                        }
122                    } else {
123                        Thread.yield();
124                    }
125                }
126                q.clear();
127                approximateCount.set(0); // Releases waiting offerer thread
128            }};
129
130        Thread scanner = new CheckedThread("scanner") {
131            protected void realRun() {
132                final Random rnd = getRandom();
133                while (! quittingTime()) {
134                    switch (rnd.nextInt(3)) {
135                    case 0: checkNotContainsNull(q); break;
136                    case 1: q.size(); break;
137                    case 2: checkNotContainsNull
138                            (Arrays.asList(q.toArray(new Long[0])));
139                        break;
140                    }
141                    Thread.yield();
142                }}};
143
144        for (Thread thread : new Thread[] { offerer, remover, scanner }) {
145            thread.join(timeoutMillis + testDurationMillis);
146            if (thread.isAlive()) {
147                System.err.printf("Hung thread: %s%n", thread.getName());
148                failed++;
149                for (StackTraceElement e : thread.getStackTrace())
150                    System.err.println(e);
151                // Kludge alert
152                thread.stop();
153                thread.join(timeoutMillis);
154            }
155        }
156    }
157
158    //--------------------- Infrastructure ---------------------------
159    volatile int passed = 0, failed = 0;
160    void pass() {passed++;}
161    void fail() {failed++; Thread.dumpStack();}
162    void fail(String msg) {System.err.println(msg); fail();}
163    void unexpected(Throwable t) {failed++; t.printStackTrace();}
164    void check(boolean cond) {if (cond) pass(); else fail();}
165    void equal(Object x, Object y) {
166        if (x == null ? y == null : x.equals(y)) pass();
167        else fail(x + " not equal to " + y);}
168    public static void main(String[] args) throws Throwable {
169        new OfferRemoveLoops(args).instanceMain(args);}
170    public void instanceMain(String[] args) throws Throwable {
171        try {test(args);} catch (Throwable t) {unexpected(t);}
172        System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
173        if (failed > 0) throw new AssertionError("Some tests failed");}
174}
175