Что означает "атомный" в программировании?

В книге "Эффективная Java" говорится:

Спецификация языка гарантирует, что чтение или запись переменная является атомарной, если переменная не имеет тип long или double [JLS, 17.4.7].

Что означает "атомный" в контексте программирования Java или программирования вообще?

Ответ 1

Вот пример, потому что пример часто яснее длинного объяснения. Предположим, что foo является переменной типа long. Следующая операция не является атомной операцией:

foo = 65465498L;

Действительно, переменная записывается с использованием двух отдельных операций: первая, которая записывает первые 32 бита, и вторую, которая записывает последние 32 бита. Это означает, что другой поток может прочитать значение foo и увидеть промежуточное состояние. Выполнение атома операции состоит в использовании механизмов синхронизации, чтобы убедиться, что операция видна из любого другого потока в виде одиночной атомной (то есть не разделенной по частям) операции. Это означает, что любой другой поток, как только операция будет сделана атомарной, либо увидит значение foo перед назначением, либо после назначения. Но никогда не промежуточное значение.

Простой способ сделать это - сделать переменную изменчивой:

private volatile long foo;

Или для синхронизации каждого доступа к переменной:

public synchronized void setFoo(long value) {
    this.foo = value;
}

public synchronized long getFoo() {
    return this.foo;
}
// no other use of foo outside of these two methods, unless also synchronized

Или заменить его на AtomicLong:

private AtomicLong foo;

Ответ 2

"Атомная операция" означает операцию, которая кажется мгновенной с точки зрения всех других потоков. Вам не нужно беспокоиться о частично полной операции, когда применяется гарантия.

Ответ 3

Это то, что "кажется, что остальная часть системы происходит мгновенно", и подпадает под категорию Linearizability в вычислительных процессах. Чтобы процитировать эту связанную статью далее:

Атомность - это гарантия изоляции от параллельных процессов. Кроме того, атомарные операции обычно имеют преемственность или неудачу определение - они либо успешно меняют состояние системы, или не имеют видимого эффекта.

Так, например, в контексте системы базы данных можно иметь "атомные коммиты", что означает, что вы можете нажимать набор обновлений для реляционной базы данных, и эти изменения будут либо представлены, либо ни один из них вообще в случае сбоя, таким образом, данные не становятся поврежденными и, следовательно, блокировками и/или очередями, следующей операцией будет другая запись или чтение, но только после факта. В контексте переменных и потоковой передачи это то же самое, что применимо к памяти.

Ваша цитата подчеркивает, что во всех случаях этого не должно ожидать поведения.

Ответ 4

В древней философии атом был конечной единицей материи, на которой основывались более сложные взгляды на материальную реальность. В компьютерном программировании атома описывает унитарное действие или объект, который по существу неделим, неизменен, цел и неприводим. Вот несколько способов использования:

1) В языке структурированных запросов атомная функция - это функция, которая либо завершит, либо вернется в исходное состояние, если произойдет прерывание питания или ненормальный конец.

2) В некоторых операционных системах Unix, атомарная операция - это операция, в которой никакое изменение не может происходить за время между установкой маски и получением сигнала для изменения маски.

3) В некоторых языках программирования, включая Lisp, атом является базовой единицей исполняемого кода или данных.

Операция, в течение которой процессор может одновременно считывать местоположение и записывать его в одну и ту же операцию шины. Это не позволяет любому другому процессору или устройству ввода/вывода записывать или считывать память до завершения операции.

Атомный подразумевает неделимость и неприводимость, поэтому атомная операция должна выполняться полностью или вообще не выполняться.

Ответ 5

Просто нашел сообщение Atomic vs. Non-Atomic Operations, чтобы быть очень полезным для меня.

"Операция, действующая на общую память, является атомарной, если она завершается за один шаг относительно других потоков.

Когда хранилище атомов выполняется в разделяемой памяти, ни один другой поток не может наблюдать полуоболочку модификации.

Когда атомная нагрузка выполняется с общей переменной, она считывает все значение, как оно появилось за один момент времени."

Ответ 6

Если у вас несколько потоков, выполняющих методы m1 и m2 в коде ниже:

class SomeClass {
    private int i = 0;

    public void m1() { i = 5; }
    public int m2() { return i; }
}

у вас есть гарантия, что любой поток, вызывающий m2, будет либо читать 0, либо 5.

С другой стороны, с этим кодом (где i длинный):

class SomeClass {
    private long i = 0;

    public void m1() { i = 1234567890L; }
    public long m2() { return i; }
}

поток, вызывающий m2, мог читать 0, 1234567890L или какое-либо другое случайное значение, потому что утверждение i = 1234567890L не гарантировано быть атомарным для long (JVM мог записать первые 32 бита, а последние 32 бит в двух операциях и поток может наблюдать i между ними). ​​