首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 共享資源同步機制:synchronized 關鍵字與關鍵區塊實戰

     編輯:Java 相關知識

內建記憶體衝突防護

對特殊資源——**物件中的記憶體**——Java 提供內建機制防止衝突。通常將資料設為 private,只透過方法存取,故只需將特定方法設為 synchronized 即可有效防止衝突。**任何時刻,只有一個執行緒可調用特定物件的一個同步方法**(雖該執行緒可調用多個物件的同步方法)。

同步方法與物件鎖

synchronized void f() { /* ... */ }
synchronized void g() { /* ... */ }

每個物件包含一把**鎖(監視器)**,自動成為物件一部分。調用任何同步方法 → 物件被鎖定,不可再調用該物件其他同步方法,除非第一個方法完成並釋放鎖。上例中,為物件調用 f() 後,不可為同物件調用 g(),除非 f() 完成釋放鎖。**該物件所有同步方法共享一把鎖**,防止多執行緒同時寫入共用記憶體。

每個類也有自己的鎖(作為 Class 物件一部分),synchronized static 方法可在類範圍內互相鎖定,防護 static 資料。

Sharing2:計數器同步修正版

//: Sharing2.java
class TwoCounter2 extends Thread {
    // ... 介面元件 ...
    public synchronized void run() { // 整個 run 同步
        while (true) {
            t1.setText(Integer.toString(count1++));
            t2.setText(Integer.toString(count2++));
            try { sleep(500); } catch (InterruptedException e){}
        }
    }
    public synchronized void synchTest() { // 同步檢查方法
        Sharing2.incrementAccess();
        if(count1 != count2) l.setText("Unsynched");
    }
}

class Watcher2 extends Thread {
    public void run() {
        while(true) {
            for(int i = 0; i < p.s.length; i++) p.s[i].synchTest();
            try { sleep(500); } catch (InterruptedException e){}
        }
    }
}

新問題:Watcher 永遠看不到事情發生

因整個 run() 同步,且必須為每個物件運行 run(),**鎖永遠不會打開**,synchTest() 永不被調用。accessCount 根本不變化。

解決方案:同步區塊——關鍵區域隔離

只將 run() 中關鍵部分隔離。想隔離的部分稱「關鍵區域」,用不同方式使用 synchronized 關鍵字:

synchronized(syncObject) {
    // 此代碼同一時間只能被一個執行緒存取,假設所有執行緒尊重 syncObject 的鎖
}

進入同步區塊前必須在 syncObject 取得鎖。若其他執行緒已取得,區塊不可進入,必須等待鎖釋放。

修正後的 run()

public void run() {
    while (true) {
        synchronized(this) { // 以當前物件為鎖
            t1.setText(Integer.toString(count1++));
            t2.setText(Integer.toString(count2++));
        }
        try { sleep(500); } catch (InterruptedException e){}
    }
}

這是對 Sharing2.java 唯一修改。現在兩計數器永不脫離同步,且 run() 執行期間仍給 Watcher 足夠存取權限。

同步效率代價

獲取鎖非「廉價」——單次方法調用代價(進入/退出,不執行主體)至少累加 4 倍,視方案可能更高。若知某方法不會衝突,**最明智做法是移除 synchronized**。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved