Использовать ThreadLocal переменные удобно, для расшаривания данных между разными частями одного потока (допустим достучаться из POJO объекта к HTTP сессии и т.п.). Другое дело, что чревато в контексте использования сервера приложений: тут треды не уничтожаются, а возвращаются в пул потоков, как следствие: GC не собирает их, они остаются в памяти, а тут, помимо явной утечки, есть ещё и потенциальная дырка в безопасности.
По ссылке статья на английском на эту тематику. Как решить теперь буду думать.
По этой ссылке:
http://wiki.apache.org/tomcat/MemoryLeakProtection
Можно почитать про разные MemLeaks в веб-приложениях (точнее про технологию защиты от оных в Tomcat)
UPD: подкатом решение (???)
Решение
какое выбирать, решать вам, я выбрал второй вариант с наследованием класса. Скопирую его тут с форматированием:
import java.lang.ref.SoftReference;
public abstract class SoftThreadLocal<T> extends ThreadLocal<T>
{
// Encapsulation required because Generics is stupid about references, and there is no interface for ThreadLocal,
//so I can't simply extend a single ThreadLocal, grr! Java has so many brittle design mistakes in it.
private final ThreadLocal<SoftReference<T>> local = new ThreadLocal<SoftReference<T>>();
@Override
public T get()
{
SoftReference<T> ref = local.get();
T result = null;
if (null != ref)
{
result = ref.get();
}
if (null == result)
{
result = initialValue();
ref = new SoftReference<T>(result);
local.set(ref);
}
return result;
}
@Override
public void set(T value)
{
if (null == value)
{
remove();
}
else
{
local.set(new SoftReference<T>(value));
}
}
@Override
public void remove()
{
local.remove();
}
}
Далее работа классическая, к примеру, как у меня через ThreadLocal Singleton:
import java.util.HashMap;
/**
* Небольшой вспомогательный статический класс
* для расшариванить локальных для треда переменных. Значение будет для каждого треда своё.
*
* Допустим, получая в методе doPost()/doGet() сервлета значение сессии и для проброса во все дочерние
* классы, без необходимости передачи оных параметром, что, собственно говоря, не всегда возможно.
*
* @author hatred
* 2011-01-27
*/
public class ThreadContext
{
private /*static*/ final SoftThreadLocal<HashMap<Object, Object>> _context = new SoftThreadLocal<HashMap<Object, Object>>()
{
protected HashMap<Object,Object> initialValue()
{
return new HashMap<Object,Object>();
}
};
private static ThreadContext _instance = null;
//
synchronized public static ThreadContext getContext()
{
if (_instance == null)
{
_instance = new ThreadContext();
}
return _instance;
}
synchronized public static void releaseContext()
{
if (_instance != null)
{
_instance.clear();
_instance.contextRemove();
}
_instance = null;
}
public void put(Object key, Object value)
{
_context.get().put(key, value);
}
public Object get(Object key)
{
return _context.get().get(key);
}
public void remove(Object key)
{
_context.get().remove(key);
}
public void clear()
{
_context.get().clear();
}
protected void contextRemove()
{
_context.remove();
}
}
Кстати, не могу понять, насколько правильно делать getContext() и releaseContext() synchronized?