views:

272

answers:

3

I am looking for a class similar to ThreadLocal which would work on thread groups instead of threads.

If there is not such a class (in some open source library) how would you implement it? Some better idea than having thread groups in WeakHashMap?

I am implementing a debugging framework tunable in run-time with various parameters in global, per-thread and per-thread group contexts. As a very simple example, you can have a reporting statement:

debug.log( category, message);

and specify that the log entry with that specific category will be displayed only when called by a thread in group of threads servicing network requests.

+1  A: 

The last time i looked at the implementation (well a few years ago) Thread Locals were implemented as a simple hash table indexed by the thread id. Nothing fancy and miles away from the efficiency of C++.

You can do the same and use the thread group object as a key for your own thread group locals hash table.

Lothar
Even (Sun) 1.2 has been updated not to do that. It's very inefficient.
Tom Hawtin - tackline
Yes i know it was a long time ago.
Lothar
I think it is now a hash table inside of the Thread instance, indexed by ThreadLocal object. This removes synchronization overhead, one private hash table per thread.
Thilo
+3  A: 

ThreadGroup is rarely used, so there isn't platform support.

Using [Weak/Identity/Concurrent]HashMap<ThreadGroup,T> will just about work, if not very fast. You really want the map to be all weak, identity and concurrent but with the Java library you only get to choose one, currently.

To improve performance, note that Threads do not change ThreadGroup. Therefore, cache the value with a ThreadLocal (override initialValue). ThreadLocal has good performance (a couple dozen cycles per get).

Tom Hawtin - tackline
Nice performance trick, thanks.
Viliam
+1  A: 

I would store a value holder in a thread local and initialize it to the same value holder for all threads of the same group.

 public class ThreadGroupLocal<T> extends ThreadLocal<ValueHolder> {
     private static class ValueHolder {
         public Object value;
     }
     // Weak & Concurrent would be even the better, but Java API wont offer that :(
     private static ConcurrentMap<ThreadGroup, ValueHolder> map = new ConcurrentHashMap<ThreadGroup, ValueHolder>;
     private static ValueHolder valueHolderForThread(Thread t) {
         map.putIfAbsent(t.getThreadGroup(), new ValueHolder());
         return map.get(t.getThreadGroup());
     }
     @Override 
     protected ValueHolder initialValue() {
         return valueHolderForThread(Thread.currentThread());
     }
     public T getValue() { (T) get().value; }
     public void setValue(T value) { get().value = value; }
 }

and then use

 ThreadGroupLocal<String> groupLocal = new ThreadGroupLocal<String>();
 groupLocal.setValue("foo");
 //...
 String foo = groupLocal.getValue();

That does (expect for the initialization) perform exactly like a thread local.

Adrian
Why didn't you generify ValueHolder? And why did you make it extend ThreadLocal? The use of ThreadLocal<ValueHolder> is an implementation detail.
Laurence Gonsalves
Good points, they are worth being considered. I wrote that code in a hurry as proof-of-concept, so please review (and test!!!) it before using it in production. (PS: *I recall now why ValueHolder is not generified, because they are stored in a static hash map that would degenerate to `<?>` so you need to cast anyway.*)
Adrian