synchronized的四種作用域以及不能被繼承解析


synchronizedjava中用於同步的關鍵字,其典型的作用域如下所示.

1 對象鎖


@Slf4j
public class SynchronizedExample1 {

    private final int loopNum = 20;

    // 修飾一個代碼塊
    private void test1(int j) {
        synchronized (this) {
            for (int i = 0; i < loopNum; i++) {
                log.info("test1 {} - {}", j, i);
            }
        }
    }

    // 修飾一個方法
    private synchronized void test2(int num) {
        for (int i = 0; i < loopNum; i++) {
            log.info("test2 {} - {}", num, i);
        }
    }

    public static void main(String[] args) {
        SynchronizedExample1 example1 = new SynchronizedExample1();
        SynchronizedExample1 example2 = new SynchronizedExample1();
        ExecutorService executorService = Executors.newCachedThreadPool();

        executorService.execute(() -> {
            example1.test2(1);
        });
        executorService.execute(() -> {
            example2.test2(2);
        });
        executorService.shutdown();
    }
}

1.1 代碼塊修飾(對象)

此時,synchronized用於保證test1函數中的被synchronized大括號包裹的代碼同步執行.
synchronized作用的對象為SynchronizedExample1的對象實例,例如main函數中的example1以及example2.

Tips:
1.example1若在多個線程中被調用,其輸出順序將保證同步,按照1,2,3...19,20的順序執行.
2.若example1example2均在多個線程中執行,則test1...之間保持同步輸出,test2...之間保持同步輸出,但是test1...test2...之間輸出不保證順序.

1.2 非靜態函數修飾

synchronized添加於test2函數聲明中,其作用類似於1.1中的代碼塊修飾,區別點僅僅在於其同步代碼塊擴充至整個函數(test2).

2. 類鎖

@Slf4j
public class SynchronizedExample2 {

    private static final int loopNum = 20;

    // 修飾一個類
    private static void test1(int j) {
        synchronized (SynchronizedExample2.class) {
            for (int i = 0; i < loopNum; i++) {
                log.info("test1 {} - {}", j, i);
            }
        }
    }

    // 修飾一個靜態方法
    private static synchronized void test2(int j) {
        for (int i = 0; i < loopNum; i++) {
            log.info("test2 {} - {}", j, i);
        }
    }

    public static void main(String[] args) {
        SynchronizedExample2 example1 = new SynchronizedExample2();
        SynchronizedExample2 example2 = new SynchronizedExample2();
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.execute(() -> {
            example1.test1(1);
        });
        executorService.execute(() -> {
            example2.test1(2);
        });
    }
}

2.1 代碼塊修飾(類)

1.1中區別在於,synchronized函數修飾的是SynchronizedExample2類.
SynchronizedExample2對象,諸如example1或者example2在任意多的線程中調用test1函數,其輸出順序均會被保證(1,2,3,4...19,20).

2.2 靜態函數修飾

功能與2.1類似,均是對對象加鎖,確保多個類對象調用函數時保持順序.

Tips:
示例中,因為類上加鎖的原因,test1test2對象保持順序執行,不會出現test1...test2...交叉出現的現象.

3 synchronized不能被繼承

需要注意,若synchronized修飾於函數中,如1.2以及2.2,若有類繼承於SynchronizedExample1或者SynchronizedExample1,子類對象調用test2不同步.

原因:synchronized非函數簽名,因此無法被繼承,所以無法保證子類調用同步.

PS:
如果您覺得我的文章對您有幫助,可以掃碼領取下紅包,謝謝!


免責聲明!

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



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