JAVA同時プログラミング:三大特性-原子性
2514 ワード
生活する
生活は生まれて、生きていくことです.
————
JAVAでの同時プログラミングは,プログラムのスレッドセキュリティを保証するためには,コードの原子性,可視性,秩序性を保証する.今日はまず原子性についてお話しします.
原子性とは何ですか.
原子性、すなわち1つの操作または複数の操作は、すべて実行され、実行中に中断されないか、すべて実行されないかのいずれかです.(相互反発アクセスが提供され、同じ時点で1つのスレッドしかアクセスできません)
JAVA自体の原子性
JAVAメモリモデルにより原子変数操作を直接保証するread/load/use/assign/store/write,すなわち基本データ型の付与に対して,読み出し操作時に原子性を持つ.(32ビットシステムではlongタイプに対する付与読み取りは原子的ではない).
次の原子性を持つ操作はありますか?
第1のx=1は,単純な付与操作であり,原子性を満たす.第2条y=xは、実際には2つの操作であり、それぞれx変数を読み出し、xをyに付与する.この2つの操作はそれぞれ原子的であるが、合わせればそうではない.第3条x++は、実際には3つの操作であり、変数を先に読み出し、+1操作を行い、xに値を付与し、原子性第4条x=x+1を満たさない同上で、原子性を満たさない
原子性を満たさないケースを見てみましょう
期待値1000は,実際に何度走っても1000以下でありnum++という操作が原子性を満たさないことを示している.
JAVAが提供する原子力の技術保障は以下の通りである.
1、synchronized(反発ロック)2、Lock(反発ロック)3、原子類(CAS楽観ロック)
上記2つはいずれも反発ロックによって実現され,すなわち同じ時点で1つのスレッドのみがこの変数を操作することを許可し,原子性を保障し,何も言うことはない.原子類の実現は見ることができる.int変数に対応する原子類AtomicIntegerは、原子類によって原子性を実現するため、具体的なコード修正は以下の通りである:public static int num public static AtomicInteger num=new AtomicInteger(0);num++ num.incrementAndGet(); System.out.println(Inc.num); System.out.println(Inc.num.get());
結局何度走っても1000で、確かに原子性が実現したことを示しています.原子類の++の操作の細部はすべてincrementAndGetの中で、簡単にソースコードを見ます:unsafeの中の方法を呼び出します
原子類の利点:ロックをかける必要がなく、性能が良い.欠点:高い同時シーンの下で、CASが失敗する確率はとても高くて、長い時間のスピンはCPUの消耗が比較的に大きいことを招きます
後記
楽観ロック、悲観ロックについて2つの穴を埋めます.CASのABAについては後ほどお話しします.
生活は生まれて、生きていくことです.
————
JAVAでの同時プログラミングは,プログラムのスレッドセキュリティを保証するためには,コードの原子性,可視性,秩序性を保証する.今日はまず原子性についてお話しします.
原子性とは何ですか.
原子性、すなわち1つの操作または複数の操作は、すべて実行され、実行中に中断されないか、すべて実行されないかのいずれかです.(相互反発アクセスが提供され、同じ時点で1つのスレッドしかアクセスできません)
JAVA自体の原子性
JAVAメモリモデルにより原子変数操作を直接保証するread/load/use/assign/store/write,すなわち基本データ型の付与に対して,読み出し操作時に原子性を持つ.(32ビットシステムではlongタイプに対する付与読み取りは原子的ではない).
次の原子性を持つ操作はありますか?
x=1;
y=x;
x++;
x=x+1;
第1のx=1は,単純な付与操作であり,原子性を満たす.第2条y=xは、実際には2つの操作であり、それぞれx変数を読み出し、xをyに付与する.この2つの操作はそれぞれ原子的であるが、合わせればそうではない.第3条x++は、実際には3つの操作であり、変数を先に読み出し、+1操作を行い、xに値を付与し、原子性第4条x=x+1を満たさない同上で、原子性を満たさない
原子性を満たさないケースを見てみましょう
public class YZXTest {
public static void main(String[] args) {
CountDownLatch latch = new CountDownLatch(1000);
for(int i=0;i<1000;i++) {
new Thread(new Inc(latch)).start();
}
try {
latch.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Inc.num);
}
static class Inc implements Runnable{
private CountDownLatch latch;
public static int num;
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
num++;
latch.countDown();
}
public Inc(CountDownLatch latch) {
super();
this.latch = latch;
}
}
}
期待値1000は,実際に何度走っても1000以下でありnum++という操作が原子性を満たさないことを示している.
JAVAが提供する原子力の技術保障は以下の通りである.
1、synchronized(反発ロック)2、Lock(反発ロック)3、原子類(CAS楽観ロック)
上記2つはいずれも反発ロックによって実現され,すなわち同じ時点で1つのスレッドのみがこの変数を操作することを許可し,原子性を保障し,何も言うことはない.原子類の実現は見ることができる.int変数に対応する原子類AtomicIntegerは、原子類によって原子性を実現するため、具体的なコード修正は以下の通りである:public static int num public static AtomicInteger num=new AtomicInteger(0);num++ num.incrementAndGet(); System.out.println(Inc.num); System.out.println(Inc.num.get());
結局何度走っても1000で、確かに原子性が実現したことを示しています.原子類の++の操作の細部はすべてincrementAndGetの中で、簡単にソースコードを見ます:unsafeの中の方法を呼び出します
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
。
原子類の利点:ロックをかける必要がなく、性能が良い.欠点:高い同時シーンの下で、CASが失敗する確率はとても高くて、長い時間のスピンはCPUの消耗が比較的に大きいことを招きます
後記
楽観ロック、悲観ロックについて2つの穴を埋めます.CASのABAについては後ほどお話しします.