Java基礎問題系列-同步之Synchronized關鍵字

一個問題,有簡單的類如下,有一個靜態synchronized方法,兩個非靜態synchronized方法,這個類的兩個對象(實例):A,B,那麼以下幾種情況中,那種組合的方法執行會發生互斥(鎖競爭)?

1、SyncTest.method1,A.method1;2、A.method2, B.method2;3、SyncTest.method1,A.method2;4、A.method2,A.method3

類示例代碼如下:

public class SyncTest {

    public synchronized static void method1(String name){
        System.out.println(name+" is running method1 start");
        try{
            Thread.sleep(2000);
        }catch (InterruptedException e){

        }
        System.out.println(name+" is running method1 end");
    }

    public synchronized void method2(String name){
        System.out.println(name+" is running method2 start");
        try{
            Thread.sleep(2000);
        }catch (InterruptedException e){

        }
        System.out.println(name+" is running method2 end");
    }

    public synchronized void method3(String name){
        System.out.println(name+" is running method3 start");
        try{
            Thread.sleep(2000);
        }catch (InterruptedException e){

        }
        System.out.println(name+" is running method3 end");
    }

}

先說結果:

發生互斥情況的組合爲: 1、SyncTest.method1,A.method1;4、A.method2,A.method3

不互斥的情況爲:2、A.method2, B.method2;3、SyncTest.method1,A.method2;

其實也並不複雜,瞭解synchronize的作用域這個問題就很清晰了、

1、synchronized修飾靜態方法時,鎖是類鎖(.class)。這個範圍就比對象鎖大。這裏就算是不同對象,但是隻要是該類的對象,就使用的是同一把鎖。多個線程調用該類的同步的靜態方法時,都會阻塞。所以 1 成立

2、synchronized修飾普通方法時,鎖是對象鎖(this)。

當該類中有多個普通方法被synchronized修飾(同步),那麼這些方法的鎖都是這個類的一個對象this。多個線程訪問這些方法時,如果這些線程調用方法時使用的是同一個該類的對象,雖然他們訪問不同方法,但是他們使用同一個對象來調用,那麼這些方法的鎖就是一樣的,就是這個對象,那麼會造成阻塞。如果多個線程通過不同的對象來調用方法(一般都是通過同一個對象訪問),那麼他們的鎖就是不一樣的,不會造成阻塞。

所以4 是使用一個對象中的兩個synchronized方法,執行時都鎖當前對象,導致出現競爭。

用於驗證的執行代碼示例如下:

package com.java.learn.mine.basic.lock.synchronizetest;


public class SyncTest {

    public synchronized static void method1(String name){
        System.out.println(name+" is running method1 start");
        try{
            Thread.sleep(2000);
        }catch (InterruptedException e){

        }
        System.out.println(name+" is running method1 end");
    }

    public synchronized void method2(String name){
        System.out.println(name+" is running method2 start");
        try{
            Thread.sleep(2000);
        }catch (InterruptedException e){

        }
        System.out.println(name+" is running method2 end");
    }

    public synchronized void method3(String name){
        System.out.println(name+" is running method3 start");
        try{
            Thread.sleep(2000);
        }catch (InterruptedException e){

        }
        System.out.println(name+" is running method3 end");
    }

    public static void main(String[] args){
        SyncTest syncTest = new SyncTest();
//        SyncTest syncTestA2 = new SyncTest();


        Thread threadA = new ThreadA(syncTest);
        Thread threadB = new ThreadB(syncTest);

        threadA.start();
        threadB.start();
    }
}

class ThreadA extends Thread{
    private SyncTest syncTest;

    public ThreadA(SyncTest syncTest){
        this.syncTest = syncTest;
    }

    @Override
    public void run(){
//        SyncTest.method1("ThreadA");

//        SyncTest syncTest = new SyncTest();
//        syncTest.method2("ThreadA");

//        syncTest.method2(ThreadA.class.getName());

        SyncTest.method1(ThreadA.class.getName());
    }
}

class ThreadB extends Thread{
    private SyncTest syncTest;

    public ThreadB(SyncTest syncTest){
        this.syncTest = syncTest;
    }

    @Override
    public void run(){
//        SyncTest syncTest = new SyncTest();
//        SyncTest.method1("ThreadB");
//        syncTest.method1("ThreadB");

//        syncTest.method2(ThreadB.class.getName());
        syncTest.method3(ThreadB.class.getName());
    }
}

執行後,可以通過打印信息中的start、end來判定兩個線程是否同時開始執行方法;進而確定是否發生了鎖競爭

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章