1. 程式人生 > >[Java]同步鎖synchronized

[Java]同步鎖synchronized

在多執行緒操作資料時需要考慮使用synchronized關鍵詞修飾屬性或方法,同步鎖synchronized大致可分為兩類:物件鎖全域性鎖。在分析同步鎖程式碼時需要關心兩個問題:鎖的物件是誰誰持有鎖

①物件鎖:

當一個執行緒訪問物件object的一個synchronized(this)同步程式碼塊或synchronized修飾的例項方法時,其他執行緒對該object中所有其它synchronized(this)同步程式碼塊或synchronized修飾的例項方法的訪問將被阻塞。

public class Demo {

	public static void main(String[] args) {
		MyRunnable myRunnable = new MyRunnable();
		for(int i = 0;i < 3;i++) {
			Thread t = new Thread(myRunnable);
			t.start();
		}
	}

}
class MyRunnable implements Runnable{

	static int i;

	@Override
	public void run() {
		add();
	}

	synchronized void add() {
		System.out.println(Thread.currentThread().getName()+"開始,i = "+i);
		i++;
		System.out.println(Thread.currentThread().getName()+"結束,i = "+i);
	}
}

輸出結果:

在上面的例子中,synchronized 修飾例項方法,鎖的物件是myRunnable,持有鎖的為當前執行該方法的執行緒。迴圈建立並啟動的三個執行緒都呼叫myRunnable物件的同步add()方法,當其中某個執行緒執行add()方法時需要先獲得myRunnable物件的鎖,若物件鎖被其他執行緒佔用,該執行緒將阻塞在此,等待鎖的獲得。

②全域性鎖

當一個執行緒訪問類的一個synchronized(類名.class)同步程式碼塊或synchronized修飾的類方法時,其他執行緒對該類中所有其它synchronized(類名.class)同步程式碼塊或synchronized修飾的類方法的訪問將被阻塞。

public class Demo {

	public static void main(String[] args) {
		for(int i = 0;i < 3;i++) {
			Thread t = new Thread() {
				@Override
				public void run() {
					Sync.add();
				}
			};
			t.start();
		}
	}

}
class Sync{
	static int i;
	synchronized static void add() {
		System.out.println(Thread.currentThread().getName()+"開始,i = "+i);
		i++;
		System.out.println(Thread.currentThread().getName()+"結束,i = "+i);
	}
}

輸出結果:

在上面的例子中,synchronized 修飾類方法,鎖的物件是Sync.class,持有鎖的為當前執行該方法的執行緒。迴圈建立並啟動的三個執行緒都呼叫Sync類的靜態方法add(),當其中某個執行緒執行add()方法時需要先獲得Sync類的鎖,若物件鎖被其他執行緒佔用,該執行緒將阻塞在此,等待鎖的獲得。

總結:

1.使用synchronized物件鎖時,執行緒需要拿到的是該物件的鎖,否則將無法操作該物件中所有帶有物件鎖的屬性和方法。

2.使用全域性鎖時,需要拿到的是類檔案的鎖,否則將無法操作該類所有帶全域性鎖的屬性和方法。