views:

330

answers:

4

Hi,

I'm implementing a "manager" in my web app that can be called to set and get which web site context the current thread is in (we white label our site so the web site context represents which site we're on)

I'm trying to work out what the best strategy to do this, currently I'm implementing the store of Threads to WebSiteContexts in a concurrent hash map:

private final ConcurrentHashMap<Thread, WebSiteContext> chm = new ConcurrentHashMap<Thread, WebSiteContext>();

at the beginning of the thread (either through a Servlet Filter or through manually setting it) the thread will be associated to its WebSiteContext,

but want to clean up the Map to avoid a memory leak. So I guess one strategy is to iterate through the Thread keys of the map to find out whether the threads are "alive" (thread.isAlive()) and if not remove it for example like this:

 public class Cleaner implements Runnable {
      private static final int INTERVAL = 6 * 1000; // 6 seconds
      public Cleaner() {
      }
      public void run() {
            // soo every interval iterate through the threads if they're dead then remove it from the map.
            while(true) {
               try {
                     Set<Thread> threads = chm.keySet();
                     Set<Thread> staleThreads = new HashSet<Thread>();
                     for (Thread tmpThread : threads) {

                        // if we get to a dead thread then clean the fucker up
                        if (!tmpThread.isAlive()) {
                           // think that we're going to get a run condition anyway
                           chm.remove(tmpThread);
                        }
                     }
                  Thread.sleep(INTERVAL);
               } catch (Exception e) {
                  log.error("caught exception e:", e);
               }
            }
      }
   }

, but this I guess requires me to synchronize access to the map (or does it?) which is something I want to avoid.

Is there any "idiomatic" pattern for storing attributes in threads in java or indeed cleaning up maps that have Thread objects as keys? I'm open to using WeakReference / SoftReferences or indeed if there is some equivalent of Thread.getCurrentThread().setAttribute(Object, Object), that would be great

Cheers Simon B

+2  A: 

Have you thought about ThreadLocal?

Tom Hawtin - tackline
+1 I don't think there is any better option
sfussenegger
that seems to be exactly what I needed, cheers
Simon B
A: 
denis.zhdanov
A: 

You are defining a "thread local" variable space for the duration of one servlet call. The best way here is to remove the mapping at the same level as you added it, so if you add to the map in a ServletFilter I would add a finally block that removed the mapping on the way out. The same holds for a "manual" addition in a servlet.

Alternatives are having this information in your ServletContext or adding it as a ThreadLocal attribute.

rsp
+1  A: 

Your approach may work but you would end up doing more work than neeeded. ThreadLocal is what you are looking for. This will allow you to store objects related to each thread in your application. The typical way to use it is to implement the initialValue() method which assigns it the first value. Example:

 private static final ThreadLocal<String> localAttribute = new ThreadLocal<String> () {
         protected Integer initialValue() {
             return "InitialValue";
     }
 };

This will give you a new thread local with the initial value to "InitialValue" when you first call localAttribute.get(). You can then call localAttribute.set() to assign it a different value. Each requester thread will have different values for the same attribute.

The nice thing about using ThreadLocal is that when the thread dies, the thread local should allow your data to be available for garbage collection.

Chris Dail
Cheers, that's exactly the thing that I need, have already incorporated it, and it seems to work fine, like you say, the good thing is that the GC will clean up after the thread is no longer alive
Simon B