synchronized鎖住的是代碼還是對象


不同的對象

public class Sync {
    public synchronized void test() {
        System.out.println("test start");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("test end");
    }
}

#

public class MyThread extends Thread{
    public void run() {
        Sync sync = new Sync();
        sync.test();
    }

    public static void main(String[] args) {
        for (int i = 0; i < 3; ++i) {
            Thread thread = new MyThread();
            thread.start();
        }
    }
}

執行結果

test start
test start
test start
test end
test end
test end  

現象

在MyThread中,每次都new一個新的Sync對象,可以看到代碼塊test雖然被加了synchonized但是還是並行執行的,初步結論:鎖住的不是代碼塊

同一個對象

public class MyThread2 extends Thread{
    public Sync sync;
    MyThread2(Sync sync) {
        this.sync = sync;
    }

    public void run() {
        System.out.println("hi....");
        sync.test();
    }

    public static void main(String[] args) {
        Sync sync = new Sync();
        for (int i = 0; i < 3; ++i) {
            Thread thread = new MyThread2(sync);
            thread.start();
        }
    }

執行結果

hi....
test start
hi....
hi....
test end
test start
test end
test start
test end  

現象

可以看到當他們共用一個對象的時候,synchonized起了作用,這塊代碼是串行執行的

結論

鎖住的是對象

如何在多對象的時候任然鎖住代碼?

解決也很簡單,只要鎖住同一個對象就行了。例如:synchronized后的括號中鎖同一個固定對象,這樣就行了。

這樣是沒問題,但是,比較多的做法是讓synchronized鎖這個類對應的Class對象。

public class Sync2 {
    public void test() {
        synchronized (Sync2.class) {
            System.out.println("test start");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("test end");
        }
    }
}

#

public class MyThread3 extends Thread{
    public void run() {
        Sync2 sync = new Sync2();
        sync.test();
    }

    public static void main(String[] args) {
        for (int i = 0; i < 3; ++i) {
            Thread thread = new MyThread3();
            thread.start();
        }
    }
}

執行結果

test start
test end
test start
test end
test start
test end

synchronized的兩大不足

  • 由於我們沒辦法設置synchronized關鍵字在獲取鎖的時候等待時間,所以synchronized可能會導致線程為了加鎖而無限期地處於阻塞狀態
  • 使用synchronized關鍵字等同於使用了互斥鎖,即其他線程都無法獲得鎖對象的訪問權。這種策略對於讀多寫少的應用而言是很不利的,因為即使多個讀者看似可以並發運行,但他們實際上還是串行的,並將最終導致並發性能的下降。 

雖然synchronized已經作為一個關鍵字被固化在Java語言中了,但它只提供了一種相當保守的線程安全策略,且該策略開放給程序員的控制能力極弱

參考

synchonized控制對象還是代碼段

synchronized的兩大不足

 


免責聲明!

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



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