Сделайте потокобезопасным обычный класс с помощью ThreadLocal‹T›

У меня есть обычный класс, предназначенный для доступа к одному потоку, и я хочу сделать его thread-safe, чтобы многие потоки могли использовать один экземпляр одновременно. Есть некоторые методы и переменные уровня класса, которые я сделаю статическими и, используя locks, сделаю их thread-safe. Также методы, которые только используют локальные переменные, по умолчанию безопасны (каждый поток имеет свой стек).

Мой вопрос касается properties старого класса или вообще любой переменной non-static. Могу ли я просто использовать ThreadLocal<T>, и каждый поток имеет свой собственный набор properties? Конечно, я буду использовать locks и другие проблемы thread-safety внутри setters (я предполагаю, что getters безопасны).

И является ли ThreadLocal<T> убийцей производительности?


person Xaqron    schedule 29.12.2010    source источник
comment
Без описания того, что делает этот класс и почему могут возникать помехи от нескольких потоков, никто не сможет дать вам хороший ответ.   -  person Anon    schedule 30.12.2010
comment
Что именно, по вашему мнению, делает ThreadLocal? Потому что я не думаю, что он делает то, что вы думаете. Можете ли вы объяснить, почему вы считаете, что локальное хранилище потоков является правильным решением?   -  person Eric Lippert    schedule 30.12.2010
comment
@Eric: я читал, что это делает переменную локальной для потока. Итак, у нас столько свойств, сколько запущенных потоков. Таким образом, объект может иметь состояние для каждого потока.   -  person Xaqron    schedule 30.12.2010
comment
Правильно: он создает состояние для каждого потока. Итак, предположим, что у вас есть объект Customer со свойством Name, доступ к которому осуществляется из двух разных потоков. Ваша идея о том, как сделать поток объекта Customer безопасным, чтобы у клиента было два разных имени, в зависимости от того, какой поток запрашивает? Локальное хранилище потока почти никогда не является тем, что вам нужно при создании объекта, ориентированного на многопотоковое исполнение, поэтому я просто хочу убедиться, что вы лаете в правильном направлении.   -  person Eric Lippert    schedule 30.12.2010
comment
Данные принадлежат потокам. Я имею в виду, что класс работает как поставщик услуг для потоков, но его методы должны использовать данные для правильного функционирования одного и того же потока (работающий поток получит правильный ответ на основе своих собственных данных).   -  person Xaqron    schedule 30.12.2010
comment
Тогда это звучит так, как будто вы смотрите на правильную вещь. Однако меня беспокоит ваш комментарий о том, что блокировки должны выполняться сеттерами, а не геттерами. Это не имеет никакого смысла. Что, если геттер запускается, пока сеттер находится на полпути к установке свойства? Если вы собираетесь использовать блокировки, имеет смысл всегда использовать их.   -  person Eric Lippert    schedule 30.12.2010
comment
Что касается вопроса производительности: вы единственный, кто может ответить на него. Напишите несколько тестов и измерьте производительность в реальных ситуациях и посмотрите, приемлема ли эта производительность для ваших пользователей. Мы не знаем, какое оборудование вы используете, сколько памяти вы потребляете и нужен ли вашим клиентам код, который дает правильный ответ за две минуты или две микросекунды.   -  person Eric Lippert    schedule 30.12.2010


Ответы (2)


Добытчики не так безопасны, как вы думаете. Модель памяти Java дает каждому потоку собственное представление кучи, поэтому, если вы не синхронизируете доступ к переменным, потоки могут читать устаревшие данные. Создание переменной volatile предотвратит устаревшее чтение и подойдет для примитивов, но volatile не сделает доступ атомарным.

В пакете java.util.concurrent есть куча классов, которые могут вам помочь. Писать потокобезопасный код сложно, поэтому я бы порекомендовал прочитать хорошую книгу на эту тему. "Параллелизм Java на практике" Брайана Гетца довольно хорош.

person Cameron Skinner    schedule 29.12.2010
comment
кто-то добавил Java в теги вопросов (отредактировано). Это класс С#. - person Xaqron; 30.12.2010
comment
Ах. Что ж, если вы когда-нибудь будете что-то делать на Java, помните о памяти. - person Cameron Skinner; 30.12.2010

Это не совсем то, для чего нужны локальные потоки. Они предназначены для случаев, когда каждый поток будет иметь свои собственные данные.

В вашем случае я бы предложил изменить тип поля на Map<Object, Object> и использовать Collections.synchronizedMap, чтобы сделать его потокобезопасным.

person sblundy    schedule 29.12.2010
comment
кто-то добавил Java к тегам вопросов (отредактировано). Это C# класс. - person Xaqron; 30.12.2010