多線程下synchronized修飾static方法與非static方法的區別

一直對多線程的概念比較模糊,今天就寫了個關於變量原子操作的小程序,好讓自己加深一下理解

代碼如下:

package atomic;

public class JoinThread extends Thread {

	public static int i = 0;

	//public static AtomicInteger atomicInteger = new AtomicInteger(0);
	
	public synchronized void inc(){
		i ++;
	}
	@Override
	public void run() {
		for (int x = 0; x < 10; x++) {
			inc();
			try {
				Thread.sleep(33);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	public static void main(String[] args) throws InterruptedException {
		// TODO Auto-generated method stub
		// JoinThread jt = new JoinThread();
		Thread[] t = new Thread[100];
		for (int i = 0; i < t.length; i++) {
			t[i] = new JoinThread();
		}
		for (int i = 0; i < t.length; i++) {
			t[i].start();
		}
		for (int i = 0; i < t.length; i++) {
			t[i].join();
		}
		System.out.println(JoinThread.i);
	}

}

執行完發現,i並沒有如想像中的輸出1000,即使i添加volatile進行修飾,也不會輸出1000,值是隨機變化的。


將inc()方法添加static修飾,結果無問題,準確無誤的輸出1000。


另外一種改法,將代碼改成:

Thread[] t = new Thread[100];
for (int i = 0; i < t.length; i++) {
	t[i] = new JoinThread();
}
修改成:

JoinThread jt = new JoinThread();
Thread[] t = new Thread[100];
for (int i = 0; i < t.length; i++) {
	t[i] = new Thread(jt);
}
結果無問題,準確無誤的輸出1000


這裏主要涉及到類對象(static方法),對象方法(非static方法)

我們知道,當synchronized修飾一個static方法時,多線程下,獲取的是類鎖(即Class本身,注意:不是實例);

當synchronized修飾一個非static方法時,多線程下,獲取的是對象鎖(即類的實例對象)

所以,當synchronized修飾一個static方法時,創建線程不管是new JoinThread()還是new Thread(new JoinThread()),在run方法中執行inc()方法都是同步的;

相反,當synchronized修飾一個非static方法時,如果用new JoinThread()還是new Thread(new JoinThread())方式創建線程,就無法保證同步操作,因爲這時

inc()是屬於對象方法,每個線程都執有一個獨立的對象實例new JoinThread(),所以多線程下執行inc()方法並不會產生互斥,也不會有同步操作。


另外如果考慮到變更的原子操作,可使用atomic包下面的包裝對象,這些對象都是對volatile修飾變量的一種延伸,可保證變量的原子操作而不用去同步方法或

代碼塊是否同步。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章