爲什麼說java的synchronized 鎖定代碼塊和synchronized鎖定類對象都指的類對象?

鎖定代碼塊等價於鎖定對象

首選看一下鎖定代碼塊的語法?

    synchronized (對象)
    {
        // 代碼塊
    }

上面的語法中的"對象",指的是實例對象,可以是this,Class.clss或者其他共享對象.所以代碼塊鎖定的等價於對象鎖定.我們甚至還可以假設一下.把上面代碼的"對象"做成變量:

    public void func1(Object lock) { // 這個方法沒有鎖定,鎖定的是裏面的代碼塊

        synchronized (lock) {

            System.out.println("方法開始");
            try {
                Thread.sleep(3000);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("方法結束");
        }
    }

那如果我們鎖住的不是lock對象,而是func1裏面的代碼,那無論傳入的lock對象是什麼,這段代碼都不能併發執行了.這顯然是不可能的.我們看看輸出也再次證明了這個結論:

方法開始
方法開始
方法結束
方法結束

鎖定非靜態方法等價於鎖定對象

先拋出原因:

對象的非靜態 synchronized 方法被調用的時候,會先將對象鎖定,類似自動調用synchronized(this).

驗證:

假如我們一個進程先調用對象的非靜態 synchronized 方法,然後另一個進程調用 synchronized(this).
如果第一個進程沒有爲對象加鎖,第二個進程就能調用成功,然後兩者是並行的,結論不成立
反之,第二個進程無法獲得對象鎖,兩個進程就必須串行,結論成立

  1. 先定義共享對象
class TestSyn {

    public synchronized void func1() { // 這個方法沒有鎖定,鎖定的是裏面的代碼塊


        System.out.println("我是方法10");
        try {
            Thread.sleep(3000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("我是方法11");
    }

    public void func2() {

        synchronized (this)
        {
            System.out.println("我是方法20");

            try {
                Thread.sleep(3000);
            } catch (Exception e) {
                e.printStackTrace();
            }

            System.out.println("我是方法21");
        }
    }
}

2.然後定義兩個線程分別調用共享對象的不同方法

public class Singleton {
    public static void main(String[] args) throws InterruptedException {
        TestSyn testSyn = new TestSyn();
        new Thread(new Runnable() {
            @Override
            public void run() {
                testSyn.func1();
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                testSyn.func2();
            }
        }).start();
    }
}

3.查看輸出

我是方法10
我是方法11
我是方法20
我是方法21

最後得出結論

程序串行執行,所以第二個人線程調用方法fun2的時候沒有得到this的鎖.說明this已經被鎖定.

引申: 同一個對象的兩個同步非靜態方法可以併發執行嗎?

答案:不行,因爲兩者都要獲得this鎖,屬於競爭關係

證明:

  1. 先定義同步對象
class TestSyn {

    public synchronized void func1() { // 這個方法沒有鎖定,鎖定的是裏面的代碼塊


        System.out.println("我是方法10");
        try {
            Thread.sleep(3000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("我是方法11");
    }

    public synchronized void func2() {

        System.out.println("我是方法20");

        try {
            Thread.sleep(3000);
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("我是方法21");
    }
}
  1. 然後定義兩個線程分別調用這兩個方法
public class Singleton {
    public static void main(String[] args) throws InterruptedException {
        TestSyn testSyn = new TestSyn();
        new Thread(new Runnable() {
            @Override
            public void run() {
                testSyn.func1();
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                testSyn.func2();
            }
        }).start();
    }
}
  1. 查看輸出是串行執行.
我是方法10
我是方法11
我是方法20
我是方法21
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章