ThreadLocal — удобный способ хранить данные, привязанные к потоку. Например, для
SimpleDateFormat или текущего пользователя в рамках запроса. Но с ним легко получить утечку памяти, особенно в thread pool'ах.📌 Почему?
ThreadLocal-хранилище (
Thread.threadLocals) живёт столько же, сколько поток. А потоки из пулов живут долго. Если ты забыл вызвать remove() — данные останутся в памяти навсегда.Пример:
private static final ThreadLocal<UserContext> context = ThreadLocal.withInitial(UserContext::new);
public void handleRequest() {
try {
context.set(new UserContext("user123"));
// работа с контекстом
} finally {
context.remove(); // ОБЯЗАТЕЛЬНО!
}
}
⚠️ Что пойдёт не так без
remove()?- Поток из пула закончит обрабатывать запрос, но
UserContext останется висеть в ThreadLocalMap этого потока.- Если
UserContext содержит ссылки на другие объекты (например, HttpSession, EntityManager и т.д.) — вся эта цепочка не будет GC-шиться.- И так накапливается утечка.
💡 Советы:
- Всегда вызывай
remove() в finally.- Для Spring можно использовать
RequestScope или @ControllerAdvice вместо ThreadLocal.- Проверяй код сторонних библиотек, если они используют
ThreadLocal, особенно в фильтрах и интерсепторах.📲 Мы в MAX
👉@BookJava


