synchronized 保證三大特性


synchronized 能夠保證在同一時刻最多只有一個線程執行該段代碼,以達到保證並發安全的效果;

synchronized(鎖對象) {
    // 受保護資源;
}

synchronized 與原子性

  目標:學習使用 synchronized 保證原子性的原理

使用 synchronized 保證原子性

  案例:5個線程各執行10000次 i++

package juc.synchronized_test.prove;
​
import java.util.ArrayList;
import java.util.List;
​
/**
 * @author : 雪飛oubai
 * @date : 2020/4/9 11:27
 * 目標:演示原子性問題
 * 1、定義一個共享變量 number
 * 2、對number進行1000次 ++ 操作
 * 3、使用 5 個線程來進行
 */
public class Test02Atomicity {
    //1、定義一個共享變量 number
    private static int number = 0;
    private static Object obj = new Object();
​
    public static void main(String[] args) throws InterruptedException {
        Runnable increment = () -> {
            for (int i = 0; i < 10000; i++) {
                synchronized (obj) {
                    number++;
                }
            }
        };
        List<Thread> list = new ArrayList<>();
​
        for (int i = 0; i < 5; i++) {
            Thread t = new Thread(increment);
            t.start();
            list.add(t);
        }
        for (Thread thread : list) {
            thread.join();
        }
        System.out.println("number=" + number);
    }
}

synchronized 保證原子性的原理

對 number++;增加同步代碼快,保證同一時間只有一個線程操作 number++;。就不會出現安全問題;


synchronized 與可見性

目標:學習使用 synchronized 保證可見性的原理

使用 synchronized 保證可見性

  案例演示:一個線程根據 boolean 類型標記 flag,while循環,另一個線程改變這個flag變量的值,另一個線程不會停止循環

package juc.synchronized_test.prove;
​
import java.util.concurrent.TimeUnit;
​
/**
 * @author : 雪飛oubai
 * @date : 2020/4/9 11:07
 * 目的:演示可見性問題
 * 1、創建一個貢獻變量
 * 2、創建一條線程不斷的讀取共享變量
 * 3、創建一條線程修改共享變量
 */
public class Test01Visibility {
    // 多個線程都會訪問的數據,我們稱為線程的共享數據
    private static boolean flag = true;
    private static Object obj = new Object();
​
    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            while (flag) {
                synchronized (obj) {
                }
            }
        }).start();
​
        TimeUnit.SECONDS.sleep(1);
​
        new Thread(() -> {
            flag = false;
            System.out.println("時間到,線程2設置為false");
        }).start();
    }
}

小結:

synchronized 保證可見性的原理,執行 synchronized時,會對應執行 lock 原子操作會刷新工作內存中共享變量的值;


synchronized 與有序性

  目標:學習使用 synchronized 保證有序性的原理

為什么要重排序

  為了提高程序的執行效率,編譯器和CPU對象程序中的代碼進行重排序;

as-if-serial語義

  as-if-serial語義的意思是:不管編譯器和CPU如何重排序,必須保證單線程情況下程序的結果是正確的;

以下數據有依賴關系,不能重排序

寫后讀

int a = 1;
int b = a;

寫后寫

int a =  1;
int b = a;

讀后寫

int a = 1;
int b = a;
int a = 2;

編譯器和處理器不會存在數據依賴關系的操作做重排序,因為這種排序會改變執行結果。但是,如果操作之間不存在依賴關系,這些操作就可能被編譯器和處理器重排序;

int a = 1;
int b = 2;
int c = a + b;

上面 3 個操作的數據依賴關系如圖所示:

如圖所示 a 和 c 之間存在數據依賴關系,同時 b 和 c 之間也存在數據依賴關系。因此在最終執行的指令序列中,c 不能被重排序到 a 和 b 的前面。但是 a 和 b 之間沒有數據依賴關系,編譯器和處理器可以重排序 a 和 b 之間的執行順序;下圖是該程序的兩種執行順序;

使用 synchronized 保證有序性


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM