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 id=default
26 * @summary Test virtual threads entering a lot of monitors with contention
27 * @library /test/lib
28 * @run main LotsOfContendedMonitorEnter
29 */
30
31 import java.util.concurrent.CountDownLatch;
32 import jdk.test.lib.thread.VThreadRunner;
33
34 public class LotsOfContendedMonitorEnter {
35
36 public static void main(String[] args) throws Exception {
37 int depth;
38 if (args.length > 0) {
39 depth = Integer.parseInt(args[0]);
40 } else {
41 depth = 1024;
42 }
43 VThreadRunner.run(() -> testContendedEnter(depth));
44 }
45
46 /**
47 * Enter the monitor for a new object, racing with another virtual thread that
48 * attempts to enter around the same time, then repeat to the given depth.
49 */
50 private static void testContendedEnter(int depthRemaining) throws Exception {
51 if (depthRemaining > 0) {
52 var lock = new Object();
53
54 // start thread to enter monitor for brief period, then enters again when signalled
55 var started = new CountDownLatch(1);
56 var signal = new CountDownLatch(1);
57 var thread = Thread.ofVirtual().start(() -> {
58 started.countDown();
59
60 // enter, may be contended
61 synchronized (lock) {
62 Thread.onSpinWait();
63 }
64
65 // wait to be signalled
66 try {
67 signal.await();
68 } catch (InterruptedException e) { }
69
70 // enter again, this will block until the main thread releases
71 synchronized (lock) {
72 // do nothing
73 }
74 });
75 try {
76 // wait for thread to start
77 started.await();
78
79 // enter, may be contended
80 synchronized (lock) {
81 // signal thread to enter monitor again, it should block
82 signal.countDown();
83 await(thread, Thread.State.BLOCKED);
84 testContendedEnter(depthRemaining - 1);
85 }
86 } finally {
87 thread.join();
88 }
89 }
90 }
91
92 /**
93 * Waits for the given thread to reach a given state.
94 */
95 private static void await(Thread thread, Thread.State expectedState) {
96 Thread.State state = thread.getState();
97 while (state != expectedState) {
98 assert state != Thread.State.TERMINATED : "Thread has terminated";
99 Thread.yield();
100 state = thread.getState();
101 }
102 }
103 }
|
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 id=default
26 * @summary Test virtual threads entering a lot of monitors with contention
27 * @library /test/lib
28 * @run main/timeout=480 LotsOfContendedMonitorEnter
29 */
30
31 import java.time.Instant;
32 import java.util.concurrent.atomic.AtomicReference;
33 import java.util.concurrent.CountDownLatch;
34 import jdk.test.lib.thread.VThreadRunner;
35
36 public class LotsOfContendedMonitorEnter {
37 static int depth;
38
39 public static void main(String[] args) throws Exception {
40 if (args.length > 0) {
41 depth = Integer.parseInt(args[0]);
42 } else {
43 depth = 1024;
44 }
45
46 var exRef = new AtomicReference<Throwable>();
47 var thread = Thread.ofVirtual().start(() -> {
48 try {
49 testContendedEnter(depth);
50 } catch (Exception e) {
51 exRef.set(e);
52 }
53 });
54 thread.join();
55 assert exRef.get() == null;
56 }
57
58 /**
59 * Enter the monitor for a new object, racing with another virtual thread that
60 * attempts to enter around the same time, then repeat to the given depth.
61 */
62 private static void testContendedEnter(int depthRemaining) throws Exception {
63 boolean doLog = depthRemaining % 10 == 0;
64 if (depthRemaining > 0) {
65 var lock = new Object();
66
67 // start thread to enter monitor for brief period, then enters again when signalled
68 var started = new CountDownLatch(1);
69 var signal = new CountDownLatch(1);
70 var thread = Thread.ofVirtual().start(() -> {
71 started.countDown();
72
73 // enter, may be contended
74 synchronized (lock) {
75 Thread.onSpinWait();
76 }
77
78 // wait to be signalled
79 try {
80 signal.await();
81 } catch (InterruptedException e) { }
82
83 // enter again, this will block until the main thread releases
84 synchronized (lock) {
85 // do nothing
86 }
87 });
88 try {
89 // wait for thread to start
90 started.await();
91
92 // enter, may be contended
93 synchronized (lock) {
94 // signal thread to enter monitor again, it should block
95 signal.countDown();
96 await(thread, Thread.State.BLOCKED);
97 if (doLog) {
98 System.out.println(Instant.now() + " => at depth: " + (depth - depthRemaining));
99 }
100 testContendedEnter(depthRemaining - 1);
101 }
102 } finally {
103 thread.join();
104 }
105 }
106 if (doLog) {
107 System.out.println(Instant.now() + " => returning from depth: " + (depth - depthRemaining));
108 }
109 }
110
111 /**
112 * Waits for the given thread to reach a given state.
113 */
114 private static void await(Thread thread, Thread.State expectedState) {
115 Thread.State state = thread.getState();
116 while (state != expectedState) {
117 assert state != Thread.State.TERMINATED : "Thread has terminated";
118 Thread.yield();
119 state = thread.getState();
120 }
121 }
122 }
|