1. 程式人生 > >synchronized靜態方法與非靜態方法

synchronized靜態方法與非靜態方法

    一個物件裡面如果有多個synchronized方法,某一個時刻內,只要一個執行緒去呼叫其中的一個synchronized方法了,其它的執行緒都只能等待,換句話說,某一個時刻內,只能有唯一一個執行緒去訪問這些synchronized。

我們需要先弄清楚synchronized 在類方法上使用的兩個關鍵點。
1.非靜態方法的鎖預設為  this,也就是我們所說的物件鎖,  靜態方法的鎖為 對應的 Class 例項,也就是類鎖
2.某一個時刻內,只能有一個執行緒持有鎖,無論幾個方法。

例如:

/**
 * 
 * @Description :synchronized方法
 * @author Bush羅
 * @date 2018年8月5日
 *
 */
public class Main {
	public static void main(String[] args) {
		ThreadDemo demo1 = new ThreadDemo();
		ThreadDemo demo2 = new ThreadDemo();

		new Thread(new Runnable() {
			@Override
			public void run() {
				demo1.getFrist();//1
			}
		}).start();

		new Thread(new Runnable() {
			@Override
			public void run() {
				demo1.getSecond();//2
				//demo2.getSecond();//3
			}
		}).start();
	}
}

class ThreadDemo {

	public synchronized void getFrist() {
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
		}
		System.out.println("Frist");
	}
	public synchronized void getSecond() {
		System.out.println("Second");
	}
}

情況1:如上面程式碼一樣.輸出結果,先延遲三秒列印Frist,再列印Second。

兩個執行緒操作的是同一個例項demo1,裡面的synchronized方法是非靜態方法,預設使用的是this這把物件鎖,所以他們使用的是同一把鎖,當執行緒1首先拿到這個鎖時,執行緒2就被阻塞在方法外面進不來了,所以會先延遲三秒列印Frist,再列印Second。

情況2:.如果執行緒1執行demo1.getFrist();方法,執行緒2執行demo2.getSecond();方法,那麼會先列印Second,然後延遲三秒列印Frist。

兩個執行緒操作的是兩個不同例項,那麼就是兩把不同的物件鎖,所以是非同步執行的,執行緒1與執行緒2互不干擾,所以先列印Second,然後延遲三秒列印Frist。

情況3:把getFrist()方法改成靜態方法,然後執行緒1執行demo1.getFrist();方法,執行緒2執行demo1.getSecond();方法

	public static synchronized void getFrist() {
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
		}
		System.out.println("Frist");
	}

結果為:先列印Second,然後延遲三秒列印Frist。

因為getFrist()方法為靜態方法,持有的鎖為類鎖,而getSecond不是靜態方法,持有的鎖為物件鎖,兩個執行緒雖然操作用一個例項,但是所擁有的鎖不是同一把,所以是非同步執行,先列印Second,然後延遲三秒列印Frist。

總結:

   所有的非靜態同步方法用的都是同一把鎖一一例項物件本身,也就是說如果一個例項物件的非靜態同步方法獲取鎖後,該例項物件的其他非靜態同步方法必須等待獲取鎖的方法釋放鎖後才能獲取鎖,可是別的例項物件的非靜態同步方法因為跟該例項物件的非靜態同步方法用的是不同的鎖,所以毋須等待該例項物件已獲取鎖的非靜態同步方法釋放鎖就可以獲取他們自己的鎖。


   所有的靜態同步方法用的也是同一把鎖一一類物件本身,這兩把鎖是兩個不同的物件,所以靜態同步方法與非靜態同步方法之間是不會有亮態條件的。但是一旦一個靜態同步方法獲取鎖後,其他的靜態同步方法都必須等待該方法釋放鎖後才能獲取鎖,而不管是同一個例項物件的靜態同步方法之間,還是不同的例項物件的靜態同步方法之間,只要它們同一個類的例項物件!