static修飾的類方法,被synchronized修飾後鎖定的是類對象仍是實例對象

主要明白一點: synchronized static 被鎖定的是同一塊區域,爲啥?由於static修飾的變量和方法在內存中都是惟一的java

package Thread;

import java.util.concurrent.CountDownLatch;

public class TestSynStatic {

    /**
     *  當每一個線程都new出來一個對象時,線程在執行時會建立本身的字段 i 和 add1 的副本,是線程安全的。
     *  當每一個線程都共用new出來的一個對象時,不是線程安全的。
     */
    int i = 0;
    public void add1(){
        for (int i1 = 0; i1 < 100; i1++) {
            i++;
        }
        System.out.println("i:" + i);
    }

    /**
     *  存在在安全性問題, static 關鍵詞修飾的變量會被線程共享,該變量 j 放在JVM的靜態區域共享
     */
    static int j = 0;
    public void add2(){
        for (int i1 = 0; i1 < 100; i1++) {
            j++;
        }
        System.out.println("j:" + j);
    }

    /**
     *  存在在安全性問題, static 關鍵詞修飾的變量,該變量 k 放在JVM的靜態區域被多線程共享
     *  鎖定的是新的實例
     *  當每一個線程都共用new出來的一個對象時,是線程安全的。
     *  當每一個線程都new出來一個對象時,不是線程安全的。
     */
    static int k = 0;
    public synchronized void add3(){
        for (int i1 = 0; i1 < 100; i1++) {
            k++;
        }
        System.out.println("k:" + k);
    }

    /**
     *  鎖定的是JVM中的類,注意不是JVM中new出來的對象,線程安全
     */
    static int m = 0;
    public synchronized static void add4(){
        for (int i1 = 0; i1 < 100; i1++) {
            m++;
        }
        System.out.println("m:" + m);
    }

    public static void main(String[] args) {
        CountDownLatch countDownLatch = new CountDownLatch(50);
        TestSynStatic testSynStatic = new TestSynStatic();


        for (int i = 0; i < 50; i++) {
            new Thread(() -> {
//                TestSynStatic testSynStatic = new TestSynStatic();
//                testSynStatic.add1();
//                testSynStatic.add2();
//                testSynStatic.add3(); // 鎖定的是新的實例,不是線程安全的。
                testSynStatic.add4(); // 鎖定的是JVM中的類,線程安全
                countDownLatch.countDown();
            }).start();
        }

        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
相關文章
相關標籤/搜索