有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

多线程是不是没有办法迭代或复制Java ThreadLocal的所有值?

背景:

static ThreadLocal<MyType> threadLocalMyType = ...

我想说的是:

for (ThreadLocalEntry e: threadLocalMyType.getMapLikeThing() {
    // Thread t = e.getKey(); 
    // I don't need the thread value right now, but it might be useful for 
    // something else. 

    MyType theMyType = e.getValue();
    // [...do something with theMyType...]
}

共 (3) 个答案

  1. # 1 楼答案

    不,因为它在内部是不同的实现:每个线程都有一个类似于地图的局部对象。如果ThreadLocal允许,您想要做的是固有的线程不安全。显然,每个线程在访问自己的局部变量时都不使用任何类型的同步:没有其他线程可以这样做,因此不需要同步。因此,从任何其他线程访问局部映射(如果可能的话)都是线程不安全的

    正如Bozho所建议的,您可以通过子类化ThreadLocal并在其他地方复制值来实现这一点。别忘了正确同步对“其他地方”的访问

  2. # 2 楼答案

    我遇到了同样的问题,在这里看到答案后,我决定使用混合方法:

    public class PersistentThreadLocal<T> extends ThreadLocal<T> {
    
        final Map<Thread, T> allValues;
        final Supplier<? extends T> valueGetter;
    
        public PersistentThreadLocal(Supplier<? extends T> initialValue) {
            this(0, initialValue);
        }
    
        public PersistentThreadLocal(int numThreads, Supplier<? extends T> initialValue) {
            allValues = Collections.synchronizedMap(
                numThreads > 0 ? new WeakHashMap<>(numThreads) : new WeakHashMap<>()
            );
            valueGetter = initialValue;
        }
    
        @Override
        protected T initialValue() {
            T value = valueGetter != null ? valueGetter.get() : super.initialValue();
            allValues.put(Thread.currentThread(), value);
            return value;
        }
    
        @Override
        public void set(T value) {
            super.set(value);
            allValues.put(Thread.currentThread(), value);
        }
    
        @Override
        public void remove() {
            super.remove();
            allValues.remove(Thread.currentThread());
        }
    
        public Collection<T> getAll() {
            return allValues.values();
        }
    
        public void clear() {
            allValues.clear();
        }
    }
    

    编辑:如果您计划将其用于ThreadPoolExecutor,请将WeakHashMap更改为常规HashMap,否则会发生奇怪的事情

  3. # 3 楼答案

    一种方法是手动处理:

    • 使用ThreadLocal的包装器(扩展它)
    • 每当设置一个值时,都要保留(staticMap个线程和值

    或者,通过一些反射(getDeclaredMethod()setAccessible(true)),您可以:

    • 调用Thread.getThreads()
    • 调用yourThreadLocal.getMap(thread)(针对上述每个线程)
    • 调用map.getEntry(yourThreadLocal)

    第一种更可取