【併發】android中的synchronized 1 使用synchronized修飾方法 2 使用synchronized修飾代碼塊

synchronized用於多線程訪問,並且被修飾的部分不能同時被執行,是代碼同步的一種方式。

1 使用synchronized修飾方法

1.1 synchronized修飾方法原理

  • 過程:當多個線程同時訪問被synchronized修飾的方法是,有且僅有一個線程可以被訪問,當一個線程在訪問時,其它線程只能等待。當一個線程訪問完畢後,下一個線程纔可以訪問。
  • 原理:當方法被synchronized修飾後,如果想要執行該方法就必須獲得相應的鎖。每個類有且僅有一個鎖(針對靜態方法),每個類的實例也是有且僅有一個鎖。當多個線程在同時訪問同一個方法時,執行該方法就必須獲得相應的鎖,同時鎖只有一個,所以只能有一個線程可以獲得鎖,其它的線程必須等待該線程釋放鎖後才能獲取到該鎖。
  • 進階說明:由於每個類只有一個鎖,所以當一個類中有多個方法被synchronized修飾時,在同一時間內只能有一個方法可以獲得鎖,所以只有一個被synchronized修飾的方法可以執行。

1.2 synchronized修飾方法示例

    public void showDo(String msg){
        for(int i=0;i<1000000;i++){
            if (i%100000==0){
                System.out.println("打印結果"+msg+i/100000);
            }
        }
    }

//使用
        new Thread(){
            @Override
            public void run() {
                super.run();
                showDo("線程一");
            }
        }.start();
        new Thread(){
            @Override
            public void run() {
                super.run();
                showDo("線程二");
            }
        }.start();

結果:


未加synchronized修飾方法,可以看到執行順序是打亂的,無序的。加了synchronized後:

    public synchronized void showDo(String msg){
        for(int i=0;i<1000000;i++){
            if (i%100000==0){
                System.out.println("打印結果"+msg+i/100000);
            }
        }
    }

結果


2 使用synchronized修飾代碼塊

2.1使用synchronized修飾代碼塊說明

當使用synchronized在修飾代碼塊的時候需要一個自定義鎖,當在多線程訪問代碼塊的時候,只要獲得自定義鎖就可以執行。自定義鎖可以是一個類,也可以是一個實例(可以是Object的子類,也可以是當前類自己),當具有相同自定義鎖時代碼塊會順序執行,當鎖不同的時候互不影響。

2.2 使用synchronized修飾代碼塊示例

    private static String s1 = "";
    private static String s2 = "aa";

    public void showDo(String msg) {
        synchronized (s1){
            for (int i = 0; i < 1000000; i++) {
                if (i % 100000 == 0) {
                    System.out.println("打印結果" + msg + i / 100000);
                }
            }
        }
    }

    public void showDo1(String msg) {
        synchronized (s2){
            for (int i = 0; i < 1000000; i++) {
                if (i % 100000 == 0) {
                    System.out.println("打印" + msg + i / 100000);
                }
            }
        }
    }

//調用
        new Thread() {
            @Override
            public void run() {
                super.run();
                showDo1("線程一");
            }
        }.start();
        new Thread() {
            @Override
            public void run() {
                super.run();
                showDo("線程二");
                showDo1("線程二");
            }
        }.start();

結果:


由上可得,多個同步鎖,只有競爭同一個同步鎖纔會需要等待,不是競爭同一個鎖的代碼塊互不影響。

  • synchronized不能修飾構造函數
  • 定義接口方法時不能使用synchronized
  • synchronized(this)鎖的是當前對象,當前有幾個對象,this就有多少份
  • synchronized(XX.class)這個與當前對象無關,只要鎖是XX.class的都會被同步
  • 如果同一個類中有多個方法使用了同步鎖synchronized(this)或者多個方法被synchronized修飾,則多個線程訪問該類中同步方法時,每次只能訪問一個,其它的被阻塞。如:
public synchronized void A(){
    ......
}
public synchronized void B(){
    ......
}

有兩個線程分別訪問同一個對象T的A方法和B方法,則同時只能有一個方法被其中一個線程訪問,另一個線程處於阻塞狀態,因爲方法A和B持有同一個對象鎖,synchronized(this)也是類似的情況。

  • 同一個類中有多個方法使用了同步鎖synchronized修飾,且這些類是靜態的,因爲靜態方法是屬於類的,而不是屬於某個對象的,所以它與synchronized(XX.class)類似。
public synchronized static void method() {
   // todo
}
  • 每個對象只有一個鎖(lock)與之相關聯,誰拿到這個鎖誰就可以運行它所控制的那段代碼。
  • 實現同步是要很大的系統開銷作爲代價的,甚至可能造成死鎖,所以儘量避免無謂的同步控制。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章