mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 23:04:50 +02:00
8304919: Implementation of Virtual Threads
Reviewed-by: lmesnik, cjplummer, psandoz, mchung, sspitsyn, jpai
This commit is contained in:
parent
39398075b7
commit
2586f36120
205 changed files with 1379 additions and 1342 deletions
|
@ -29,9 +29,11 @@ import java.lang.ref.WeakReference;
|
|||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import jdk.internal.misc.CarrierThreadLocal;
|
||||
import jdk.internal.misc.TerminatingThreadLocal;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
/**
|
||||
* This class provides thread-local variables. These variables differ from
|
||||
|
@ -77,6 +79,8 @@ import jdk.internal.misc.TerminatingThreadLocal;
|
|||
* @since 1.2
|
||||
*/
|
||||
public class ThreadLocal<T> {
|
||||
private static final boolean TRACE_VTHREAD_LOCALS = traceVirtualThreadLocals();
|
||||
|
||||
/**
|
||||
* ThreadLocals rely on per-thread linear-probe hash maps attached
|
||||
* to each thread (Thread.threadLocals and
|
||||
|
@ -161,11 +165,8 @@ public class ThreadLocal<T> {
|
|||
* thread-local variable. If the variable has no value for the
|
||||
* current thread, it is first initialized to the value returned
|
||||
* by an invocation of the {@link #initialValue} method.
|
||||
* If the current thread does not support thread locals then
|
||||
* this method returns its {@link #initialValue}.
|
||||
*
|
||||
* @return the current thread's value of this thread-local
|
||||
* @see Thread.Builder#allowSetThreadLocals(boolean)
|
||||
*/
|
||||
public T get() {
|
||||
return get(Thread.currentThread());
|
||||
|
@ -183,15 +184,11 @@ public class ThreadLocal<T> {
|
|||
private T get(Thread t) {
|
||||
ThreadLocalMap map = getMap(t);
|
||||
if (map != null) {
|
||||
if (map == ThreadLocalMap.NOT_SUPPORTED) {
|
||||
return initialValue();
|
||||
} else {
|
||||
ThreadLocalMap.Entry e = map.getEntry(this);
|
||||
if (e != null) {
|
||||
@SuppressWarnings("unchecked")
|
||||
T result = (T) e.value;
|
||||
return result;
|
||||
}
|
||||
ThreadLocalMap.Entry e = map.getEntry(this);
|
||||
if (e != null) {
|
||||
@SuppressWarnings("unchecked")
|
||||
T result = (T) e.value;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return setInitialValue(t);
|
||||
|
@ -211,7 +208,7 @@ public class ThreadLocal<T> {
|
|||
|
||||
private boolean isPresent(Thread t) {
|
||||
ThreadLocalMap map = getMap(t);
|
||||
if (map != null && map != ThreadLocalMap.NOT_SUPPORTED) {
|
||||
if (map != null) {
|
||||
return map.getEntry(this) != null;
|
||||
} else {
|
||||
return false;
|
||||
|
@ -227,7 +224,6 @@ public class ThreadLocal<T> {
|
|||
private T setInitialValue(Thread t) {
|
||||
T value = initialValue();
|
||||
ThreadLocalMap map = getMap(t);
|
||||
assert map != ThreadLocalMap.NOT_SUPPORTED;
|
||||
if (map != null) {
|
||||
map.set(this, value);
|
||||
} else {
|
||||
|
@ -236,6 +232,9 @@ public class ThreadLocal<T> {
|
|||
if (this instanceof TerminatingThreadLocal<?> ttl) {
|
||||
TerminatingThreadLocal.register(ttl);
|
||||
}
|
||||
if (TRACE_VTHREAD_LOCALS) {
|
||||
dumpStackIfVirtualThread();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
@ -247,14 +246,12 @@ public class ThreadLocal<T> {
|
|||
*
|
||||
* @param value the value to be stored in the current thread's copy of
|
||||
* this thread-local.
|
||||
*
|
||||
* @throws UnsupportedOperationException if the current thread is not
|
||||
* allowed to set its copy of thread-local variables
|
||||
*
|
||||
* @see Thread.Builder#allowSetThreadLocals(boolean)
|
||||
*/
|
||||
public void set(T value) {
|
||||
set(Thread.currentThread(), value);
|
||||
if (TRACE_VTHREAD_LOCALS) {
|
||||
dumpStackIfVirtualThread();
|
||||
}
|
||||
}
|
||||
|
||||
void setCarrierThreadLocal(T value) {
|
||||
|
@ -264,9 +261,6 @@ public class ThreadLocal<T> {
|
|||
|
||||
private void set(Thread t, T value) {
|
||||
ThreadLocalMap map = getMap(t);
|
||||
if (map == ThreadLocalMap.NOT_SUPPORTED) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
if (map != null) {
|
||||
map.set(this, value);
|
||||
} else {
|
||||
|
@ -296,7 +290,7 @@ public class ThreadLocal<T> {
|
|||
|
||||
private void remove(Thread t) {
|
||||
ThreadLocalMap m = getMap(t);
|
||||
if (m != null && m != ThreadLocalMap.NOT_SUPPORTED) {
|
||||
if (m != null) {
|
||||
m.remove(this);
|
||||
}
|
||||
}
|
||||
|
@ -394,9 +388,6 @@ public class ThreadLocal<T> {
|
|||
}
|
||||
}
|
||||
|
||||
// Placeholder when thread locals not supported
|
||||
static final ThreadLocalMap NOT_SUPPORTED = new ThreadLocalMap();
|
||||
|
||||
/**
|
||||
* The initial capacity -- MUST be a power of two.
|
||||
*/
|
||||
|
@ -807,4 +798,43 @@ public class ThreadLocal<T> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads the value of the jdk.traceVirtualThreadLocals property to determine if
|
||||
* a stack trace should be printed when a virtual thread sets a thread local.
|
||||
*/
|
||||
private static boolean traceVirtualThreadLocals() {
|
||||
String propValue = GetPropertyAction.privilegedGetProperty("jdk.traceVirtualThreadLocals");
|
||||
return (propValue != null)
|
||||
&& (propValue.isEmpty() || Boolean.parseBoolean(propValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* Print a stack trace if the current thread is a virtual thread.
|
||||
*/
|
||||
static void dumpStackIfVirtualThread() {
|
||||
if (Thread.currentThread() instanceof VirtualThread vthread) {
|
||||
try {
|
||||
var stack = StackWalkerHolder.STACK_WALKER.walk(s ->
|
||||
s.skip(1) // skip caller
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
// switch to carrier thread to avoid recursive use of thread-locals
|
||||
vthread.executeOnCarrierThread(() -> {
|
||||
System.out.println(vthread);
|
||||
for (StackWalker.StackFrame frame : stack) {
|
||||
System.out.format(" %s%n", frame.toStackTraceElement());
|
||||
}
|
||||
return null;
|
||||
});
|
||||
} catch (Exception e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class StackWalkerHolder {
|
||||
static final StackWalker STACK_WALKER = StackWalker.getInstance();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue