Фитонциды против атомной [дубликат]
этот вопрос уже есть ответ здесь:
- В чем разница между 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 НС.