Стоит ли очищать ThreadLocals в фильтре для решения проблем, связанных с пулом потоков?
Вкратце - tomcat использует пул потоков, поэтому потоки повторно используются. Некоторые библиотеки используют переменные ThreadLocal
, но не очищают их (используя .remove()
), поэтому на самом деле они возвращают "грязные" потоки в пул.
Tomcat имеет новые функции обнаружения этих вещей при выключении и очистки локаторов потоков. Но это означает, что потоки "грязны" во время всего выполнения.
Что я могу сделать, это реализовать Filter
, и сразу после завершения запроса (и поток возвращается в пул) очистите все ThreadLocal
s, используя code from tomcat (метод называется checkThreadLocalsForLeaks
).
Вопрос в том, стоит ли это? Два плюса:
- предотвращение утечки памяти
- предотвращение неопределенного поведения библиотеками, которые предполагают, что поток "свежий"
Один символ:
- Решение использует отражение, поэтому оно потенциально замедляется. Все данные отражения (
Field
s) будут, конечно, кэшированы, но все же.
Другой вариант - сообщить об этой проблеме в библиотеки, которые не очищают локаторы потоков.
Ответы
Ответ 1
Я бы рассмотрел маршрут сообщения о проблеме разработчикам библиотеки по двум причинам:
- Это поможет другим людям, которые хотят использовать одну и ту же библиотеку, но не имеют навыков/времени, чтобы найти такую УЖАСНУЮ утечку памяти.
- Чтобы разработчики библиотеки могли создавать лучший продукт.
Честно говоря, я никогда раньше не видел такого типа ошибок, и я думаю, что это исключение, а не то, что мы должны охранять, как это часто бывает. Не могли бы вы поделиться с какой библиотекой вы видели это поведение?
В качестве побочного примечания я бы не прочь включить этот фильтр в среду разработки/тестирования и зарегистрировать критическую ошибку, если переменная ThreadLocal по-прежнему подключена.
Ответ 2
в теории, это кажется хорошей идеей. однако я мог видеть некоторые ситуации, когда вы, возможно, не захотите этого делать. например, некоторые из связанных с xml технологий имеют некоторые нетривиальные затраты на установку (например, создание DocumentBuilders и Transformers). если вы много чего делаете в своем webapp, может иметь смысл кэшировать эти экземпляры в ThreadLocals (поскольку утилит обычно не являются потокобезопасными). в этом случае вы, вероятно, не хотите очищать их между запросами.
Ответ 3
Если вы считаете, что вероятность того, что загрязнение нитей действительно вызовет проблемы, то это разумная вещь. По возможности следует избегать проблем.
Использование threadlocals может быть неправильным поведением библиотеки, и вы должны обязательно сообщать об этом авторам, но, к сожалению, прямо сейчас вам решать, как это сделать.
Я бы не слишком беспокоился о производительности. Медленный бит в отражении - это поиск метаданных; как только у вас есть объект Field, то его использование довольно быстро и с течением времени становится быстрее - AIUI, он начинает работать, создавая собственный вызов в JVM, но после некоторого количества применений он генерирует байт-код для доступа, который затем может быть скомпилирован в собственный код, оптимизирован, встроен и т.д., поэтому он не должен быть намного медленнее, чем прямой доступ к полям. Я не думаю, что код Tomcat повторно использует объекты Field во всех запросах, поэтому, если вы хотите воспользоваться этим, вам придется написать свой собственный код очистки. В любом случае, стоимость исполнения будет намного меньше стоимости IO, связанной с запросом.