有没有办法迭代或复制Java ThreadLocal的所有值?

时间:2010-05-08 20:06:56

标签: java multithreading thread-local

背景:

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 个答案:

答案 0 :(得分:6)

一种方法是手动处理:

  • 使用ThreadLocal(扩展名)
  • 的包装
  • 无论何时设置值,请保留(staticMap主题和值

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

  • 致电Thread.getThreads()
  • 致电yourThreadLocal.getMap(thread)(针对以上每个主题)
  • 致电map.getEntry(yourThreadLocal)

第一是更优选的。

答案 1 :(得分:1)

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

正如Bozho建议的那样,你可以通过继承ThreadLocal并在其他地方复制值来做到这一点。不要忘记正确地同步访问“其他地方”。

答案 2 :(得分:0)

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

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,否则会发生奇怪的事情!