Java線程(一):synchronized

一、什麼時候會出現線程安全問題?

當多個線程同時訪問一個資源(共享資源)時會出現線程安全。資源可以是一個變量、一個對象、一個文件、一個數據庫表等。需要注意的是如果多個程序同時訪問一個方法,定義在方法內部的局部變量並不是臨界資源(共享資源),因爲方法是在棧中執行的,而棧是線程私有的,因此不會出現線程安全問題。

二、如何解決線程安全問題?

通常來說在通過對訪問共享資源代碼加鎖,當一個線程來訪問時加鎖,其他線程等待這個線程釋放鎖,當前線程執行完後加鎖代碼後釋放鎖資源。其他線程就可以訪問共享資源了。在Java中,每一個對象都擁有一個鎖標記(monitor),也稱爲監視器,多線程同時訪問某個對象時,線程只有獲取了該對象的鎖才能訪問。

    Java提供了兩種方式來實現同步互斥訪問:synchronized和Lock。

三、synchronized同步代碼塊和同步方法代碼示例

package sync;

public class TestSynchronized {
	
	static TestSynchronized ts = new TestSynchronized();//所有線程共用這一個鎖

	public static void main(String[] args) {
		new TestSynchronized().new Thread1().start();
		new TestSynchronized().new Thread2().start();
	}

	private void invoke() {
		try {
			synchronized (ts) {//同步代碼塊
				for (int i = 0; i < 5; i++) {
					System.out.println(Thread.currentThread().getName() + ":" + "寫數據庫" + i);
					Thread.sleep(100);
				}
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	class Thread1 extends Thread{
		public void run(){
			ts.invoke();
		}
	}
	
	class Thread2 extends Thread{
		public void run(){
			ts.invoke();
		}
	}
}



運行結果:Thread-0和Thread-1依次執行,沒有出現相互競爭執行。

Thread-0:寫數據庫0
Thread-0:寫數據庫1
Thread-0:寫數據庫2
Thread-0:寫數據庫3
Thread-0:寫數據庫4
Thread-1:寫數據庫0
Thread-1:寫數據庫1
Thread-1:寫數據庫2
Thread-1:寫數據庫3
Thread-1:寫數據庫4

如果將鎖加在方法上執行,結果依然一樣:

	private synchronized void invoke() {
		try {
			for (int i = 0; i < 5; i++) {
				System.out.println(Thread.currentThread().getName() + ":" + "寫數據庫" + i);
				Thread.sleep(100);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
運行結果:
Thread-0:寫數據庫0
Thread-0:寫數據庫1
Thread-0:寫數據庫2
Thread-0:寫數據庫3
Thread-0:寫數據庫4
Thread-1:寫數據庫0
Thread-1:寫數據庫1
Thread-1:寫數據庫2
Thread-1:寫數據庫3
Thread-1:寫數據庫4

四、同步方法和同步代碼塊的區別。

synchronized代碼塊使用起來比synchronized方法要靈活得多。因爲也許一個方法中只有一部分代碼只需要同步,如果此時對整個方法用synchronized進行同步,會影響程序執行效率。而使用synchronized代碼塊就可以避免這個問題,synchronized代碼塊可以實現只對需要同步的地方進行同步。

五、synchronized需要注意的幾點。

1)當一個線程訪問一個對象的synchronized方法func1其他線程不能訪問這個對象方法func1,因爲一個對象只有一個鎖。只有釋放了鎖才能訪問func1。

2)當一個線程訪問一個對象的synchronized方法func1其他線程可以訪問這個對象的非synchronized方法,因爲其他方法不需要該對象的鎖。

3)如果一個類有static synchronized方法f1和synchronized方法f2,當兩個線程分別訪問f1和f2時是不會發生互斥的問題,因爲一個是對象鎖一個是類鎖,不是同一個鎖。

4)如果synchronized方法或者synchronized代碼塊發生異常,是不會出現由於異常導致死鎖,因爲發生異常後JVM會釋放鎖,這個Lock不一樣,lock需要手動釋放鎖。


發佈了38 篇原創文章 · 獲贊 16 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章