Javaスレッドロック機構を深く研究する

2861 ワード

今日はiteyeで+操作とスレッドの安全について質問しました。友達の答えは一言で夢の中の人を目覚めさせました。これで私はJavaスレッドロックについてもっと深く認識しました。ここでまとめてみます。参考にしてください。
まずコードを見てください。
コード1:
public class TestMultiThread2 implements Runnable{

	private static Object o = new Object();
	
	private static Integer si = 0;
	
	private static AtomicInteger flag = new AtomicInteger();
	
	@Override
	public void run() {
		for(int k=0;k<2000000;k++){
			synchronized(si){
				si++;
			}
		}
		flag.incrementAndGet();
	}
	public static void main(String[] args) throws InterruptedException{
		TestMultiThread2 t1 = new TestMultiThread2();
		TestMultiThread2 t2 = new TestMultiThread2();
		ExecutorService exec1 = Executors.newCachedThreadPool();
		ExecutorService exec2 = Executors.newCachedThreadPool();
		exec1.execute(t1);
		exec2.execute(t2);
		while(true){
			if(flag.intValue()==2){
				System.out.println("si>>>>>"+si);	
				break;
			}
			Thread.sleep(50);
		}

		
	}	
	
}
簡単に見るために、重複したものは挿入しません。コードの二からコードの四まではrun()メソッドのコードを挿入します。他のところは同じです。
コード二:
    public void run() {  
        for(int k=0;k<2000000;k++){  
            synchronized(o){  
                si++;  
            }  
        }  
        flag.incrementAndGet();  
    }  
コード3:
    public void run() {  
        for(int k=0;k<2000000;k++){  
            synchronized(o){  
                si++;  
                o = new Object();  
            }  
        }  
        flag.incrementAndGet();  
    }  
コード四:
   public void run() {  
        for(int k=0;k<2000000;k++){  
            synchronized(o){  
                si++;  
                Object temp = o;  
                o = new Object();  
                o = temp;  
            }  
        }  
        flag.incrementAndGet();  
    }  
この4つのコードがあります。問題は大体分かりました。ここで出力を話してください。
コードの一:<400000
コード二:=400 0000
コード三:<400000
コード四:<400000(PS:この結果は非常に400万に近い)
ここで私がテスト中にあった問題を説明します。コード四はずっと走っていません。私のほしい結果は主に私が設定したサイクルの回数が少なすぎます。実はここでこの現象を求めるなら、もっと明らかにしたいのですが、中間に多いnewのObjectがいくつかあります。
コード5:
    public void run() {  
        for(int k=0;k<2000000;k++){  
            synchronized(o){  
                si++;  
                Object temp = o;  
                for(int m=0;m<10;m++){  
                    o = new Object();  
                }  
                o = temp;  
            }  
        }  
        flag.incrementAndGet();  
    }  
なぜ上記の現象が現れましたか?
コードの一:siが++操作をした後(バイトコードを直接見ることができます。ここでは貼りません。)putstaticの前に何段階の操作がありますか?つまり私達がよく言っている非原子操作です。この時siはもう元の対象ではありません。このようにロックはもう一つのスレッドに無効になります。コード三とコード四は一番いい証拠です。コード四はもっと説得力があります。その時は予想外の状況で困惑していました。
ここでバイトコードで説明するのはあまり厳密ではありません。一番いいのはもちろん直接コードを作ることです。
何か問題があれば、読者の皆さんに指摘してもらいたいです。