1. 程式人生 > >JAVA 同步之 synchronized 修飾方法被多物件訪問是否執行緒安全?

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 方法這段程式碼時就會形成互斥。