java中的策略来清理/删除未使用的地图元素

时间:2009-11-02 12:44:47

标签: java memory-leaks maps concurrenthashmap concurrent-programming

我正在我的网络应用程序中实现一个“经理”,可以调用它来设置和获取当前线程所在的网站上下文(我们在网站上标记白色标签,以便网站上下文代表我们所在的网站)

我正在尝试找出最佳策略,目前我正在并发哈希映射中实现Threads到WebSiteContexts的存储:

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

在线程的开头(通过Servlet过滤器或通过手动设置)线程将与其WebSiteContext相关联,

但想要清理Map以避免内存泄漏。所以我想一个策略是遍历地图的Thread键来查明线程是否“活着”(thread.isAlive()),如果没有删除它,例如像这样:

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

,但我猜这需要我同步访问地图(或者是吗?),这是我想要避免的。

是否有任何“惯用”模式用于在java中的线程中存储属性,或者确实清理了将Thread对象作为键的映射?我愿意使用WeakReference / SoftReferences,或者确实如果有一些等效的Thread.getCurrentThread()。setAttribute(Object,Object),那就太棒了

干杯 西蒙B

4 个答案:

答案 0 :(得分:2)

您是否考虑过ThreadLocal

答案 1 :(得分:1)

你的方法可能会奏效,但你最终会做更多的工作而不是必要的。 ThreadLocal正是您所寻找的。这将允许您在应用程序中存储与每个线程相关的对象。使用它的典型方法是实现initialValue()方法,该方法为其赋予第一个值。例如:

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

当您第一次调用localAttribute.get()时,这将为您提供一个本地新线程,其初始值为“InitialValue”。然后,您可以调用localAttribute.set()为其分配不同的值。每个请求者线程对同一属性都有不同的值。

使用ThreadLocal的好处是,当线程死亡时,本地线程应允许您的数据可用于垃圾回收。

答案 2 :(得分:0)

答案 3 :(得分:0)

您正在为一个servlet调用的持续时间定义“线程本地”变量空间。这里最好的方法是删除与添加映射时相同级别的映射,因此如果您在ServletFilter中添加到地图,我会添加一个finally块,删除出路上的映射。这同样适用于servlet中的“手动”添加。

替代方案是在ServletContext中提供此信息或将其添加为ThreadLocal属性。