Фитонциды против атомной [дубликат]
этот вопрос уже есть ответ здесь:
- В чем разница между atomic / volatile / synchronized? 6 ответов
Я читал где-то ниже линии.
ключевое слово Java volatile не означает атомарный, его распространенное заблуждение что после объявления переменной,
++
операция будет атомной, чтобы сделать операция atomic вам все равно нужно обеспечить эксклюзивный доступ с помощьюsynchronized
метод или блок в Java.
Так что же произойдет, если два потока атакуют a volatile
примитивная переменная в то же время?
означает ли это, что тот, кто берет блокировку на него, что будет устанавливать его значение в первую очередь. И если в то же время какой-то другой поток появляется и читает старое значение, пока первый поток меняет свое значение, то не новый поток будет читать его старый ценность?
в чем разница между атомной и ключевое слово volatile?
6 ответов:
эффект
volatile
ключевое слово-это примерно то, что каждая отдельная операция чтения или записи в этой переменной является атомарной.примечательно, однако, что операция, которая требует более одного чтения / записи - например,
i++
, что эквивалентноi = i + 1
, что не читать и писать -- это не атомарный, так как другой поток может писать вi
между чтением и записью.The
Atomic
классов, какAtomicInteger
иAtomicReference
, обеспечить более широкий спектр операций атомарно, в частности, включая инкремент дляAtomicInteger
.
летучие и атомарные-это две разные концепции. Volatile гарантирует, что определенное ожидаемое состояние (память) верно для разных потоков, в то время как Atomics гарантирует, что операции с переменными выполняются атомарно.
возьмем следующий пример двух потоков в Java:
Thread A:
value = 1; done = true;
Поток B:
if (done) System.out.println(value);
начиная с
value = 0
иdone = false
правило резьбы говорит нам, что оно не определено, является ли поток B выведет значение. кроме того стоимостью также не определено в этот момент! чтобы объяснить это, вам нужно немного знать об управлении памятью Java (которое может быть сложным), короче говоря: потоки могут создавать локальные копии переменных, а JVM может переупорядочивать код для его оптимизации, поэтому нет никакой гарантии, что приведенный выше код выполняется именно в таком порядке. Установка сделано в true и затем установка значения 1 может быть возможным результатом JIT процессы оптимизации.
volatile
только гарантирует, что в момент доступа к такой переменной новое значение будет сразу видно всем остальным потокам и порядок выполнения гарантирует, что код находится в состоянии, которое вы ожидаете. Так что в случае кода выше, определяяdone
как летучие гарантирует, что всякий раз, когда поток B проверяет переменную, она либо ложна, либо истинна, и если это правда, тоvalue
имеет значение 1 Как что ж.как побочный эффект летучие, значение такой переменной задается по всему потоку атомарно (при очень незначительной стоимости скорости выполнения). Однако это важно только для 32-разрядных систем, которые используют длинные (64-разрядные) переменные (или аналогичные), в большинстве других случаев установка/чтение переменной является атомарным в любом случае. Но есть важное различие между атомарным доступом и атомной операцией. Volatile только гарантирует, что доступ является атомарным, в то время как Атомика убедитесь, что операция атомарно.
рассмотрим пример:
i = i + 1;
независимо от того, как вы определяете i, другой поток, считывающий значение только тогда, когда выполняется приведенная выше строка, может получить i или i + 1, потому что операция не атомарно. Если другой поток устанавливает i в другое значение, в худшем случае я мог бы вернуться к тому, что было раньше потоком A, потому что это было только в середине вычисления i + 1 на основе старого значения, а затем снова установите i в это старое значение + 1. Пояснение:
Assume i = 0 Thread A reads i, calculates i+1, which is 1 Thread B sets i to 1000 and returns Thread A now sets i to the result of the operation, which is i = 1
Атомики, такие как AtomicInteger, гарантируют, что такие операции происходят атомарно. Таким образом, вышеуказанная проблема не может произойти, я бы либо 1000, либо 1001, как только оба потока будут завершены.
есть два важных понятия в многопоточной среде.
- атомарность
- видимость
Volatile
устраняет проблему видимости, но она не имеет дело с атомарностью.Volatile
не позволит компилятору переупорядочить инструкцию, которая включает запись и последующее чтение изменчивой переменной. например,k++
Здесьk++
это не одна машинная инструкция, а три машины инструкции.
- скопируйте значение для регистрации
- наоборот
- поместить его обратно
так что даже если вы объявляете переменную
volatile
это не сделает эту операцию атомарной, что означает, что другой поток может видеть промежуточный результат, который является устаревшим или нежелательным значением для другого потока.но
AtomicInteger
,AtomicReference
на основе сравнить и поменять инструкция. CAS имеет три операнда: a место памятиV
на котором работать, ожидаемое старое значениеA
, и новое значениеB
.CAS
атомарно обновляетV
новое значениеB
, но только если значениеV
соответствует ожидаемому старому значениюA
; в противном случае он ничего не делает. В любом случае, он возвращает значение в настоящее время вV
. Это используется JVM вAtomicInteger
,AtomicReference
и они называют функции какcompareAndSet()
. Если эта функция не поддерживается базовым процессором, то JVM реализует его с помощью spin lock.
как ни старайся,
volatile
имеет дело только с видимостью.рассмотрим этот фрагмент в параллельной среде:
boolean isStopped = false; : : while (!isStopped) { // do some kind of work }
идея здесь заключается в том, что некоторый поток может изменить значение
isStopped
от false к true, чтобы указать последующему циклу, что пришло время прекратить цикл.интуитивно, нет никаких проблем. Логично, если другой поток делает
isStopped
равен true, то цикл должен завершиться. Реальность такова, что цикл, скорее всего, никогда не завершится, даже если другой поток делаетisStopped
равно true.причина этого не интуитивно понятна, но учтите, что современные процессоры имеют несколько ядер и что каждое ядро имеет несколько регистров и несколько уровней кэш-памяти, которые недоступны для других процессоров. Другими словами, значения, которые кэшируются в локальной памяти одного процессора являются не видно для потоков, выполняющихся на разных процессорах. В этом заключается одна из центральных проблем параллелизма: видимость.
модель памяти Java не дает никаких гарантий относительно того, когда изменения, внесенные в переменную в потоке, могут стать видимыми для других потоков. Чтобы гарантировать, что обновления будут видны сразу же после их создания, необходимо выполнить синхронизацию.
The
volatile
ключевое слово является слабой формой синхронизации. Хотя он ничего не делает для взаимного исключения или атомарности, он обеспечивает гарантию того, что изменения, внесенные в переменную в одном потоке, будут видны другим потокам, как только они будут сделаны. Поскольку отдельные чтения и записи в переменные, которые не являются 8 байтами, являются атомарными в Java, объявляя переменныеvolatile
обеспечивает легкий механизм для обеспечивать видимость в ситуациях где никакие другие требования к атомарности или взаимного исключения.
The
volatile
ключевое слово используется:
- чтобы сделать неатомные 64-разрядные операции атомарными:
long
иdouble
. (все другие, примитивные обращения уже гарантированно будут атомарными!)- чтобы гарантировать, что обновления переменных будут видны другим потокам + эффекты видимости: после записи в переменную volatile все переменные, которые были видны до записи этой переменной, становятся видимыми для другого потока после чтения той же переменной volatile (бывает-перед заказом).
The
java.util.concurrent.atomic.*
классов, в соответствии с java docs:небольшой набор классов, поддерживающих потокобезопасность без блокировки программирование на отдельных переменных. По сути, классы в этом пакет расширяет понятие изменчивых значений, полей и массива элементы для тех, которые также обеспечивают атомарное условное обновление работа формы:
boolean compareAndSet(expectedValue, updateValue);
атомарные классы построены вокруг атомарного
compareAndSet(...)
функция, которая сопоставляется с атомной инструкцией процессора. Атомарные классы вводят происходят-перед заказ какvolatile
переменные. (за одним исключением:weakCompareAndSet(...)
).из документов java:
когда поток видит обновление атомарной переменной, вызванное weakCompareAndSet, он не обязательно видит обновления для любого другого переменные, которые произошли до weakCompareAndSet.
на ваш вопрос:
означает ли это, что кто бы ни взял блокировку на нем, это будет настройка его значение в первую очередь. И если тем временем, появится какая-то другая нить и прочитать старое значение, пока первый поток не меняет своего значения, то не новый поток будет читать его старое значение?
вы ничего не блокируете, то, что вы описываете, является типичным состоянием гонки, которое будет произойдет в конечном итоге, если потоки получают доступ к общим данным без надлежащей синхронизации. Как уже упоминалось объявление переменной
volatile
в этом случае будет только гарантировать, что другие потоки увидят изменение переменной (значение не будет кэшироваться в регистре некоторого кэша, который виден только одним потоком).в чем разница между
AtomicInteger
иvolatile int
?
AtomicInteger
обеспечивает атомарные операции наint
при правильном синхронизация (например.incrementAndGet()
,getAndAdd(...)
, ...),volatile int
просто обеспечит видимостьint
к другим потокам.
Так что же произойдет, если два потока атакуют изменчивую примитивную переменную одновременно?
обычно каждый из них может увеличить значение. Однако когда-нибудь оба будут обновлять значение одновременно и вместо увеличения на 2 итого, оба потока увеличиваются на 1 и добавляется только 1.
означает ли это, что тот, кто берет блокировку на него, что будет устанавливать его значение в первую очередь.
нет замка. То есть что
synchronized
для.и если тем временем какой-то другой поток появляется и читает старое значение, пока первый поток меняет свое значение, то разве новый поток не будет читать свое старое значение?
да
в чем разница между атомной и ключевое слово volatile?
AtomicXxxx обертывает летучие, поэтому они в основном одинаковы, разница в том, что он обеспечивает операции более высокого уровня, такие как CompareAndSwap, которые используется для реализации инкремента.
AtomicXxxx также поддерживает lazySet. Это похоже на изменчивый набор, но не останавливает конвейер, ожидая завершения записи. Это может означать, что если Вы читаете значение, которое вы просто пишете, вы можете увидеть старое значение, но вы все равно не должны этого делать. Разница в том, что установка volatile занимает около 5 НС, bit lazySet занимает около 0,5 НС.