Java多線程 synchronized與可見性的關係以及可見性問題總結

@[toc]java

能保證可見性的措施

除了volatile 可讓變量保證可見性外.緩存

以下這篇文章中,介紹的happens-before九大規則. 都是可以保證可見性的. 其中就包含了鎖操做(synchronized 和 lock) 和 volatile 修飾的變量安全

https://javaweixin6.blog.csdn.net/article/details/108423590app

synchronized做用的昇華

  • synchronized 關鍵字不單單保證了其代碼塊中的原子性 ,也保證了可見性. 例如以下代碼中的i++操做 , 使用了synchronized 代碼塊保護起來, 使得兩個線程對其相加的時候, 能夠正確的得出20萬的結果.
    這個結果不單單是保證了其i相加時候的原子性. 也說明保證了其可見性. 不然一個線程加完了以後, 另一個線程沒有獲取i的最新的值的話, 也會致使相加的結果變少.
  • synchronized 不單單讓被保護的代碼安全, 還會保證對synchronized 修飾的代碼執行完畢以後, 下一個synchronized 進入以前, 整個synchronized 保護的代碼塊,都會被以後執行的代碼看獲得. 而且synchronized 以前的全部的代碼也會被看到 . 以下面這幅圖, 線程B拿到鎖以後, 對於線程A的全部的操做都是可見的. 這是一個連帶效應.
    以下的代碼中, 對可見性的代碼進行了修改. 把賦值操做的方法中, 最後一個變量的賦值, 加上了synchronized修飾. 打印的方法中, 第一行代碼加上了synchronized修飾. 這樣就保證了原子性和可見性. 寫線程在執行完成d=6的時候, 會釋放鎖. 打印的線程得到鎖的時候, 就能知道寫線程的全部的操做, 得到其最新的值.
    完整的代碼以下.
package com.thread.jmm;

/**
 * 類名稱:FieldVisibility
 * 類描述:  演示可見性問題
 *
 * @author: https://javaweixin6.blog.csdn.net/
 * 建立時間:2020/9/5 14:31
 * Version 1.0
 */
public class FieldVisibility {

     int a = 1;
     int b = 2;
     int c = 3;
     int d = 4;

    //給a 賦值, 並把值給b
    private void change() {
        a = 3;
        b = a;
        c = a;
        synchronized (this) {
            d = 6;
        }
    }

    /**
     * 打印出a b
     */
    private  void print() {
        synchronized (this) {
            int aa = a ;
        }

        int bb = b ;
        int cc = c ;
        int dd = d ;

        System.out.println("b=" + b + ";a=" + a);
    }

    public static void main(String[] args) {

        while (true) {

            FieldVisibility test = new FieldVisibility();

            new Thread(() -> {

                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                //給 a b 從新賦值
                test.change();

            }).start();

            new Thread(() -> {
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //給 a b 打印出來
                test.print();
            }).start();

        }
    }
}

可見性總結

  1. 演示什麼是可見性 https://javaweixin6.blog.csdn.net/article/details/108419450
  2. 爲何會有可見性問題: CPU的多級緩存, 致使沒有從主內存中獲取最新值 . https://javaweixin6.blog.csdn.net/article/details/108421939
  3. JMM的抽象 : 主內存和本地內存. https://javaweixin6.blog.csdn.net/article/details/108422267
  4. happens-before原則與規則https://javaweixin6.blog.csdn.net/article/details/108422677 https://javaweixin6.blog.csdn.net/article/details/108423590
  5. volatile 關鍵字 https://javaweixin6.blog.csdn.net/article/details/108431303
  6. 能保證可見性的措施, 與happens-before原則一致.
  7. 對synchronized認識的昇華, 不單單是保證了原子性, 也保證了可見性. 同時 對於synchronized修飾的代碼, synchronized以前執行的代碼也是可見的 .
相關文章
相關標籤/搜索