【Java】【多執行緒】同步方法和同步程式碼塊、死鎖

love_Aym發表於2018-04-16

轉載:https://blog.csdn.net/u010002184/article/details/72566874?locationNum=11&fps=1

一、java的內建鎖

        每個java物件都可以用做一個實現同步的鎖,這些鎖成為內建鎖。執行緒進入同步程式碼塊或方法的時候會自動獲得該鎖,在退出同步程式碼塊或方法時會釋放該鎖。

    獲得內建鎖的唯一途徑就是進入這個鎖的保護的同步程式碼塊或方法。

    java內建鎖是一個互斥鎖,這就是意味著最多隻有一個執行緒能夠獲得該鎖,當執行緒A嘗試去獲得執行緒B持有的內建鎖時,執行緒A必須等待或者阻塞,知道執行緒B釋放這個鎖,如果B執行緒不釋放這個鎖,那麼A執行緒將永遠等待下去。

  • java的物件鎖和類鎖:java的物件鎖和類鎖在鎖的概念上基本上和內建鎖是一致的,但是,兩個鎖實際是有很大的區別的,物件鎖是用於物件非靜態例項方法,類鎖是用於類的靜態方法或者一個類的class物件上的。我們知道,類的物件例項可以有很多個,但是每個類只有一個class物件,所以不同物件例項的物件鎖是互不干擾的,但是每個類只有一個類鎖。但是有一點必須注意的是,其實類鎖只是一個概念上的東西,並不是真實存在的,它只是用來幫助我們理解鎖定例項方法和靜態方法的區別的。

二、同步

1、同步程式碼塊

  • 用synchronized關鍵字加上一個鎖物件來定義一段程式碼, 這就叫同步程式碼塊
  • 多個同步程式碼塊如果使用相同的鎖物件, 那麼他們就是同步的。鎖物件可以是任意物件,但是被鎖的程式碼需要保證是同一把鎖,不能用匿名物件
class Printer {
	Demo d = new Demo();
	public static void print1() {
	    synchronized(d){	           //鎖物件可以是任意物件,但是被鎖的程式碼需要保證是同一把鎖,不能用匿名物件
		System.out.print("黑");
		System.out.print("馬");
		System.out.print("程");
		System.out.print("序");
		System.out.print("員");
		System.out.print("\r\n");
		}
	}
	
	public static void print2() {	
	    synchronized(d){	
		System.out.print("傳");
		System.out.print("智");
		System.out.print("播");
		System.out.print("客");
		System.out.print("\r\n");
		}
	}
}

2、同步方法

  • 使用synchronized關鍵字修飾一個方法, 該方法中所有的程式碼都是同步的

  • 非靜態方法的鎖機制為this
  • 靜態方法的鎖機制為位元組碼物件,類名.class
class Printer {
    public static void print1() {
	synchronized(Printer.class){				//鎖物件可以是任意物件,但是被鎖的程式碼需要保證是同一把鎖,不能用匿名物件
		System.out.print("黑");
		System.out.print("馬");
		System.out.print("程");
		System.out.print("序");
		System.out.print("員");
		System.out.print("\r\n");
		}
	}	
	/*
	* 非靜態同步函式的鎖是:this
	* 靜態的同步函式的鎖是:位元組碼物件
	*/
    public static synchronized void print2() {	
	System.out.print("傳");
		System.out.print("智");
		System.out.print("播");
		System.out.print("客");
		System.out.print("\r\n");
		}
	}

轉載1:https://blog.csdn.net/zhenwodefengcaii/article/details/54601098(棒)

    Java語言的關鍵字,當它用來修飾一個方法或者一個程式碼塊的時候,能夠保證在同一時刻最多隻有一個執行緒執行該段程式碼。

     1、當兩個併發執行緒訪問同一個物件object中的這個synchronized(this)同步程式碼塊時,一個時間內只能有一個執行緒得到執行。另一個執行緒必須等待當前執行緒執行完這個程式碼塊以後才能執行該程式碼塊。
   2、然而,當一個執行緒訪問object的一個synchronized(this)同步程式碼塊時,另一個執行緒仍然可以訪問該object中的非synchronized(this)同步程式碼塊。
  3、尤其關鍵的是,當一個執行緒訪問object的一個synchronized(this)同步程式碼塊時,其他執行緒對object中所有其它synchronized(this)同步程式碼塊的訪問將被阻塞。
    4、第三個例子同樣適用其它同步程式碼塊。也就是說,當一個執行緒訪問object的一個synchronized(this)同步程式碼塊時,它就獲得了這個object的物件鎖。結果,其它執行緒對該object物件所有同步程式碼部分的訪問都被暫時阻塞。
    5、以上規則對其它物件鎖同樣適用.

其他更多解釋,直接看連結~~~~


轉載2:https://www.cnblogs.com/sgzs/archive/2017/12/01/7943647.html

深刻通俗理解:

雖然寫法不同,但實際上,只有一種,就是【同步程式碼塊】。這是核心核心核心。同步方法也是同步程式碼塊。

同步就是:一個物件同一時間只能為一個同步程式碼塊服務

同步程式碼塊需要傳遞的物件(鎖物件):就是鎖住這個物件,表示這個物件正在為我服務,其他人不能用(非synchronized程式碼塊、方法除外)。

同步方法:就是同步程式碼塊,同步鎖物件是this

同步靜態方法:就是同步程式碼塊,同步鎖物件是類的class物件(Demo類裡的靜態方法鎖物件就是Demo.class)

OK了,這就是同步原理。再說簡單點(當一個物件被鎖住之後,在該程式碼塊之外去使用此物件的方法,只要遇到同步程式碼塊,就會進入等待狀態)


四、死鎖

多執行緒同步的時候, 如果同步程式碼巢狀, 使用相同鎖, 就有可能出現死鎖。

第一個執行緒中需獲取第二個執行緒,第二個執行緒執行時需獲取第一個執行緒,而此時第一個執行緒還沒執行完沒被釋放,此時就陷入了僵持狀態,進入死鎖。


五、回顧以前說過的執行緒安全問題

    * 看原始碼:Vecto,StringBuffer,Hashtable,Collections.synchroinzed(xxx)

  •  Vector是執行緒安全的,ArrayList是執行緒不安全的;
  • StringBuffer是執行緒安全的,StringBuilder是執行緒不安全的;
  •  Hashtable是執行緒安全的,HashMap是執行緒不安全的。



相關文章