< prev index next >

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

Print this page

   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/othervm --enable-native-access=ALL-UNNAMED 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
  39  *     --enable-native-access=ALL-UNNAMED ThreadAPI
  40  */
  41 
  42 import java.time.Duration;
  43 import java.util.Arrays;
  44 import java.util.ArrayList;
  45 import java.util.List;
  46 import java.util.Map;
  47 import java.util.Set;
  48 import java.util.concurrent.CopyOnWriteArrayList;
  49 import java.util.concurrent.CountDownLatch;
  50 import java.util.concurrent.ExecutorService;
  51 import java.util.concurrent.Executor;
  52 import java.util.concurrent.Executors;
  53 import java.util.concurrent.ForkJoinPool;
  54 import java.util.concurrent.ScheduledExecutorService;
  55 import java.util.concurrent.ThreadFactory;
  56 import java.util.concurrent.TimeUnit;
  57 import java.util.concurrent.atomic.AtomicBoolean;
  58 import java.util.concurrent.atomic.AtomicReference;
  59 import java.util.concurrent.locks.LockSupport;
  60 import java.util.concurrent.locks.ReentrantLock;
  61 import java.util.stream.Stream;
  62 import java.nio.channels.Selector;
  63 
  64 import jdk.test.lib.thread.VThreadPinner;
  65 import jdk.test.lib.thread.VThreadRunner;
  66 import jdk.test.lib.thread.VThreadScheduler;
  67 import org.junit.jupiter.api.Test;
  68 import org.junit.jupiter.api.BeforeAll;
  69 import org.junit.jupiter.api.AfterAll;
  70 import org.junit.jupiter.api.Disabled;

  71 import org.junit.jupiter.params.ParameterizedTest;
  72 import org.junit.jupiter.params.provider.MethodSource;
  73 import org.junit.jupiter.params.provider.ValueSource;
  74 import static org.junit.jupiter.api.Assertions.*;
  75 import static org.junit.jupiter.api.Assumptions.*;
  76 
  77 class ThreadAPI {
  78     private static final Object lock = new Object();
  79 
  80     // used for scheduling thread interrupt
  81     private static ScheduledExecutorService scheduler;
  82 
  83     @BeforeAll
  84     static void setup() {
  85         ThreadFactory factory = Executors.defaultThreadFactory();
  86         scheduler = Executors.newSingleThreadScheduledExecutor(factory);
  87 
  88         // need >=2 carriers for testing pinning
  89         VThreadRunner.ensureParallelism(2);
  90     }

1065 
1066         // running
1067         thread.start();
1068         try {
1069             assertTrue(thread.isDaemon());
1070             assertThrows(IllegalThreadStateException.class, () -> thread.setDaemon(true));
1071             assertThrows(IllegalArgumentException.class, () -> thread.setDaemon(false));
1072         } finally {
1073             LockSupport.unpark(thread);
1074         }
1075         thread.join();
1076 
1077         // terminated
1078         assertTrue(thread.isDaemon());
1079     }
1080 
1081     /**
1082      * Test Thread.yield releases carrier thread.
1083      */
1084     @Test
1085     void testYield1() throws Exception {
1086         assumeTrue(VThreadScheduler.supportsCustomScheduler(), "No support for custom schedulers");
1087         var list = new CopyOnWriteArrayList<String>();
1088         try (ExecutorService scheduler = Executors.newFixedThreadPool(1)) {
1089             ThreadFactory factory = VThreadScheduler.virtualThreadFactory(scheduler);
1090             var thread = factory.newThread(() -> {
1091                 list.add("A");
1092                 var child = factory.newThread(() -> {
1093                     list.add("B");
1094                     Thread.yield();
1095                     list.add("B");
1096                 });
1097                 child.start();
1098                 Thread.yield();
1099                 list.add("A");
1100                 try { child.join(); } catch (InterruptedException e) { }
1101             });
1102             thread.start();
1103             thread.join();
1104         }
1105         assertEquals(List.of("A", "B", "A", "B"), list);
1106     }
1107 
1108     /**
1109      * Test Thread.yield when thread is pinned by native frame.
1110      */
1111     @Test
1112     void testYield2() throws Exception {































1113         assumeTrue(VThreadScheduler.supportsCustomScheduler(), "No support for custom schedulers");
1114         var list = new CopyOnWriteArrayList<String>();
1115         try (ExecutorService scheduler = Executors.newFixedThreadPool(1)) {
1116             ThreadFactory factory = VThreadScheduler.virtualThreadFactory(scheduler);
1117             var thread = factory.newThread(() -> {
1118                 list.add("A");
1119                 var child = factory.newThread(() -> {
1120                     list.add("B");
1121                 });
1122                 child.start();
1123                 VThreadPinner.runPinned(() -> {
1124                     Thread.yield();   // pinned so will be a no-op
1125                     list.add("A");
1126                 });
1127                 try { child.join(); } catch (InterruptedException e) { }
1128             });
1129             thread.start();
1130             thread.join();
1131         }
1132         assertEquals(List.of("A", "A", "B"), list);
1133     }
1134 
1135     /**
1136      * Test Thread.yield does not consume the thread's parking permit.
1137      */
1138     @Test
1139     void testYield3() throws Exception {
1140         var thread = Thread.ofVirtual().start(() -> {
1141             LockSupport.unpark(Thread.currentThread());
1142             Thread.yield();
1143             LockSupport.park();  // should not park
1144         });
1145         thread.join();
1146     }
1147 
1148     /**
1149      * Test Thread.yield does not make available the thread's parking permit.
1150      */
1151     @Test
1152     void testYield4() throws Exception {
1153         var thread = Thread.ofVirtual().start(() -> {
1154             Thread.yield();
1155             LockSupport.park();  // should park
1156         });
1157         try {
1158             await(thread, Thread.State.WAITING);
1159         } finally {
1160             LockSupport.unpark(thread);
1161             thread.join();
1162         }
1163     }
1164 
1165     /**
1166      * Test Thread.onSpinWait.
1167      */
1168     @Test
1169     void testOnSpinWait() throws Exception {
1170         VThreadRunner.run(() -> {
1171             Thread me = Thread.currentThread();
1172             Thread.onSpinWait();

1954     void testHoldsLock1() throws Exception {
1955         VThreadRunner.run(() -> {
1956             var lock = new Object();
1957             assertFalse(Thread.holdsLock(lock));
1958         });
1959     }
1960 
1961     /**
1962      * Test Thread.holdsLock when lock held.
1963      */
1964     @Test
1965     void testHoldsLock2() throws Exception {
1966         VThreadRunner.run(() -> {
1967             var lock = new Object();
1968             synchronized (lock) {
1969                 assertTrue(Thread.holdsLock(lock));
1970             }
1971         });
1972     }
1973 
































1974     /**
1975      * Test Thread::getStackTrace on unstarted thread.
1976      */
1977     @Test
1978     void testGetStackTraceUnstarted() {
1979         var thread = Thread.ofVirtual().unstarted(() -> { });
1980         StackTraceElement[] stack = thread.getStackTrace();
1981         assertTrue(stack.length == 0);
1982     }
1983 
1984     /**
1985      * Test Thread::getStackTrace on thread that has been started but has not run.
1986      */
1987     @Test
1988     void testGetStackTraceStarted() throws Exception {
1989         assumeTrue(VThreadScheduler.supportsCustomScheduler(), "No support for custom schedulers");
1990         Executor scheduler = task -> { };
1991         ThreadFactory factory = VThreadScheduler.virtualThreadFactory(scheduler);
1992         Thread thread = factory.newThread(() -> { });
1993         thread.start();

   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 jdk.management
  29  * @library /test/lib
  30  * @build LockingMode
  31  * @run junit/othervm --enable-native-access=ALL-UNNAMED ThreadAPI
  32  */
  33 
  34 /*
  35  * @test id=no-vmcontinuations
  36  * @requires vm.continuations
  37  * @modules java.base/java.lang:+open jdk.management
  38  * @library /test/lib
  39  * @build LockingMode
  40  * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations
  41  *     --enable-native-access=ALL-UNNAMED ThreadAPI
  42  */
  43 
  44 import java.time.Duration;
  45 import java.util.Arrays;
  46 import java.util.ArrayList;
  47 import java.util.List;
  48 import java.util.Map;
  49 import java.util.Set;
  50 import java.util.concurrent.CopyOnWriteArrayList;
  51 import java.util.concurrent.CountDownLatch;
  52 import java.util.concurrent.ExecutorService;
  53 import java.util.concurrent.Executor;
  54 import java.util.concurrent.Executors;
  55 import java.util.concurrent.ForkJoinPool;
  56 import java.util.concurrent.ScheduledExecutorService;
  57 import java.util.concurrent.ThreadFactory;
  58 import java.util.concurrent.TimeUnit;
  59 import java.util.concurrent.atomic.AtomicBoolean;
  60 import java.util.concurrent.atomic.AtomicReference;
  61 import java.util.concurrent.locks.LockSupport;
  62 import java.util.concurrent.locks.ReentrantLock;
  63 import java.util.stream.Stream;
  64 import java.nio.channels.Selector;
  65 
  66 import jdk.test.lib.thread.VThreadPinner;
  67 import jdk.test.lib.thread.VThreadRunner;   // ensureParallelism requires jdk.management
  68 import jdk.test.lib.thread.VThreadScheduler;
  69 import org.junit.jupiter.api.Test;
  70 import org.junit.jupiter.api.BeforeAll;
  71 import org.junit.jupiter.api.AfterAll;
  72 import org.junit.jupiter.api.Disabled;
  73 import org.junit.jupiter.api.condition.DisabledIf;
  74 import org.junit.jupiter.params.ParameterizedTest;
  75 import org.junit.jupiter.params.provider.MethodSource;
  76 import org.junit.jupiter.params.provider.ValueSource;
  77 import static org.junit.jupiter.api.Assertions.*;
  78 import static org.junit.jupiter.api.Assumptions.*;
  79 
  80 class ThreadAPI {
  81     private static final Object lock = new Object();
  82 
  83     // used for scheduling thread interrupt
  84     private static ScheduledExecutorService scheduler;
  85 
  86     @BeforeAll
  87     static void setup() {
  88         ThreadFactory factory = Executors.defaultThreadFactory();
  89         scheduler = Executors.newSingleThreadScheduledExecutor(factory);
  90 
  91         // need >=2 carriers for testing pinning
  92         VThreadRunner.ensureParallelism(2);
  93     }

1068 
1069         // running
1070         thread.start();
1071         try {
1072             assertTrue(thread.isDaemon());
1073             assertThrows(IllegalThreadStateException.class, () -> thread.setDaemon(true));
1074             assertThrows(IllegalArgumentException.class, () -> thread.setDaemon(false));
1075         } finally {
1076             LockSupport.unpark(thread);
1077         }
1078         thread.join();
1079 
1080         // terminated
1081         assertTrue(thread.isDaemon());
1082     }
1083 
1084     /**
1085      * Test Thread.yield releases carrier thread.
1086      */
1087     @Test
1088     void testYieldReleasesCarrier() throws Exception {
1089         assumeTrue(VThreadScheduler.supportsCustomScheduler(), "No support for custom schedulers");
1090         var list = new CopyOnWriteArrayList<String>();
1091         try (ExecutorService scheduler = Executors.newFixedThreadPool(1)) {
1092             ThreadFactory factory = VThreadScheduler.virtualThreadFactory(scheduler);
1093             var thread = factory.newThread(() -> {
1094                 list.add("A");
1095                 var child = factory.newThread(() -> {
1096                     list.add("B");
1097                     Thread.yield();
1098                     list.add("B");
1099                 });
1100                 child.start();
1101                 Thread.yield();
1102                 list.add("A");
1103                 try { child.join(); } catch (InterruptedException e) { }
1104             });
1105             thread.start();
1106             thread.join();
1107         }
1108         assertEquals(List.of("A", "B", "A", "B"), list);
1109     }
1110 
1111     /**
1112      * Test Thread.yield releases carrier thread when virtual thread holds a monitor.
1113      */
1114     @Test
1115     @DisabledIf("LockingMode#isLegacy")
1116     void testYieldReleasesCarrierWhenHoldingMonitor() throws Exception {
1117         assumeTrue(VThreadScheduler.supportsCustomScheduler(), "No support for custom schedulers");
1118         var list = new CopyOnWriteArrayList<String>();
1119         try (ExecutorService scheduler = Executors.newFixedThreadPool(1)) {
1120             ThreadFactory factory = VThreadScheduler.virtualThreadFactory(scheduler);
1121             var lock = new Object();
1122             var thread = factory.newThread(() -> {
1123                 list.add("A");
1124                 var child = factory.newThread(() -> {
1125                     list.add("B");
1126                     synchronized (lock) {
1127                         Thread.yield();
1128                     }
1129                     list.add("B");
1130                 });
1131                 child.start();
1132                 Thread.yield();
1133                 list.add("A");
1134                 try { child.join(); } catch (InterruptedException e) { }
1135             });
1136             thread.start();
1137             thread.join();
1138         }
1139         assertEquals(List.of("A", "B", "A", "B"), list);
1140     }
1141 
1142     /**
1143      * Test Thread.yield when thread is pinned.
1144      */
1145     @Test
1146     void testYieldWhenPinned() throws Exception {
1147         assumeTrue(VThreadScheduler.supportsCustomScheduler(), "No support for custom schedulers");
1148         var list = new CopyOnWriteArrayList<String>();
1149         try (ExecutorService scheduler = Executors.newFixedThreadPool(1)) {
1150             ThreadFactory factory = VThreadScheduler.virtualThreadFactory(scheduler);
1151             var thread = factory.newThread(() -> {
1152                 list.add("A");
1153                 var child = factory.newThread(() -> {
1154                     list.add("B");
1155                 });
1156                 child.start();
1157                 VThreadPinner.runPinned(() -> {
1158                     Thread.yield();   // pinned so will be a no-op
1159                     list.add("A");
1160                 });
1161                 try { child.join(); } catch (InterruptedException e) { }
1162             });
1163             thread.start();
1164             thread.join();
1165         }
1166         assertEquals(List.of("A", "A", "B"), list);
1167     }
1168 
1169     /**
1170      * Test Thread.yield does not consume the thread's parking permit.
1171      */
1172     @Test
1173     void testYieldDoesNotConsumParkingPermit() throws Exception {
1174         var thread = Thread.ofVirtual().start(() -> {
1175             LockSupport.unpark(Thread.currentThread());
1176             Thread.yield();
1177             LockSupport.park();  // should not park
1178         });
1179         thread.join();
1180     }
1181 
1182     /**
1183      * Test Thread.yield does not make available the thread's parking permit.
1184      */
1185     @Test
1186     void testYieldDoesNotOfferParkingPermit() throws Exception {
1187         var thread = Thread.ofVirtual().start(() -> {
1188             Thread.yield();
1189             LockSupport.park();  // should park
1190         });
1191         try {
1192             await(thread, Thread.State.WAITING);
1193         } finally {
1194             LockSupport.unpark(thread);
1195             thread.join();
1196         }
1197     }
1198 
1199     /**
1200      * Test Thread.onSpinWait.
1201      */
1202     @Test
1203     void testOnSpinWait() throws Exception {
1204         VThreadRunner.run(() -> {
1205             Thread me = Thread.currentThread();
1206             Thread.onSpinWait();

1988     void testHoldsLock1() throws Exception {
1989         VThreadRunner.run(() -> {
1990             var lock = new Object();
1991             assertFalse(Thread.holdsLock(lock));
1992         });
1993     }
1994 
1995     /**
1996      * Test Thread.holdsLock when lock held.
1997      */
1998     @Test
1999     void testHoldsLock2() throws Exception {
2000         VThreadRunner.run(() -> {
2001             var lock = new Object();
2002             synchronized (lock) {
2003                 assertTrue(Thread.holdsLock(lock));
2004             }
2005         });
2006     }
2007 
2008     /**
2009      * Test Thread.holdsLock when lock held by carrier thread.
2010      */
2011     @Disabled
2012     @Test
2013     void testHoldsLock3() throws Exception {
2014         assumeTrue(VThreadScheduler.supportsCustomScheduler(), "No support for custom schedulers");
2015 
2016         Object lock = new Object();
2017 
2018         // carrier thread runs all tasks while holding the lock
2019         ThreadFactory carrierThreadFactory = task -> Thread.ofPlatform().unstarted(() -> {
2020             synchronized (lock) {
2021                 task.run();
2022             }
2023         });
2024         try (ExecutorService pool = Executors.newSingleThreadExecutor(carrierThreadFactory)) {
2025             Executor scheduler = task -> pool.submit(task::run);
2026             ThreadFactory factory = VThreadScheduler.virtualThreadFactory(scheduler);
2027 
2028             // start virtual that tests if it holds the lock
2029             var result = new AtomicReference<Boolean>();
2030             Thread vthread = factory.newThread(() -> {
2031                 result.set(Thread.holdsLock(lock));
2032             });
2033             vthread.start();
2034             vthread.join();
2035             boolean holdsLock = result.get();
2036             assertFalse(holdsLock, "Thread.holdsLock should return false");
2037         }
2038     }
2039 
2040     /**
2041      * Test Thread::getStackTrace on unstarted thread.
2042      */
2043     @Test
2044     void testGetStackTraceUnstarted() {
2045         var thread = Thread.ofVirtual().unstarted(() -> { });
2046         StackTraceElement[] stack = thread.getStackTrace();
2047         assertTrue(stack.length == 0);
2048     }
2049 
2050     /**
2051      * Test Thread::getStackTrace on thread that has been started but has not run.
2052      */
2053     @Test
2054     void testGetStackTraceStarted() throws Exception {
2055         assumeTrue(VThreadScheduler.supportsCustomScheduler(), "No support for custom schedulers");
2056         Executor scheduler = task -> { };
2057         ThreadFactory factory = VThreadScheduler.virtualThreadFactory(scheduler);
2058         Thread thread = factory.newThread(() -> { });
2059         thread.start();
< prev index next >