天天看點

synchronized修飾方法前言一、Synchronized修飾非靜态方法二、Synchronized修飾靜态方法三、類鎖和對象鎖的通路是不沖突的四、總結

文章目錄

  • 前言
  • 一、Synchronized修飾非靜态方法
  • 二、Synchronized修飾靜态方法
  • 三、類鎖和對象鎖的通路是不沖突的
  • 四、總結

前言

直接說結論:

1.Synchronized修飾非靜态方法,實際上是對調用該方法的對象加鎖,俗稱“對象鎖”。

2.Synchronized修飾靜态方法,實際上是對該類對象加鎖,俗稱“類鎖”。

3.對于類鎖synchronized static,是通過該類直接調用加類鎖的方法,而對象鎖是建立對象調用加對象鎖的方法,兩者通路是不沖突的,對于同一類型鎖鎖住的方法,同一對象是無法同時通路的.

一、Synchronized修飾非靜态方法

Synchronized修飾非靜态方法,實際上是對調用該方法的對象加鎖,俗稱“對象鎖”。

如果采用形象的比喻就是,對于這個對象可能有很多方法(房間),有一些加了鎖(鎖門的房間),而這些房間共用一把鑰匙,導緻當一個被鎖方法被通路時,無法通路其他帶鎖的方法。

但是需要注意:一個對象可以拿一把鑰匙,多個對象可以插隊執行。

考慮下圖代碼,想一下會輸出什麼。

public class TestSyn {
    public static void main(String[] args) {
        Number number = new Number();

        new Thread(new Runnable() {
            @Override
            public void run() {
                number.getOne();
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                number.getTwo();
            }
        }).start();
    }
}

class Number{
    public synchronized void getOne(){
        try {
            Thread.sleep(2000);
            System.out.println("one");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public synchronized void getTwo(){
        System.out.println("two");
    }
}

           

答案是輸出one two

因為getOne()雖然要停止2秒,但上了對象鎖,getTwo()不能超車(通路),要等getOne()被調用完,把鑰匙換回來,才能繼續執行

二、Synchronized修飾靜态方法

Synchronized修飾靜态方法,實際上是對該類對象加鎖,俗稱“類鎖”。

類對象隻有一個,隻在郊外有這一棟别墅,裡面的靜态方法也被一把鎖管着。因為一個類對象隻能拿一把鎖。

将兩個方法都設為static,猜猜會輸出什麼

package JUC_test;

public class TestSyn {
    public static void main(String[] args) {
        Number number = new Number();

        new Thread(new Runnable() {
            @Override
            public void run() {
                number.getOne();
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                number.getTwo();
            }
        }).start();
    }
}

class Number{
    public static synchronized void getOne(){
        try {
            Thread.sleep(2000);
            System.out.println("one");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public static synchronized  void getTwo(){
        System.out.println("two");
    }
}

           

輸出one two

也可以不new對象直接類對象調用

package JUC_test;

public class TestSyn {
    public static void main(String[] args) {
        Number number = new Number();

        new Thread(new Runnable() {
            @Override
            public void run() {
//                number.getOne();
                Number.getOne();
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
//                number.getTwo();
                Number.getTwo();
            }
        }).start();
    }
}

class Number{
    public static synchronized void getOne(){
        try {
            Thread.sleep(2000);
            System.out.println("one");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public static synchronized  void getTwo(){
        System.out.println("two");
    }
}
           

答案是 one two

顯然,這次我們直接插隊進别墅大門失敗了,很好地解釋了類鎖

三、類鎖和對象鎖的通路是不沖突的

現在我們設定為one靜态,two非靜态,猜猜會發生什麼

package JUC_test;

public class TestSyn {
    public static void main(String[] args) {
        Number number = new Number();

        new Thread(new Runnable() {
            @Override
            public void run() {
//                number.getOne();
                Number.getOne();
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                number.getTwo();
//                Number.getTwo();
            }
        }).start();
    }
}

class Number{
    public static synchronized void getOne(){
        try {
            Thread.sleep(2000);
            System.out.println("one");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public synchronized  void getTwo(){
        System.out.println("two");
    }
}
           

答案是 two one

你開别墅大門,關我别墅内的狗窩什麼事?

package JUC_test;

public class TestSyn {
    public static void main(String[] args) {
        Number number = new Number();

        new Thread(new Runnable() {
            @Override
            public void run() {
                number.getOne();
//                Number.getOne();
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
//                number.getTwo();
                Number.getTwo();
            }
        }).start();
    }
}

class Number{
    public  synchronized void getOne(){
        try {
            Thread.sleep(2000);
            System.out.println("one");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public static synchronized  void getTwo(){
        System.out.println("two");
    }
}

           

答案是 two one

同理,你開狗窩大門,關我别墅什麼事?

四、總結

對于synchronized修飾方法的調用

我們考慮了

非靜态 非靜态

靜态 靜态

靜态 非靜态

非靜态 靜态

四種情況,

可以留下思考,如果這些換成兩個對象去調用呢?

答案會是什麼呢?

two one

one two(有兩個執行個體對象,但隻有一個類對象)

two one

two one