我正在我的网络应用程序中实现一个“经理”,可以调用它来设置和获取当前线程所在的网站上下文(我们在网站上标记白色标签,以便网站上下文代表我们所在的网站)
我正在尝试找出最佳策略,目前我正在并发哈希映射中实现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
答案 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
属性。