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  * @test
25  * @bug 8023234
26  * @summary StampedLock serializes readers on writer unlock
27  * @author Dmitry Chyuko
28  * @author Aleksey Shipilev
29  */
30 
31 import java.util.concurrent.CyclicBarrier;
32 import java.util.concurrent.atomic.AtomicReference;
33 import java.util.concurrent.locks.StampedLock;
34 
35 public class ReadersUnlockAfterWriteUnlock {
main(String[] args)36     public static void main(String[] args) throws InterruptedException {
37         final int RNUM = 2;
38         final int REPS = 128;
39         final StampedLock sl = new StampedLock();
40         final AtomicReference<Throwable> bad = new AtomicReference<>();
41 
42         final CyclicBarrier iterationStart = new CyclicBarrier(RNUM + 1);
43         final CyclicBarrier readersHaveLocks = new CyclicBarrier(RNUM);
44         final CyclicBarrier writerHasLock = new CyclicBarrier(RNUM + 1);
45 
46         Runnable reader = () -> {
47             try {
48                 for (int i = 0; i < REPS; i++) {
49                     iterationStart.await();
50                     writerHasLock.await();
51                     long rs = sl.readLock();
52 
53                     // single reader blocks here indefinitely if readers
54                     // are serialized
55                     readersHaveLocks.await();
56 
57                     sl.unlockRead(rs);
58                 }
59             } catch (Throwable ex) {
60                 ex.printStackTrace();
61                 bad.set(ex);
62             }
63         };
64 
65         Thread[] threads = new Thread[RNUM];
66         for (int i = 0 ; i < RNUM; i++) {
67             Thread thread = new Thread(reader, "Reader");
68             threads[i] = thread;
69             thread.start();
70         }
71         for (int i = 0; i < REPS; i++) {
72             try {
73                 iterationStart.await();
74                 long ws = sl.writeLock();
75                 writerHasLock.await();
76                 awaitWaitState(threads);
77                 sl.unlockWrite(ws);
78             } catch (Exception e) {
79                 throw new IllegalStateException(e);
80             }
81         }
82         for (Thread thread : threads)
83             thread.join();
84         if (bad.get() != null)
85             throw new AssertionError(bad.get());
86     }
87 
awaitWaitState(Thread[] threads)88     static void awaitWaitState(Thread[] threads) {
89         restart: for (;;) {
90             for (Thread thread : threads) {
91                 if (thread.getState() != Thread.State.WAITING) {
92                     Thread.yield();
93                     continue restart;
94                 }
95             }
96             break;
97         }
98     }
99 }
100