61 import org.junit.jupiter.params.provider.ValueSource;
62 import static org.junit.jupiter.api.Assertions.*;
63 import static org.junit.jupiter.api.Assumptions.*;
64
65 public class VirtualThreads {
66
67 /**
68 * Test that ThreadMXBean.dumpAllThreads does not include virtual threads.
69 */
70 @ParameterizedTest
71 @ValueSource(ints = {0, Integer.MAX_VALUE})
72 void testDumpAllThreads(int maxDepth) {
73 Thread vthread = Thread.startVirtualThread(LockSupport::park);
74 try {
75 ThreadMXBean bean = ManagementFactory.getThreadMXBean();
76 ThreadInfo[] infos = bean.dumpAllThreads(false, false, maxDepth);
77 Set<Long> tids = Arrays.stream(infos)
78 .map(ThreadInfo::getThreadId)
79 .collect(Collectors.toSet());
80
81 // current thread should be included
82 assertTrue(tids.contains(Thread.currentThread().threadId()));
83
84 // virtual thread should not be included
85 assertFalse(tids.contains(vthread.threadId()));
86 } finally {
87 LockSupport.unpark(vthread);
88 }
89 }
90
91 /**
92 * Test that ThreadMXBean::getAllThreadsIds does not include virtual threads.
93 */
94 @Test
95 void testGetAllThreadIds() {
96 Thread vthread = Thread.startVirtualThread(LockSupport::park);
97 try {
98 long[] tids = ManagementFactory.getThreadMXBean().getAllThreadIds();
99
100 // current thread should be included
101 long currentTid = Thread.currentThread().threadId();
102 assertTrue(Arrays.stream(tids).anyMatch(tid -> tid == currentTid));
103
104 // virtual thread should not be included
105 long vtid = vthread.threadId();
106 assertFalse(Arrays.stream(tids).anyMatch(tid -> tid == vtid));
107 } finally {
108 LockSupport.unpark(vthread);
109 }
110 }
111
112 /**
113 * Test that ThreadMXBean.getThreadInfo(long, maxDepth) returns null for a virtual
114 * thread.
115 */
116 @ParameterizedTest
117 @ValueSource(ints = {0, Integer.MAX_VALUE})
118 void testGetThreadInfo1(int maxDepth) {
119 Thread vthread = Thread.startVirtualThread(LockSupport::park);
120 try {
121 long tid = vthread.threadId();
122 ThreadInfo info = ManagementFactory.getThreadMXBean().getThreadInfo(tid, maxDepth);
136 VThreadRunner.run(() -> {
137 long tid = Thread.currentThread().threadId();
138 ThreadInfo info = ManagementFactory.getThreadMXBean().getThreadInfo(tid, maxDepth);
139 assertNull(info);
140 });
141 }
142
143 /**
144 * Test that ThreadMXBean.getThreadInfo(long[], maxDepth) returns a null ThreadInfo
145 * for elements that correspond to a virtual thread.
146 */
147 @ParameterizedTest
148 @ValueSource(ints = {0, Integer.MAX_VALUE})
149 void testGetThreadInfo3(int maxDepth) {
150 Thread vthread = Thread.startVirtualThread(LockSupport::park);
151 try {
152 long tid0 = Thread.currentThread().threadId();
153 long tid1 = vthread.threadId();
154 long[] tids = new long[] { tid0, tid1 };
155 ThreadInfo[] infos = ManagementFactory.getThreadMXBean().getThreadInfo(tids, maxDepth);
156 assertEquals(tid0, infos[0].getThreadId());
157 assertNull(infos[1]);
158 } finally {
159 LockSupport.unpark(vthread);
160 }
161 }
162
163 /**
164 * Test that ThreadMXBean.getThreadInfo(long[], boolean, boolean, maxDepth) returns
165 * a null ThreadInfo for elements that correspond to a virtual thread.
166 */
167 @ParameterizedTest
168 @ValueSource(ints = {0, Integer.MAX_VALUE})
169 void testGetThreadInfo4(int maxDepth) {
170 Thread vthread = Thread.startVirtualThread(LockSupport::park);
171 try {
172 long tid0 = Thread.currentThread().threadId();
173 long tid1 = vthread.threadId();
174 long[] tids = new long[] { tid0, tid1 };
175 ThreadMXBean bean = ManagementFactory.getThreadMXBean();
176 ThreadInfo[] infos = bean.getThreadInfo(tids, false, false, maxDepth);
177 assertEquals(tid0, infos[0].getThreadId());
178 assertNull(infos[1]);
179 } finally {
180 LockSupport.unpark(vthread);
181 }
182 }
183
184 /**
185 * Test ThreadMXBean.getThreadInfo(long) with the thread id of a carrier thread.
186 * The stack frames of the virtual thread should not be returned.
187 */
188 @Test
189 void testGetThreadInfoCarrierThread() throws Exception {
190 assumeTrue(supportsCustomScheduler(), "No support for custom schedulers");
191 try (ExecutorService pool = Executors.newFixedThreadPool(1)) {
192 var carrierRef = new AtomicReference<Thread>();
193 Executor scheduler = (task) -> {
194 pool.execute(() -> {
195 carrierRef.set(Thread.currentThread());
196 task.run();
197 });
|
61 import org.junit.jupiter.params.provider.ValueSource;
62 import static org.junit.jupiter.api.Assertions.*;
63 import static org.junit.jupiter.api.Assumptions.*;
64
65 public class VirtualThreads {
66
67 /**
68 * Test that ThreadMXBean.dumpAllThreads does not include virtual threads.
69 */
70 @ParameterizedTest
71 @ValueSource(ints = {0, Integer.MAX_VALUE})
72 void testDumpAllThreads(int maxDepth) {
73 Thread vthread = Thread.startVirtualThread(LockSupport::park);
74 try {
75 ThreadMXBean bean = ManagementFactory.getThreadMXBean();
76 ThreadInfo[] infos = bean.dumpAllThreads(false, false, maxDepth);
77 Set<Long> tids = Arrays.stream(infos)
78 .map(ThreadInfo::getThreadId)
79 .collect(Collectors.toSet());
80
81 // if current thread is a platform thread then it should be included
82 boolean expected = !Thread.currentThread().isVirtual();
83 assertEquals(expected, tids.contains(Thread.currentThread().threadId()));
84
85 // virtual thread should not be included
86 assertFalse(tids.contains(vthread.threadId()));
87 } finally {
88 LockSupport.unpark(vthread);
89 }
90 }
91
92 /**
93 * Test that ThreadMXBean::getAllThreadsIds does not include virtual threads.
94 */
95 @Test
96 void testGetAllThreadIds() {
97 Thread vthread = Thread.startVirtualThread(LockSupport::park);
98 try {
99 long[] tids = ManagementFactory.getThreadMXBean().getAllThreadIds();
100
101 // if current thread is a platform thread then it should be included
102 boolean expected = !Thread.currentThread().isVirtual();
103 long currentTid = Thread.currentThread().threadId();
104 assertEquals(expected, Arrays.stream(tids).anyMatch(tid -> tid == currentTid));
105
106 // virtual thread should not be included
107 long vtid = vthread.threadId();
108 assertFalse(Arrays.stream(tids).anyMatch(tid -> tid == vtid));
109 } finally {
110 LockSupport.unpark(vthread);
111 }
112 }
113
114 /**
115 * Test that ThreadMXBean.getThreadInfo(long, maxDepth) returns null for a virtual
116 * thread.
117 */
118 @ParameterizedTest
119 @ValueSource(ints = {0, Integer.MAX_VALUE})
120 void testGetThreadInfo1(int maxDepth) {
121 Thread vthread = Thread.startVirtualThread(LockSupport::park);
122 try {
123 long tid = vthread.threadId();
124 ThreadInfo info = ManagementFactory.getThreadMXBean().getThreadInfo(tid, maxDepth);
138 VThreadRunner.run(() -> {
139 long tid = Thread.currentThread().threadId();
140 ThreadInfo info = ManagementFactory.getThreadMXBean().getThreadInfo(tid, maxDepth);
141 assertNull(info);
142 });
143 }
144
145 /**
146 * Test that ThreadMXBean.getThreadInfo(long[], maxDepth) returns a null ThreadInfo
147 * for elements that correspond to a virtual thread.
148 */
149 @ParameterizedTest
150 @ValueSource(ints = {0, Integer.MAX_VALUE})
151 void testGetThreadInfo3(int maxDepth) {
152 Thread vthread = Thread.startVirtualThread(LockSupport::park);
153 try {
154 long tid0 = Thread.currentThread().threadId();
155 long tid1 = vthread.threadId();
156 long[] tids = new long[] { tid0, tid1 };
157 ThreadInfo[] infos = ManagementFactory.getThreadMXBean().getThreadInfo(tids, maxDepth);
158 if (Thread.currentThread().isVirtual()) {
159 assertNull(infos[0]);
160 } else {
161 assertEquals(tid0, infos[0].getThreadId());
162 }
163 assertNull(infos[1]);
164 } finally {
165 LockSupport.unpark(vthread);
166 }
167 }
168
169 /**
170 * Test that ThreadMXBean.getThreadInfo(long[], boolean, boolean, maxDepth) returns
171 * a null ThreadInfo for elements that correspond to a virtual thread.
172 */
173 @ParameterizedTest
174 @ValueSource(ints = {0, Integer.MAX_VALUE})
175 void testGetThreadInfo4(int maxDepth) {
176 Thread vthread = Thread.startVirtualThread(LockSupport::park);
177 try {
178 long tid0 = Thread.currentThread().threadId();
179 long tid1 = vthread.threadId();
180 long[] tids = new long[] { tid0, tid1 };
181 ThreadMXBean bean = ManagementFactory.getThreadMXBean();
182 ThreadInfo[] infos = bean.getThreadInfo(tids, false, false, maxDepth);
183 if (Thread.currentThread().isVirtual()) {
184 assertNull(infos[0]);
185 } else {
186 assertEquals(tid0, infos[0].getThreadId());
187 }
188 assertNull(infos[1]);
189 } finally {
190 LockSupport.unpark(vthread);
191 }
192 }
193
194 /**
195 * Test ThreadMXBean.getThreadInfo(long) with the thread id of a carrier thread.
196 * The stack frames of the virtual thread should not be returned.
197 */
198 @Test
199 void testGetThreadInfoCarrierThread() throws Exception {
200 assumeTrue(supportsCustomScheduler(), "No support for custom schedulers");
201 try (ExecutorService pool = Executors.newFixedThreadPool(1)) {
202 var carrierRef = new AtomicReference<Thread>();
203 Executor scheduler = (task) -> {
204 pool.execute(() -> {
205 carrierRef.set(Thread.currentThread());
206 task.run();
207 });
|