Что такое спин -блокировка
Говоря о спиновых замках, нам нужно начать с механизма блокировки под многопоточным. Поскольку некоторые ресурсы в многопроцессорной системной среде ограничены, они иногда требуют взаимного исключения. В настоящее время будет введен механизм блокировки. Только процесс, который приобретает блокировку, может получить доступ к ресурсам. То есть только один процесс может приобрести замок за раз, чтобы войти в свою критическую область. В то же время два или более процессов не могут войти в критическую область. При выходе из критической области замок будет выпущен.
При разработке алгоритма Mutex вы всегда сталкиваетесь с ситуацией, когда у вас нет замка, то есть что вы должны делать, если не получите замок?
Обычно есть 2 способа справиться с этим:
Одним из них является то, что вызывающий абонент, который не получил замок, зацикливается там, чтобы увидеть, выпустил ли держатель спинового блокировки. Это в центре внимания этой статьи - Spin Lock. Ему не нужно блокировать город линии (не блокировки).
Другой способ заключается в том, что процесс без получения блоков блокировки сам (блокировку) и продолжает выполнять другие задачи в потоке, который является мутекс (включая встроенный синхронизированный блокировки, повторный зал и т. Д.).
введение
CAS (сравнение и обмен), то есть сравнение и обмен, также является основной операцией, которая реализует то, что мы обычно называем спин -блокировкой или оптимистичным блокировкой.
Его реализация очень проста, которая заключается в сравнении ожидаемого значения с значением памяти. Если два значения равны, замените значение памяти на ожидаемое значение и верните True. В противном случае вернуть ложь.
Обеспечить атомную работу
Любая технология возникает для решения определенных конкретных проблем. Проблема, которую необходимо решить CAS, заключается в обеспечении атомных операций. Что такое атомная операция? Атомы являются наименьшим и непристойным, а атомная операция является самой маленькой и непристойной работой. То есть, как только операция начнется, ее нельзя прервать и знает, что операция завершена. В многопоточной среде атомные операции являются важным средством для обеспечения безопасности потока. Например, предположим, что работают два потока, и они хотят изменить определенное значение. Возьмите операцию самостоятельного достижения в качестве примера. Для выполнения операции самостоятельного введения в целое число I требуется три основных шага:
1. Прочитайте текущее значение I;
2. Добавить 1 к значению I;
3. Напишите значение I обратно в память;
Предположим, что оба процесса читают текущее значение I, предполагая, что это 0, в настоящее время резьба A добавляет 1 к I, температуру B также добавляет 1, и, наконец, I - 1, а не 2. Это связано с тем, что операция автоинспентации не является атомной работой, а три шага, разделенные на то, с чем можно вмешиваться. Как и в примере ниже, для 10 потоков каждый поток выполняет 10 000 операций I ++, ожидаемое значение составляет 100 000, но, к сожалению, результат всегда составляет менее 100 000.
статический int i = 0; public static void add () {i ++; } частный статический класс плюс реализует runnable {@Override public void run () {for (int k = 0; k <10000; k ++) {add (); }}} public static void main (string [] args) бросает прерывание {thread [] Threads = новый поток [10]; for (int i = 0; i <10; i ++) {threads [i] = new Thread (new Plus ()); Threads [i] .start (); } for (int i = 0; i <10; i ++) {threads [i] .join (); } System.out.println (i); }В этом случае, что мне делать? Правильно, возможно, вы уже подумали об этом, вы можете заблокировать или использовать синхронизированную реализацию, например, изменить метод add () на следующее:
публичный синхронизированный статический void add () {i ++; }В качестве альтернативы, операция блокировки реализована, например, с использованием reentrantlock (reentrantlock).
частная статическая блокировка блокировки = new Reentrantlock (); public static void add () {lock.lock (); i ++; lock.unlock (); } CAS реализует спин -блокировку
Поскольку атомные операции могут быть реализованы с использованием ключевого слова блокировки или синхронизации, зачем использовать CAS? Поскольку блокировка или использование синхронизированных ключевых слов приносит большую потерю производительности, в то время как использование CAS может достичь оптимистичной блокировки. На самом деле он напрямую использует инструкции на уровне процессора, поэтому производительность очень высока.
Как упомянуто выше, CAS является основой для реализации спиновых замков. CAS использует инструкции процессора, чтобы обеспечить атомичность операции для достижения эффекта блокировки. Что касается спина, то также очень ясно читать буквальное значение. Если вы вращаете его сами, это петля. Обычно он реализуется с использованием бесконечной петли. Таким образом, операция CAS выполняется в бесконечной петле. Когда операция успешна и возвращает истину, петля заканчивается; Когда ложно, петля выполняется, и операция CAS не будет продолжена до возврата True.
Фактически, многие места в JDK используют CAS, особенно в пакете Java.Util.concurrent, таких как Countdownlatch, Semaphore, Reentrantlock и Java.util.concurrent.atomic Package. Я считаю, что все использовали атомные*, такие как Atomicboolean, Atomicinteger и т. Д.
Здесь мы принимаем Atomicboolean в качестве примера, потому что это достаточно просто.
Общедоступный класс Atomicboolean реализует java.io.serializable {Private Static Long Long SerialVersionuid = 4654671469794556979L; // Настройка для использования uncafe.compareAndswapint для обновлений Частный статический окончательный конечный небезопасный небезопасный = небезопасно.getunsafe (); частный статический окончательный длительный сет; static {try {valueOffset = uncefe.objectFieldOffset (atomicboolean.class.getDeclaredfield ("value")); } catch (Exception ex) {бросить новую ошибку (ex); }} частное изменение int value; public final Boolean get () {return Value! = 0; } public final Boolean Compareandeset (Boolean ожидание, логическое обновление) {int e = ожидание? 1: 0; int u = обновление? 1: 0; вернуть uncafe.compareandswapint (это, valueoffset, e, u); }}Это является частью Кодекса Atomicboolean, и мы видим несколько ключевых методов и свойств здесь.
1. Используется объект sun.misc.unsafe. Этот класс предоставляет ряд методов для непосредственной эксплуатации объектов памяти, но используется только внутри JDK и не рекомендуется для разработчиков;
2. Значение представляет фактическое значение. Вы можете видеть, что метод GET фактически судит логическое значение, основанное на том, равно ли значение 0. Значение здесь определяется как летучие, поскольку волатильное может обеспечить видимость памяти, то есть до тех пор, пока значение значения изменяется, другие потоки могут сразу увидеть измененное значение. В следующей статье рассказывается о видимости нестабильности, добро пожаловать
3.
4. Метод сравнения, это основной метод реализации CAS. При использовании метода Atomicboolean вам необходимо пройти только ожидаемое значение и значение, которое нужно обновлять. Вызов метод небезопасно. Это собственный метод, реализованный в C ++, и конкретный код не будет опубликован. Короче говоря, он использует инструкцию CPU CMMPXCHG для завершения сравнения и замены. Конечно, в зависимости от конкретной версии системы, существуют также различия в реализации. Те, кто заинтересован, могут сами искать соответствующие статьи.
Используйте сценарии
Например, Atomicboolean может использоваться в таком сценарии. Система должна определить, необходимо ли выполнять некоторые операции инициализации на основе свойств состояния логической переменной. Если это многопоточная среда и избегать повторных выполнений, она может быть реализована с использованием Atomicboolean. Псевдокод выглядит следующим образом:
Частный финальный статический атомный флаг = новый Atomicboolean (); if (flag.compareAndset (false, true)) {init (); }Например, AtomicInteger может использоваться в прилавках и в многопоточных средах для обеспечения точного подсчета.
АБА вопросы
Существует проблема с CAS, которая заключается в том, что значение изменяется от A на B, а затем от B на A. В данном случае CAS подумает, что значение не изменилось, но на самом деле оно изменилось. В связи с этим в параллельных пакетах существует AtomicStampedReference, которая обеспечивает реализацию, основанную на номере версии, которая может решить некоторые проблемы.
Суммировать
Вышеуказанное - все содержание этой статьи. Я надеюсь, что содержание этой статьи имеет определенную справочную ценность для каждого обучения или работы. Если у вас есть какие -либо вопросы, вы можете оставить сообщение для общения. Спасибо за поддержку Wulin.com.