< prev index next >

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

Print this page

   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 id=default
  26  * @bug 8284161 8286788
  27  * @summary Test Thread API with virtual threads
  28  * @modules java.base/java.lang:+open
  29  * @library /test/lib
  30  * @run junit ThreadAPI
  31  */
  32 
  33 /*
  34  * @test id=no-vmcontinuations
  35  * @requires vm.continuations
  36  * @modules java.base/java.lang:+open
  37  * @library /test/lib
  38  * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations ThreadAPI
  39  */
  40 
  41 import java.time.Duration;
  42 import java.util.Arrays;
  43 import java.util.ArrayList;
  44 import java.util.List;
  45 import java.util.Map;
  46 import java.util.Set;

  89     /**
  90      * An operation that does not return a result but may throw an exception.
  91      */
  92     @FunctionalInterface
  93     interface ThrowingRunnable {
  94         void run() throws Exception;
  95     }
  96 
  97     /**
  98      * Test Thread.currentThread before/after park.
  99      */
 100     @Test
 101     void testCurrentThread1() throws Exception {
 102         var before = new AtomicReference<Thread>();
 103         var after = new AtomicReference<Thread>();
 104         var thread = Thread.ofVirtual().start(() -> {
 105             before.set(Thread.currentThread());
 106             LockSupport.park();
 107             after.set(Thread.currentThread());
 108         });
 109         awaitParked(thread);
 110         LockSupport.unpark(thread);
 111         thread.join();
 112         assertTrue(before.get() == thread);
 113         assertTrue(after.get() == thread);
 114     }
 115 
 116     /**
 117      * Test Thread.currentThread before/after entering synchronized block.
 118      */
 119     @Test
 120     void testCurrentThread2() throws Exception {
 121         var ref1 = new AtomicReference<Thread>();
 122         var ref2 = new AtomicReference<Thread>();
 123         var ref3 = new AtomicReference<Thread>();
 124         var thread = Thread.ofVirtual().unstarted(() -> {
 125             ref1.set(Thread.currentThread());
 126             synchronized (lock) {
 127                 ref2.set(Thread.currentThread());
 128             }
 129             ref3.set(Thread.currentThread());
 130         });
 131         synchronized (lock) {
 132             thread.start();
 133             awaitBlocked(thread);
 134         }
 135         thread.join();
 136         assertTrue(ref1.get() == thread);
 137         assertTrue(ref2.get() == thread);
 138         assertTrue(ref3.get() == thread);
 139     }
 140 
 141     /**
 142      * Test Thread.currentThread before/after acquiring lock.
 143      */
 144     @Test
 145     void testCurrentThread3() throws Exception {
 146         var ref1 = new AtomicReference<Thread>();
 147         var ref2 = new AtomicReference<Thread>();
 148         var ref3 = new AtomicReference<Thread>();
 149         var lock = new ReentrantLock();
 150         var thread = Thread.ofVirtual().unstarted(() -> {
 151             ref1.set(Thread.currentThread());
 152             lock.lock();
 153             try {
 154                 ref2.set(Thread.currentThread());
 155             } finally {
 156                 lock.unlock();
 157             }
 158             ref3.set(Thread.currentThread());
 159         });
 160         lock.lock();
 161         try {
 162             thread.start();
 163             awaitParked(thread);
 164         } finally {
 165             lock.unlock();
 166         }
 167         thread.join();
 168         assertTrue(ref1.get() == thread);
 169         assertTrue(ref2.get() == thread);
 170         assertTrue(ref3.get() == thread);
 171     }
 172 
 173     /**
 174      * Test Thread::run.
 175      */
 176     @Test
 177     void testRun1() throws Exception {
 178         var ref = new AtomicBoolean();
 179         var thread = Thread.ofVirtual().unstarted(() -> ref.set(true));
 180         thread.run();
 181         assertFalse(ref.get());
 182     }
 183 

 748     }
 749 
 750     /**
 751      * Test platform thread invoking timed-Thread.join on a thread that is parking
 752      * and unparking while pinned.
 753      */
 754     @Test
 755     void testJoin33() throws Exception {
 756         AtomicBoolean done = new AtomicBoolean();
 757         Thread thread = Thread.ofVirtual().start(() -> {
 758             synchronized (lock) {
 759                 while (!done.get()) {
 760                     LockSupport.parkNanos(Duration.ofMillis(20).toNanos());
 761                 }
 762             }
 763         });
 764         try {
 765             assertFalse(thread.join(Duration.ofMillis(100)));
 766         } finally {
 767             done.set(true);

 768         }
 769     }
 770 
 771     /**
 772      * Test virtual thread invoking timed-Thread.join on a thread that is parking
 773      * and unparking while pinned.
 774      */
 775     @Test
 776     void testJoin34() throws Exception {
 777         // need at least two carrier threads due to pinning
 778         int previousParallelism = VThreadRunner.ensureParallelism(2);
 779         try {
 780             VThreadRunner.run(this::testJoin33);
 781         } finally {
 782             // restore
 783             VThreadRunner.setParallelism(previousParallelism);
 784         }
 785     }
 786 
 787     /**

 880 
 881     /**
 882      * Test Thread.interrupt of thread parked in sleep.
 883      */
 884     @Test
 885     void testInterrupt6() throws Exception {
 886         var exception = new AtomicReference<Exception>();
 887         var thread = Thread.ofVirtual().start(() -> {
 888             try {
 889                 try {
 890                     Thread.sleep(60*1000);
 891                     fail("sleep not interrupted");
 892                 } catch (InterruptedException e) {
 893                     // interrupt status should be reset
 894                     assertFalse(Thread.interrupted());
 895                 }
 896             } catch (Exception e) {
 897                 exception.set(e);
 898             }
 899         });
 900         awaitParked(thread);
 901         thread.interrupt();
 902         thread.join();
 903         assertNull(exception.get());
 904     }
 905 
 906     /**
 907      * Test Thread.interrupt of parked thread.
 908      */
 909     @Test
 910     void testInterrupt7() throws Exception {
 911         var exception = new AtomicReference<Exception>();
 912         var thread = Thread.ofVirtual().start(() -> {
 913             try {
 914                 LockSupport.park();
 915                 assertTrue(Thread.currentThread().isInterrupted());
 916             } catch (Exception e) {
 917                 exception.set(e);
 918             }
 919         });
 920         awaitParked(thread);
 921         thread.interrupt();
 922         thread.join();
 923         assertNull(exception.get());
 924     }
 925 
 926     /**
 927      * Test trying to park with interrupt status set.
 928      */
 929     @Test
 930     void testInterrupt8() throws Exception {
 931         VThreadRunner.run(() -> {
 932             Thread me = Thread.currentThread();
 933             me.interrupt();
 934             LockSupport.park();
 935             assertTrue(Thread.interrupted());
 936         });
 937     }
 938 
 939     /**
 940      * Test trying to wait with interrupt status set.

1015             thread.setName("fred2");
1016             assertEquals("fred2", thread.getName());
1017         } finally {
1018             LockSupport.unpark(thread);
1019             thread.join();
1020         }
1021 
1022         // terminated
1023         assertEquals("fred2", thread.getName());
1024         thread.setName("fred3");
1025         assertEquals("fred3", thread.getName());
1026     }
1027 
1028     /**
1029      * Test Thread.getPriority and setPriority from current thread.
1030      */
1031     @Test
1032     void testSetPriority1() throws Exception {
1033         VThreadRunner.run(() -> {
1034             Thread me = Thread.currentThread();
1035             assertTrue(me.getPriority() == Thread.NORM_PRIORITY);
1036 
1037             me.setPriority(Thread.MAX_PRIORITY);
1038             assertTrue(me.getPriority() == Thread.NORM_PRIORITY);
1039 
1040             me.setPriority(Thread.NORM_PRIORITY);
1041             assertTrue(me.getPriority() == Thread.NORM_PRIORITY);
1042 
1043             me.setPriority(Thread.MIN_PRIORITY);
1044             assertTrue(me.getPriority() == Thread.NORM_PRIORITY);
1045 
1046             assertThrows(IllegalArgumentException.class, () -> me.setPriority(-1));
1047         });
1048     }
1049 
1050     /**
1051      * Test Thread.getPriority and setPriority from another thread.
1052      */
1053     @Test
1054     void testSetPriority2() throws Exception {
1055         var thread = Thread.ofVirtual().unstarted(LockSupport::park);
1056 
1057         // not started
1058         assertTrue(thread.getPriority() == Thread.NORM_PRIORITY);
1059 
1060         thread.setPriority(Thread.MAX_PRIORITY);
1061         assertTrue(thread.getPriority() == Thread.NORM_PRIORITY);
1062 
1063         thread.setPriority(Thread.NORM_PRIORITY);
1064         assertTrue(thread.getPriority() == Thread.NORM_PRIORITY);
1065 
1066         thread.setPriority(Thread.MIN_PRIORITY);
1067         assertTrue(thread.getPriority() == Thread.NORM_PRIORITY);
1068 
1069         assertThrows(IllegalArgumentException.class, () -> thread.setPriority(-1));
1070 
1071         // running
1072         thread.start();
1073         try {
1074             assertTrue(thread.getPriority() == Thread.NORM_PRIORITY);
1075             thread.setPriority(Thread.NORM_PRIORITY);
1076 
1077             thread.setPriority(Thread.MAX_PRIORITY);
1078             assertTrue(thread.getPriority() == Thread.NORM_PRIORITY);
1079 
1080             thread.setPriority(Thread.NORM_PRIORITY);
1081             assertTrue(thread.getPriority() == Thread.NORM_PRIORITY);
1082 
1083             thread.setPriority(Thread.MIN_PRIORITY);
1084             assertTrue(thread.getPriority() == Thread.NORM_PRIORITY);
1085 
1086             assertThrows(IllegalArgumentException.class, () -> thread.setPriority(-1));
1087 
1088         } finally {
1089             LockSupport.unpark(thread);
1090         }
1091         thread.join();
1092 
1093         // terminated
1094         assertTrue(thread.getPriority() == Thread.NORM_PRIORITY);
1095     }
1096 
1097     /**
1098      * Test Thread.isDaemon and setDaemon from current thread.
1099      */
1100     @Test
1101     void testSetDaemon1() throws Exception {
1102         VThreadRunner.run(() -> {
1103             Thread me = Thread.currentThread();
1104             assertTrue(me.isDaemon());
1105             assertThrows(IllegalThreadStateException.class, () -> me.setDaemon(true));
1106             assertThrows(IllegalArgumentException.class, () -> me.setDaemon(false));
1107         });
1108     }
1109 
1110     /**
1111      * Test Thread.isDaemon and setDaemon from another thread.
1112      */
1113     @Test
1114     void testSetDaemon2() throws Exception {

1173             Thread.Builder builder = ThreadBuilders.virtualThreadBuilder(scheduler);
1174             ThreadFactory factory = builder.factory();
1175             var thread = factory.newThread(() -> {
1176                 list.add("A");
1177                 var child = factory.newThread(() -> {
1178                     list.add("B");
1179                 });
1180                 child.start();
1181                 synchronized (lock) {
1182                     Thread.yield();   // pinned so will be a no-op
1183                     list.add("A");
1184                 }
1185                 try { child.join(); } catch (InterruptedException e) { }
1186             });
1187             thread.start();
1188             thread.join();
1189         }
1190         assertEquals(List.of("A", "A", "B"), list);
1191     }
1192 






























1193     /**
1194      * Test Thread.onSpinWait.
1195      */
1196     @Test
1197     void testOnSpinWait() throws Exception {
1198         VThreadRunner.run(() -> {
1199             Thread me = Thread.currentThread();
1200             Thread.onSpinWait();
1201             assertTrue(Thread.currentThread() == me);
1202         });
1203     }
1204 
1205     /**
1206      * Test Thread.sleep(-1).
1207      */
1208     @Test
1209     void testSleep1() throws Exception {
1210         VThreadRunner.run(() -> {
1211             assertThrows(IllegalArgumentException.class, () -> Thread.sleep(-1));
1212             assertThrows(IllegalArgumentException.class, () -> Thread.sleep(-1, 0));

1633         // terminated
1634         assertTrue(vthread.threadId() == tid);
1635         assertTrue(vthread.getId() == tid);
1636     }
1637 
1638     /**
1639      * Test that each Thread has a unique ID
1640      */
1641     @Test
1642     void testThreadId2() throws Exception {
1643         // thread ID should be unique
1644         long tid1 = Thread.ofVirtual().unstarted(() -> { }).threadId();
1645         long tid2 = Thread.ofVirtual().unstarted(() -> { }).threadId();
1646         long tid3 = Thread.currentThread().threadId();
1647         assertFalse(tid1 == tid2);
1648         assertFalse(tid1 == tid3);
1649         assertFalse(tid2 == tid3);
1650     }
1651 
1652     /**
1653      * Test Thread::getState when thread is not started.
1654      */
1655     @Test
1656     void testGetState1() {
1657         var thread = Thread.ofVirtual().unstarted(() -> { });
1658         assertTrue(thread.getState() == Thread.State.NEW);
1659     }
1660 
1661     /**
1662      * Test Thread::getState when thread is runnable (mounted).
1663      */
1664     @Test
1665     void testGetState2() throws Exception {
1666         VThreadRunner.run(() -> {
1667             Thread.State state = Thread.currentThread().getState();
1668             assertTrue(state == Thread.State.RUNNABLE);
















1669         });










1670     }
1671 
1672     /**
1673      * Test Thread::getState when thread is runnable (not mounted).
1674      */
1675     @Test
1676     void testGetState3() throws Exception {
1677         assumeTrue(ThreadBuilders.supportsCustomScheduler(), "No support for custom schedulers");
1678         AtomicBoolean completed = new AtomicBoolean();
1679         try (ExecutorService scheduler = Executors.newFixedThreadPool(1)) {
1680             Thread.Builder builder = ThreadBuilders.virtualThreadBuilder(scheduler);
1681             Thread t1 = builder.start(() -> {
1682                 Thread t2 = builder.unstarted(LockSupport::park);
1683                 assertTrue(t2.getState() == Thread.State.NEW);
1684 
1685                 // start t2 to make it runnable
1686                 t2.start();
1687                 try {
1688                     assertTrue(t2.getState() == Thread.State.RUNNABLE);
1689 
1690                     // yield to allow t2 to run and park
1691                     Thread.yield();
1692                     assertTrue(t2.getState() == Thread.State.WAITING);
1693                 } finally {
1694                     // unpark t2 to make it runnable again
1695                     LockSupport.unpark(t2);
1696                 }
1697 
1698                 // t2 should be runnable (not mounted)
1699                 assertTrue(t2.getState() == Thread.State.RUNNABLE);
1700 
1701                 completed.set(true);
1702             });
1703             t1.join();
1704         }
1705         assertTrue(completed.get() == true);
1706     }
1707 
1708     /**
1709      * Test Thread::getState when thread is parked.
1710      */
1711     @Test
1712     void testGetState4() throws Exception {
1713         var thread = Thread.ofVirtual().start(LockSupport::park);
1714         while (thread.getState() != Thread.State.WAITING) {
1715             Thread.sleep(20);








1716         }
1717         LockSupport.unpark(thread);
1718         thread.join();
1719     }
1720 
1721     /**
1722      * Test Thread::getState when thread is parked while holding a monitor.
1723      */
1724     @Test
1725     void testGetState5() throws Exception {
1726         var thread = Thread.ofVirtual().start(() -> {
1727             synchronized (lock) {
1728                 LockSupport.park();
1729             }
1730         });
1731         while (thread.getState() != Thread.State.WAITING) {
1732             Thread.sleep(20);




1733         }
1734         LockSupport.unpark(thread);
1735         thread.join();
1736     }
1737 
1738     /**
1739      * Test Thread::getState when thread is waiting for a monitor.
1740      */
1741     @Test
1742     void testGetState6() throws Exception {
1743         var thread = Thread.ofVirtual().unstarted(() -> {
1744             synchronized (lock) { }
1745         });
1746         synchronized (lock) {
1747             thread.start();
1748             while (thread.getState() != Thread.State.BLOCKED) {
1749                 Thread.sleep(20);
1750             }







1751         }
1752         thread.join();
1753     }
1754 
1755     /**
1756      * Test Thread::getState when thread is waiting in Object.wait.
1757      */
1758     @Test
1759     void testGetState7() throws Exception {






























1760         var thread = Thread.ofVirtual().start(() -> {

1761             synchronized (lock) {
1762                 try { lock.wait(); } catch (InterruptedException e) { }


1763             }
1764         });
1765         while (thread.getState() != Thread.State.WAITING) {
1766             Thread.sleep(20);








1767         }
1768         thread.interrupt();
1769         thread.join();
1770     }
1771 
1772     /**
1773      * Test Thread::getState when thread is terminated.
1774      */
1775     @Test
1776     void testGetState8() throws Exception {
1777         var thread = Thread.ofVirtual().start(() -> { });
1778         thread.join();
1779         assertTrue(thread.getState() == Thread.State.TERMINATED);


















1780     }
1781 
1782     /**
1783      * Test Thread::isAlive.
1784      */
1785     @Test
1786     void testIsAlive1() throws Exception {
1787         // unstarted
1788         var thread = Thread.ofVirtual().unstarted(LockSupport::park);
1789         assertFalse(thread.isAlive());
1790 
1791         // started
1792         thread.start();
1793         try {
1794             assertTrue(thread.isAlive());
1795         } finally {
1796             LockSupport.unpark(thread);
1797             thread.join();
1798         }
1799 

1882                     task.run();
1883                 });
1884             };
1885 
1886             Thread.Builder builder = ThreadBuilders.virtualThreadBuilder(scheduler);
1887             Thread vthread = builder.start(() -> {
1888                 synchronized (lock) {
1889                     try {
1890                         lock.wait();
1891                     } catch (Exception e) { }
1892                 }
1893             });
1894 
1895             // get carrier Thread
1896             Thread carrier;
1897             while ((carrier = ref.get()) == null) {
1898                 Thread.sleep(20);
1899             }
1900 
1901             // wait for virtual thread to block in wait
1902             while (vthread.getState() != Thread.State.WAITING) {
1903                 Thread.sleep(20);
1904             }
1905 
1906             // get stack trace of both carrier and virtual thread
1907             StackTraceElement[] carrierStackTrace = carrier.getStackTrace();
1908             StackTraceElement[] vthreadStackTrace = vthread.getStackTrace();
1909 
1910             // allow virtual thread to terminate
1911             synchronized (lock) {
1912                 lock.notifyAll();
1913             }
1914 
1915             // check carrier thread's stack trace
1916             assertTrue(contains(carrierStackTrace, "java.util.concurrent.ForkJoinPool.runWorker"));
1917             assertFalse(contains(carrierStackTrace, "java.lang.Object.wait"));
1918 
1919             // check virtual thread's stack trace
1920             assertFalse(contains(vthreadStackTrace, "java.util.concurrent.ForkJoinPool.runWorker"));
1921             assertTrue(contains(vthreadStackTrace, "java.lang.Object.wait"));
1922         }
1923     }
1924 
1925     /**
1926      * Test Thread::getStackTrace on parked thread.
1927      */
1928     @Test
1929     void testGetStackTrace5() throws Exception {
1930         var thread = Thread.ofVirtual().start(LockSupport::park);
1931 
1932         // wait for thread to park
1933         while (thread.getState() != Thread.State.WAITING) {
1934             Thread.sleep(20);
1935         }
1936 
1937         try {
1938             StackTraceElement[] stack = thread.getStackTrace();
1939             assertTrue(contains(stack, "LockSupport.park"));
1940         } finally {
1941             LockSupport.unpark(thread);
1942             thread.join();
1943         }
1944     }
1945 
1946     /**
1947      * Test Thread::getStackTrace on terminated thread.
1948      */
1949     @Test
1950     void testGetStackTrace6() throws Exception {
1951         var thread = Thread.ofVirtual().start(() -> { });
1952         thread.join();
1953         StackTraceElement[] stack = thread.getStackTrace();
1954         assertTrue(stack.length == 0);
1955     }
1956 

1979                     task.run();
1980                 });
1981             };
1982 
1983             Thread.Builder builder = ThreadBuilders.virtualThreadBuilder(scheduler);
1984             Thread vthread = builder.start(() -> {
1985                 synchronized (lock) {
1986                     try {
1987                         lock.wait();
1988                     } catch (Exception e) { }
1989                 }
1990             });
1991 
1992             // get carrier Thread
1993             Thread carrier;
1994             while ((carrier = ref.get()) == null) {
1995                 Thread.sleep(20);
1996             }
1997 
1998             // wait for virtual thread to block in wait
1999             while (vthread.getState() != Thread.State.WAITING) {
2000                 Thread.sleep(20);
2001             }
2002 
2003             // get all stack traces
2004             Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces();
2005 
2006             // allow virtual thread to terminate
2007             synchronized (lock) {
2008                 lock.notifyAll();
2009             }
2010 
2011             // get stack trace for the carrier thread
2012             StackTraceElement[] stackTrace = map.get(carrier);
2013             assertNotNull(stackTrace);
2014             assertTrue(contains(stackTrace, "java.util.concurrent.ForkJoinPool"));
2015             assertFalse(contains(stackTrace, "java.lang.Object.wait"));
2016 
2017             // there should be no stack trace for the virtual thread
2018             assertNull(map.get(vthread));
2019         }
2020     }
2021 
2022     private boolean contains(StackTraceElement[] stack, String expected) {
2023         return Stream.of(stack)
2024                 .map(Object::toString)
2025                 .anyMatch(s -> s.contains(expected));
2026     }
2027 
2028     /**
2029      * Test Thread::getThreadGroup on virtual thread created by platform thread.
2030      */
2031     @Test
2032     void testThreadGroup1() throws Exception {
2033         var thread = Thread.ofVirtual().unstarted(LockSupport::park);
2034         var vgroup = thread.getThreadGroup();
2035         thread.start();
2036         try {
2037             assertTrue(thread.getThreadGroup() == vgroup);
2038         } finally {
2039             LockSupport.unpark(thread);
2040             thread.join();
2041         }
2042         assertNull(thread.getThreadGroup());
2043     }
2044 
2045     /**
2046      * Test Thread::getThreadGroup on platform thread created by virtual thread.
2047      */
2048     @Test
2049     void testThreadGroup2() throws Exception {
2050         VThreadRunner.run(() -> {
2051             ThreadGroup vgroup = Thread.currentThread().getThreadGroup();
2052             Thread child = new Thread(() -> { });
2053             ThreadGroup group = child.getThreadGroup();
2054             assertTrue(group == vgroup);
2055         });
2056     }
2057 
2058     /**
2059      * Test ThreadGroup returned by Thread::getThreadGroup and subgroup
2060      * created with 2-arg ThreadGroup constructor.
2061      */
2062     @Test
2063     void testThreadGroup3() throws Exception {
2064         var ref = new AtomicReference<ThreadGroup>();
2065         var thread = Thread.startVirtualThread(() -> {
2066             ref.set(Thread.currentThread().getThreadGroup());
2067         });
2068         thread.join();
2069 
2070         ThreadGroup vgroup = ref.get();
2071         assertTrue(vgroup.getMaxPriority() == Thread.MAX_PRIORITY);
2072 
2073         ThreadGroup group = new ThreadGroup(vgroup, "group");
2074         assertTrue(group.getParent() == vgroup);
2075         assertTrue(group.getMaxPriority() == Thread.MAX_PRIORITY);
2076 
2077         vgroup.setMaxPriority(Thread.MAX_PRIORITY - 1);
2078         assertTrue(vgroup.getMaxPriority() == Thread.MAX_PRIORITY);
2079         assertTrue(group.getMaxPriority() == Thread.MAX_PRIORITY - 1);
2080 
2081         vgroup.setMaxPriority(Thread.MIN_PRIORITY);
2082         assertTrue(vgroup.getMaxPriority() == Thread.MAX_PRIORITY);
2083         assertTrue(group.getMaxPriority() == Thread.MIN_PRIORITY);
2084     }
2085 
2086     /**
2087      * Test ThreadGroup returned by Thread::getThreadGroup and subgroup
2088      * created with 1-arg ThreadGroup constructor.
2089      */
2090     @Test
2091     void testThreadGroup4() throws Exception {
2092         VThreadRunner.run(() -> {
2093             ThreadGroup vgroup = Thread.currentThread().getThreadGroup();
2094 
2095             assertTrue(vgroup.getMaxPriority() == Thread.MAX_PRIORITY);
2096 
2097             ThreadGroup group = new ThreadGroup("group");
2098             assertTrue(group.getParent() == vgroup);
2099             assertTrue(group.getMaxPriority() == Thread.MAX_PRIORITY);
2100 
2101             vgroup.setMaxPriority(Thread.MAX_PRIORITY - 1);
2102             assertTrue(vgroup.getMaxPriority() == Thread.MAX_PRIORITY);
2103             assertTrue(group.getMaxPriority() == Thread.MAX_PRIORITY - 1);
2104 
2105             vgroup.setMaxPriority(Thread.MIN_PRIORITY);
2106             assertTrue(vgroup.getMaxPriority() == Thread.MAX_PRIORITY);
2107             assertTrue(group.getMaxPriority() == Thread.MIN_PRIORITY);
2108         });
2109     }
2110 
2111     /**
2112      * Test Thread.enumerate(false).
2113      */
2114     @Test
2115     void testEnumerate1() throws Exception {
2116         VThreadRunner.run(() -> {
2117             ThreadGroup vgroup = Thread.currentThread().getThreadGroup();
2118             Thread[] threads = new Thread[100];
2119             int n = vgroup.enumerate(threads, /*recurse*/false);
2120             assertTrue(n == 0);
2121         });
2122     }
2123 
2124     /**
2125      * Test Thread.enumerate(true).
2126      */
2127     @Test

2191      */
2192     @Test
2193     void testToString2() throws Exception {
2194         VThreadRunner.run(() -> {
2195             Thread me = Thread.currentThread();
2196             me.setName("fred");
2197             assertTrue(me.toString().contains("fred"));
2198         });
2199     }
2200 
2201     /**
2202      * Test toString on parked thread.
2203      */
2204     @Test
2205     void testToString3() throws Exception {
2206         Thread thread = Thread.ofVirtual().start(() -> {
2207             Thread me = Thread.currentThread();
2208             me.setName("fred");
2209             LockSupport.park();
2210         });
2211         while (thread.getState() != Thread.State.WAITING) {
2212             Thread.sleep(10);
2213         }
2214         try {
2215             assertTrue(thread.toString().contains("fred"));
2216         } finally {
2217             LockSupport.unpark(thread);
2218             thread.join();
2219         }
2220     }
2221 
2222     /**
2223      * Test toString on terminated thread.
2224      */
2225     @Test
2226     void testToString4() throws Exception {
2227         Thread thread = Thread.ofVirtual().start(() -> {
2228             Thread me = Thread.currentThread();
2229             me.setName("fred");
2230         });
2231         thread.join();
2232         assertTrue(thread.toString().contains("fred"));
2233     }
2234 
2235     /**
2236      * Waits for the given thread to park.
2237      */
2238     static void awaitParked(Thread thread) throws InterruptedException {
2239         Thread.State state = thread.getState();
2240         while (state != Thread.State.WAITING && state != Thread.State.TIMED_WAITING) {
2241             assertTrue(state != Thread.State.TERMINATED, "Thread has terminated");
2242             Thread.sleep(10);
2243             state = thread.getState();
2244         }
2245     }
2246 
2247     /**
2248      * Waits for the given thread to block waiting on a monitor.
2249      */
2250     static void awaitBlocked(Thread thread) throws InterruptedException {
2251         Thread.State state = thread.getState();
2252         while (state != Thread.State.BLOCKED) {
2253             assertTrue(state != Thread.State.TERMINATED, "Thread has terminated");
2254             Thread.sleep(10);
2255             state = thread.getState();
2256         }
2257     }
2258 
2259     /**
2260      * Schedule a thread to be interrupted after a delay.
2261      */
2262     private void scheduleInterrupt(Thread thread, long delayInMillis) {
2263         scheduler.schedule(thread::interrupt, delayInMillis, TimeUnit.MILLISECONDS);
2264     }
2265 }

   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 id=default
  26  * @bug 8284161 8286788 8321270
  27  * @summary Test Thread API with virtual threads
  28  * @modules java.base/java.lang:+open
  29  * @library /test/lib
  30  * @run junit ThreadAPI
  31  */
  32 
  33 /*
  34  * @test id=no-vmcontinuations
  35  * @requires vm.continuations
  36  * @modules java.base/java.lang:+open
  37  * @library /test/lib
  38  * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations ThreadAPI
  39  */
  40 
  41 import java.time.Duration;
  42 import java.util.Arrays;
  43 import java.util.ArrayList;
  44 import java.util.List;
  45 import java.util.Map;
  46 import java.util.Set;

  89     /**
  90      * An operation that does not return a result but may throw an exception.
  91      */
  92     @FunctionalInterface
  93     interface ThrowingRunnable {
  94         void run() throws Exception;
  95     }
  96 
  97     /**
  98      * Test Thread.currentThread before/after park.
  99      */
 100     @Test
 101     void testCurrentThread1() throws Exception {
 102         var before = new AtomicReference<Thread>();
 103         var after = new AtomicReference<Thread>();
 104         var thread = Thread.ofVirtual().start(() -> {
 105             before.set(Thread.currentThread());
 106             LockSupport.park();
 107             after.set(Thread.currentThread());
 108         });
 109         await(thread, Thread.State.WAITING);
 110         LockSupport.unpark(thread);
 111         thread.join();
 112         assertTrue(before.get() == thread);
 113         assertTrue(after.get() == thread);
 114     }
 115 
 116     /**
 117      * Test Thread.currentThread before/after entering synchronized block.
 118      */
 119     @Test
 120     void testCurrentThread2() throws Exception {
 121         var ref1 = new AtomicReference<Thread>();
 122         var ref2 = new AtomicReference<Thread>();
 123         var ref3 = new AtomicReference<Thread>();
 124         var thread = Thread.ofVirtual().unstarted(() -> {
 125             ref1.set(Thread.currentThread());
 126             synchronized (lock) {
 127                 ref2.set(Thread.currentThread());
 128             }
 129             ref3.set(Thread.currentThread());
 130         });
 131         synchronized (lock) {
 132             thread.start();
 133             await(thread, Thread.State.BLOCKED);
 134         }
 135         thread.join();
 136         assertTrue(ref1.get() == thread);
 137         assertTrue(ref2.get() == thread);
 138         assertTrue(ref3.get() == thread);
 139     }
 140 
 141     /**
 142      * Test Thread.currentThread before/after acquiring lock.
 143      */
 144     @Test
 145     void testCurrentThread3() throws Exception {
 146         var ref1 = new AtomicReference<Thread>();
 147         var ref2 = new AtomicReference<Thread>();
 148         var ref3 = new AtomicReference<Thread>();
 149         var lock = new ReentrantLock();
 150         var thread = Thread.ofVirtual().unstarted(() -> {
 151             ref1.set(Thread.currentThread());
 152             lock.lock();
 153             try {
 154                 ref2.set(Thread.currentThread());
 155             } finally {
 156                 lock.unlock();
 157             }
 158             ref3.set(Thread.currentThread());
 159         });
 160         lock.lock();
 161         try {
 162             thread.start();
 163             await(thread, Thread.State.WAITING);
 164         } finally {
 165             lock.unlock();
 166         }
 167         thread.join();
 168         assertTrue(ref1.get() == thread);
 169         assertTrue(ref2.get() == thread);
 170         assertTrue(ref3.get() == thread);
 171     }
 172 
 173     /**
 174      * Test Thread::run.
 175      */
 176     @Test
 177     void testRun1() throws Exception {
 178         var ref = new AtomicBoolean();
 179         var thread = Thread.ofVirtual().unstarted(() -> ref.set(true));
 180         thread.run();
 181         assertFalse(ref.get());
 182     }
 183 

 748     }
 749 
 750     /**
 751      * Test platform thread invoking timed-Thread.join on a thread that is parking
 752      * and unparking while pinned.
 753      */
 754     @Test
 755     void testJoin33() throws Exception {
 756         AtomicBoolean done = new AtomicBoolean();
 757         Thread thread = Thread.ofVirtual().start(() -> {
 758             synchronized (lock) {
 759                 while (!done.get()) {
 760                     LockSupport.parkNanos(Duration.ofMillis(20).toNanos());
 761                 }
 762             }
 763         });
 764         try {
 765             assertFalse(thread.join(Duration.ofMillis(100)));
 766         } finally {
 767             done.set(true);
 768             thread.join();
 769         }
 770     }
 771 
 772     /**
 773      * Test virtual thread invoking timed-Thread.join on a thread that is parking
 774      * and unparking while pinned.
 775      */
 776     @Test
 777     void testJoin34() throws Exception {
 778         // need at least two carrier threads due to pinning
 779         int previousParallelism = VThreadRunner.ensureParallelism(2);
 780         try {
 781             VThreadRunner.run(this::testJoin33);
 782         } finally {
 783             // restore
 784             VThreadRunner.setParallelism(previousParallelism);
 785         }
 786     }
 787 
 788     /**

 881 
 882     /**
 883      * Test Thread.interrupt of thread parked in sleep.
 884      */
 885     @Test
 886     void testInterrupt6() throws Exception {
 887         var exception = new AtomicReference<Exception>();
 888         var thread = Thread.ofVirtual().start(() -> {
 889             try {
 890                 try {
 891                     Thread.sleep(60*1000);
 892                     fail("sleep not interrupted");
 893                 } catch (InterruptedException e) {
 894                     // interrupt status should be reset
 895                     assertFalse(Thread.interrupted());
 896                 }
 897             } catch (Exception e) {
 898                 exception.set(e);
 899             }
 900         });
 901         await(thread, Thread.State.TIMED_WAITING);
 902         thread.interrupt();
 903         thread.join();
 904         assertNull(exception.get());
 905     }
 906 
 907     /**
 908      * Test Thread.interrupt of parked thread.
 909      */
 910     @Test
 911     void testInterrupt7() throws Exception {
 912         var exception = new AtomicReference<Exception>();
 913         var thread = Thread.ofVirtual().start(() -> {
 914             try {
 915                 LockSupport.park();
 916                 assertTrue(Thread.currentThread().isInterrupted());
 917             } catch (Exception e) {
 918                 exception.set(e);
 919             }
 920         });
 921         await(thread, Thread.State.WAITING);
 922         thread.interrupt();
 923         thread.join();
 924         assertNull(exception.get());
 925     }
 926 
 927     /**
 928      * Test trying to park with interrupt status set.
 929      */
 930     @Test
 931     void testInterrupt8() throws Exception {
 932         VThreadRunner.run(() -> {
 933             Thread me = Thread.currentThread();
 934             me.interrupt();
 935             LockSupport.park();
 936             assertTrue(Thread.interrupted());
 937         });
 938     }
 939 
 940     /**
 941      * Test trying to wait with interrupt status set.

1016             thread.setName("fred2");
1017             assertEquals("fred2", thread.getName());
1018         } finally {
1019             LockSupport.unpark(thread);
1020             thread.join();
1021         }
1022 
1023         // terminated
1024         assertEquals("fred2", thread.getName());
1025         thread.setName("fred3");
1026         assertEquals("fred3", thread.getName());
1027     }
1028 
1029     /**
1030      * Test Thread.getPriority and setPriority from current thread.
1031      */
1032     @Test
1033     void testSetPriority1() throws Exception {
1034         VThreadRunner.run(() -> {
1035             Thread me = Thread.currentThread();
1036             assertEquals(Thread.NORM_PRIORITY, me.getPriority());
1037 
1038             me.setPriority(Thread.MAX_PRIORITY);
1039             assertEquals(Thread.NORM_PRIORITY, me.getPriority());
1040 
1041             me.setPriority(Thread.NORM_PRIORITY);
1042             assertEquals(Thread.NORM_PRIORITY, me.getPriority());
1043 
1044             me.setPriority(Thread.MIN_PRIORITY);
1045             assertEquals(Thread.NORM_PRIORITY, me.getPriority());
1046 
1047             assertThrows(IllegalArgumentException.class, () -> me.setPriority(-1));
1048         });
1049     }
1050 
1051     /**
1052      * Test Thread.getPriority and setPriority from another thread.
1053      */
1054     @Test
1055     void testSetPriority2() throws Exception {
1056         var thread = Thread.ofVirtual().unstarted(LockSupport::park);
1057 
1058         // not started
1059         assertEquals(Thread.NORM_PRIORITY, thread.getPriority());
1060 
1061         thread.setPriority(Thread.MAX_PRIORITY);
1062         assertEquals(Thread.NORM_PRIORITY, thread.getPriority());
1063 
1064         thread.setPriority(Thread.NORM_PRIORITY);
1065         assertEquals(Thread.NORM_PRIORITY, thread.getPriority());
1066 
1067         thread.setPriority(Thread.MIN_PRIORITY);
1068         assertEquals(Thread.NORM_PRIORITY, thread.getPriority());
1069 
1070         assertThrows(IllegalArgumentException.class, () -> thread.setPriority(-1));
1071 
1072         // running
1073         thread.start();
1074         try {
1075             assertEquals(Thread.NORM_PRIORITY, thread.getPriority());
1076             thread.setPriority(Thread.NORM_PRIORITY);
1077 
1078             thread.setPriority(Thread.MAX_PRIORITY);
1079             assertEquals(Thread.NORM_PRIORITY, thread.getPriority());
1080 
1081             thread.setPriority(Thread.NORM_PRIORITY);
1082             assertEquals(Thread.NORM_PRIORITY, thread.getPriority());
1083 
1084             thread.setPriority(Thread.MIN_PRIORITY);
1085             assertEquals(Thread.NORM_PRIORITY, thread.getPriority());
1086 
1087             assertThrows(IllegalArgumentException.class, () -> thread.setPriority(-1));
1088 
1089         } finally {
1090             LockSupport.unpark(thread);
1091         }
1092         thread.join();
1093 
1094         // terminated
1095         assertEquals(Thread.NORM_PRIORITY, thread.getPriority());
1096     }
1097 
1098     /**
1099      * Test Thread.isDaemon and setDaemon from current thread.
1100      */
1101     @Test
1102     void testSetDaemon1() throws Exception {
1103         VThreadRunner.run(() -> {
1104             Thread me = Thread.currentThread();
1105             assertTrue(me.isDaemon());
1106             assertThrows(IllegalThreadStateException.class, () -> me.setDaemon(true));
1107             assertThrows(IllegalArgumentException.class, () -> me.setDaemon(false));
1108         });
1109     }
1110 
1111     /**
1112      * Test Thread.isDaemon and setDaemon from another thread.
1113      */
1114     @Test
1115     void testSetDaemon2() throws Exception {

1174             Thread.Builder builder = ThreadBuilders.virtualThreadBuilder(scheduler);
1175             ThreadFactory factory = builder.factory();
1176             var thread = factory.newThread(() -> {
1177                 list.add("A");
1178                 var child = factory.newThread(() -> {
1179                     list.add("B");
1180                 });
1181                 child.start();
1182                 synchronized (lock) {
1183                     Thread.yield();   // pinned so will be a no-op
1184                     list.add("A");
1185                 }
1186                 try { child.join(); } catch (InterruptedException e) { }
1187             });
1188             thread.start();
1189             thread.join();
1190         }
1191         assertEquals(List.of("A", "A", "B"), list);
1192     }
1193 
1194     /**
1195      * Test that Thread.yield does not consume the thread's parking permit.
1196      */
1197     @Test
1198     void testYield3() throws Exception {
1199         var thread = Thread.ofVirtual().start(() -> {
1200             LockSupport.unpark(Thread.currentThread());
1201             Thread.yield();
1202             LockSupport.park();  // should not park
1203         });
1204         thread.join();
1205     }
1206 
1207     /**
1208      * Test that Thread.yield does not make available the thread's parking permit.
1209      */
1210     @Test
1211     void testYield4() throws Exception {
1212         var thread = Thread.ofVirtual().start(() -> {
1213             Thread.yield();
1214             LockSupport.park();  // should park
1215         });
1216         try {
1217             await(thread, Thread.State.WAITING);
1218         } finally {
1219             LockSupport.unpark(thread);
1220             thread.join();
1221         }
1222     }
1223 
1224     /**
1225      * Test Thread.onSpinWait.
1226      */
1227     @Test
1228     void testOnSpinWait() throws Exception {
1229         VThreadRunner.run(() -> {
1230             Thread me = Thread.currentThread();
1231             Thread.onSpinWait();
1232             assertTrue(Thread.currentThread() == me);
1233         });
1234     }
1235 
1236     /**
1237      * Test Thread.sleep(-1).
1238      */
1239     @Test
1240     void testSleep1() throws Exception {
1241         VThreadRunner.run(() -> {
1242             assertThrows(IllegalArgumentException.class, () -> Thread.sleep(-1));
1243             assertThrows(IllegalArgumentException.class, () -> Thread.sleep(-1, 0));

1664         // terminated
1665         assertTrue(vthread.threadId() == tid);
1666         assertTrue(vthread.getId() == tid);
1667     }
1668 
1669     /**
1670      * Test that each Thread has a unique ID
1671      */
1672     @Test
1673     void testThreadId2() throws Exception {
1674         // thread ID should be unique
1675         long tid1 = Thread.ofVirtual().unstarted(() -> { }).threadId();
1676         long tid2 = Thread.ofVirtual().unstarted(() -> { }).threadId();
1677         long tid3 = Thread.currentThread().threadId();
1678         assertFalse(tid1 == tid2);
1679         assertFalse(tid1 == tid3);
1680         assertFalse(tid2 == tid3);
1681     }
1682 
1683     /**
1684      * Test Thread::getState when thread is new/unstarted.
1685      */
1686     @Test
1687     void testGetState1() {
1688         var thread = Thread.ofVirtual().unstarted(() -> { });
1689         assertEquals(Thread.State.NEW, thread.getState());
1690     }
1691 
1692     /**
1693      * Test Thread::getState when thread is terminated.
1694      */
1695     @Test
1696     void testGetState2() throws Exception {
1697         var thread = Thread.ofVirtual().start(() -> { });
1698         thread.join();
1699         assertEquals(Thread.State.TERMINATED, thread.getState());
1700     }
1701 
1702     /**
1703      * Test Thread::getState when thread is runnable (mounted).
1704      */
1705     @Test
1706     void testGetState3() throws Exception {
1707         var started = new CountDownLatch(1);
1708         var done = new AtomicBoolean();
1709         var thread = Thread.ofVirtual().start(() -> {
1710             started.countDown();
1711 
1712             // spin until done
1713             while (!done.get()) {
1714                 Thread.onSpinWait();
1715             }
1716         });
1717         try {
1718             // wait for thread to start
1719             started.await();
1720 
1721             // thread should be runnable
1722             assertEquals(Thread.State.RUNNABLE, thread.getState());
1723         } finally {
1724             done.set(true);
1725             thread.join();
1726         }
1727     }
1728 
1729     /**
1730      * Test Thread::getState when thread is runnable (not mounted).
1731      */
1732     @Test
1733     void testGetState4() throws Exception {
1734         assumeTrue(ThreadBuilders.supportsCustomScheduler(), "No support for custom schedulers");
1735         AtomicBoolean completed = new AtomicBoolean();
1736         try (ExecutorService scheduler = Executors.newFixedThreadPool(1)) {
1737             Thread.Builder builder = ThreadBuilders.virtualThreadBuilder(scheduler);
1738             Thread t1 = builder.start(() -> {
1739                 Thread t2 = builder.unstarted(LockSupport::park);
1740                 assertEquals(Thread.State.NEW, t2.getState());
1741 
1742                 // start t2 to make it runnable
1743                 t2.start();
1744                 try {
1745                     assertEquals(Thread.State.RUNNABLE, t2.getState());
1746 
1747                     // yield to allow t2 to run and park
1748                     Thread.yield();
1749                     assertEquals(Thread.State.WAITING, t2.getState());
1750                 } finally {
1751                     // unpark t2 to make it runnable again
1752                     LockSupport.unpark(t2);
1753                 }
1754 
1755                 // t2 should be runnable (not mounted)
1756                 assertEquals(Thread.State.RUNNABLE, t2.getState());
1757 
1758                 completed.set(true);
1759             });
1760             t1.join();
1761         }
1762         assertTrue(completed.get() == true);
1763     }
1764 
1765     /**
1766      * Test Thread::getState when thread is waiting to enter a monitor.
1767      */
1768     @Test
1769     void testGetState5() throws Exception {
1770         var started = new CountDownLatch(1);
1771         var thread = Thread.ofVirtual().unstarted(() -> {
1772             started.countDown();
1773             synchronized (lock) { }
1774         });
1775         synchronized (lock) {
1776             thread.start();
1777             started.await();
1778 
1779             // wait for thread to block
1780             await(thread, Thread.State.BLOCKED);
1781         }

1782         thread.join();
1783     }
1784 
1785     /**
1786      * Test Thread::getState when thread is waiting in Object.wait.
1787      */
1788     @Test
1789     void testGetState6() throws Exception {
1790         var thread = Thread.ofVirtual().start(() -> {
1791             synchronized (lock) {
1792                 try { lock.wait(); } catch (InterruptedException e) { }
1793             }
1794         });
1795         try {
1796             // wait for thread to wait
1797             await(thread, Thread.State.WAITING);
1798         } finally {
1799             thread.interrupt();
1800             thread.join();
1801         }


1802     }
1803 
1804     /**
1805      * Test Thread::getState when thread is waiting in Object.wait(millis).
1806      */
1807     @Test
1808     void testGetState7() throws Exception {
1809         var thread = Thread.ofVirtual().start(() -> {
1810             synchronized (lock) {
1811                 try {
1812                     lock.wait(Long.MAX_VALUE);
1813                 } catch (InterruptedException e) { }


1814             }
1815         });
1816         try {
1817             // wait for thread to wait
1818             await(thread, Thread.State.TIMED_WAITING);
1819         } finally {
1820             thread.interrupt();
1821             thread.join();
1822         }

1823     }
1824 
1825     /**
1826      * Test Thread::getState when thread is parked.
1827      */
1828     @Test
1829     void testGetState8() throws Exception {
1830         var thread = Thread.ofVirtual().start(LockSupport::park);
1831         try {
1832             await(thread, Thread.State.WAITING);
1833         } finally {
1834             LockSupport.unpark(thread);
1835             thread.join();
1836         }
1837     }
1838 
1839     /**
1840      * Test Thread::getState when thread is timed parked.
1841      */
1842     @Test
1843     void testGetState9() throws Exception {
1844         var thread = Thread.ofVirtual().start(() -> LockSupport.parkNanos(Long.MAX_VALUE));
1845         try {
1846             await(thread, Thread.State.TIMED_WAITING);
1847         } finally {
1848             LockSupport.unpark(thread);
1849             thread.join();
1850         }
1851     }
1852 
1853     /**
1854      * Test Thread::getState when thread is parked while holding a monitor.
1855      */
1856     @Test
1857     void testGetState10() throws Exception {
1858         var started = new CountDownLatch(1);
1859         var done = new AtomicBoolean();
1860         var thread = Thread.ofVirtual().start(() -> {
1861             started.countDown();
1862             synchronized (lock) {
1863                 while (!done.get()) {
1864                     LockSupport.park();
1865                 }
1866             }
1867         });
1868         try {
1869             // wait for thread to start
1870             started.await();
1871 
1872             // wait for thread to park
1873             await(thread, Thread.State.WAITING);
1874         } finally {
1875             done.set(true);
1876             LockSupport.unpark(thread);
1877             thread.join();
1878         }


1879     }
1880 
1881     /**
1882      * Test Thread::getState when thread is timed parked while holding a monitor.
1883      */
1884     @Test
1885     void testGetState11() throws Exception {
1886         var started = new CountDownLatch(1);
1887         var done = new AtomicBoolean();
1888         var thread = Thread.ofVirtual().start(() -> {
1889             started.countDown();
1890             synchronized (lock) {
1891                 while (!done.get()) {
1892                     LockSupport.parkNanos(Long.MAX_VALUE);
1893                 }
1894             }
1895         });
1896         try {
1897             // wait for thread to start
1898             started.await();
1899 
1900             // wait for thread to park
1901             await(thread, Thread.State.TIMED_WAITING);
1902         } finally {
1903             done.set(true);
1904             LockSupport.unpark(thread);
1905             thread.join();
1906         }
1907     }
1908 
1909     /**
1910      * Test Thread::isAlive.
1911      */
1912     @Test
1913     void testIsAlive1() throws Exception {
1914         // unstarted
1915         var thread = Thread.ofVirtual().unstarted(LockSupport::park);
1916         assertFalse(thread.isAlive());
1917 
1918         // started
1919         thread.start();
1920         try {
1921             assertTrue(thread.isAlive());
1922         } finally {
1923             LockSupport.unpark(thread);
1924             thread.join();
1925         }
1926 

2009                     task.run();
2010                 });
2011             };
2012 
2013             Thread.Builder builder = ThreadBuilders.virtualThreadBuilder(scheduler);
2014             Thread vthread = builder.start(() -> {
2015                 synchronized (lock) {
2016                     try {
2017                         lock.wait();
2018                     } catch (Exception e) { }
2019                 }
2020             });
2021 
2022             // get carrier Thread
2023             Thread carrier;
2024             while ((carrier = ref.get()) == null) {
2025                 Thread.sleep(20);
2026             }
2027 
2028             // wait for virtual thread to block in wait
2029             await(vthread, Thread.State.WAITING);


2030 
2031             // get stack trace of both carrier and virtual thread
2032             StackTraceElement[] carrierStackTrace = carrier.getStackTrace();
2033             StackTraceElement[] vthreadStackTrace = vthread.getStackTrace();
2034 
2035             // allow virtual thread to terminate
2036             synchronized (lock) {
2037                 lock.notifyAll();
2038             }
2039 
2040             // check carrier thread's stack trace
2041             assertTrue(contains(carrierStackTrace, "java.util.concurrent.ForkJoinPool.runWorker"));
2042             assertFalse(contains(carrierStackTrace, "java.lang.Object.wait"));
2043 
2044             // check virtual thread's stack trace
2045             assertFalse(contains(vthreadStackTrace, "java.util.concurrent.ForkJoinPool.runWorker"));
2046             assertTrue(contains(vthreadStackTrace, "java.lang.Object.wait"));
2047         }
2048     }
2049 
2050     /**
2051      * Test Thread::getStackTrace on parked thread.
2052      */
2053     @Test
2054     void testGetStackTrace5() throws Exception {
2055         var thread = Thread.ofVirtual().start(LockSupport::park);
2056         await(thread, Thread.State.WAITING);





2057         try {
2058             StackTraceElement[] stack = thread.getStackTrace();
2059             assertTrue(contains(stack, "LockSupport.park"));
2060         } finally {
2061             LockSupport.unpark(thread);
2062             thread.join();
2063         }
2064     }
2065 
2066     /**
2067      * Test Thread::getStackTrace on terminated thread.
2068      */
2069     @Test
2070     void testGetStackTrace6() throws Exception {
2071         var thread = Thread.ofVirtual().start(() -> { });
2072         thread.join();
2073         StackTraceElement[] stack = thread.getStackTrace();
2074         assertTrue(stack.length == 0);
2075     }
2076 

2099                     task.run();
2100                 });
2101             };
2102 
2103             Thread.Builder builder = ThreadBuilders.virtualThreadBuilder(scheduler);
2104             Thread vthread = builder.start(() -> {
2105                 synchronized (lock) {
2106                     try {
2107                         lock.wait();
2108                     } catch (Exception e) { }
2109                 }
2110             });
2111 
2112             // get carrier Thread
2113             Thread carrier;
2114             while ((carrier = ref.get()) == null) {
2115                 Thread.sleep(20);
2116             }
2117 
2118             // wait for virtual thread to block in wait
2119             await(vthread, Thread.State.WAITING);


2120 
2121             // get all stack traces
2122             Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces();
2123 
2124             // allow virtual thread to terminate
2125             synchronized (lock) {
2126                 lock.notifyAll();
2127             }
2128 
2129             // get stack trace for the carrier thread
2130             StackTraceElement[] stackTrace = map.get(carrier);
2131             assertNotNull(stackTrace);
2132             assertTrue(contains(stackTrace, "java.util.concurrent.ForkJoinPool"));
2133             assertFalse(contains(stackTrace, "java.lang.Object.wait"));
2134 
2135             // there should be no stack trace for the virtual thread
2136             assertNull(map.get(vthread));
2137         }
2138     }
2139 
2140     private boolean contains(StackTraceElement[] stack, String expected) {
2141         return Stream.of(stack)
2142                 .map(Object::toString)
2143                 .anyMatch(s -> s.contains(expected));
2144     }
2145 
2146     /**
2147      * Test Thread::getThreadGroup on virtual thread created by platform thread.
2148      */
2149     @Test
2150     void testThreadGroup1() throws Exception {
2151         var thread = Thread.ofVirtual().unstarted(LockSupport::park);
2152         var vgroup = thread.getThreadGroup();
2153         thread.start();
2154         try {
2155             assertEquals(vgroup, thread.getThreadGroup());
2156         } finally {
2157             LockSupport.unpark(thread);
2158             thread.join();
2159         }
2160         assertNull(thread.getThreadGroup());
2161     }
2162 
2163     /**
2164      * Test Thread::getThreadGroup on platform thread created by virtual thread.
2165      */
2166     @Test
2167     void testThreadGroup2() throws Exception {
2168         VThreadRunner.run(() -> {
2169             ThreadGroup vgroup = Thread.currentThread().getThreadGroup();
2170             Thread child = new Thread(() -> { });
2171             ThreadGroup group = child.getThreadGroup();
2172             assertEquals(vgroup, group);
2173         });
2174     }
2175 
2176     /**
2177      * Test ThreadGroup returned by Thread::getThreadGroup and subgroup
2178      * created with 2-arg ThreadGroup constructor.
2179      */
2180     @Test
2181     void testThreadGroup3() throws Exception {
2182         var ref = new AtomicReference<ThreadGroup>();
2183         var thread = Thread.startVirtualThread(() -> {
2184             ref.set(Thread.currentThread().getThreadGroup());
2185         });
2186         thread.join();
2187 
2188         ThreadGroup vgroup = ref.get();
2189         assertEquals(Thread.MAX_PRIORITY, vgroup.getMaxPriority());
2190 
2191         ThreadGroup group = new ThreadGroup(vgroup, "group");
2192         assertTrue(group.getParent() == vgroup);
2193         assertEquals(Thread.MAX_PRIORITY, group.getMaxPriority());
2194 
2195         vgroup.setMaxPriority(Thread.MAX_PRIORITY - 1);
2196         assertEquals(Thread.MAX_PRIORITY, vgroup.getMaxPriority());
2197         assertEquals(Thread.MAX_PRIORITY - 1, group.getMaxPriority());
2198 
2199         vgroup.setMaxPriority(Thread.MIN_PRIORITY);
2200         assertEquals(Thread.MAX_PRIORITY, vgroup.getMaxPriority());
2201         assertEquals(Thread.MIN_PRIORITY, group.getMaxPriority());
2202     }
2203 
2204     /**
2205      * Test ThreadGroup returned by Thread::getThreadGroup and subgroup
2206      * created with 1-arg ThreadGroup constructor.
2207      */
2208     @Test
2209     void testThreadGroup4() throws Exception {
2210         VThreadRunner.run(() -> {
2211             ThreadGroup vgroup = Thread.currentThread().getThreadGroup();
2212             assertEquals(Thread.MAX_PRIORITY, vgroup.getMaxPriority());

2213 
2214             ThreadGroup group = new ThreadGroup("group");
2215             assertEquals(vgroup, group.getParent());
2216             assertEquals(Thread.MAX_PRIORITY, group.getMaxPriority());
2217 
2218             vgroup.setMaxPriority(Thread.MAX_PRIORITY - 1);
2219             assertEquals(Thread.MAX_PRIORITY, vgroup.getMaxPriority());
2220             assertEquals(Thread.MAX_PRIORITY - 1, group.getMaxPriority());
2221 
2222             vgroup.setMaxPriority(Thread.MIN_PRIORITY);
2223             assertEquals(Thread.MAX_PRIORITY, vgroup.getMaxPriority());
2224             assertEquals(Thread.MIN_PRIORITY, group.getMaxPriority());
2225         });
2226     }
2227 
2228     /**
2229      * Test Thread.enumerate(false).
2230      */
2231     @Test
2232     void testEnumerate1() throws Exception {
2233         VThreadRunner.run(() -> {
2234             ThreadGroup vgroup = Thread.currentThread().getThreadGroup();
2235             Thread[] threads = new Thread[100];
2236             int n = vgroup.enumerate(threads, /*recurse*/false);
2237             assertTrue(n == 0);
2238         });
2239     }
2240 
2241     /**
2242      * Test Thread.enumerate(true).
2243      */
2244     @Test

2308      */
2309     @Test
2310     void testToString2() throws Exception {
2311         VThreadRunner.run(() -> {
2312             Thread me = Thread.currentThread();
2313             me.setName("fred");
2314             assertTrue(me.toString().contains("fred"));
2315         });
2316     }
2317 
2318     /**
2319      * Test toString on parked thread.
2320      */
2321     @Test
2322     void testToString3() throws Exception {
2323         Thread thread = Thread.ofVirtual().start(() -> {
2324             Thread me = Thread.currentThread();
2325             me.setName("fred");
2326             LockSupport.park();
2327         });
2328         await(thread, Thread.State.WAITING);


2329         try {
2330             assertTrue(thread.toString().contains("fred"));
2331         } finally {
2332             LockSupport.unpark(thread);
2333             thread.join();
2334         }
2335     }
2336 
2337     /**
2338      * Test toString on terminated thread.
2339      */
2340     @Test
2341     void testToString4() throws Exception {
2342         Thread thread = Thread.ofVirtual().start(() -> {
2343             Thread me = Thread.currentThread();
2344             me.setName("fred");
2345         });
2346         thread.join();
2347         assertTrue(thread.toString().contains("fred"));
2348     }
2349 
2350     /**
2351      * Waits for the given thread to reach a given state.












2352      */
2353     private void await(Thread thread, Thread.State expectedState) throws InterruptedException {
2354         Thread.State state = thread.getState();
2355         while (state != expectedState) {
2356             assertTrue(state != Thread.State.TERMINATED, "Thread has terminated");
2357             Thread.sleep(10);
2358             state = thread.getState();
2359         }
2360     }
2361 
2362     /**
2363      * Schedule a thread to be interrupted after a delay.
2364      */
2365     private void scheduleInterrupt(Thread thread, long delayInMillis) {
2366         scheduler.schedule(thread::interrupt, delayInMillis, TimeUnit.MILLISECONDS);
2367     }
2368 }
< prev index next >