1 /* 2 * Copyright (c) 2021, 2022, 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; 28 import java.lang.Thread.Builder.OfPlatform; 29 import java.lang.Thread.Builder.OfVirtual; 30 import java.lang.Thread.UncaughtExceptionHandler; 31 import java.lang.invoke.MethodHandles; 32 import java.lang.invoke.VarHandle; 33 import java.util.Locale; 34 import java.util.Objects; 35 import java.util.concurrent.Executor; 36 import java.util.concurrent.ThreadFactory; 37 import jdk.internal.misc.Unsafe; 38 import jdk.internal.vm.ContinuationSupport; 39 40 /** 41 * Defines static methods to create platform and virtual thread builders. 42 */ 43 class ThreadBuilders { 44 45 /** 46 * Base implementation of ThreadBuilder. 47 */ 48 static abstract non-sealed 49 class BaseThreadBuilder<T extends Builder> implements Builder { 50 private String name; 51 private long counter; 52 private int characteristics; 53 private UncaughtExceptionHandler uhe; 54 55 String name() { 56 return name; 57 } 58 59 long counter() { 60 return counter; 61 } 62 63 int characteristics() { 64 return characteristics; 65 } 66 67 UncaughtExceptionHandler uncaughtExceptionHandler() { 68 return uhe; 69 } 70 71 String nextThreadName() { 72 if (name != null && counter >= 0) { 73 return name + (counter++); 74 } else { 75 return name; 76 } 77 } 78 79 @Override 80 @SuppressWarnings("unchecked") 81 public T name(String name) { 82 this.name = Objects.requireNonNull(name); 83 this.counter = -1; 84 return (T) this; 85 } 86 87 @Override 88 @SuppressWarnings("unchecked") 89 public T name(String prefix, long start) { 90 Objects.requireNonNull(prefix); 91 if (start < 0) 92 throw new IllegalArgumentException("'start' is negative"); 93 this.name = prefix; 94 this.counter = start; 95 return (T) this; 96 } 97 98 @Override 99 @SuppressWarnings("unchecked") 100 public T allowSetThreadLocals(boolean allow) { 101 if (allow) { 102 characteristics &= ~Thread.NO_THREAD_LOCALS; 103 } else { 104 characteristics |= Thread.NO_THREAD_LOCALS; 105 } 106 return (T) this; 107 } 108 109 @Override 110 @SuppressWarnings("unchecked") 111 public T inheritInheritableThreadLocals(boolean inherit) { 112 if (inherit) { 113 characteristics &= ~Thread.NO_INHERIT_THREAD_LOCALS; 114 } else { 115 characteristics |= Thread.NO_INHERIT_THREAD_LOCALS; 116 } 117 return (T) this; 118 } 119 120 @Override 121 @SuppressWarnings("unchecked") 122 public T uncaughtExceptionHandler(UncaughtExceptionHandler ueh) { 123 this.uhe = Objects.requireNonNull(ueh); 124 return (T) this; 125 } 126 } 127 128 /** 129 * ThreadBuilder.OfPlatform implementation. 130 */ 131 static final class PlatformThreadBuilder 132 extends BaseThreadBuilder<OfPlatform> implements OfPlatform { 133 private ThreadGroup group; 134 private boolean daemon; 135 private boolean daemonChanged; 136 private int priority; 137 private long stackSize; 138 139 PlatformThreadBuilder() { 140 } 141 142 @Override 143 String nextThreadName() { 144 String name = super.nextThreadName(); 145 return (name != null) ? name : Thread.genThreadName(); 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, null); 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 /** 208 * ThreadBuilder.OfVirtual implementation. 209 */ 210 static final class VirtualThreadBuilder 211 extends BaseThreadBuilder<OfVirtual> implements OfVirtual { 212 private Executor scheduler; 213 214 VirtualThreadBuilder() { 215 } 216 217 // invoked by tests 218 VirtualThreadBuilder(Executor scheduler) { 219 if (!ContinuationSupport.isSupported()) 220 throw new UnsupportedOperationException(); 221 this.scheduler = Objects.requireNonNull(scheduler); 222 } 223 224 @Override 225 public Thread unstarted(Runnable task) { 226 Objects.requireNonNull(task); 227 var thread = newVirtualThread(scheduler, nextThreadName(), characteristics(), task); 228 UncaughtExceptionHandler uhe = uncaughtExceptionHandler(); 229 if (uhe != null) 230 thread.uncaughtExceptionHandler(uhe); 231 return thread; 232 } 233 234 @Override 235 public Thread start(Runnable task) { 236 Thread thread = unstarted(task); 237 thread.start(); 238 return thread; 239 } 240 241 @Override 242 public ThreadFactory factory() { 243 return new VirtualThreadFactory(scheduler, name(), counter(), characteristics(), 244 uncaughtExceptionHandler()); 245 } 246 } 247 248 /** 249 * Base ThreadFactory implementation. 250 */ 251 private static abstract class BaseThreadFactory implements ThreadFactory { 252 private static final VarHandle COUNT; 253 static { 254 try { 255 MethodHandles.Lookup l = MethodHandles.lookup(); 256 COUNT = l.findVarHandle(BaseThreadFactory.class, "count", long.class); 257 } catch (Exception e) { 258 throw new InternalError(e); 259 } 260 } 261 private final String name; 262 private final int characteristics; 263 private final UncaughtExceptionHandler uhe; 264 265 private final boolean hasCounter; 266 private volatile long count; 267 268 BaseThreadFactory(String name, 269 long start, 270 int characteristics, 271 UncaughtExceptionHandler uhe) { 272 this.name = name; 273 if (name != null && start >= 0) { 274 this.hasCounter = true; 275 this.count = start; 276 } else { 277 this.hasCounter = false; 278 } 279 this.characteristics = characteristics; 280 this.uhe = uhe; 281 } 282 283 int characteristics() { 284 return characteristics; 285 } 286 287 UncaughtExceptionHandler uncaughtExceptionHandler() { 288 return uhe; 289 } 290 291 String nextThreadName() { 292 if (hasCounter) { 293 return name + (long) COUNT.getAndAdd(this, 1); 294 } else { 295 return name; 296 } 297 } 298 } 299 300 /** 301 * ThreadFactory for platform threads. 302 */ 303 private static class PlatformThreadFactory extends BaseThreadFactory { 304 private final ThreadGroup group; 305 private final boolean daemonChanged; 306 private final boolean daemon; 307 private final int priority; 308 private final long stackSize; 309 310 PlatformThreadFactory(ThreadGroup group, 311 String name, 312 long start, 313 int characteristics, 314 boolean daemonChanged, 315 boolean daemon, 316 int priority, 317 long stackSize, 318 UncaughtExceptionHandler uhe) { 319 super(name, start, characteristics, uhe); 320 this.group = group; 321 this.daemonChanged = daemonChanged; 322 this.daemon = daemon; 323 this.priority = priority; 324 this.stackSize = stackSize; 325 } 326 327 @Override 328 String nextThreadName() { 329 String name = super.nextThreadName(); 330 return (name != null) ? name : Thread.genThreadName(); 331 } 332 333 @Override 334 public Thread newThread(Runnable task) { 335 Objects.requireNonNull(task); 336 String name = nextThreadName(); 337 Thread thread = new Thread(group, name, characteristics(), task, stackSize, null); 338 if (daemonChanged) 339 thread.daemon(daemon); 340 if (priority != 0) 341 thread.priority(priority); 342 UncaughtExceptionHandler uhe = uncaughtExceptionHandler(); 343 if (uhe != null) 344 thread.uncaughtExceptionHandler(uhe); 345 return thread; 346 } 347 } 348 349 /** 350 * ThreadFactory for virtual threads. 351 */ 352 private static class VirtualThreadFactory extends BaseThreadFactory { 353 private final Executor scheduler; 354 355 VirtualThreadFactory(Executor scheduler, 356 String name, 357 long start, 358 int characteristics, 359 UncaughtExceptionHandler uhe) { 360 super(name, start, characteristics, uhe); 361 this.scheduler = scheduler; 362 } 363 364 @Override 365 public Thread newThread(Runnable task) { 366 Objects.requireNonNull(task); 367 String name = nextThreadName(); 368 Thread thread = newVirtualThread(scheduler, name, characteristics(), task); 369 UncaughtExceptionHandler uhe = uncaughtExceptionHandler(); 370 if (uhe != null) 371 thread.uncaughtExceptionHandler(uhe); 372 return thread; 373 } 374 } 375 376 /** 377 * Creates a new virtual thread to run the given task. 378 */ 379 static Thread newVirtualThread(Executor scheduler, 380 String name, 381 int characteristics, 382 Runnable task) { 383 if (ContinuationSupport.isSupported()) { 384 return new VirtualThread(scheduler, name, characteristics, task); 385 } else { 386 if (scheduler != null) 387 throw new UnsupportedOperationException(); 388 return new BoundVirtualThread(name, characteristics, task); 389 } 390 } 391 392 /** 393 * A "virtual thread" that is backed by a platform thread. This implementation 394 * is intended for platforms that don't have the underlying VM support for 395 * continuations. It can also be used for testing. 396 */ 397 static final class BoundVirtualThread extends BaseVirtualThread { 398 private static final Unsafe U = Unsafe.getUnsafe(); 399 private final Runnable task; 400 private boolean runInvoked; 401 402 BoundVirtualThread(String name, int characteristics, Runnable task) { 403 super(name, characteristics, true); 404 this.task = task; 405 } 406 407 @Override 408 public void run() { 409 // run is specified to do nothing when Thread is a virtual thread 410 if (Thread.currentThread() == this && !runInvoked) { 411 runInvoked = true; 412 task.run(); 413 } 414 } 415 416 @Override 417 void park() { 418 U.park(false, 0L); 419 } 420 421 @Override 422 void parkNanos(long nanos) { 423 U.park(false, nanos); 424 } 425 426 @Override 427 void unpark() { 428 U.unpark(this); 429 } 430 431 @Override 432 public String toString() { 433 StringBuilder sb = new StringBuilder("VirtualThread[#"); 434 sb.append(threadId()); 435 String name = getName(); 436 if (!name.isEmpty()) { 437 sb.append(","); 438 sb.append(name); 439 } 440 sb.append("]/"); 441 String stateAsString = threadState().toString(); 442 sb.append(stateAsString.toLowerCase(Locale.ROOT)); 443 return sb.toString(); 444 } 445 } 446 }