Is there no way to iterate over or copy all Java ThreadLocal values?

Context:

static ThreadLocal<MyType> threadLocalMyType = ... 

I would like 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...] } 
+4
java multithreading thread-local
May 08 '10 at 20:06
source share
3 answers

One way is by hand:

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

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

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

The first is preferable.

+5
May 08 '10 at 20:30
source share

No, because internally it is implemented in different ways: each stream has cartographic information about its locales. What you want to do would essentially be unsafe if ThreadLocal allowed this. Each thread, obviously, does not use any kind of synchronization when accessing its own locales: no other thread can do this, so synchronization is not required. For this reason, accessing the locale map from any other stream (if possible) would be unsafe.

As Bojo suggested, you can do this by subclassing ThreadLocal and duplicating values ​​somewhere else. Remember to synchronize access to this “somewhere else” correctly.

+1
May 08 '10 at 20:36
source share

I ran into the same problem, and 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 ThreadPoolExecutor, change WeakHashMap to a regular HashMap , otherwise strange things will happen!

+1
Nov 13 '17 at 15:28
source share



All Articles