java中清理/删除未使用映射元素的策略

java中清理/删除未使用映射元素的策略,java,memory-leaks,maps,concurrenthashmap,concurrent-programming,Java,Memory Leaks,Maps,Concurrenthashmap,Concurrent Programming,我正在我的web应用程序中实现一个“管理器”,可以调用该管理器来设置和获取当前线程所在的网站上下文(我们为网站贴上白色标签,以便网站上下文表示我们所在的网站) 我正试图找出实现这一点的最佳策略,目前我正在并行哈希映射中实现从线程到网站上下文的存储: private final ConcurrentHashMap<Thread, WebSiteContext> chm = new ConcurrentHashMap<Thread, WebSiteContext>(); p

我正在我的web应用程序中实现一个“管理器”,可以调用该管理器来设置和获取当前线程所在的网站上下文(我们为网站贴上白色标签,以便网站上下文表示我们所在的网站)

我正试图找出实现这一点的最佳策略,目前我正在并行哈希映射中实现从线程到网站上下文的存储:

private final ConcurrentHashMap<Thread, WebSiteContext> chm = new ConcurrentHashMap<Thread, WebSiteContext>();
private final ConcurrentHashMap chm=new ConcurrentHashMap();
在线程开始时(通过Servlet过滤器或手动设置),线程将与其WebSiteContext相关联

但我希望清理映射以避免内存泄漏。因此,我想一种策略是迭代映射的线程键,以确定线程是否“活动”(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);
               }
            }
      }
   }
公共类清理器实现可运行{
私有静态最终整数间隔=6*1000;//6秒
公共清洁工(){
}
公开募捐{
//所以,如果线程死了,每个间隔都会遍历线程,然后将其从映射中删除。
while(true){
试一试{
Set threads=chm.keySet();
Set staleThreads=newhashset();
用于(线程tmpThread:threads){
//如果我们到了死线,那就把他妈的清理干净
如果(!tmpThread.isAlive()){
//认为我们无论如何都会得到一个运行条件
chm.remove(tmpThread);
}
}
睡眠(间隔);
}捕获(例外e){
log.error(“捕获异常e:,e”);
}
}
}
}
,但我想这需要我同步访问地图(或者是吗?),这是我想要避免的

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

干杯
Simon B

你有没有想过
ThreadLocal

你有没有想过
ThreadLocal

  • )
  • 将目标信息绑定到servlet请求属性
      • )
      • 将目标信息绑定到servlet请求属性
          您正在为一个servlet调用的持续时间定义一个“线程本地”变量空间。这里最好的方法是在添加映射的同一级别删除映射,因此如果在
          ServletFilter
          中添加映射,我会添加一个
          finally
          块,该块在退出时删除映射。servlet中的“手动”添加也是如此

          替代方法是在
          ServletContext
          中包含此信息,或者将其添加为
          ThreadLocal
          属性。

          您正在为一个servlet调用的持续时间定义一个“thread local”变量空间。这里最好的方法是在添加映射的同一级别删除映射,因此如果在
          ServletFilter
          中添加映射,我会添加一个
          finally
          块,该块在退出时删除映射。servlet中的“手动”添加也是如此


          备选方案是在
          ServletContext
          中包含此信息,或将其添加为
          ThreadLocal
          属性。

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

           private static final ThreadLocal<String> localAttribute = new ThreadLocal<String> () {
                   protected Integer initialValue() {
                       return "InitialValue";
               }
           };
          
          private static final ThreadLocal localAttribute=new ThreadLocal(){
          受保护的整数初始值(){
          返回“初始值”;
          }
          };
          
          当您第一次调用localAttribute.get()时,这将为您提供一个初始值为“InitialValue”的新本地线程。然后可以调用localAttribute.set()为其指定不同的值。对于同一属性,每个请求程序线程将具有不同的值


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

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

           private static final ThreadLocal<String> localAttribute = new ThreadLocal<String> () {
                   protected Integer initialValue() {
                       return "InitialValue";
               }
           };
          
          private static final ThreadLocal localAttribute=new ThreadLocal(){
          受保护的整数初始值(){
          返回“初始值”;
          }
          };
          
          当您第一次调用localAttribute.get()时,这将为您提供一个初始值为“InitialValue”的新本地线程。然后可以调用localAttribute.set()为其指定不同的值。对于同一属性,每个请求程序线程将具有不同的值


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

          干杯,这正是我需要的东西,已经将其合并,并且它似乎工作正常,如您所说,好的方面是GC会在线程不再是aliveCheers之后清理,这正是我需要的,已经合并了它,并且它似乎工作得很好,就像你说的,好的方面是GC会在线程不再是活动的之后清理