synchronized 持有的鎖分析?是對象的鎖仍是類的鎖?

1.synchronized關鍵字是用來控制多線程同步時候使用的一種方式,在多線程的狀態下,控制synchronized代碼段不被多個線程同時執行。能夠加在一段代碼上,也能夠加在方法上。java

2.synchronized實現的鎖機制是一種不公平的鎖,在某種意義上,可能致使某些線程的飢餓,但相比於公平鎖能提升吞吐率。多線程

3. 不要認爲隨意的給方法或者代碼塊上面加上synchronized就能夠實現鎖併發

    請看下面的代碼this

class Sync {

	public synchronized void test() {
		System.out.println("test開始..");
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("test結束..");
	}
}

  

class MyThread extends Thread {

	public void run() {
		Sync sync = new Sync();
		sync.test();
	}
}

 

public class Main {

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

運行的結果test開始.. test開始.. test開始.. test結束.. test結束.. test結束..spa

上面的程序起了三個線程,同時運行Sync類中的test()方法,雖然test()方法加上了synchronized,可是仍是同時運行起來,貌似synchronized沒起做用。 線程

 再試運行下面的程序:code

    

public void test() {
	synchronized(this){
		System.out.println("test開始..");
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("test結束..");
	}
}

將synchronized加在代碼塊上面:對象

運行結果test開始.. test開始.. test開始.. test結束.. test結束.. test結束..同步

實際上,synchronized(this)以及非static的synchronized方法(至於static synchronized方法請往下看),只能防止多個線程同時執行同一個對象的同步代碼段。io

synchronized鎖住的是代碼仍是對象。答案是:synchronized鎖住的是括號裏的對象,而不是代碼。對於非static的synchronized方法,鎖的就是對象自己也就是this。

當synchronized鎖住一個對象後,別的線程若是也想拿到這個對象的鎖,就必須等待這個線程執行完成釋放鎖,才能再次給對象加鎖,這樣才達到線程同步的目的。即便兩個不一樣的代碼段,都要鎖同一個對象,那麼這兩個代碼段也不能在多線程環境下同時運行。

因此咱們在用synchronized關鍵字的時候,能縮小代碼段的範圍就儘可能縮小,能在代碼段上加同步就不要再整個方法上加同步。這叫減少鎖的粒度,使代碼更大程度的併發。緣由是基於以上的思想,鎖的代碼段太長了,別的線程是否是要等好久,等的花兒都謝了。固然這段是題外話,與本文核心思想並沒有太大關聯。

再看上面的代碼,每一個線程中都new了一個Sync類的對象,也就是產生了三個Sync對象,因爲不是同一個對象,因此能夠多線程同時運行synchronized方法或代碼段。

 

驗證:

class MyThread extends Thread {

	private Sync sync;

	public MyThread(Sync sync) {
		this.sync = sync;
	}

	public void run() {
		sync.test();
	}
}

public class Main {

	public static void main(String[] args) {
		Sync sync = new Sync();
		for (int i = 0; i < 3; i++) {
			Thread thread = new MyThread(sync);
			thread.start();
		}
	}
}

注意此時new的是統一對象。

運行結果:test開始.. test結束.. test開始.. test結束.. test開始.. test結束..

那麼,若是真的想鎖住這段代碼,要怎麼作?也就是,若是仍是最開始的那段代碼,每一個線程new一個Sync對象,怎麼才能讓test方法不會被多線程執行。 

解決也很簡單,只要鎖住同一個對象不就好了。例如,synchronized後的括號中鎖同一個固定對象,這樣就好了。這樣是沒問題,可是,比較多的作法是讓synchronized鎖這個類對應的Class對象。

關鍵:synchronized(Sync.class)

 

class Sync {

	public void test() {
		synchronized (Sync.class) {
			System.out.println("test開始..");
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("test結束..");
		}
	}
}

class MyThread extends Thread {

	public void run() {
		Sync sync = new Sync();
		sync.test();
	}
}

public class Main {

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

運行結果: test開始.. test結束.. test開始.. test結束.. test開始.. test結束..

static synchronized方法,static方法能夠直接類名加方法名調用,方法中沒法使用this,因此它鎖的不是this,而是類的Class對象,因此,static synchronized方法也至關於全局鎖,至關於鎖住了代碼段。

相關文章
相關標籤/搜索