< prev index next >

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

Print this page
@@ -21,11 +21,11 @@
   * questions.
   */
  
  /*
   * @test id=default
-  * @bug 8284161 8286788
+  * @bug 8284161 8286788 8321270
   * @summary Test Thread API with virtual threads
   * @modules java.base/java.lang:+open
   * @library /test/lib
   * @run junit ThreadAPI
   */

@@ -104,11 +104,11 @@
          var thread = Thread.ofVirtual().start(() -> {
              before.set(Thread.currentThread());
              LockSupport.park();
              after.set(Thread.currentThread());
          });
-         awaitParked(thread);
+         await(thread, Thread.State.WAITING);
          LockSupport.unpark(thread);
          thread.join();
          assertTrue(before.get() == thread);
          assertTrue(after.get() == thread);
      }

@@ -128,11 +128,11 @@
              }
              ref3.set(Thread.currentThread());
          });
          synchronized (lock) {
              thread.start();
-             awaitBlocked(thread);
+             await(thread, Thread.State.BLOCKED);
          }
          thread.join();
          assertTrue(ref1.get() == thread);
          assertTrue(ref2.get() == thread);
          assertTrue(ref3.get() == thread);

@@ -158,11 +158,11 @@
              ref3.set(Thread.currentThread());
          });
          lock.lock();
          try {
              thread.start();
-             awaitParked(thread);
+             await(thread, Thread.State.WAITING);
          } finally {
              lock.unlock();
          }
          thread.join();
          assertTrue(ref1.get() == thread);

@@ -763,10 +763,11 @@
          });
          try {
              assertFalse(thread.join(Duration.ofMillis(100)));
          } finally {
              done.set(true);
+             thread.join();
          }
      }
  
      /**
       * Test virtual thread invoking timed-Thread.join on a thread that is parking

@@ -895,11 +896,11 @@
                  }
              } catch (Exception e) {
                  exception.set(e);
              }
          });
-         awaitParked(thread);
+         await(thread, Thread.State.TIMED_WAITING);
          thread.interrupt();
          thread.join();
          assertNull(exception.get());
      }
  

@@ -915,11 +916,11 @@
                  assertTrue(Thread.currentThread().isInterrupted());
              } catch (Exception e) {
                  exception.set(e);
              }
          });
-         awaitParked(thread);
+         await(thread, Thread.State.WAITING);
          thread.interrupt();
          thread.join();
          assertNull(exception.get());
      }
  

@@ -1030,20 +1031,20 @@
       */
      @Test
      void testSetPriority1() throws Exception {
          VThreadRunner.run(() -> {
              Thread me = Thread.currentThread();
-             assertTrue(me.getPriority() == Thread.NORM_PRIORITY);
+             assertEquals(Thread.NORM_PRIORITY, me.getPriority());
  
              me.setPriority(Thread.MAX_PRIORITY);
-             assertTrue(me.getPriority() == Thread.NORM_PRIORITY);
+             assertEquals(Thread.NORM_PRIORITY, me.getPriority());
  
              me.setPriority(Thread.NORM_PRIORITY);
-             assertTrue(me.getPriority() == Thread.NORM_PRIORITY);
+             assertEquals(Thread.NORM_PRIORITY, me.getPriority());
  
              me.setPriority(Thread.MIN_PRIORITY);
-             assertTrue(me.getPriority() == Thread.NORM_PRIORITY);
+             assertEquals(Thread.NORM_PRIORITY, me.getPriority());
  
              assertThrows(IllegalArgumentException.class, () -> me.setPriority(-1));
          });
      }
  

@@ -1053,47 +1054,47 @@
      @Test
      void testSetPriority2() throws Exception {
          var thread = Thread.ofVirtual().unstarted(LockSupport::park);
  
          // not started
-         assertTrue(thread.getPriority() == Thread.NORM_PRIORITY);
+         assertEquals(Thread.NORM_PRIORITY, thread.getPriority());
  
          thread.setPriority(Thread.MAX_PRIORITY);
-         assertTrue(thread.getPriority() == Thread.NORM_PRIORITY);
+         assertEquals(Thread.NORM_PRIORITY, thread.getPriority());
  
          thread.setPriority(Thread.NORM_PRIORITY);
-         assertTrue(thread.getPriority() == Thread.NORM_PRIORITY);
+         assertEquals(Thread.NORM_PRIORITY, thread.getPriority());
  
          thread.setPriority(Thread.MIN_PRIORITY);
-         assertTrue(thread.getPriority() == Thread.NORM_PRIORITY);
+         assertEquals(Thread.NORM_PRIORITY, thread.getPriority());
  
          assertThrows(IllegalArgumentException.class, () -> thread.setPriority(-1));
  
          // running
          thread.start();
          try {
-             assertTrue(thread.getPriority() == Thread.NORM_PRIORITY);
+             assertEquals(Thread.NORM_PRIORITY, thread.getPriority());
              thread.setPriority(Thread.NORM_PRIORITY);
  
              thread.setPriority(Thread.MAX_PRIORITY);
-             assertTrue(thread.getPriority() == Thread.NORM_PRIORITY);
+             assertEquals(Thread.NORM_PRIORITY, thread.getPriority());
  
              thread.setPriority(Thread.NORM_PRIORITY);
-             assertTrue(thread.getPriority() == Thread.NORM_PRIORITY);
+             assertEquals(Thread.NORM_PRIORITY, thread.getPriority());
  
              thread.setPriority(Thread.MIN_PRIORITY);
-             assertTrue(thread.getPriority() == Thread.NORM_PRIORITY);
+             assertEquals(Thread.NORM_PRIORITY, thread.getPriority());
  
              assertThrows(IllegalArgumentException.class, () -> thread.setPriority(-1));
  
          } finally {
              LockSupport.unpark(thread);
          }
          thread.join();
  
          // terminated
-         assertTrue(thread.getPriority() == Thread.NORM_PRIORITY);
+         assertEquals(Thread.NORM_PRIORITY, thread.getPriority());
      }
  
      /**
       * Test Thread.isDaemon and setDaemon from current thread.
       */

@@ -1188,10 +1189,40 @@
              thread.join();
          }
          assertEquals(List.of("A", "A", "B"), list);
      }
  
+     /**
+      * Test that Thread.yield does not consume the thread's parking permit.
+      */
+     @Test
+     void testYield3() throws Exception {
+         var thread = Thread.ofVirtual().start(() -> {
+             LockSupport.unpark(Thread.currentThread());
+             Thread.yield();
+             LockSupport.park();  // should not park
+         });
+         thread.join();
+     }
+ 
+     /**
+      * Test that Thread.yield does not make available the thread's parking permit.
+      */
+     @Test
+     void testYield4() throws Exception {
+         var thread = Thread.ofVirtual().start(() -> {
+             Thread.yield();
+             LockSupport.park();  // should park
+         });
+         try {
+             await(thread, Thread.State.WAITING);
+         } finally {
+             LockSupport.unpark(thread);
+             thread.join();
+         }
+     }
+ 
      /**
       * Test Thread.onSpinWait.
       */
      @Test
      void testOnSpinWait() throws Exception {

@@ -1648,137 +1679,233 @@
          assertFalse(tid1 == tid3);
          assertFalse(tid2 == tid3);
      }
  
      /**
-      * Test Thread::getState when thread is not started.
+      * Test Thread::getState when thread is new/unstarted.
       */
      @Test
      void testGetState1() {
          var thread = Thread.ofVirtual().unstarted(() -> { });
-         assertTrue(thread.getState() == Thread.State.NEW);
+         assertEquals(Thread.State.NEW, thread.getState());
      }
  
      /**
-      * Test Thread::getState when thread is runnable (mounted).
+      * Test Thread::getState when thread is terminated.
       */
      @Test
      void testGetState2() throws Exception {
-         VThreadRunner.run(() -> {
-             Thread.State state = Thread.currentThread().getState();
-             assertTrue(state == Thread.State.RUNNABLE);
+         var thread = Thread.ofVirtual().start(() -> { });
+         thread.join();
+         assertEquals(Thread.State.TERMINATED, thread.getState());
+     }
+ 
+     /**
+      * Test Thread::getState when thread is runnable (mounted).
+      */
+     @Test
+     void testGetState3() throws Exception {
+         var started = new CountDownLatch(1);
+         var done = new AtomicBoolean();
+         var thread = Thread.ofVirtual().start(() -> {
+             started.countDown();
+ 
+             // spin until done
+             while (!done.get()) {
+                 Thread.onSpinWait();
+             }
          });
+         try {
+             // wait for thread to start
+             started.await();
+ 
+             // thread should be runnable
+             assertEquals(Thread.State.RUNNABLE, thread.getState());
+         } finally {
+             done.set(true);
+             thread.join();
+         }
      }
  
      /**
       * Test Thread::getState when thread is runnable (not mounted).
       */
      @Test
-     void testGetState3() throws Exception {
+     void testGetState4() throws Exception {
          assumeTrue(ThreadBuilders.supportsCustomScheduler(), "No support for custom schedulers");
          AtomicBoolean completed = new AtomicBoolean();
          try (ExecutorService scheduler = Executors.newFixedThreadPool(1)) {
              Thread.Builder builder = ThreadBuilders.virtualThreadBuilder(scheduler);
              Thread t1 = builder.start(() -> {
                  Thread t2 = builder.unstarted(LockSupport::park);
-                 assertTrue(t2.getState() == Thread.State.NEW);
+                 assertEquals(Thread.State.NEW, t2.getState());
  
                  // start t2 to make it runnable
                  t2.start();
                  try {
-                     assertTrue(t2.getState() == Thread.State.RUNNABLE);
+                     assertEquals(Thread.State.RUNNABLE, t2.getState());
  
                      // yield to allow t2 to run and park
                      Thread.yield();
-                     assertTrue(t2.getState() == Thread.State.WAITING);
+                     assertEquals(Thread.State.WAITING, t2.getState());
                  } finally {
                      // unpark t2 to make it runnable again
                      LockSupport.unpark(t2);
                  }
  
                  // t2 should be runnable (not mounted)
-                 assertTrue(t2.getState() == Thread.State.RUNNABLE);
+                 assertEquals(Thread.State.RUNNABLE, t2.getState());
  
                  completed.set(true);
              });
              t1.join();
          }
          assertTrue(completed.get() == true);
      }
  
      /**
-      * Test Thread::getState when thread is parked.
+      * Test Thread::getState when thread is waiting to enter a monitor.
       */
      @Test
-     void testGetState4() throws Exception {
-         var thread = Thread.ofVirtual().start(LockSupport::park);
-         while (thread.getState() != Thread.State.WAITING) {
-             Thread.sleep(20);
+     void testGetState5() throws Exception {
+         var started = new CountDownLatch(1);
+         var thread = Thread.ofVirtual().unstarted(() -> {
+             started.countDown();
+             synchronized (lock) { }
+         });
+         synchronized (lock) {
+             thread.start();
+             started.await();
+ 
+             // wait for thread to block
+             await(thread, Thread.State.BLOCKED);
          }
-         LockSupport.unpark(thread);
          thread.join();
      }
  
      /**
-      * Test Thread::getState when thread is parked while holding a monitor.
+      * Test Thread::getState when thread is waiting in Object.wait.
       */
      @Test
-     void testGetState5() throws Exception {
+     void testGetState6() throws Exception {
          var thread = Thread.ofVirtual().start(() -> {
              synchronized (lock) {
-                 LockSupport.park();
+                 try { lock.wait(); } catch (InterruptedException e) { }
              }
          });
-         while (thread.getState() != Thread.State.WAITING) {
-             Thread.sleep(20);
+         try {
+             // wait for thread to wait
+             await(thread, Thread.State.WAITING);
+         } finally {
+             thread.interrupt();
+             thread.join();
          }
-         LockSupport.unpark(thread);
-         thread.join();
      }
  
      /**
-      * Test Thread::getState when thread is waiting for a monitor.
+      * Test Thread::getState when thread is waiting in Object.wait(millis).
       */
      @Test
-     void testGetState6() throws Exception {
-         var thread = Thread.ofVirtual().unstarted(() -> {
-             synchronized (lock) { }
-         });
-         synchronized (lock) {
-             thread.start();
-             while (thread.getState() != Thread.State.BLOCKED) {
-                 Thread.sleep(20);
+     void testGetState7() throws Exception {
+         var thread = Thread.ofVirtual().start(() -> {
+             synchronized (lock) {
+                 try {
+                     lock.wait(Long.MAX_VALUE);
+                 } catch (InterruptedException e) { }
              }
+         });
+         try {
+             // wait for thread to wait
+             await(thread, Thread.State.TIMED_WAITING);
+         } finally {
+             thread.interrupt();
+             thread.join();
          }
-         thread.join();
      }
  
      /**
-      * Test Thread::getState when thread is waiting in Object.wait.
+      * Test Thread::getState when thread is parked.
       */
      @Test
-     void testGetState7() throws Exception {
+     void testGetState8() throws Exception {
+         var thread = Thread.ofVirtual().start(LockSupport::park);
+         try {
+             await(thread, Thread.State.WAITING);
+         } finally {
+             LockSupport.unpark(thread);
+             thread.join();
+         }
+     }
+ 
+     /**
+      * Test Thread::getState when thread is timed parked.
+      */
+     @Test
+     void testGetState9() throws Exception {
+         var thread = Thread.ofVirtual().start(() -> LockSupport.parkNanos(Long.MAX_VALUE));
+         try {
+             await(thread, Thread.State.TIMED_WAITING);
+         } finally {
+             LockSupport.unpark(thread);
+             thread.join();
+         }
+     }
+ 
+     /**
+      * Test Thread::getState when thread is parked while holding a monitor.
+      */
+     @Test
+     void testGetState10() throws Exception {
+         var started = new CountDownLatch(1);
+         var done = new AtomicBoolean();
          var thread = Thread.ofVirtual().start(() -> {
+             started.countDown();
              synchronized (lock) {
-                 try { lock.wait(); } catch (InterruptedException e) { }
+                 while (!done.get()) {
+                     LockSupport.park();
+                 }
              }
          });
-         while (thread.getState() != Thread.State.WAITING) {
-             Thread.sleep(20);
+         try {
+             // wait for thread to start
+             started.await();
+ 
+             // wait for thread to park
+             await(thread, Thread.State.WAITING);
+         } finally {
+             done.set(true);
+             LockSupport.unpark(thread);
+             thread.join();
          }
-         thread.interrupt();
-         thread.join();
      }
  
      /**
-      * Test Thread::getState when thread is terminated.
+      * Test Thread::getState when thread is timed parked while holding a monitor.
       */
      @Test
-     void testGetState8() throws Exception {
-         var thread = Thread.ofVirtual().start(() -> { });
-         thread.join();
-         assertTrue(thread.getState() == Thread.State.TERMINATED);
+     void testGetState11() throws Exception {
+         var started = new CountDownLatch(1);
+         var done = new AtomicBoolean();
+         var thread = Thread.ofVirtual().start(() -> {
+             started.countDown();
+             synchronized (lock) {
+                 while (!done.get()) {
+                     LockSupport.parkNanos(Long.MAX_VALUE);
+                 }
+             }
+         });
+         try {
+             // wait for thread to start
+             started.await();
+ 
+             // wait for thread to park
+             await(thread, Thread.State.TIMED_WAITING);
+         } finally {
+             done.set(true);
+             LockSupport.unpark(thread);
+             thread.join();
+         }
      }
  
      /**
       * Test Thread::isAlive.
       */

@@ -1897,13 +2024,11 @@
              while ((carrier = ref.get()) == null) {
                  Thread.sleep(20);
              }
  
              // wait for virtual thread to block in wait
-             while (vthread.getState() != Thread.State.WAITING) {
-                 Thread.sleep(20);
-             }
+             await(vthread, Thread.State.WAITING);
  
              // get stack trace of both carrier and virtual thread
              StackTraceElement[] carrierStackTrace = carrier.getStackTrace();
              StackTraceElement[] vthreadStackTrace = vthread.getStackTrace();
  

@@ -1926,16 +2051,11 @@
       * Test Thread::getStackTrace on parked thread.
       */
      @Test
      void testGetStackTrace5() throws Exception {
          var thread = Thread.ofVirtual().start(LockSupport::park);
- 
-         // wait for thread to park
-         while (thread.getState() != Thread.State.WAITING) {
-             Thread.sleep(20);
-         }
- 
+         await(thread, Thread.State.WAITING);
          try {
              StackTraceElement[] stack = thread.getStackTrace();
              assertTrue(contains(stack, "LockSupport.park"));
          } finally {
              LockSupport.unpark(thread);

@@ -1994,13 +2114,11 @@
              while ((carrier = ref.get()) == null) {
                  Thread.sleep(20);
              }
  
              // wait for virtual thread to block in wait
-             while (vthread.getState() != Thread.State.WAITING) {
-                 Thread.sleep(20);
-             }
+             await(vthread, Thread.State.WAITING);
  
              // get all stack traces
              Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces();
  
              // allow virtual thread to terminate

@@ -2032,11 +2150,11 @@
      void testThreadGroup1() throws Exception {
          var thread = Thread.ofVirtual().unstarted(LockSupport::park);
          var vgroup = thread.getThreadGroup();
          thread.start();
          try {
-             assertTrue(thread.getThreadGroup() == vgroup);
+             assertEquals(vgroup, thread.getThreadGroup());
          } finally {
              LockSupport.unpark(thread);
              thread.join();
          }
          assertNull(thread.getThreadGroup());

@@ -2049,11 +2167,11 @@
      void testThreadGroup2() throws Exception {
          VThreadRunner.run(() -> {
              ThreadGroup vgroup = Thread.currentThread().getThreadGroup();
              Thread child = new Thread(() -> { });
              ThreadGroup group = child.getThreadGroup();
-             assertTrue(group == vgroup);
+             assertEquals(vgroup, group);
          });
      }
  
      /**
       * Test ThreadGroup returned by Thread::getThreadGroup and subgroup

@@ -2066,47 +2184,46 @@
              ref.set(Thread.currentThread().getThreadGroup());
          });
          thread.join();
  
          ThreadGroup vgroup = ref.get();
-         assertTrue(vgroup.getMaxPriority() == Thread.MAX_PRIORITY);
+         assertEquals(Thread.MAX_PRIORITY, vgroup.getMaxPriority());
  
          ThreadGroup group = new ThreadGroup(vgroup, "group");
          assertTrue(group.getParent() == vgroup);
-         assertTrue(group.getMaxPriority() == Thread.MAX_PRIORITY);
+         assertEquals(Thread.MAX_PRIORITY, group.getMaxPriority());
  
          vgroup.setMaxPriority(Thread.MAX_PRIORITY - 1);
-         assertTrue(vgroup.getMaxPriority() == Thread.MAX_PRIORITY);
-         assertTrue(group.getMaxPriority() == Thread.MAX_PRIORITY - 1);
+         assertEquals(Thread.MAX_PRIORITY, vgroup.getMaxPriority());
+         assertEquals(Thread.MAX_PRIORITY - 1, group.getMaxPriority());
  
          vgroup.setMaxPriority(Thread.MIN_PRIORITY);
-         assertTrue(vgroup.getMaxPriority() == Thread.MAX_PRIORITY);
-         assertTrue(group.getMaxPriority() == Thread.MIN_PRIORITY);
+         assertEquals(Thread.MAX_PRIORITY, vgroup.getMaxPriority());
+         assertEquals(Thread.MIN_PRIORITY, group.getMaxPriority());
      }
  
      /**
       * Test ThreadGroup returned by Thread::getThreadGroup and subgroup
       * created with 1-arg ThreadGroup constructor.
       */
      @Test
      void testThreadGroup4() throws Exception {
          VThreadRunner.run(() -> {
              ThreadGroup vgroup = Thread.currentThread().getThreadGroup();
- 
-             assertTrue(vgroup.getMaxPriority() == Thread.MAX_PRIORITY);
+             assertEquals(Thread.MAX_PRIORITY, vgroup.getMaxPriority());
  
              ThreadGroup group = new ThreadGroup("group");
-             assertTrue(group.getParent() == vgroup);
-             assertTrue(group.getMaxPriority() == Thread.MAX_PRIORITY);
+             assertEquals(vgroup, group.getParent());
+             assertEquals(Thread.MAX_PRIORITY, group.getMaxPriority());
  
              vgroup.setMaxPriority(Thread.MAX_PRIORITY - 1);
-             assertTrue(vgroup.getMaxPriority() == Thread.MAX_PRIORITY);
-             assertTrue(group.getMaxPriority() == Thread.MAX_PRIORITY - 1);
+             assertEquals(Thread.MAX_PRIORITY, vgroup.getMaxPriority());
+             assertEquals(Thread.MAX_PRIORITY - 1, group.getMaxPriority());
  
              vgroup.setMaxPriority(Thread.MIN_PRIORITY);
-             assertTrue(vgroup.getMaxPriority() == Thread.MAX_PRIORITY);
-             assertTrue(group.getMaxPriority() == Thread.MIN_PRIORITY);
+             assertEquals(Thread.MAX_PRIORITY, vgroup.getMaxPriority());
+             assertEquals(Thread.MIN_PRIORITY, group.getMaxPriority());
          });
      }
  
      /**
       * Test Thread.enumerate(false).

@@ -2206,13 +2323,11 @@
          Thread thread = Thread.ofVirtual().start(() -> {
              Thread me = Thread.currentThread();
              me.setName("fred");
              LockSupport.park();
          });
-         while (thread.getState() != Thread.State.WAITING) {
-             Thread.sleep(10);
-         }
+         await(thread, Thread.State.WAITING);
          try {
              assertTrue(thread.toString().contains("fred"));
          } finally {
              LockSupport.unpark(thread);
              thread.join();

@@ -2231,27 +2346,15 @@
          thread.join();
          assertTrue(thread.toString().contains("fred"));
      }
  
      /**
-      * Waits for the given thread to park.
-      */
-     static void awaitParked(Thread thread) throws InterruptedException {
-         Thread.State state = thread.getState();
-         while (state != Thread.State.WAITING && state != Thread.State.TIMED_WAITING) {
-             assertTrue(state != Thread.State.TERMINATED, "Thread has terminated");
-             Thread.sleep(10);
-             state = thread.getState();
-         }
-     }
- 
-     /**
-      * Waits for the given thread to block waiting on a monitor.
+      * Waits for the given thread to reach a given state.
       */
-     static void awaitBlocked(Thread thread) throws InterruptedException {
+     private void await(Thread thread, Thread.State expectedState) throws InterruptedException {
          Thread.State state = thread.getState();
-         while (state != Thread.State.BLOCKED) {
+         while (state != expectedState) {
              assertTrue(state != Thread.State.TERMINATED, "Thread has terminated");
              Thread.sleep(10);
              state = thread.getState();
          }
      }
< prev index next >