Synchronized作用在靜態(tài)和非靜態(tài)方法上的區(qū)別

不就是鎖嗎怎么還這么細(xì)分,好吧得查資料看看
synchronized關(guān)鍵字的用法主要有以下幾種:

1.作用在非靜態(tài)方法上

非靜態(tài)方法是只能提供類的實(shí)例進(jìn)行調(diào)用,所以實(shí)際上就是對調(diào)用方法的對象加鎖,俗稱對象鎖

2.作用在靜態(tài)方法上

靜態(tài)方法是可以通過類名直接調(diào)用,所以實(shí)際上就是對調(diào)用方法的類加鎖,俗稱類鎖

3.作用在代碼塊

根據(jù)傳入的是類對象或類實(shí)例判斷加鎖方式

場景分析

public class SyncStaticClazz {

    public static synchronized void method1(){
       System.out.println("static ----method1----"+Thread.currentThread());
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    public static synchronized void method2(){
        System.out.println("static ----method2----"+Thread.currentThread());
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    public synchronized void method3(){
        System.out.println("unstatic ----method3----"+Thread.currentThread());
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
public class SyncClazz {

    public synchronized void method1(){
        System.out.println("normal----method1----"+Thread.currentThread());
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
    }


    public synchronized  void method2() 
            System.out.println("normal----method2----" + Thread.currentThread());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
        }
    }


    public  void method3() {
        synchronized (SyncClazz.class) {
            System.out.println("normal----method3----" + Thread.currentThread());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


    public  void method4() {
        synchronized (SyncClazz.this) {
            System.out.println("normal----method4----" + Thread.currentThread());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
  public  void method5() {
        synchronized (SyncClazz.class) {
            System.out.println("normal----method5----" + Thread.currentThread());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
}

場景1

        new Thread(new Runnable() {
            @Override
            public void run() {
              SyncStaticClazz.method1();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                SyncStaticClazz.method2();
            }
        }).start();

結(jié)果:互斥

解析:靜態(tài)同步方法的加鎖范圍是整個(gè)類,所以無論是使用對象或類去訪問靜態(tài)同步方法,鎖都會(huì)加到類對象上。就好比是房子的大門,房子內(nèi)不論有多少房間,只要有一個(gè)人打開大門進(jìn)入到房子里,其他人就只能等他出來之后再進(jìn)去,而已經(jīng)進(jìn)去的人擁有所有房間的使用權(quán)。

場景2

描述:在不同線程中用不同的類實(shí)例訪問相同靜態(tài)方法

      new Thread(new Runnable() {
            @Override
            public void run() {
                SyncStaticClazz syncStaticClazz = new SyncStaticClazz();
                syncStaticClazz.method1();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                SyncStaticClazz syncStaticClazz = new SyncStaticClazz();
                syncStaticClazz.method1();
            }
        }).start();

結(jié)果:互斥

解析:和場景1相同,靜態(tài)方法雖然可以被類實(shí)例訪問,但鎖依然是類鎖

場景3

描述:同一個(gè)對象在不同線程中訪問不同的非靜態(tài)同步方法

        SyncClazz syncClazz = new SyncClazz();
        new Thread(new Runnable() {
            @Override
            public void run() {
                syncClazz.method1();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                syncClazz.method2();
            }
        }).start();

結(jié)果:互斥

解析:非靜態(tài)方法上加的是對象鎖,當(dāng)對象調(diào)用一個(gè)非靜態(tài)的同步方法時(shí),其他的非靜態(tài)同步方法需要等待被執(zhí)行。

場景4

描述:不同對象在不同線程中訪問同一個(gè)非靜態(tài)方法

 new Thread(new Runnable() {
            @Override
            public void run() {
                SyncClazz syncClazz = new SyncClazz();
                syncClazz.method1();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                SyncClazz syncClazz = new SyncClazz();
                syncClazz.method1();
            }
        }).start();  

結(jié)果:不互斥

解析:因?yàn)橥ㄟ^不同的對象調(diào)用的是非靜態(tài)方法,雖然調(diào)用的是同一個(gè)方法,但是非靜態(tài)方法加的鎖是對象鎖,針對的是對象并不是方法,所以可以并發(fā)執(zhí)行,不會(huì)互斥。如果像場景1中的比喻的話,就是兩個(gè)對象是兩套房子,戶型相同而已。

場景5

描述:不同對象在不同線程中訪問同一個(gè)非靜態(tài)非同步方法,方法內(nèi)通過synchronized鎖定代碼塊,且鎖定對象為類對象

   new Thread(new Runnable() {
            @Override
            public void run() {
                SyncClazz syncClazz = new SyncClazz();
                syncClazz.method3();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                SyncClazz syncClazz = new SyncClazz();
                syncClazz.method3();
            }
        }).start();

結(jié)果:互斥

解析:因?yàn)榉椒╩ethod3()內(nèi)的synchronized鎖的是SyncClazz.class,也就是鎖定的是類對象,所以與場景2相同

場景6

描述:同一個(gè)對象在不同線程中訪問不同的非靜態(tài)非同步方法,方法內(nèi)通過synchronized鎖定代碼塊,且鎖定對象為類對象

        SyncClazz syncClazz = new SyncClazz();
        new Thread(new Runnable() {
            @Override
            public void run() {
                syncClazz.method3();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                syncClazz.method5();
            }
        }).start();
    }

結(jié)果:互斥

解析:因?yàn)榉椒╩ethod3()和method5()內(nèi)的synchronized鎖的是SyncClazz.class,也就是鎖定的是類對象,所以與場景2相同

場景7

描述:同一個(gè)對象在不同線程中訪問不同方法,一個(gè)調(diào)用靜態(tài)方法,一個(gè)調(diào)用非靜態(tài)方法

       SyncStaticClazz syncClazz = new SyncStaticClazz();
        new Thread(new Runnable() {
            @Override
            public void run() {
                syncClazz.method1();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                syncClazz.method3();
            }
        }).start();

結(jié)果:不互斥

解析:雖然是同一個(gè)對象調(diào)用,但是兩個(gè)方法的鎖類型不同,靜態(tài)方法是類鎖,非靜態(tài)方法是對象鎖,所以不會(huì)互斥

場景8

描述:同一個(gè)對象在不同線程中訪問不同synchronized代碼塊方法,一個(gè)調(diào)用類對象同步,一個(gè)調(diào)用類實(shí)例同步

        SyncClazz syncClazz = new SyncClazz();
        new Thread(new Runnable() {
            @Override
            public void run() {
                syncClazz.method3();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                syncClazz.method4();
            }
        }).start();

結(jié)果:不互斥

解析:與場景7相同

總結(jié)

對象鎖僅鎖當(dāng)前對象,不同對象之間不會(huì)互斥
靜態(tài)方法上的鎖是類鎖,非靜態(tài)方法上的鎖是對象鎖
所有靜態(tài)同步方法互斥,無論是通過類調(diào)用還是對象調(diào)用
靜態(tài)方法上加synchronized與在非靜態(tài)方法內(nèi)加synchronized(Xxx.class)效果一致,都是類鎖

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容