1. 程式人生 > >【多執行緒】執行緒互斥之synchronized 詳解

【多執行緒】執行緒互斥之synchronized 詳解

定義:
執行緒互斥是指某一資源同時只允許一個訪問者對其進行訪問,具有唯一性和排它性。但互斥無法限制訪問者對資源的訪問順序,即訪問是無序的。
我們都知道保證執行緒完整執行。則需要對其加鎖。使用synchronized關鍵字。在這裡鎖的物件理論上可以為任何物件。

程式碼塊同步:

    public void output(String name){

        int len=name.length();
        synchronized(this){
            for (int i = 0; i < len; i++) {
                System.out
.print(name.charAt(i)); } System.out.println(); } }

方法同步:
在方法前直接加關鍵字synchronized。
public synchronized void output2(String name){
int len=name.length();
for (int i = 0; i < len; i++) {
System.out.print(name.charAt(i));
}
System.out.println();
}

注意:該方法鎖的是this物件,也就是當前類的例項。

靜態方法加鎖

    public static synchronized void output3(String name){
        int len=name.length();
        for (int i = 0; i < len; i++) {
            System.out.print(name.charAt(i));
        }
        System.out.println(); 
    }

注意:該方法鎖的是該方法所在的類本身(並非例項)。

以上有這三種用synchronized 的方式。如果我要同時保證方式一和方式二能夠同步。則必須保證,兩個方法鎖的是用一個物件。也就是方式一要用synchronized (this)。加入這時你換成synchronized (obj)那就沒有意義了。
當然也要必須保證兩個方法都是在同一個類下呼叫。如果
Outputer outputer1=new Outputer();
Outputer outputer2=new Outputer();
然後用outputer1,outputer2分別呼叫兩種方式,那也起不到鎖的作用了。

即:類的同一個例項下,並鎖的是同一個物件。才能達到互斥的效果。

同理,由於方式三是鎖的類的本身,所以如果方式一和方式三若想同步的話也要鎖住類的本身。假如我們還應用synchronized (this),我做了一個測試。
private void init(){
final Outputer outputer=new Outputer();

new Thread(new Runnable(){
    public void run(){
        while(true){
            try {
                Thread.sleep(10);
            } catch (Exception e) {

            }
            outputer.output3("方法三mdm");
        }
    }
}).start();

new Thread(new Runnable(){
    public void run(){
        while(true){
            try {
                Thread.sleep(10);
            } catch (Exception e) {

            }
            outputer.output("方法一MDM");
        }
    }
}).start();
}
public static void main(String[] args) {
    new TraditionalThreadSynchronized().init();
}

會發現結果出現了異常。該靜態方法並沒有得到鎖的保護。兩個方法沒有實現同步互斥。

這裡寫圖片描述

因為在靜態方法中synchronized 是鎖的類本身。因此在方式一種也要鎖類的本身。例項化出來的物件是沒用的。可以鎖住類的位元組碼物件。即
synchronized (Outputer.class){
//方法體
}

有了上面的介紹,在給大家出個題。

 pulbic class Something(){
         public synchronized void isSyncA(){}
         public synchronized void isSyncB(){}
         public static synchronized void cSyncA(){}
         public static synchronized void cSyncB(){}
     }

那麼,加入有Something類的兩個例項a與b,那麼下列組方法何以被1個以上執行緒同時訪問呢

   a.   x.isSyncA()與x.isSyncB() 
   b.   x.isSyncA()與y.isSyncA()
   c.   x.cSyncA()與y.cSyncB()
   d.   x.isSyncA()與Something.cSyncA()