@Java | Thread & synchronized – [ 執行緒同步鎖 基本使用]

看不見的未來發表於2019-01-19

對實現了Runnable或者Callable介面類,可以通過多執行緒執行同一例項的runcall方法,那麼對於同一例項中的區域性變數(非方法變數)就會有多個執行緒進行更改或讀取,這就會導致資料不一致,synchronized(關鍵字)可以解決多執行緒共享資料同步的問題

synchronized使用說明

作用範圍

synchronized是Java中的關鍵字,是一種同步鎖。它修飾的物件有以下幾種:

  1. 修飾一個程式碼塊:被修飾的程式碼塊稱為同步語句塊,其作用的範圍是大括號{}括起來的程式碼,作用的物件是呼叫這個程式碼塊的物件
  2. 修飾一個非靜態方法:被修飾的方法稱為同步方法,其作用的範圍是整個方法,作用的物件是呼叫這個方法的物件
  3. 修改一個靜態的方法:其作用的範圍是整個靜態方法,作用的物件是這個類的所有物件
  4. 修改一個類:其作用的範圍是synchronized後面括號括起來的部分,作用主的物件是這個類的所有物件

高能提示:
No1 > synchronized修飾的非靜態方法:如果一個物件多個synchronized方法,只要一個執行緒訪問了其中的一個synchronized方法,則這個執行緒所屬物件其它執行緒不能同時訪問這個物件任何一個synchronized方法
No2 > synchronized關鍵字是不能繼承的:基類的方法synchronized function(){}在繼承類中並不自動是synchronized function(){},而是變成了function(){}。繼承類需要你顯式的指定它的某個方法為synchronized方法,可以通過子類呼叫父類的同步方法來實現同步
No3 > 針對synchronized修飾程式碼塊和非靜態方法,本質上鎖的是程式碼塊或非靜態方法對應的物件程式碼塊是synchronized標註的變數,非靜態方法是所在類對應的例項),如果是不同的物件是可以同時訪問的
No4 > 實現同步是要很大的系統開銷作為代價的,甚至可能造成死鎖,所以儘量避免無謂的同步控制
No5 > 每個物件只有一個鎖(lock)與之相關聯
No6 > 在定義介面方法時不能使用synchronized關鍵字
No7 > 構造方法不能使用synchronized關鍵字,但可以使用synchronized程式碼塊來進行同步

1. 修飾一個程式碼塊

public void syncCode(Object o) {
    synchronized (o) {// 同步程式碼塊}
}

上面的鎖就是o這個物件,當然多個執行緒同步需要保證o這個物件是同一個,這是有明確的物件作為鎖的情況,如果只是想單純的讓某一段程式碼同步,並沒有明確的物件作為鎖,可以建立一個特殊的instance變數來充當鎖
synchronized(o)修飾的程式碼塊,其中o可以取值一個物件或者一個變數或者this亦或者Clz.class

public class Sync implements Runnable {
    private byte[] lock = new byte[0];
    public void syncCode() {
        synchronized (lock) {// 同步程式碼塊}
    }
    public void run ....
}

零長度的byte陣列物件建立起來將比任何物件都經濟,檢視編譯後的位元組碼,生成零長度的byte[]物件只需3條操作碼,而Object lock = new Object()則需要7行操作碼

2. 修飾一個非靜態方法

public synchronized void method() {// .....}

此時鎖的是呼叫這個同步方法的物件

3. 修飾一個靜態方法

public synchronized static void method() {// .....}

synchronized修飾的靜態方法鎖定的是這個類的所有物件

4. 修飾類

public class Sync implements Runnable {
    public void syncCode() {
        synchronized (Sync.class) {// 同步程式碼塊}
    }
    public void run ....
}

和作用於靜態方法一樣,synchronized作用於一個類時,是給這個類加鎖,類的所有物件用的是同一把鎖

總結

  1. 執行緒同步的目的是為了保護多個執行緒反問一個資源時對資源的破壞。
  2. 執行緒同步方法是通過鎖來實現,每個物件都有切僅有一個鎖,這個鎖與一個特定的物件關聯,執行緒一旦獲取了物件鎖,其他訪問該物件的執行緒就無法再訪問該物件的其他非同步方法
  3. 對於靜態同步方法,鎖是針對這個類的,鎖物件是該類的Class物件。靜態和非靜態方法的鎖互不干預。一個執行緒獲得鎖,當在一個同步方法中訪問另外物件上的同步方法時,會獲取這兩個物件鎖。
  4. 對於同步,要時刻清醒在哪個物件上同步,這是關鍵。
  5. 編寫執行緒安全的類,需要時刻注意對多個執行緒競爭訪問資源的邏輯和安全做出正確的判斷,對”原子”操作做出分析,並保證原子操作期間別的執行緒無法訪問競爭資源。
  6. 當多個執行緒等待一個物件鎖時,沒有獲取到鎖的執行緒將發生阻塞。
  7. 死鎖是執行緒間相互等待鎖鎖造成的,在實際中發生的概率非常的小,一旦程式發生死鎖,程式將死掉

相關文章