1 /* 2 * Copyright (c) 2019, 2023, 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 * @summary Test virtual threads using Object.wait/notifyAll 27 * @modules java.base/java.lang:+open 28 * @library /test/lib 29 * @run junit MonitorWaitNotify 30 */ 31 32 import java.util.concurrent.Semaphore; 33 34 import jdk.test.lib.thread.VThreadRunner; 35 import org.junit.jupiter.api.Test; 36 import static org.junit.jupiter.api.Assertions.*; 37 38 class MonitorWaitNotify { 39 40 /** 41 * Test virtual thread waits, notified by platform thread. 42 */ 43 @Test 44 void testWaitNotify1() throws Exception { 45 var lock = new Object(); 46 var ready = new Semaphore(0); 47 var thread = Thread.ofVirtual().start(() -> { 48 synchronized (lock) { 49 ready.release(); 50 try { 51 lock.wait(); 52 } catch (InterruptedException e) { } 53 } 54 }); 55 // thread invokes notify 56 ready.acquire(); 57 synchronized (lock) { 58 lock.notifyAll(); 59 } 60 thread.join(); 61 } 62 63 /** 64 * Test platform thread waits, notified by virtual thread. 65 */ 66 @Test 67 void testWaitNotify2() throws Exception { 68 var lock = new Object(); 69 var ready = new Semaphore(0); 70 var thread = Thread.ofVirtual().start(() -> { 71 ready.acquireUninterruptibly(); 72 synchronized (lock) { 73 lock.notifyAll(); 74 } 75 }); 76 synchronized (lock) { 77 ready.release(); 78 lock.wait(); 79 } 80 thread.join(); 81 } 82 83 /** 84 * Test virtual thread waits, notified by another virtual thread. 85 */ 86 @Test 87 void testWaitNotify3() throws Exception { 88 // need at least two carrier threads due to pinning 89 int previousParallelism = VThreadRunner.ensureParallelism(2); 90 try { 91 var lock = new Object(); 92 var ready = new Semaphore(0); 93 var thread1 = Thread.ofVirtual().start(() -> { 94 synchronized (lock) { 95 ready.release(); 96 try { 97 lock.wait(); 98 } catch (InterruptedException e) { } 99 } 100 }); 101 var thread2 = Thread.ofVirtual().start(() -> { 102 ready.acquireUninterruptibly(); 103 synchronized (lock) { 104 lock.notifyAll(); 105 } 106 }); 107 thread1.join(); 108 thread2.join(); 109 } finally { 110 // restore 111 VThreadRunner.setParallelism(previousParallelism); 112 } 113 } 114 115 /** 116 * Test interrupt status set when calling Object.wait. 117 */ 118 @Test 119 void testWaitNotify4() throws Exception { 120 VThreadRunner.run(() -> { 121 Thread t = Thread.currentThread(); 122 t.interrupt(); 123 Object lock = new Object(); 124 synchronized (lock) { 125 try { 126 lock.wait(); 127 fail(); 128 } catch (InterruptedException e) { 129 // interrupt status should be cleared 130 assertFalse(t.isInterrupted()); 131 } 132 } 133 }); 134 } 135 136 /** 137 * Test interrupt when blocked in Object.wait. 138 */ 139 @Test 140 void testWaitNotify5() throws Exception { 141 VThreadRunner.run(() -> { 142 Thread t = Thread.currentThread(); 143 scheduleInterrupt(t, 1000); 144 Object lock = new Object(); 145 synchronized (lock) { 146 try { 147 lock.wait(); 148 fail(); 149 } catch (InterruptedException e) { 150 // interrupt status should be cleared 151 assertFalse(t.isInterrupted()); 152 } 153 } 154 }); 155 } 156 157 /** 158 * Schedule a thread to be interrupted after a delay. 159 */ 160 private static void scheduleInterrupt(Thread thread, long delay) { 161 Runnable interruptTask = () -> { 162 try { 163 Thread.sleep(delay); 164 thread.interrupt(); 165 } catch (Exception e) { 166 e.printStackTrace(); 167 } 168 }; 169 new Thread(interruptTask).start(); 170 } 171 }