1. 程式人生 > >深入探析Java執行緒鎖機制

深入探析Java執行緒鎖機制

      今天在iteye上提了一個關於++操作和執行緒安全的問題,一位朋友的回答一言點醒夢中人,至此我對Java執行緒鎖有了更加深刻的認識。在這裡也做個總結供大家參考。

      先看幾段程式碼吧!

   程式碼一:

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();  
    }  

  程式碼三:

    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();  
    }  

  有了這四段程式碼我想問題大概可以說明白了,這裡說一下輸出吧。

  程式碼一:<4000000

  程式碼二:=4000000

  程式碼三:<4000000

  程式碼四:<4000000(PS:這個結果非常接近4000000)

      這裡說明一下我測試中碰到的問題,程式碼四一直沒有跑出我想要的結果,主要是開始我設的迴圈次數太少,其實這裡如果要這個現象更加明顯一些可以在中間多new 幾個Object 如下面的程式碼五,這樣現象就比較明顯了.

  程式碼五:

    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已經不是原來的物件了,這樣鎖對另外一個執行緒來說就失效了,我想程式碼三和程式碼四就是最好的佐證,程式碼四更有說服力。當時因為沒有出現預想的情況困惑了挺久。

    其實這裡用位元組碼來解釋還不是很嚴謹,最好的當然直接是彙編程式碼

    如有什麼問題還希望各位讀者指正。