當前位置:編程學習大全網 - 源碼下載 - Synchronized 同步方法的八種使用場景

Synchronized 同步方法的八種使用場景

分析:這種情況是經典的對象鎖中的方法鎖,兩個線程爭奪同壹個對象鎖,所以會相互等待,是線程安全的。

兩個線程同時訪問同壹個對象的同步方法,是線程安全的。

這種場景就是對象鎖失效的場景,原因出在訪問的是兩個對象的同步方法,那麽這兩個線程分別持有的兩個線程的鎖,所以是互相不會受限的。加鎖的目的是為了讓多個線程競爭同壹把鎖,而這種情況多個線程之間不再競爭同壹把鎖,而是分別持有壹把鎖,所以我們的結論是:

兩個線程同時訪問兩個對象的同步方法,是線程不安全的。

運行結果:

兩個線程是並行執行的,所以線程不安全。

線程名:Thread-0,運行開始

線程名:Thread-1,運行開始

線程:Thread-0,運行結束

線程:Thread-1,運行結束

測試結束

兩個線程(thread1、thread2),訪問兩個對象(instance1、instance2)的同步方法(method()),兩個線程都有各自的鎖,不能形成兩個線程競爭壹把鎖的局勢,所以這時,synchronized修飾的方法method()和不用synchronized修飾的效果壹樣(不信去把synchronized關鍵字去掉,運行結果壹樣),所以此時的method()只是個普通方法。

若要使鎖生效,只需將method()方法用static修飾,這樣就形成了類鎖,多個實例(instance1、instance2)***同競爭壹把類鎖,就可以使兩個線程串行執行了。這也就是下壹個場景要講的內容。

這個場景解決的是場景二中出現的線程不安全問題,即用類鎖實現:

兩個線程同時訪問(壹個或兩個)對象的靜態同步方法,是線程安全的。

這個場景是兩個線程其中壹個訪問同步方法,另壹個訪問非同步方法,此時程序會不會串行執行呢,也就是說是不是線程安全的呢?

我們可以確定是線程不安全的,如果方法不加synchronized都是安全的,那就不需要同步方法了。驗證下我們的結論:

兩個線程分別同時訪問(壹個或兩個)對象的同步方法和非同步方法,是線程不安全的。

兩個線程是並行執行的,所以是線程不安去的。

線程名:Thread-0,同步方法,運行開始

線程名:Thread-1,普通方法,運行開始

線程:Thread-0,同步方法,運行結束

線程:Thread-1,普通方法,運行結束

測試結束

問題在於此:method1沒有被synchronized修飾,所以不會受到鎖的影響。即便是在同壹個對象中,當然在多個實例中,更不會被鎖影響了。結論:

非同步方法不受其它由synchronized修飾的同步方法影響

妳可能想到壹個類似場景:多個線程訪問同壹個對象中的同步方法,同步方法又調用壹個非同步方法,這個場景會是線程安全的嗎?

我們來實驗下這個場景,用兩個線程調用同步方法,在同步方法中調用普通方法;再用壹個線程直接調用普通方法,看看是否是線程安全的?

線程名:Thread-0,普通方法,運行開始

線程名:Thread-1,同步方法,運行開始

線程:Thread-1,同步方法,運行結束,開始調用普通方法

線程名:Thread-1,普通方法,運行開始

線程:Thread-0,普通方法,運行結束

線程:Thread-1,普通方法,運行結束

線程名:Thread-2,同步方法,運行開始

線程:Thread-2,同步方法,運行結束,開始調用普通方法

線程名:Thread-2,普通方法,運行開始

線程:Thread-2,普通方法,運行結束

測試結束

我們可以看出,普通方法被兩個線程並行執行,不是線程安全的。這是為什麽呢?

因為如果非同步方法,有任何其他線程直接調用,而不是僅在調用同步方法時,才調用非同步方法,此時會出現多個線程並行執行非同步方法的情況,線程就不安全了。

對於同步方法中調用非同步方法時,要想保證線程安全,就必須保證非同步方法的入口,僅出現在同步方法中。但這種控制方式不夠優雅,若被不明情況的人直接調用非同步方法,就會導致原有的線程同步不再安全。所以不推薦大家在項目中這樣使用,但我們要理解這種情況,並且我們要用語義明確的、讓人壹看就知道這是同步方法的方式,來處理線程安全的問題。

所以,最簡單的方式,是在非同步方法上,也加上synchronized關鍵字,使其變成壹個同步方法,這樣就變成了《場景五:兩個線程同時訪問同壹個對象的不同的同步方法》,這種場景下,大家就很清楚的看到,同壹個對象中的兩個同步方法,不管哪個線程調用,都是線程安全的了。

兩個線程訪問同壹個對象中的同步方法,同步方法又調用壹個非同步方法,僅在沒有其他線程直接調用非同步方法的情況下,是線程安全的。若有其他線程直接調用非同步方法,則是線程不安全的。

這個場景也是在探討對象鎖的作用範圍,對象鎖的作用範圍是對象中的所有同步方法。所以,當訪問同壹個對象中的多個同步方法時,結論是:

兩個線程同時訪問同壹個對象的不同的同步方法時,是線程安全的。

是線程安全的。

線程名:Thread-1,同步方法1,運行開始

線程:Thread-1,同步方法1,運行結束

線程名:Thread-0,同步方法0,運行開始

線程:Thread-0,同步方法0,運行結束

測試結束

兩個方法(method0()和method1())的synchronized修飾符,雖沒有指定鎖對象,但默認鎖對象為this對象為鎖對象,

所以對於同壹個實例(instance),兩個線程拿到的鎖是同壹把鎖,此時同步方法會串行執行。這也是synchronized關鍵字的可重入性的壹種體現。

線程名:Thread-0,靜態同步方法0,運行開始

線程名:Thread-1,非靜態同步方法1,運行開始

線程:Thread-1,非靜態同步方法1,運行結束

線程:Thread-0,靜態同步方法0,運行結束

測試結束

本場景探討的是synchronized釋放鎖的場景:

只有當同步方法執行完或執行時拋出異常這兩種情況,才會釋放鎖。

所以,在壹個線程的同步方法中出現異常的時候,會釋放鎖,另壹個線程得到鎖,繼續執行。而不會出現壹個線程拋出異常後,另壹個線程壹直等待獲取鎖的情況。這是因為JVM在同步方法拋出異常的時候,會自動釋放鎖對象。

線程名:Thread-0,運行開始

線程名:Thread-0,拋出異常,釋放鎖

線程名:Thread-1,運行開始

Exception in thread "Thread-0" java.lang.RuntimeException

at com.study.synchronize.conditions.Condition7.method0(Condition7.java:34)

at com.study.synchronize.conditions.Condition7.run(Condition7.java:17)

at java.lang.Thread.run(Thread.java:748)

線程:Thread-1,運行結束

測試結束

可以看出線程還是串行執行的,說明是線程安全的。而且出現異常後,不會造成死鎖現象,JVM會自動釋放出現異常線程的鎖對象,其他線程獲取鎖繼續執行。

  • 上一篇:什麽是SAF2507不銹鋼
  • 下一篇:鑄源模式有幾個系統
  • copyright 2024編程學習大全網