Фитонциды против атомной [дубликат]


этот вопрос уже есть ответ здесь:

  • В чем разница между atomic / volatile / synchronized? 6 ответов

Я читал где-то ниже линии.

ключевое слово Java volatile не означает атомарный, его распространенное заблуждение что после объявления переменной, ++ операция будет атомной, чтобы сделать операция atomic вам все равно нужно обеспечить эксклюзивный доступ с помощью synchronized метод или блок в Java.

Так что же произойдет, если два потока атакуют a volatile примитивная переменная в то же время?

означает ли это, что тот, кто берет блокировку на него, что будет устанавливать его значение в первую очередь. И если в то же время какой-то другой поток появляется и читает старое значение, пока первый поток меняет свое значение, то не новый поток будет читать его старый ценность?

в чем разница между атомной и ключевое слово volatile?

6 76

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, как только оба потока будут завершены.

есть два важных понятия в многопоточной среде.

  1. атомарность
  2. видимость

Volatile устраняет проблему видимости, но она не имеет дело с атомарностью. Volatile не позволит компилятору переупорядочить инструкцию, которая включает запись и последующее чтение изменчивой переменной. например,k++ Здесь k++ это не одна машинная инструкция, а три машины инструкции.

  1. скопируйте значение для регистрации
  2. наоборот
  3. поместить его обратно

так что даже если вы объявляете переменную 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 НС.