JUC併發工具一-jvm內存模型和CAS機制

目錄

 

1 jvm內存模型

1.1 可見性

1.2 原子性

1.3 有序性

2 CAS機制


1 jvm內存模型

java內存模型規定所有變量都存在主內存中,主內存是所有線程共享的內存,但是線程對內存數據的操作(讀寫)是在工作內存中進行的,先將變量從
主內存拷貝到工作內存,然後進行操作,然後在將變量寫回主內存,不能對變量直接進行操作。

1.1 可見性

可見性是指當一個線程修改了共享變量的值,其他線程能夠立即得知這個修改。Java內存模型是通過在變量修改後將新值同步回主內存,
每次讀取變量都從主內存中讀取來實現可見性的
    volatile:volatile的特殊規則保證了新值能立即同步到主內存,以及每次使用前立即從主內存刷新。
    synchronized:synchronized關鍵字在釋放鎖之前,必須先把此變量同步回主內存中(執行store、write操作)。
    final:被final修飾的字段在構造器中一旦初始化完成,並且構造器沒有把“this”的引用傳遞出去,那在其他線程中就能看見final字段的值

1.2 原子性

一個操作或多個操作要麼全部執行,且執行的過程不會被任何因素打斷,要麼就都不執行。
    通過synchronized關鍵字定義同步代碼塊或者同步方法保障原子性。
    通過Lock接口保障原子性。
    通過Atomic類型保障原子性。

1.3 有序性

計算機在執行程序時,爲了提高性能,編譯器和處理器往往會對指令做重排,一般分爲以下3種
    源碼->編譯器優化重排->指令並行重排->內存系統重排->最終執行指令
    volatile和synchronized兩個關鍵字來保證線程之間操作的有序性

    單例模式指令重排問題
    instance = new Singleton();

    memory = allocated(); //1 分配內存空間
    instance = (memory); // 2 初始化對象
    instance = memory; // 3 設置instance指向剛分配的內存空間
    2和3順序可能替換,如果先執行3的話則對象還未初始化完成

2 CAS機制

JUC同步類容器中最常用的就是Unsafe的CAS方法,比較並交換

/**
 * var1:需要修改屬性的對象
 * var2:需要修改對象屬性的內存地址偏移量。v通過ar1和var2兩個變量可以讀取到對象屬性當前值
 * var4:修改對象屬性時候期待當前的值
 * var5:將對象屬性替換成的目標值
 * return:如果對象當前屬性和期待值相等,則賦值成功,返回true;否則複製失敗,返回false
 */
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

新建一個User類

@Data
public class User {
	
    /**
     * 這裏一定要是基本數據類型,否則設置會失敗。如果用Long類型,則CAS請用compareAndSwapObject
     */
    private long id;

    private static final Unsafe unsafe;

    /**
     * 屬性id的內存地址偏移量
     */
    private static final long idOffset;

    static {
        try {
            // 通過反射獲取Unsafe類
            Field f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);
            unsafe = (Unsafe) f.get(null);
            Field idField = User.class.getDeclaredField("id");
            // 讀取屬性id的內存地址偏移量
            idOffset = unsafe.objectFieldOffset(idField);
        } catch (Exception e) {
            throw new Error(e);
        }
    }

    public boolean casId(long expect, long target) {
        return unsafe.compareAndSwapLong(this, idOffset, expect, target);
    }
}

測試代碼

    @Test
    public void test() {
        long id = 10L;
        User user = new User();
        user.setId(id);
        System.out.println(user.casId(1L, 15L));
        System.out.println(user.getId());
        System.out.println(user.casId(id, 15L));
        System.out.println(user.getId());
    }

結果:
false
10
true
15
 

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