java多線程之-----靜態同步synchronized方法與synchronized(class) 代碼塊

這個也是我在面試中被問到的一個題目(synchronize修飾靜態方法和非靜態方法的區別),這個沒答出來
關鍵字synchronized還可以應用在static靜態方法上,如果這樣寫,那是對當前的*.java文件對應的Class類進行持鎖,測試項目:類文件Service.java代碼如下:

public class Service {
    synchronized public static void PrintA(){
        try {
            System.out.println("線程的名稱爲:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"進入printA");
            Thread.sleep(3000);
            System.out.println("線程的名稱爲:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"離開printA");
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
    synchronized public static void PrintB(){

            System.out.println("線程的名稱爲:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"進入printB");   
            System.out.println("線程的名稱爲:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"離開printB");

    }
}

ThreadA的代碼:


public class ThreadA extends Thread{

    @Override
    public void run() {
        // TODO Auto-generated method stub
        super.run();
        Service.PrintA();
    }


}

ThreadB:

public class ThreadB extends Thread{

    @Override
    public void run() {
        // TODO Auto-generated method stub
        super.run();
        Service.PrintB();
    }


}

運行測試代碼:

public class Test1 {
    public static void main(String[] args) throws InterruptedException {    
        ThreadA a = new ThreadA();
        a.setName("A");
        a.start();
        ThreadB b = new ThreadB();
        b.setName("B");
        b.start();

    }
}

運行結果:
這裏寫圖片描述

從運行結果來看,並沒有什麼特別地方,都是同步的效果,和將synchronized關鍵字加到非靜態static方法上使用的效果是一樣的,其實還是有本質上的不同,synchronized關鍵字加到static靜態方法上是給Class類上鎖,而synchronized關鍵字加到非static靜態方法上是給對象上鎖:

爲了驗證不是同一個鎖。創建新的 項目,Service.java的代碼如下:


public class Service {
    synchronized public static void PrintA() {
        try {
            System.out.println("線程的名稱爲:" + Thread.currentThread().getName()
                    + "在" + System.currentTimeMillis() + "進入printA");
            Thread.sleep(3000);
            System.out.println("線程的名稱爲:" + Thread.currentThread().getName()
                    + "在" + System.currentTimeMillis() + "離開printA");
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    synchronized public static void PrintB() {
        System.out.println("線程的名稱爲:" + Thread.currentThread().getName() + "在"
                + System.currentTimeMillis() + "進入printB");

        System.out.println("線程的名稱爲:" + Thread.currentThread().getName() + "在"
                + System.currentTimeMillis() + "離開printB");
    }

    synchronized public void PrintC() {
        System.out.println("線程的名稱爲:" + Thread.currentThread().getName() + "在"
                + System.currentTimeMillis() + "進入printB");
        System.out.println("線程的名稱爲:" + Thread.currentThread().getName() + "在"
                + System.currentTimeMillis() + "離開printB");

    }
}

ThreadA :

public class ThreadA extends Thread{
    private Service service;
    public ThreadA(Service service) {
        // TODO Auto-generated constructor stub
        super();
        this.service = service;
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        super.run();
        service.PrintA();
    }

}

ThreadB:

public class ThreadB extends Thread{
    private Service service;
    public ThreadB(Service service) {
        // TODO Auto-generated constructor stub
        super();
        this.service = service;
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        super.run();
        service.PrintB();
    }

}

ThreadC:

public class ThreadC extends Thread{
    private Service service;
    public ThreadC(Service service) {
        // TODO Auto-generated constructor stub
        super();
        this.service = service;
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        super.run();
        service.PrintC();
    }

}

測試代碼類:


public class Test1 {
    public static void main(String[] args) throws InterruptedException {    
        Service service = new Service();
        ThreadA a = new ThreadA(service);
        a.setName("A");
        a.start();
        ThreadB b = new ThreadB(service);
        b.setName("B");
        b.start();
        ThreadC c = new ThreadC(service);
        c.setName("C");
        c.start();

    }
}

運行結果:
這裏寫圖片描述

結果產生異步的原因是持有不同的鎖,一個是對象鎖,一個是Class鎖,而Class鎖可以對類的所有對象實例起作用。如果不是Class鎖的話,則多個實例就有多個鎖,上文章有說到。下面驗證Class鎖對所有的實例起作用

修改運行測試文件如下:

public class Test1 {
    public static void main(String[] args) throws InterruptedException {    
        Service service = new Service();
        Service service2 = new Service();
        ThreadA a = new ThreadA(service);
        a.setName("A");
        a.start();
        ThreadB b = new ThreadB(service2);
        b.setName("B");
        b.start();

    }
}

運行結果:
這裏寫圖片描述

由結果來看,依然是同步進行的,也就是說明了Class鎖對所有實例起作用。

同步Synchronized(class) 的實質其實和synchronized static 方法一樣,都是給Class加鎖。驗證:
修改Service代碼:

public class Service {
    public void PrintA() {
        synchronized (Service.class) {
            try {
                System.out.println("線程的名稱爲:" + Thread.currentThread().getName()
                        + "在" + System.currentTimeMillis() + "進入printA");
                Thread.sleep(3000);
                System.out.println("線程的名稱爲:" + Thread.currentThread().getName()
                        + "在" + System.currentTimeMillis() + "離開printA");
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    }

    public  void PrintB() {
        synchronized (Service.class) {
            System.out.println("線程的名稱爲:" + Thread.currentThread().getName()
                    + "在" + System.currentTimeMillis() + "進入printB");

            System.out.println("線程的名稱爲:" + Thread.currentThread().getName()
                    + "在" + System.currentTimeMillis() + "離開printB");
        }
    }
}
注意:PrintA和PrintB方法加不加static都一樣了這時
再次運行代碼得:

這裏寫圖片描述

結論:靜態同步synchronized方法與synchronized(class)代碼塊效果一樣,沒有本質上的區別,與非靜態的方法比起來,非靜態的是給對象上鎖。多個對象的時候會給多個對象上鎖。依舊是異步的。而靜態的方法,則因爲持有的是Class鎖,所以多個對象創建的時候,因爲其Class依舊是一樣的,所有就會是同步狀態

發佈了55 篇原創文章 · 獲贊 58 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章