synchronized使用

synsynchronized的使用方法:
1、synchronized修飾方法

(1)synchronized修飾非靜態方法: 鎖的是方法的調用者

import java.util.concurrent.TimeUnit;
class Data {

    /*synchronized修飾非靜態方法,鎖的是即方法的調用者,即
       調用func1方法的對象*/
    public synchronized void func1() {
        try {
            TimeUnit.SECONDS.sleep(3);//休眠3秒
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("1....");
    }

    public synchronized void func2() {
        System.out.println("2....");
    }

}

Test1:

public class Test1 {
    public static void main(String[] args) {
       Data data=new Data();
        new  Thread(()->{
            data.func1();
        }).start();
        new  Thread(()->{
            data.func2();
        }).start();
    }
}

結果爲:
在這裏插入圖片描述
在上面的代碼中,由於synchronized修飾非靜態方法:,鎖的是方法的調用者;
所以 在本代碼中鎖的是Data類的對象,不同的Data對象,有不同的鎖,但是此代碼中只有一個data對象,第一個線程執行的是data.fun1()方法,第二個線程執行的是data.fun2()方法;

所以當第一個線程執行data.fun1()方法,獲取到data對象的鎖之後,執行data.fun1()方法,第二個線程獲取不到data對象的鎖,所以第二個線程中的方法data.fun2()方法無法執行;只有當第一個線程執行完畢(data.fun1()方法執行完),釋放了data鎖之後,第二個線程才能獲取到data的鎖,執行data.fun2()方法;

Test2:

public class Test1 {

    public static void main(String[] args) {

        Data data = new Data();
        Data data2 = new Data();
        new Thread(() -> {
            data.func1();
        }).start();
        new Thread(() -> {
            data2.func2();
        }).start();
    }
}

結果爲:

在這裏插入圖片描述
在上面的代碼中,由於synchronized修飾非靜態方法:,鎖的是方法的調用者;
所以鎖的是Data類的對象,不同的Data對象,有不同的鎖,此代碼中有兩個Data對象:data,data2;

所以當第一個線程獲取到data對象的鎖之後,執行data.fun1()方法;第二個線程執行的是data2.fun2()方法,其與第一個線程獲取的不是同一個對象的鎖,所以也能與第一個線程同時執行,但fun1()方法中,線程休眠了3秒,所以結果先輸出2,再輸出1;

(2)synchronized修飾靜態方法:鎖的是class本身

class Data2 {
    /*synchronized修飾靜態方法,鎖的是class本身,本代碼中
        鎖的是Data2這個類本身,鎖定的不是對象*/
    public synchronized static void func1() {
        try {
            TimeUnit.SECONDS.sleep(3);//休眠3秒
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("1....");
    }

    public synchronized static void func2() {

        System.out.println("2....");
    }
  
}

Test1:

public class Test2 {

    public static void main(String[] args) {
        Data2 data1=new Data2();
        new  Thread(()->{
            data1.func1();
        }).start();
        new  Thread(()->{
            data1.func2();
        }).start();
    }
}

結果爲:
在這裏插入圖片描述
上面的代碼中,由於synchronized修飾靜態方,:鎖的是class本身;

所以第一個線程執行data1.func1()方法,獲取到了Data類的鎖;而第二個線程中執行的方法是data1.func2()方法,但因爲第一個線程已經獲取了Data類的鎖,所以無法獲取鎖,只有當第一個線程執行完data1.func1()方法之後,釋放了Data類的鎖,第二個線程才能運行執行獲取到Data類的鎖,執行data1.func2()方法;

Test2:

public class Test2 {
    public static void main(String[] args) {
        Data2 data1=new Data2();
        Data2 data2=new Data2();
        new  Thread(()->{
            data1.func1();
        }).start();
        new  Thread(()->{
            data2.func2();
        }).start();
    }
}

結果爲:
在這裏插入圖片描述
在上面的代碼中,synchronized修飾的是靜態方法(static修飾的方法),則鎖的是class本身;
所以在本代碼中,鎖的是Data.class這個類對象,由於一個類只有一個class對象,所以不管該類有幾個實例對象,當一個線程獲取該類的鎖之後,其他線程就無法獲取該類的鎖了,只有當上一個線程釋放了鎖之後,其他線程才能獲取這個類的鎖,執行方法

2、synchronized修飾代碼塊

(1)synchronized(類對象)即synchronized(class):鎖的是同一個類

class Data3{
    public   void func1(Integer num) {
        synchronized (Data3.class) {//鎖的是同一個類
            System.out.println("start....");
            try {
                TimeUnit.SECONDS.sleep(3);//休眠3秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("end....");
        }
    }
}

Test:

import java.util.concurrent.TimeUnit;

public class Test3 {
    public static void main(String[] args) {

        Data3 data=new Data3();
        for(int i=0;i<5;i++){
            Integer num=Integer.valueOf(i);
            new Thread(()->{
            data.func1(num);
            }).start();
        }
    }
}

結果爲:
在這裏插入圖片描述

由於代碼中 synchronized (Data3.class)鎖的是Data3.class這個類對象,
所以對於代碼中的那5個線程,每次執行fun1(num)方法時,只有當一個線程獲取到Data3.class這個類的鎖之後,執行完func1(num)方法,釋放了Data3.class的鎖之後,才能執行下一個線程;

(2)synchronized(對象):鎖的是同一個對象

class Data3{
    public   void func2(Integer num) {
        synchronized (num) {//鎖的是同一個num對象
            System.out.println(num+"start....");
            try {
                TimeUnit.SECONDS.sleep(3);//休眠3秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("end....");
        }
    }
}

Test:

import java.util.concurrent.TimeUnit;

public class Test3 {

    public static void main(String[] args) {

        Data3 data=new Data3();
        for(int i=0;i<5;i++){
            Integer num=Integer.valueOf(1);//同一個num對象
            new Thread(()->{
                data.func2(num);
            }).start();
        }
    }
}

結果爲:
在這裏插入圖片描述

由於代碼中 synchronized (num)鎖的是num這個實例對象;
又由於 Integer num=Integer.valueOf(1),不管創建多少次,都是對應的堆中的同一個對象,
所以對於代碼中的那5個線程,每次執行fun2(num)方法時,鎖的時同一個num,只有當一個線程獲取到num這個對象的鎖之後,執行完func2(num)方法,釋放了num的鎖之後,才能執行下一個線程;

Test3:

public class Test3 {

    public static void main(String[] args) {

        Data3 data=new Data3();
        for(int i=0;i<5;i++){
            Integer num=Integer.valueOf(i);//不同的num對象
            new Thread(()->{
              data.func2(num);
            }).start();
        }
     
    }
}

結果爲:
在這裏插入圖片描述
由於代碼中 synchronized (num)鎖的是num這個實例對象;
又由於 Integer num=Integer.valueOf(i),這5次創建過程中,對應的是不同的num實例對象;

所以對於代碼中的那5個線程,每次執行fun2(num)方法時,鎖的都不是同一個num的鎖,他們互不影響,所以5個線程同時執行;

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