Repository: netty/netty
File: common/src/main/java/io/netty/util/concurrent/FastThreadLocalThread.java (Java)

Code before:
     * Returns {@code true} if this thread supports {@link FastThreadLocal}.
     */
    public static boolean currentThreadHasFastThreadLocal() {
        // intentionally doesn't accept a thread parameter to work with ScopedValue in the future
        return currentThread() instanceof FastThreadLocalThread || isFastThreadLocalVirtualThread();
    }

    private static boolean isFastThreadLocalVirtualThread() {
        return fallbackThreads.containsKey(currentThread().getId());
    }

    /**
     * Run the given task with {@link FastThreadLocal} support. This call should wrap the runnable for any thread that
     * is long-running enough to make treating it as a {@link FastThreadLocalThread} reasonable, but that can't
     * actually extend this class (e.g. because it's a virtual thread). Netty will use optimizations for recyclers and
     * allocators as if this was a {@link FastThreadLocalThread}.
     * <p>This method will clean up any {@link FastThreadLocal}s at the end, and
     * {@link #currentThreadWillCleanupFastThreadLocals()} will return {@code true}.
     * <p>At the moment, {@link FastThreadLocal} uses normal {@link ThreadLocal} as the backing storage here, but in
     * the future this may be replaced with scoped values, if semantics can be preserved and performance is good.
     *
     * @param runnable The task to run
     */
    public static void runWithFastThreadLocal(Runnable runnable) {
        long id = currentThread().getId();
        if (fallbackThreads.put(id, "") != null || currentThread() instanceof FastThreadLocalThread) {
            throw new IllegalStateException("Reentrant call to run()");
        }
        try {
            runnable.run();
        } finally {
            fallbackThreads.remove(id);
            FastThreadLocal.removeAll();
        }
    }

    /**
     * Query whether this thread is allowed to perform blocking calls or not.
     * {@link FastThreadLocalThread}s are often used in event-loops, where blocking calls are forbidden in order to
     * prevent event-loop stalls, so this method returns {@code false} by default.
     * <p>
     * Subclasses of {@link FastThreadLocalThread} can override this method if they are not meant to be used for
     * running event-loops.
     *
     * @return {@code false}, unless overriden by a subclass.
     */
    public boolean permitBlockingCalls() {
        return false;
    }
}


Review comment (suggestion):
Store a static field and use it a the dummy value ?

```
private static final Object MARKER = new Object();
....
....
if (falbackThreads.put(id, MARKER) != null ...
```


Code after:
        return isFastThreadLocalVirtualThread();
    }

    /**
     * Returns {@code true} if this thread supports {@link FastThreadLocal}.
     */
    public static boolean currentThreadHasFastThreadLocal() {
        // intentionally doesn't accept a thread parameter to work with ScopedValue in the future
        return currentThread() instanceof FastThreadLocalThread || isFastThreadLocalVirtualThread();
    }

    private static boolean isFastThreadLocalVirtualThread() {
        long[] arr = fallbackThreads.get();
        if (arr == null) {
            return false;
        }
        return Arrays.binarySearch(arr, Thread.currentThread().getId()) >= 0;
    }

    /**
     * Run the given task with {@link FastThreadLocal} support. This call should wrap the runnable for any thread that
     * is long-running enough to make treating it as a {@link FastThreadLocalThread} reasonable, but that can't
     * actually extend this class (e.g. because it's a virtual thread). Netty will use optimizations for recyclers and
     * allocators as if this was a {@link FastThreadLocalThread}.
     * <p>This method will clean up any {@link FastThreadLocal}s at the end, and
     * {@link #currentThreadWillCleanupFastThreadLocals()} will return {@code true}.
     * <p>At the moment, {@link FastThreadLocal} uses normal {@link ThreadLocal} as the backing storage here, but in
     * the future this may be replaced with scoped values, if semantics can be preserved and performance is good.
     *
     * @param runnable The task to run
     */
    public static void runWithFastThreadLocal(Runnable runnable) {
        Thread current = currentThread();
        if (current instanceof FastThreadLocalThread) {
            throw new IllegalStateException("Caller is a real FastThreadLocalThread");
        }
        long id = current.getId();
        fallbackThreads.updateAndGet(arr -> {
            if (arr == null) {
                return new long[] { id };
            }
            int index = Arrays.binarySearch(arr, id);
            if (index >= 0) {
                throw new IllegalStateException("Reentrant call to run()");
            }
            index = ~index; // same as -(index + 1)
            long[] next = new long[arr.length + 1];
            System.arraycopy(arr, 0, next, 0, index);
            next[index] = id;
            System.arraycopy(arr, index, next, index + 1, arr.length - index);
            return next;