JAVA 同步之 synchronized 修飾方法


在JAVA多線程編程中,將需要並發執行的代碼放在Thread類的run方法里面,然后創建多個Thread類的對象,調用start()方法,線程啟動執行。

當某段代碼需要互斥時,可以用 synchronized 關鍵字修飾,這里討論 synchronized 關鍵字修飾方法時,是如何互斥的。

synchronized 修飾方法時鎖定的是調用該方法的對象。它並不能使調用該方法的多個對象在執行順序上互斥。

下面舉個具體的例子說明:

Test.java 通過 implements Runnable 成為一個線程類,它有一個MethodSync實例變量,這樣,每當實例化一個Test對象時(相當於創建一個線程)就會初始化一個相應的MethodSync對象。然后在Test類的run()方法里面調用 synchronized 修飾的方法。

Test.java

 1 public class Test implements Runnable{
 2     private String name;
 3 //    private static MethodSync methodSync = new MethodSync();
 4     private MethodSync methodSync = new MethodSync();
 5     
 6     public Test(String name){
 7         this.name = name;
 8     }
 9     
10     @Override
11     public void run() {
12         methodSync.method(name);
13     }
14     
15     public static void main(String[] args) {
16         Thread t1 = new Thread(new Test("test 1"));
17         Thread t2 = new Thread(new Test("test 2"));
18         t1.start();
19         t2.start();
20     }
21 }

上面創建了二個Test類的對象,相當於啟動了兩個線程, 這兩個線程將會並發地執行它們的run方法中的代碼。

 

MethodSync.java ,該類只擁有一個用來測試的 synchronized 方法

 1 public class MethodSync {
 2     
 3     /*
 4      * @Task : 測試 synchronized 修飾方法時鎖定的是調用該方法的對象
 5      * @param name  線程的標記名稱
 6      */
 7     public synchronized void method(String name){
 8         System.out.println(name + " Start a sync method");
 9         try{
10             Thread.sleep(300);
11         }catch(InterruptedException e){}
12         System.out.println(name + " End the sync method");
13     }
14 }

 

先看執行結果:

test1 先於 test2 執行 同步方法,但是卻后於 test2 結束。這里並沒有達到互斥的效果!原因是:MethodSync是實例變量,每次創建一個Test對象就會創建一個MethodSync對象, synchronized 只會鎖定調用method()方法的那個MethodSync對象,而這里創建的兩個線程分別擁有兩個不同的MethodSync對象,它們調用method方法時就沒有互斥關系。

 

當把Test.java 中的MethodSync 變量 用 static 來修飾時,執行結果如下:

這里,正確實現了同步作用。原因如下:這里也創建了二個線程(Test 對象),但是每個Test對象共享MethodSync 變量,也即只有一個MethodSync 變量在兩個線程中執行 method方法,這樣兩個線程在執行到method 方法這段代碼時就會形成互斥。

 

2018.12.13更新:

記錄一下我對synchronized關鍵字的理解:

1,相對於ReentrantLock而言,synchronized鎖是重量級鎖,重量級體現在活躍性差一點。synchronized鎖是內置鎖,意味着JVM能基於synchronized鎖做一些優化:比如增加鎖的粒度(鎖粗化)、鎖消除。

2,在synchronized鎖上阻塞的線程是不可中斷的:線程A獲得了synchronized鎖,當線程B也去獲取synchronized鎖時會被阻塞。而且,線程B無法被其他線程中斷(不可中斷的阻塞),而ReentrantLock鎖能實現可中斷的阻塞。

3,synchronized鎖釋放是自動的,當線程執行退出synchronized鎖保護的同步代碼塊時,會自動釋放synchronized鎖。而ReentrantLock需要顯示地釋放:即在try-finally塊中釋放鎖。

4,線程在競爭synchronized鎖時是非公平的:假設synchronized鎖目前被線程A占有,線程B請求鎖未果,被放入隊列中,線程C請求鎖未果,也被 放入隊列中,線程D也來請求鎖,恰好此時線程A將鎖釋放了,那么線程D將跳過隊列中所有的等待線程(即:線程B和線程C)並獲得這個鎖。

而ReentrantLock能夠實現鎖的公平性。

5,synchronized鎖是讀寫互斥並且 讀讀也互斥,ReentrantReadWriteLock 分為讀鎖和寫鎖,而讀鎖可以同時被多個線程持有,適合於讀多寫少場景的並發。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM