1 /*
2 * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package java.lang;
26
27 import java.lang.Thread.Builder.OfPlatform;
28 import java.lang.Thread.Builder.OfVirtual;
29 import java.lang.Thread.UncaughtExceptionHandler;
30 import java.lang.invoke.MethodHandles;
31 import java.lang.invoke.VarHandle;
32 import java.util.Locale;
33 import java.util.Objects;
34 import java.util.concurrent.ThreadFactory;
35 import jdk.internal.misc.Unsafe;
36 import jdk.internal.invoke.MhUtil;
37 import jdk.internal.vm.ContinuationSupport;
38
39 /**
40 * Defines static methods to create platform and virtual thread builders.
41 */
42 class ThreadBuilders {
43 private ThreadBuilders() { }
44
45 /**
46 * Base class for Thread.Builder implementations.
47 */
48 private static class BaseThreadBuilder {
49 private String name;
50 private long counter;
51 private int characteristics;
52 private UncaughtExceptionHandler uhe;
53
54 String name() {
55 return name;
56 }
57
58 long counter() {
59 return counter;
60 }
61
62 int characteristics() {
63 return characteristics;
64 }
65
66 UncaughtExceptionHandler uncaughtExceptionHandler() {
67 return uhe;
68 }
69
70 String nextThreadName() {
71 if (name != null && counter >= 0) {
72 return name + (counter++);
73 } else {
74 return name;
75 }
76 }
77
78 void setName(String name) {
79 this.name = Objects.requireNonNull(name);
80 this.counter = -1;
81 }
82
83 void setName(String prefix, long start) {
84 Objects.requireNonNull(prefix);
85 if (start < 0)
86 throw new IllegalArgumentException("'start' is negative");
87 this.name = prefix;
88 this.counter = start;
89 }
90
91 void setInheritInheritableThreadLocals(boolean inherit) {
92 if (inherit) {
93 characteristics &= ~Thread.NO_INHERIT_THREAD_LOCALS;
94 } else {
95 characteristics |= Thread.NO_INHERIT_THREAD_LOCALS;
96 }
97 }
98
99 void setUncaughtExceptionHandler(UncaughtExceptionHandler ueh) {
100 this.uhe = Objects.requireNonNull(ueh);
101 }
102 }
103
104 /**
105 * ThreadBuilder.OfPlatform implementation.
106 */
107 static final class PlatformThreadBuilder
108 extends BaseThreadBuilder implements OfPlatform {
109 private ThreadGroup group;
110 private boolean daemon;
111 private boolean daemonChanged;
112 private int priority;
113 private long stackSize;
114
115 PlatformThreadBuilder() {
116 }
117
118 @Override
119 String nextThreadName() {
120 String name = super.nextThreadName();
121 return (name != null) ? name : Thread.genThreadName();
122 }
123
124 @Override
125 public OfPlatform name(String name) {
126 setName(name);
127 return this;
128 }
129
130 @Override
131 public OfPlatform name(String prefix, long start) {
132 setName(prefix, start);
133 return this;
134 }
135
136 @Override
137 public OfPlatform inheritInheritableThreadLocals(boolean inherit) {
138 setInheritInheritableThreadLocals(inherit);
139 return this;
140 }
141
142 @Override
143 public OfPlatform uncaughtExceptionHandler(UncaughtExceptionHandler ueh) {
144 setUncaughtExceptionHandler(ueh);
145 return this;
146 }
147
148 @Override
149 public OfPlatform group(ThreadGroup group) {
150 this.group = Objects.requireNonNull(group);
151 return this;
152 }
153
154 @Override
155 public OfPlatform daemon(boolean on) {
156 daemon = on;
157 daemonChanged = true;
158 return this;
159 }
160
161 @Override
162 public OfPlatform priority(int priority) {
163 if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY)
164 throw new IllegalArgumentException();
165 this.priority = priority;
166 return this;
167 }
168
169 @Override
170 public OfPlatform stackSize(long stackSize) {
171 if (stackSize < 0L)
172 throw new IllegalArgumentException();
173 this.stackSize = stackSize;
174 return this;
175 }
176
177 @Override
178 public Thread unstarted(Runnable task) {
179 Objects.requireNonNull(task);
180 String name = nextThreadName();
181 var thread = new Thread(group, name, characteristics(), task, stackSize);
182 if (daemonChanged)
183 thread.daemon(daemon);
184 if (priority != 0)
185 thread.priority(priority);
186 UncaughtExceptionHandler uhe = uncaughtExceptionHandler();
187 if (uhe != null)
188 thread.uncaughtExceptionHandler(uhe);
189 return thread;
190 }
191
192 @Override
193 public Thread start(Runnable task) {
194 Thread thread = unstarted(task);
195 thread.start();
196 return thread;
197 }
198
199 @Override
200 public ThreadFactory factory() {
201 return new PlatformThreadFactory(group, name(), counter(), characteristics(),
202 daemonChanged, daemon, priority, stackSize, uncaughtExceptionHandler());
203 }
204 }
205
206 /**
207 * ThreadBuilder.OfVirtual implementation.
208 */
209 static final class VirtualThreadBuilder
210 extends BaseThreadBuilder implements OfVirtual {
211 private Thread.VirtualThreadScheduler scheduler;
212
213 VirtualThreadBuilder() {
214 }
215
216 @Override
217 public OfVirtual name(String name) {
218 setName(name);
219 return this;
220 }
221
222 @Override
223 public OfVirtual name(String prefix, long start) {
224 setName(prefix, start);
225 return this;
226 }
227
228 @Override
229 public OfVirtual inheritInheritableThreadLocals(boolean inherit) {
230 setInheritInheritableThreadLocals(inherit);
231 return this;
232 }
233
234 @Override
235 public OfVirtual uncaughtExceptionHandler(UncaughtExceptionHandler ueh) {
236 setUncaughtExceptionHandler(ueh);
237 return this;
238 }
239
240 Thread unstarted(Runnable task, Thread preferredCarrier) {
241 Objects.requireNonNull(task);
242 var thread = newVirtualThread(scheduler,
243 preferredCarrier,
244 nextThreadName(),
245 characteristics(),
246 task);
247 UncaughtExceptionHandler uhe = uncaughtExceptionHandler();
248 if (uhe != null)
249 thread.uncaughtExceptionHandler(uhe);
250 return thread;
251 }
252
253 @Override
254 public Thread unstarted(Runnable task) {
255 return unstarted(task, null);
256 }
257
258 @Override
259 public Thread start(Runnable task) {
260 Thread thread = unstarted(task);
261 thread.start();
262 return thread;
263 }
264
265 @Override
266 public ThreadFactory factory() {
267 return new VirtualThreadFactory(scheduler, name(), counter(), characteristics(),
268 uncaughtExceptionHandler());
269 }
270 }
271
272 /**
273 * Base ThreadFactory implementation.
274 */
275 private abstract static class BaseThreadFactory implements ThreadFactory {
276 private static final VarHandle COUNT = MhUtil.findVarHandle(
277 MethodHandles.lookup(), "count", long.class);
278
279 private final String name;
280 private final int characteristics;
281 private final UncaughtExceptionHandler uhe;
282
283 private final boolean hasCounter;
284 private volatile long count;
285
286 BaseThreadFactory(String name,
287 long start,
288 int characteristics,
289 UncaughtExceptionHandler uhe) {
290 this.name = name;
291 if (name != null && start >= 0) {
292 this.hasCounter = true;
293 this.count = start;
294 } else {
295 this.hasCounter = false;
296 }
297 this.characteristics = characteristics;
298 this.uhe = uhe;
299 }
300
301 int characteristics() {
302 return characteristics;
303 }
304
305 UncaughtExceptionHandler uncaughtExceptionHandler() {
306 return uhe;
307 }
308
309 String nextThreadName() {
310 if (hasCounter) {
311 return name + (long) COUNT.getAndAdd(this, 1L);
312 } else {
313 return name;
314 }
315 }
316 }
317
318 /**
319 * ThreadFactory for platform threads.
320 */
321 private static class PlatformThreadFactory extends BaseThreadFactory {
322 private final ThreadGroup group;
323 private final boolean daemonChanged;
324 private final boolean daemon;
325 private final int priority;
326 private final long stackSize;
327
328 PlatformThreadFactory(ThreadGroup group,
329 String name,
330 long start,
331 int characteristics,
332 boolean daemonChanged,
333 boolean daemon,
334 int priority,
335 long stackSize,
336 UncaughtExceptionHandler uhe) {
337 super(name, start, characteristics, uhe);
338 this.group = group;
339 this.daemonChanged = daemonChanged;
340 this.daemon = daemon;
341 this.priority = priority;
342 this.stackSize = stackSize;
343 }
344
345 @Override
346 String nextThreadName() {
347 String name = super.nextThreadName();
348 return (name != null) ? name : Thread.genThreadName();
349 }
350
351 @Override
352 public Thread newThread(Runnable task) {
353 Objects.requireNonNull(task);
354 String name = nextThreadName();
355 Thread thread = new Thread(group, name, characteristics(), task, stackSize);
356 if (daemonChanged)
357 thread.daemon(daemon);
358 if (priority != 0)
359 thread.priority(priority);
360 UncaughtExceptionHandler uhe = uncaughtExceptionHandler();
361 if (uhe != null)
362 thread.uncaughtExceptionHandler(uhe);
363 return thread;
364 }
365 }
366
367 /**
368 * ThreadFactory for virtual threads.
369 */
370 private static class VirtualThreadFactory extends BaseThreadFactory {
371 private final Thread.VirtualThreadScheduler scheduler;
372
373 VirtualThreadFactory(Thread.VirtualThreadScheduler scheduler,
374 String name,
375 long start,
376 int characteristics,
377 UncaughtExceptionHandler uhe) {
378 super(name, start, characteristics, uhe);
379 this.scheduler = scheduler;
380 }
381
382 @Override
383 public Thread newThread(Runnable task) {
384 Objects.requireNonNull(task);
385 String name = nextThreadName();
386 Thread thread = newVirtualThread(scheduler, null, name, characteristics(), task);
387 UncaughtExceptionHandler uhe = uncaughtExceptionHandler();
388 if (uhe != null)
389 thread.uncaughtExceptionHandler(uhe);
390 return thread;
391 }
392 }
393
394 /**
395 * Creates a new virtual thread to run the given task.
396 */
397 private static Thread newVirtualThread(Thread.VirtualThreadScheduler scheduler,
398 Thread preferredCarrier,
399 String name,
400 int characteristics,
401 Runnable task) {
402 if (ContinuationSupport.isSupported()) {
403 return new VirtualThread(scheduler, preferredCarrier, name, characteristics, task);
404 } else {
405 if (scheduler != null)
406 throw new UnsupportedOperationException();
407 return new BoundVirtualThread(name, characteristics, task);
408 }
409 }
410
411 static Thread newVirtualThread(String name, int characteristics, Runnable task) {
412 return newVirtualThread(null, null, name, characteristics, task);
413 }
414
415 /**
416 * A "virtual thread" that is backed by a platform thread. This implementation
417 * is intended for platforms that don't have the underlying VM support for
418 * continuations. It can also be used for testing.
419 */
420 static final class BoundVirtualThread extends BaseVirtualThread {
421 private static final Unsafe U = Unsafe.getUnsafe();
422 private final Runnable task;
423 private boolean runInvoked;
424
425 BoundVirtualThread(String name, int characteristics, Runnable task) {
426 super(name, characteristics, true);
427 this.task = task;
428 }
429
430 @Override
431 public void run() {
432 // run is specified to do nothing when Thread is a virtual thread
433 if (Thread.currentThread() == this && !runInvoked) {
434 runInvoked = true;
435 Object bindings = Thread.scopedValueBindings();
436 runWith(bindings, task);
437 }
438 }
439
440 @Override
441 void park() {
442 U.park(false, 0L);
443 }
444
445 @Override
446 void parkNanos(long nanos) {
447 U.park(false, nanos);
448 }
449
450 @Override
451 void unpark() {
452 U.unpark(this);
453 }
454
455 @Override
456 public String toString() {
457 StringBuilder sb = new StringBuilder("VirtualThread[#");
458 sb.append(threadId());
459 String name = getName();
460 if (!name.isEmpty()) {
461 sb.append(",");
462 sb.append(name);
463 }
464 sb.append("]/");
465 String stateAsString = threadState().toString();
466 sb.append(stateAsString.toLowerCase(Locale.ROOT));
467 return sb.toString();
468 }
469 }
470 }