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