プログラミングにおける「アトミック」とはどういう意味ですか?


276

効果的なJavaの本では、それは述べています:

言語仕様は、変数がタイプlongまたはdouble[JLS、17.4.7] でない限り、変数の読み取りまたは書き込みがアトミックであることを保証します。

「アトミック」とは、Javaプログラミングのコンテキスト、またはプログラミング全般の意味を教えてください。


24
一度に1つの操作。
Subhrajyoti Majumder 2013

1
変数に対して一度に実行できる操作は1つだけです。
kaysush



一部の変数はデフォルトではアトミックな読み取りと書き込みを持たないことに注意して、それらを宣言するvolatile longvolatile double、読み取りをアトミックにして書き込みをアトミックにします。
H2ONaCl 2016年

回答:


372

例は長い説明よりも明確であることが多いため、ここに例を示します。fooがタイプの変数であるとしますlong。次の操作はアトミック操作ではありません:

foo = 65465498L;

実際、変数は2つの別々の操作を使用して書き込まれます。最初の32ビットを書き込む操作と、最後の32ビットを書き込む2番目の操作です。つまり、別のスレッドがの値を読み取り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;

75
したがって、これは32ビットシステムで実行されていることを前提としています。64ビットシステムの場合はどうなりますか?foo = 65465498L; それならアトミックですか?
Harke、

46
@Harke 64ビットJavaを実行している場合は、そうです。
Jeroen 14

4
これはC#と.NETにも適用されますか?はいの場合、fooがアトミック動作を取得するには、CLRが64ビットである必要がありますか?
Fabiano 2015

5
@Fabianoこれは当てはまります。Javaのようなsynchronizedキーワードがないため、.NETでそれを実現する方法を次に示します。stackoverflow.com/questions/541194/…–
マフィンマン

2
次に、スレッドAがlong値を割り当て、スレッドBが途中で値を読み取ろうとしたとします。操作Aがアトミックの場合、スレッドBはそれが完了するまで待機しますか?これは、アトミック操作が暗黙のスレッドセーフを提供することを意味しますか?
Teoman Shipahi 16

60

「アトミック操作」とは、他のすべてのスレッドから見ると瞬時に見える操作を意味します。保証が適用される場合、部分的に完全な操作について心配する必要はありません。


25

これは、「システムの他の部分から瞬時に発生するように見え」、コンピューティングプロセスの線形化可能性の分類に該当するものです。そのリンクされた記事をさらに引用するには:

原子性は、並行プロセスからの分離を保証します。さらに、アトミック操作には通常、成功または失敗の定義があり、システムの状態を正常に変更するか、明らかな影響を与えません。

したがって、たとえば、データベースシステムのコンテキストでは、「アトミックコミット」を使用できます。つまり、更新の変更セットをリレーショナルデータベースにプッシュすると、それらの変更はすべて送信されるか、まったく送信されません。障害が発生した場合、このようにしてデータは破損せず、ロックやキューの結果として、次の操作は別の書き込みまたは読み取りになりますが、事後のみです。変数とスレッドのコンテキストでは、これはほとんど同じで、メモリに適用されます。

あなたの引用は、これがすべてのインスタンスで予期される動作である必要はないことを強調しています。


15

Atomic vs. Non-Atomic Operationsの投稿が私にとって非常に役立つことを見つけました。

「共有メモリに作用する操作は、他のスレッドと比較して単一のステップで完了する場合、アトミックです。

アトミックストアが共有メモリで実行されると、他のスレッドは変更が半分完了したことを確認できません。

共有変数でアトミックロードが実行されると、一度に表示された値全体が読み取られます。」


14

次のコードでメソッド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がaのアトミックであることが保証されていないためですlong(JVMは2つの操作で最初の32ビットと最後の32ビットを書き込むことができi、その間にスレッドが観察する可能性があります)。 。


「long」が問題を引き起こすのに対し、「int」は問題を引き起こさないと思いますか?こちらをご覧くださいgeekswithblogs.net/BlackRabbitCoder/archive/2012/08/09/...を
onmyway133

1
@entropyのlongおよびdouble割り当ては、Javaでアトミックであることが保証されていません。したがって、割り当て後にビットの半分だけが更新された長い読み取りができます。
assylias 2013

0

Javaでは、longとdoubleを除くすべてのタイプのフィールドの読み書きはアトミックに発生し、フィールドがvolatile修飾子で宣言されている場合、longとdoubleでもアトミックに読み書きされます。つまり、そこに何があったか、何が起こったのか、または変数に中間結果があり得ないかのいずれかで100%を取得します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.