А также этот пакет содержит классы обновления, такие как AtomicReferenceFieldUpdater, которые можно использовать для операций compareAndSet для поля volatile класса.
Метод compareAndSet означает «Обновить переменную этим новым значением, но отказать, если другой поток изменил значение после моего последнего просмотра».
В этом примере сначала создается экземпляр AtomicInteger с начальным значением 123.
Затем сравнивается значение AtomicInteger с ожидаемым значением 123, и, если они равны, новое значение AtomicInteger становится 234.
Среди других атомарных классов также есть такие классы как AtomicBoolean и AtomicLong.
Для переменных типа Float и Double атомарность можно обеспечить с помощью классов AtomicInteger и AtomicLong и методов конвертации floatToIntBits, intBitstoFloat, doubleToLongBits, и longBitsToDouble.
В случае атомарных классов недостатком является то, что, если не получается установить значение из-за гонки с другим потоком, попытка установить значение будет повторяться.
При высокой конкуренции это может превратиться в прямую блокировку, в которой поток должен постоянно пытаться установить значение в бесконечном цикле, пока он не преуспеет.
Поддержание одного единственного счетчика, суммы и т. д., значения которого обновляется, возможно, многими потоками, является общей проблемой масштабируемости.
И масштабируемая поддержка обновляемых переменных представлена с помощью таких классов, как DoubleAccumulator, DoubleAdder, LongAccumulator, LongAdder, в которых используются техники сокращения конкуренции, которые обеспечивают значительное увеличение пропускной способности по сравнению с атомарными переменными.
Классы LongAdder и DoubleAdder могут использоваться в качестве альтернативы AtomicLong для последовательного сложения чисел.
С точки зрения использования, применение этих классов очень похоже на использование атомарных классов.
Просто создается LongAdder и используются его методы, такие как intValue и add, чтобы получить и установить значение.
Магия происходит за кулисами.
Что делает этот класс, когда операция сравнения и замены не удается из-за конкуренции, этот класс хранит дельту во внутреннем объекте ячейки, выделенном для этого потока.
Затем он добавляет значение ожидающих ячеек в сумму при вызове функции intValue.
Это уменьшает необходимость возврата и выполнения операции сравнения и замены.
Таким образом, вместо того, чтобы складывать числа сразу, этот класс просто хранит у себя набор слагаемых, чтобы уменьшить взаимодействие между потоками.
Этот класс используется в ситуациях, когда добавлять числа приходится гораздо чаще, чем запрашивать результат.
И несложно догадаться, что, давая прирост в производительности, LongAdder требует гораздо большего количества памяти из-за того, что он хранит все слагаемые.
Классы LongAccumulator и DoubleAccumulator можно использовать для накопления результатов в соответствии с предоставленным LongBinaryOperator и DoubleBinaryOperator.
То есть вместо простого сложения класс обрабатывает входящие значения с помощью лямбды типа LongBinaryOperator или DoubleBinaryOperator, которая передаётся при инициализации.
Так же, как и Adder, Accumulator хранит весь набор переданных значений в памяти, уменьшая взаимодействие между потоками.
Важно помнить, что Accumulator будет работать правильно, если мы снабдим его коммутативной функцией, где порядок накопления не имеет значения.
В этом примере мы создаем LongAccumulator, который добавляет новое значение к значению, которое уже было в накопителе.
При передаче числа в качестве аргумента методу accumulate, этот метод вызовет функцию sum.
ThreadLocal
Предположим, что у нас есть веб приложение, которое состоит из многих компонентов, и нам в любой точке кода может понадобится информация о пользователе, от которого пришел http запрос.
Причем не в каждой точке кода будет доступ к Http сессии, поэтому не везде можно будет узнать от какого пользователя пришел запрос.
Встает вопрос, что делать.
Добавлять в каждый метод каждого класса дополнительный параметр, представляющий данные пользователя?
Эту проблему можно решить с помощью переменной ThreadLocal.
С использованием ThreadLocal мы можем привязать данные о пользователе к потоку обработки http запроса, и достать эту информацию в любом месте программы.
ThreadLocal можно рассматривать как область доступа потока, например, область запроса или область сеанса.
Вы можете установить любой объект в ThreadLocal, и этот объект будет своим для каждого потока.
К значениям, хранящимся в ThreadLocal, можно получить доступ из любой точки внутри этого потока.
Если поток вызывает методы из нескольких классов, то все методы могут видеть переменную ThreadLocal, заданную другими методами, потому что они выполняются в одном потоке.
При этом значения, хранящиеся в Thread Local, являются уникальными для потока, то есть каждый поток будет иметь собственную переменную Thread.
Один поток не может получить доступ и изменить переменную ThreadLocal другого потока.
ExecutorService и пул потоков
Вильям Л Саймон , Вильям Саймон , Наталья Владимировна Макеева , Нора Робертс , Юрий Викторович Щербатых
Зарубежная компьютерная, околокомпьютерная литература / ОС и Сети, интернет / Короткие любовные романы / Психология / Прочая справочная литература / Образование и наука / Книги по IT / Словари и Энциклопедии