JAVA同時プログラミング:三大特性-原子性

2514 ワード

生活する
生活は生まれて、生きていくことです.
————
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については後ほどお話しします.