Question

Context:

static ThreadLocal<MyType> threadLocalMyType = ...

What i'd like is to say something like:

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...]
}
Was it helpful?

Solution

One way would be to handle this manually:

  • use a wrapper of ThreadLocal (extend it)
  • whenever a value is set, keep a (static) Map of Threads and values

Alternatively, with some reflection (getDeclaredMethod() and setAccessible(true)), you can:

  • call Thread.getThreads()
  • call yourThreadLocal.getMap(thread) (for each of the above threads)
  • call map.getEntry(yourThreadLocal)

The 1st is more preferable.

OTHER TIPS

No, because internally it is implement differently: each thread has a map-like thing of its locals. What you want to do would be inherently thread-unsafe if ThreadLocal allowed it. Each thread obviously doesn't use any kind of synchronization when accessing its own locals: no other thread can do that, so synchronization is not needed. For this reason, accessing the locals map from any other thread (if that was possible) would be thread-unsafe.

As Bozho suggested, you could do that by subclassing ThreadLocal and duplicating values somewhere else. Don't forget to synchronize access to that "somewhere else" properly.

I came acrosss the same problem and after seeing the answers here, I decided to use a hybrid approach:

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();
    }
}

EDIT: if you plan to use this with a ThreadPoolExecutor, change the WeakHashMap to a regular HashMap, otherwise strange things will happen!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top