Использование ThreadLocal в переменных экземпляра

Делать JavaThreadLocal переменные создают локальные значения потока, если они используются в качестве переменных экземпляра (например, в методе, который генерирует локальные объекты потока), или они всегда должны быть статическими для этого?

В качестве примера предположим типичный сценарий, в котором несколько, дорогостоящих для инициализации объектов класса, которые не являются поточно-ориентированными, должны быть созданы в одном статическом блоке инициализации, хранящемся в статических переменных одного класса (например, вMap структура данных) и с тех пор используется для интенсивной обработки многочисленными различными потоками.

Для достижения безопасности потока, очевидно, должна быть передана отдельная копия каждого статического объекта. Например, JavaDateFormat объекты, которые необходимо безопасно использовать в разных потоках.

Во многих примерах, которые можно найти в Интернете, подход, по-видимому, объявляет каждыйThreadLocal переменная, создать новый объект вinitialValue() метод, а затем использоватьget() метод, чтобы получить локальный экземпляр потока.

Этот подход не очень эффективен, если создаются десятки или сотни таких объектов, каждый из которых имеет свои параметры инициализации. Например, многиеSimpleDateFormat объекты с различным шаблоном даты каждый.

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

Исходя из вышеизложенного, следующий общий статический метод не будет работать, поскольку одна и та же ссылка создается при каждом вызове initialValue ():

// Each value is an object initialized prior to calling getLocal(...)
public static final <T> T getLocal(final T value)
{
    ThreadLocal<T> local = new ThreadLocal<T>()
    {
        @Override
        protected T initialValue()
        {
            return value;
        }
    };

    return local.get();
}

Вместо этого необходим механизм для создания нового объекта в initialValue (). Таким образом, единственный общий подход, вероятно, использует отражение в схеме, аналогичной

private static final <T> T getLocal(
        final Constructor<T> constructor, final Object[] initargs)
{
    ThreadLocal<T> local = new ThreadLocal<T>()
    {           
        @Override
        protected T initialValue()
        {
            T value = null;

            try // Null if the value object cannot be created
            {
                value = constructor.newInstance(initargs);
            }
            catch (Exception e)
            {
            }

            return value;
        }
    };

    return local.get();
}

Затем, конечно, есть опция для конкретного типа, где можно просто использоватьThreadLocal шаблон в цикле для объявления каждой переменной.

Например, в случаеDateFormatв одном статическом блоке инициализации можно

private static String[] patterns = ... // Get date patterns
private static DateFormat format;

public static Map<String, DateFormat> formats = new HashMap<String, DateFormat>();

static
{
    for (final String pattern:patterns)
    {
        format = new ThreadLocal<DateFormat>()
        {           
                @Override
            protected DateFormat initialValue()
                {
            return new SimpleDateFormat(pattern);
            }
        }.get();

        formats.put(pattern, format);
}

С тех порformats карта будет читаться разными классами, в разных потоках, каждый раз, чтобы вызватьformat() или жеparse() метод одного или несколькихDateFormat объекты, хранящиеся на карте.

Имеет ли какой-либо из вышеперечисленных подходов смысл для описанного случая, или еслиThreadLocal объявления будут статичными?

Ответы на вопрос(2)

Ваш ответ на вопрос