Synchronize使用靜態變量作爲對象鎖

前言:
有人覺得使用靜態變量作爲對象鎖,用的是類鎖,還有人覺得靜態變量在使用的過程中,裏面的值改變,對象的地址會改變,所以用的就不是通一把鎖,今天我們驗證下。
一、使用同一把靜態變量鎖的情況:

public class SynchronizeTest {
    public static List<Person>list1;
    static {
        list1 = new ArrayList<>();
    }
    public static void method1(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (list1) {
                    for (int i = 0; i < 20; i++) {
                        System.out.println("method1");
                        try {
                            Thread.sleep(10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }).start();
    }
    public static void method2(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (list1) {
                    for (int i = 0; i < 20; i++) {
                        System.out.println("method2");
                        try {
                            Thread.sleep(10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }).start();
    }
    public static void main(String[] args) {
        SynchronizeTest t1 = new SynchronizeTest();
        SynchronizeTest t2 = new SynchronizeTest();
        t1.method1();
        t2.method2();
    }

結果:
運行完method1後再運行method2;因此使用的是同一把鎖,但只要使用靜態變量就是類鎖嗎?不是的,結果看實驗二。

二、使用不同的靜態變量鎖的情況:

public class SynchronizeTest {
    public static List<Person>list1;
    public static List<Person>list2;
    static {
        list1 = new ArrayList<>();
        list2 = new ArrayList<>();
    }
    public static void method1(){

        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (list1) {
                    for (int i = 0; i < 20; i++) {
                        System.out.println("method1");
                        try {
                            Thread.sleep(10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }).start();
    }
    public static void method2(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (list2) {
                    for (int i = 0; i < 20; i++) {
                        System.out.println("method2");
                        try {
                            Thread.sleep(10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }

        }).start();
    }
    public static void main(String[] args) {
        SynchronizeTest t1 = new SynchronizeTest();
        SynchronizeTest t2 = new SynchronizeTest();
        t1.method1();
        t2.method2();
    }
}

結果:method1和method2交替運行。因此,使用靜態變量作爲鎖,用的不是類鎖。
在這裏插入圖片描述三、對靜態變量值的改變,對鎖是否有影響。

我在對method1和method2這兩個方法使用list1這個鎖的過程中,開闢了第三個線程對list1的值的改變,發現list1這個鎖的不受影響,依然是method1執行完畢後再執行method2。

public class SynchronizeTest {

    public static Person person;
    public static List<Person>list1;
    static {
        list1 = new ArrayList<>();
        person = new Person(0);
    }
    public static void method1(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (list1) {
                    for (int i = 0; i < 20; i++) {
                        System.out.println("method1");
                        try {
                            Thread.sleep(20);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }

        }).start();
    }
    public static void method2(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (list1) {
                    for (int i = 0; i < 20; i++) {
                        System.out.println("method2");
                        try {
                            Thread.sleep(20);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }).start();
    }
    public static void method3(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i=0;i<20;i++){
                    try {
                        Thread.sleep(20);
                        System.out.println("-----");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    Person p = new Person(i);
                    list1.add(person);
                }
            }
        }).start();
    }
    public static void main(String[] args) {
        SynchronizeTest t1 = new SynchronizeTest();
        SynchronizeTest t2 = new SynchronizeTest();
        SynchronizeTest t3 = new SynchronizeTest();
        t1.method1();
        t2.method2();
        t3.method3();
    }
}

最後總結
使用list1和list2後使用的分別是list1和list2的對象鎖,雖然是靜態變量,但使用的不是類鎖。
使用靜態變量,對靜態變量值的改變,不會影響到此變量的地址,用的依然是同一把鎖。

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