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 Thread lazyStart(Runnable task) {
267 Thread thread = unstarted(task);
268 if (thread instanceof VirtualThread vthread) {
269 vthread.lazyStart();
270 } else {
271 thread.start();
272 }
273 return thread;
274 }
275
276 @Override
277 public ThreadFactory factory() {
278 return new VirtualThreadFactory(scheduler, name(), counter(), characteristics(),
279 uncaughtExceptionHandler());
280 }
281 }
282
283 /**
284 * Base ThreadFactory implementation.
285 */
286 private abstract static class BaseThreadFactory implements ThreadFactory {
287 private static final VarHandle COUNT = MhUtil.findVarHandle(
288 MethodHandles.lookup(), "count", long.class);
289
290 private final String name;
291 private final int characteristics;
292 private final UncaughtExceptionHandler uhe;
293
294 private final boolean hasCounter;
295 private volatile long count;
296
297 BaseThreadFactory(String name,
298 long start,
299 int characteristics,
300 UncaughtExceptionHandler uhe) {
301 this.name = name;
302 if (name != null && start >= 0) {
303 this.hasCounter = true;
304 this.count = start;
305 } else {
306 this.hasCounter = false;
307 }
308 this.characteristics = characteristics;
309 this.uhe = uhe;
310 }
311
312 int characteristics() {
313 return characteristics;
314 }
315
316 UncaughtExceptionHandler uncaughtExceptionHandler() {
317 return uhe;
318 }
319
320 String nextThreadName() {
321 if (hasCounter) {
322 return name + (long) COUNT.getAndAdd(this, 1L);
323 } else {
324 return name;
325 }
326 }
327 }
328
329 /**
330 * ThreadFactory for platform threads.
331 */
332 private static class PlatformThreadFactory extends BaseThreadFactory {
333 private final ThreadGroup group;
334 private final boolean daemonChanged;
335 private final boolean daemon;
336 private final int priority;
337 private final long stackSize;
338
339 PlatformThreadFactory(ThreadGroup group,
340 String name,
341 long start,
342 int characteristics,
343 boolean daemonChanged,
344 boolean daemon,
345 int priority,
346 long stackSize,
347 UncaughtExceptionHandler uhe) {
348 super(name, start, characteristics, uhe);
349 this.group = group;
350 this.daemonChanged = daemonChanged;
351 this.daemon = daemon;
352 this.priority = priority;
353 this.stackSize = stackSize;
354 }
355
356 @Override
357 String nextThreadName() {
358 String name = super.nextThreadName();
359 return (name != null) ? name : Thread.genThreadName();
360 }
361
362 @Override
363 public Thread newThread(Runnable task) {
364 Objects.requireNonNull(task);
365 String name = nextThreadName();
366 Thread thread = new Thread(group, name, characteristics(), task, stackSize);
367 if (daemonChanged)
368 thread.daemon(daemon);
369 if (priority != 0)
370 thread.priority(priority);
371 UncaughtExceptionHandler uhe = uncaughtExceptionHandler();
372 if (uhe != null)
373 thread.uncaughtExceptionHandler(uhe);
374 return thread;
375 }
376 }
377
378 /**
379 * ThreadFactory for virtual threads.
380 */
381 private static class VirtualThreadFactory extends BaseThreadFactory {
382 private final Thread.VirtualThreadScheduler scheduler;
383
384 VirtualThreadFactory(Thread.VirtualThreadScheduler scheduler,
385 String name,
386 long start,
387 int characteristics,
388 UncaughtExceptionHandler uhe) {
389 super(name, start, characteristics, uhe);
390 this.scheduler = scheduler;
391 }
392
393 @Override
394 public Thread newThread(Runnable task) {
395 Objects.requireNonNull(task);
396 String name = nextThreadName();
397 Thread thread = newVirtualThread(scheduler, null, name, characteristics(), task);
398 UncaughtExceptionHandler uhe = uncaughtExceptionHandler();
399 if (uhe != null)
400 thread.uncaughtExceptionHandler(uhe);
401 return thread;
402 }
403 }
404
405 /**
406 * Creates a new virtual thread to run the given task.
407 */
408 private static Thread newVirtualThread(Thread.VirtualThreadScheduler scheduler,
409 Thread preferredCarrier,
410 String name,
411 int characteristics,
412 Runnable task) {
413 if (ContinuationSupport.isSupported()) {
414 return new VirtualThread(scheduler, preferredCarrier, name, characteristics, task);
415 } else {
416 if (scheduler != null)
417 throw new UnsupportedOperationException();
418 return new BoundVirtualThread(name, characteristics, task);
419 }
420 }
421
422 static Thread newVirtualThread(String name, int characteristics, Runnable task) {
423 return newVirtualThread(null, null, name, characteristics, task);
424 }
425
426 /**
427 * A "virtual thread" that is backed by a platform thread. This implementation
428 * is intended for platforms that don't have the underlying VM support for
429 * continuations. It can also be used for testing.
430 */
431 static final class BoundVirtualThread extends BaseVirtualThread {
432 private static final Unsafe U = Unsafe.getUnsafe();
433 private final Runnable task;
434 private boolean runInvoked;
435
436 BoundVirtualThread(String name, int characteristics, Runnable task) {
437 super(name, characteristics, true);
438 this.task = task;
439 }
440
441 @Override
442 public void run() {
443 // run is specified to do nothing when Thread is a virtual thread
444 if (Thread.currentThread() == this && !runInvoked) {
445 runInvoked = true;
446 Object bindings = Thread.scopedValueBindings();
447 runWith(bindings, task);
448 }
449 }
450
451 @Override
452 void park() {
453 U.park(false, 0L);
454 }
455
456 @Override
457 void parkNanos(long nanos) {
458 U.park(false, nanos);
459 }
460
461 @Override
462 void unpark() {
463 U.unpark(this);
464 }
465
466 @Override
467 public String toString() {
468 StringBuilder sb = new StringBuilder("VirtualThread[#");
469 sb.append(threadId());
470 String name = getName();
471 if (!name.isEmpty()) {
472 sb.append(",");
473 sb.append(name);
474 }
475 sb.append("]/");
476 String stateAsString = threadState().toString();
477 sb.append(stateAsString.toLowerCase(Locale.ROOT));
478 return sb.toString();
479 }
480 }
481 }