CAS && Unsafe的使用

1 CAS

1.1 基本介紹

Compare And Set,直譯過來就是比較並設值,解決多線程並行情況下使用鎖造成性能損耗的一種機制,CAS操作包含三個操作數—內存位置(V)、預期原值(A)和新值(B)。如果內存位置的值與預期原值相匹配,那麼處理器會自動將該位置值更新爲新值。否則,處理器不做任何操作。

/**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
*
* @param expect the expected value
* @param update the new value
* @return {@code true} if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(int expect, int update) {
    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

1.2 案例

public static void main(String[] args)  {
    //期望12,設置爲20
    AtomicInteger atomicInteger=new AtomicInteger(10);
    boolean b = atomicInteger.compareAndSet(12, 20);
    System.out.println(b);
    System.out.println(atomicInteger.get());
    System.out.println("#######################");
    //期望10,設置爲20
    AtomicInteger atomicInteger1=new AtomicInteger(10);
    boolean b1 = atomicInteger1.compareAndSet(10, 20);
    System.out.println(b1);
    System.out.println(atomicInteger1.get());
}

在這裏插入圖片描述

2 Unsafe

2.1 簡介

Java 不能直接訪問操作系統底層,而是通過本地方法來訪問。Unsafe 類提供了硬件級別的原子操作。Unsafe 類在 sun.misc 包下,不屬於 Java 標準。很多 Java 的基礎類庫,包括一些被廣泛使用的高性能開發庫都是基於 Unsafe 類開發,比如 Netty、Hadoop、Kafka 等。
(1) Unsafe 是用於在實質上擴展 Java 語言表達能力、便於在更高層(Java 層)代碼裏實現原本要在更低層(C 層)實現的核心庫功能用的。
(2) 這些功能包括裸內存的申請/釋放/訪問,低層硬件的 atomic/volatile 支持,創建未初始化對象等。
(3) 它原本的設計就只應該被標準庫使用,因此不建議在生產環境中使用。

2.2 獲取Unsafe

public final class UnsafeUtils {
    private UnsafeUtils() {
    }
    /**
     * 獲取Unsafe
     */
    public static Unsafe getUnsafe() {
        try {
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            return (Unsafe) field.get(null);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

3 Unsafe實現CAS鎖

3.1 接口

public interface Counter {

    void increment();

    long getCounter();

}

3.2 CasCounter

public class CasCounter implements Counter {

    private volatile long counter = 0;

    private Unsafe unsafe;

    private long offset;

    public CasCounter() throws Exception {
        //獲取unsafe
        unsafe = UnsafeUtils.getUnsafe();
        //設置偏移量爲counter
        offset = unsafe.objectFieldOffset(CasCounter.class.getDeclaredField("counter"));
    }

    @Override
    public void increment() {
        long current = counter;
        /**
         * compareAndSwapLong(Object var1, long var2, long var4, long var6)
         * var1:對象,var2:偏移量,var4:expect(期望值),var6:update(更新值)
         */
        while (!unsafe.compareAndSwapLong(this, offset, current, current + 1)) {
            current=counter;
        }
    }

    @Override
    public long getCounter() {
        return counter;
    }
}

3.3 測試類

/**
 * @Description: 每個線程對Counter進行累加MAX_SUM次,MAX_THREAD個線程同時累加
 * @Auther: zhurongsheng
 * @Date: 2020/4/2 11:15
 */
public class UnsafeTest {


    private static final int MAX_THREAD = 1000;

    private static final int MAX_SUM = 10000;


    public static void main(String[] args) throws Exception {

        ExecutorService service = Executors.newFixedThreadPool(MAX_THREAD);
        Counter counter = new CasCounter();
        for (int i = 0; i < 1000; i++) {
            service.submit(new CounterRunnable(counter, MAX_SUM));
        }
        //關閉不接受新任務
        service.shutdown();
        //阻塞,直到所有任務執行完畢 或 1小時後中斷
        service.awaitTermination(1, TimeUnit.HOURS);
        System.out.println("Counter result:" + counter.getCounter());
    }
}

在這裏插入圖片描述

4 unsafe創建對象繞過對象的構造

4.1 pojo

class Simple {
    public Simple() {
        System.out.println("Simple invoke NoArgsConstructor");
    }
    public void sayHello(){
        System.out.println("hello world");
    }
}

4.2 測試類

/**
* @Description: 通過Unsafe創建對象可以繞過對象的構造
* @Auther: zhurongsheng
* @Date: 2020/4/2 13:45
*/
public class UnsafeTest {
    public static void main(String[] args) throws Exception {
        //通過new 直接新建Simple
        System.out.println("創建:");
        new Simple();
        //通過反射創建Simple
        System.out.println("反射:");
        Simple.class.newInstance();
        //通過unsafe
        System.out.println("【unsafe】:");
        Unsafe unsafe = UnsafeUtils.getUnsafe();
        Simple instance = (Simple) unsafe.allocateInstance(Simple.class);
        instance.sayHello();
    }
}

在這裏插入圖片描述

5 unsafe直接修改私有變量

5.1 pojo

class Simple {
    private boolean access = false;
    private boolean allow() {
        return access == true;
    }
    public void work() {
        if (allow()) {
            System.out.println("工作使我快樂");
            return;
        }
        System.out.println("我不要工作,來世我要當一個被子,要麼躺牀上,要麼曬太陽。");
    }
}

5.2 測試類

public class UnsafeTest {
    public static void main(String[] args) throws Exception {
        //1 直接new
        System.out.println("直接創建對象:");
        Simple simple1 = new Simple();
        simple1.work();
        System.out.println("###########################");
        //2 反射
        System.out.println("通過反射直接修改私有變量:");
        Simple simple2 = Simple.class.newInstance();
        Field access = simple2.getClass().getDeclaredField("access");
        access.setAccessible(true);
        access.set(simple2,true);
        simple2.work();
        System.out.println("###########################");
        //3 unsafe
        System.out.println("通過unsafe修改私有變量:");
        Unsafe unsafe = UnsafeUtils.getUnsafe();
        Simple simple3 = Simple.class.newInstance();
        Field access1 = simple3.getClass().getDeclaredField("access");
        //對象,偏移量,設置值
        unsafe.putBoolean(simple3,unsafe.objectFieldOffset(access1),true);
        simple3.work();
    }
}

在這裏插入圖片描述

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