ThreadLocal Lean и WeakReference

Мое ограниченное понимание ThreadLocal заключается в том, что он утечка ресурсов вопросы. Я понимаю, что эта проблема может быть устранена путем правильного использования WeakReferences с помощью ThreadLocal (хотя я, возможно, неправильно понял этот вопрос.) Мне просто понравился шаблон или пример для правильного использования ThreadLocal с WeakReference, если он существует. Например, в этом фрагменте кода, где будет введено значение WeakReference?

static class DateTimeFormatter {
    private static final ThreadLocal<SimpleDateFormat> DATE_PARSER_THREAD_LOCAL = new ThreadLocal<SimpleDateFormat>() {
        protected SimpleDateFormat initialValue() {
            return new SimpleDateFormat("yyyy/MM/dd HH:mmz");
        }
    };
    public String format(final Date date) {
        return DATE_PARSER_THREAD_LOCAL.get().format(date);
    }
    public Date parse(final String date) throws ParseException
    {
      return DATE_PARSER_THREAD_LOCAL.get().parse(date);
    }
}

Ответ 1

ThreadLocal использует WeakReference внутренне. Если параметр ThreadLocal не привязан к тексту, он будет собираться с мусором, хотя различные потоки имеют значения, хранящиеся через ThreadLocal.

Кроме того, значения ThreadLocal фактически хранятся в Thread; если нить умирает, все значения, связанные с этим потоком через ThreadLocal, собираются.

Если у вас есть ThreadLocal как последний член класса, это сильная ссылка, и она не может быть собрана до тех пор, пока класс не будет выгружен. Но так работает любой член класса и не считается утечкой памяти.


Обновление: указанная проблема входит в игру только тогда, когда значение, хранящееся в ThreadLocal, сильно ссылается на ThreadLocal — тип циклической ссылки.

В этом случае значение (a SimpleDateFormat) не имеет обратной ссылки на ThreadLocal. В этом коде отсутствует утечка памяти.

Ответ 2

Я предполагаю, что вы прыгаете через эти обручи, так как SimpleDateFormat не является потокобезопасным.

Пока я знаю, что я не решаю вашу проблему выше, могу ли я предложить вам посмотреть Joda для вашей даты/времени Работа? У Joda есть механизм форматирования даты и времени с потоком. Вы не будете тратить свое время на изучение API Joda, поскольку он является основой для нового стандартного предложения API даты/времени.

Ответ 3

Не должно быть такой проблемы.

Поток Ссылка ThreadLocal определяется как существующий только до тех пор, пока соответствующий поток жив (см. javadoc) - или иначе, если поток не жив, если ThreadLocal был единственной ссылкой на этот объект, то объект становится пригодным для сбора мусора.

Итак, либо вы нашли подлинную ошибку, и должны сообщить об этом, либо вы делаете что-то еще неправильно!

Ответ 4

Я понимаю, что это не является строго ответом на ваш вопрос, но, как правило, я не буду предлагать использовать ThreadLocal в ситуации, когда в конце запроса/взаимодействия нет четкого слеза. Классик делает такие вещи в контейнере сервлетов, на первый взгляд это кажется прекрасным, но поскольку потоки объединены, становится проблемой, когда ThreadLocal висит на ресурсе даже после обработки каждого запроса.

Предложения:

  • Используйте фильтр подобной обертки для каждого взаимодействия, чтобы очистить ThreadLocal в конце каждого взаимодействия.
  • Вы можете использовать альтернативу SimpleDateFormat, например FastDateFormat из commons-lang или Joda, поскольку кто-то уже предложил
  • Просто создайте новый SimpleDateFormat каждый раз, когда вам это нужно. Кажется расточительным я знаю, но в большинстве приложений вы просто не заметите разницу

Ответ 5

Просто чтобы добавить к тому, что сказал @Neil Coffey, это не должно быть проблемой, если ваш экземпляр ThreadLocal статичен. Поскольку вы храните вызов get() в статическом экземпляре, он всегда должен содержать ту же ссылку на ваш простой формат даты. Поэтому, как сказал Нил, когда поток прекращается, единственный экземпляр простого форматирования даты должен иметь право на сбор мусора.

Если у вас есть номера или какая-то другая форма отладки, которая показывает эти проблемы с ресурсами, то это еще одна история. Но я считаю, что это не должно быть проблемой.

Ответ 6

В вашем примере не должно быть проблем с использованием ThreadLocal вообще.

Местные жители нитей (и одиночные игры тоже!) становятся проблемой, когда локаторы потоков устанавливаются в экземпляры, загруженные загрузчиком классов, которые будут выгружены позже. Типичная ситуация в контейнере сервлетов (например, tomcat):

  • Webapp устанавливает локальный поток во время обработки запроса.
  • Управление потоком осуществляется контейнером.
  • Webapp должен быть нераспределенным.
  • загрузчик классов Webapp не может быть сфотографирован, потому что есть ссылка слева: от потока локального до экземпляра до его класса до его загрузчика классов.

То же самое с синглтонами (java.sql.DriverManger и JDBC-драйверами, предлагаемыми webapp).

Поэтому избегайте таких вещей, особенно в средах, которые не находятся под вашим полным контролем!

Ответ 7

очистите поток локально после его использования, добавьте фильтр сервлета, чтобы сделать это:

protected ThreadLocal myThreadLocal = new ThreadLocal();

public void doFilter (ServletRequest req, ServletResponse res, chain) throws IOException, ServletException {
    try {
        // Set ThreadLocal (eg. to store heavy computation result done only once per request)
        myThreadLocal.set(context());

        chain.doFilter(req, res);
    } finally {
        // Important : cleanup ThreaLocal to prevent memory leak
        userIsSmartTL.remove();
    }
}