< prev index next >

test/jdk/java/lang/Thread/virtual/MonitorWaitNotify.java

Print this page
*** 1,7 ***
  /*
!  * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.
--- 1,7 ---
  /*
!  * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.

*** 27,11 ***
--- 27,14 ---
   * @modules java.base/java.lang:+open
   * @library /test/lib
   * @run junit MonitorWaitNotify
   */
  
+ import java.util.concurrent.CountDownLatch;
  import java.util.concurrent.Semaphore;
+ import java.util.concurrent.atomic.AtomicBoolean;
+ import java.util.concurrent.locks.LockSupport;
  
  import jdk.test.lib.thread.VThreadRunner;
  import org.junit.jupiter.api.Test;
  import static org.junit.jupiter.api.Assertions.*;
  

*** 152,10 ***
--- 155,209 ---
                  }
              }
          });
      }
  
+     /**
+      * Testing invoking Object.wait with interrupt status set.
+      */
+     @Test
+     void testWaitWithInterruptSet() throws Exception {
+         VThreadRunner.run(() -> {
+             Object obj = new Object();
+             synchronized (obj) {
+                 Thread.currentThread().interrupt();
+                 assertThrows(InterruptedException.class, obj::wait);
+                 assertFalse(Thread.currentThread().isInterrupted());
+             }
+         });
+     }
+ 
+     /**
+      * Test interrupting a virtual thread waiting in Object.wait.
+      */
+     @Test
+     void testInterruptWait() throws Exception {
+         var lock = new Object();
+         var started = new CountDownLatch(1);
+         var interruptedException = new AtomicBoolean();
+         var vthread = Thread.ofVirtual().start(() -> {
+             started.countDown();
+             synchronized (lock) {
+                 try {
+                     lock.wait();
+                 } catch (InterruptedException e) {
+                     interruptedException.set(true);
+                 }
+             }
+         });
+ 
+         // wait for thread to start and wait
+         started.await();
+         await(vthread, Thread.State.WAITING);
+ 
+         // interrupt thread, it should throw InterruptedException and terminate
+         vthread.interrupt();
+         vthread.join();
+         assertTrue(interruptedException.get());
+     }
+ 
+     /**
+      * Test interrupting a virtual thread blocked waiting to reenter after waiting.
+      */
+     @Test
+     void testInterruptReenter() throws Exception {
+         var lock = new Object();
+         var started = new CountDownLatch(1);
+         var interruptedException = new AtomicBoolean();
+         var vthread = Thread.ofVirtual().start(() -> {
+             started.countDown();
+             synchronized (lock) {
+                 try {
+                     lock.wait();
+                 } catch (InterruptedException e) {
+                     interruptedException.set(true);
+                 }
+             }
+         });
+ 
+         // wait for thread to start and wait
+         started.await();
+         await(vthread, Thread.State.WAITING);
+ 
+         // notify, thread should block waiting to reenter
+         synchronized (lock) {
+             lock.notifyAll();
+             await(vthread, Thread.State.BLOCKED);
+             vthread.interrupt();
+         }
+ 
+         vthread.join();
+         assertFalse(interruptedException.get());
+         assertTrue(vthread.isInterrupted());
+     }
+ 
+     /**
+      * Test that Object.wait does not consume the thread's parking permit.
+      */
+     @Test
+     void testParkingPermitNotConsumed() throws Exception {
+         var lock = new Object();
+         var started = new CountDownLatch(1);
+         var completed = new AtomicBoolean();
+         var vthread = Thread.ofVirtual().start(() -> {
+             started.countDown();
+             LockSupport.unpark(Thread.currentThread());
+             synchronized (lock) {
+                 try {
+                     lock.wait();
+                 } catch (InterruptedException e) {
+                     fail("wait interrupted");
+                 }
+             }
+             LockSupport.park();      // should not park
+             completed.set(true);
+         });
+ 
+         // wait for thread to start and wait
+         started.await();
+         await(vthread, Thread.State.WAITING);
+ 
+         // wakeup thread
+         synchronized (lock) {
+             lock.notifyAll();
+         }
+ 
+         // thread should terminate
+         vthread.join();
+         assertTrue(completed.get());
+     }
+ 
+     /**
+      * Test that Object.wait does not make available the thread's parking permit.
+      */
+     @Test
+     void testParkingPermitNotOffered() throws Exception {
+         var lock = new Object();
+         var started = new CountDownLatch(1);
+         var readyToPark = new CountDownLatch(1);
+         var completed = new AtomicBoolean();
+         var vthread = Thread.ofVirtual().start(() -> {
+             started.countDown();
+             synchronized (lock) {
+                 try {
+                     lock.wait();
+                 } catch (InterruptedException e) {
+                     fail("wait interrupted");
+                 }
+             }
+             readyToPark.countDown();
+             LockSupport.park();      // should park
+             completed.set(true);
+         });
+ 
+         // wait for thread to start and wait
+         started.await();
+         await(vthread, Thread.State.WAITING);
+ 
+         // wakeup thread
+         synchronized (lock) {
+             lock.notifyAll();
+         }
+ 
+         // thread should park
+         readyToPark.await();
+         await(vthread, Thread.State.WAITING);
+ 
+         LockSupport.unpark(vthread);
+ 
+         // thread should terminate
+         vthread.join();
+         assertTrue(completed.get());
+     }
+ 
+     /**
+      * Test that wait(long) throws IAE when timeout is negative.
+      */
+     @Test
+     void testIllegalArgumentException() throws Exception {
+         VThreadRunner.run(() -> {
+             Object obj = new Object();
+             synchronized (obj) {
+                 assertThrows(IllegalArgumentException.class, () -> obj.wait(-1L));
+                 assertThrows(IllegalArgumentException.class, () -> obj.wait(-1000L));
+                 assertThrows(IllegalArgumentException.class, () -> obj.wait(Long.MIN_VALUE));
+             }
+         });
+     }
+ 
+     /**
+      * Test that wait throws IMSE when not owner.
+      */
+     @Test
+     void testIllegalMonitorStateException() throws Exception {
+         VThreadRunner.run(() -> {
+             Object obj = new Object();
+             assertThrows(IllegalMonitorStateException.class, () -> obj.wait());
+             assertThrows(IllegalMonitorStateException.class, () -> obj.wait(0));
+             assertThrows(IllegalMonitorStateException.class, () -> obj.wait(1000));
+             assertThrows(IllegalMonitorStateException.class, () -> obj.wait(Long.MAX_VALUE));
+         });
+     }
+ 
+     /**
+      * Waits for the given thread to reach a given state.
+      */
+     private void await(Thread thread, Thread.State expectedState) throws InterruptedException {
+         Thread.State state = thread.getState();
+         while (state != expectedState) {
+             assertTrue(state != Thread.State.TERMINATED, "Thread has terminated");
+             Thread.sleep(10);
+             state = thread.getState();
+         }
+     }
+ 
      /**
       * Schedule a thread to be interrupted after a delay.
       */
      private static void scheduleInterrupt(Thread thread, long delay) {
          Runnable interruptTask = () -> {
< prev index next >