6.Javaマルチスレッドの初心者:volatileキーワードの慎重な使用

2432 ワード


Javaマルチスレッドの学習でvolatileキーワードが使用される場合があります.volatileキーワードは、int、float、booleanなどの単純なタイプの変数を宣言するために使用されます.使用には一定の制限があります.
volatileキーワードはJavaマルチスレッドを知っている読者がその役割をよく知っていると信じています.volatileキーワードは、int、float、booleanなどの単純なタイプの変数を宣言するために使用されます.これらの単純なデータ型がvolatileとして宣言されると、それらの操作は原子レベルになります.しかし、これは一定の制限があります.たとえば、次の例のnは原子レベルではありません.
package mythread;

public class JoinThread extends Thread {
	public static volatile int n = 0;

	public void run() {
		for (int i = 0; i < 10; i++)
			try {
				n = n + 1;
				sleep(3); //           ,  3  
			} catch (Exception e) {
			}
	}

	public static void main(String[] args) throws Exception {
		Thread threads[] = new Thread[100];
		for (int i = 0; i < threads.length; i++)
			//   100   
			threads[i] = new JoinThread();
		for (int i = 0; i < threads.length; i++)
			//        100   
			threads[i].start();
		for (int i = 0; i < threads.length; i++)
			// 100          
			threads[i].join();
		System.out.println("n=" + JoinThread.n);
	}
}

nに対する動作が原子レベルである場合、最終出力の結果はn=1000であるべきであり、上面積コードを実行する場合、多くの場合、出力されるnは1000未満であり、これはn=n+1が原子レベルの動作ではないことを示す.なぜなら、volatileとして宣言された単純な変数が、現在の値がその変数の以前の値によって関連付けられている場合、volatileキーワードは機能しません.つまり、次の式は原子操作ではありません.
n = n + 1;n++;
このような状況を原子操作にするにはsynchronizedキーワードを使用する必要があります.上記のコードは次のような形式に変更できます.
package mythread;

public class JoinThread extends Thread {
	public static int n = 0;

	public static synchronized void inc() {
		n++;
	}

	public void run() {
		for (int i = 0; i < 10; i++)
			try {
				inc(); // n = n + 1     inc();
				sleep(3); //           ,  3  
			} catch (Exception e) {
			}
	}

	public static void main(String[] args) throws Exception {
		Thread threads[] = new Thread[100];
		for (int i = 0; i < threads.length; i++)
			//   100   
			threads[i] = new JoinThread();
		for (int i = 0; i < threads.length; i++)
			//        100   
			threads[i].start();
		for (int i = 0; i < threads.length; i++)
			// 100          
			threads[i].join();
		System.out.println("n=" + JoinThread.n);
	}
}

上記のコードはn=n+1をinc()に変更し、incメソッドはsynchronizedキーワードを使用してメソッド同期を行う.したがって、volatileキーワードを使用する場合は慎重に、単純なタイプの変数がvolatile修飾を使用する限り、この変数のすべての操作が元の操作であるわけではありません.変数の値が自分の前の値によって決定された場合、n=n+1、n++など、volatileキーワードは失効し、変数の値が自分の前の値とは関係ない場合にのみその変数の操作が原子レベルである場合、n=m+1のように、これは元のレベルです.だからvolatileを使う肝心な時必ず慎重で、もし自分で自信がなければsynchronizedを使ってvolatileの代わりに使うことができます.