天天看點

unsafe類學習

unsafe類作為java多線程包裡面的基石,沒有了解的話,對于後面的讀寫鎖和 AQS等子產品了解還是不太友好,建議學習一些,以下是學的時候的一些代碼
import org.junit.Test;
import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.util.concurrent.TimeUnit;

public class UnsafeTest {

    public class Car {

        private String name;

        public Car() {
        }

        public Car(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

    }

    @Test
    public void testUnsafe() throws NoSuchFieldException, IllegalAccessException, InterruptedException {
        Car car = new Car("bmw");

        //Unsafe unsafe = new Unsafe(); // private Unsafe() { }
        //擷取unsafe,私有的構造方法,沒法直接new,隻能用反射擷取
        Field field = Unsafe.class.getDeclaredField("theUnsafe");
        field.setAccessible(true);
        Unsafe unsafe = (Unsafe) field.get(null);

        //1.操作對象和屬性  objectFieldOffset   可用于你想跳過構造器的場景或者對象初始化的場景,繞過安全檢查等 allocateInstance
        Field carName = Car.class.getDeclaredField("name");
        //擷取對象屬性的偏移位址
        long carNameOffsite = unsafe.objectFieldOffset(carName);
        //unsafe類操作類的屬性,即便是私有的
        unsafe.putObject(car, carNameOffsite, "mini");
        System.out.println(car.getName());

        //2.操作數組  arrayBaseOffset  arrayIndexScale 可用于一些大數組的場景,Integer.MAX_VALUE,堆外記憶體技術
        int[] a = {1, 2, 3, 4, 5};
        //擷取數組的第一個元素的偏移位址
        int aFirstOffsite = unsafe.arrayBaseOffset(a.getClass());
        //擷取數組中元素的增量位址
        int aEachOffsite = unsafe.arrayIndexScale(a.getClass());
        //需要修改元素的位置  把3改成998
        long three = aFirstOffsite + 2 * aEachOffsite;
        unsafe.putInt(a, three, 998);
        System.out.println(a[2]);


        //3.線程的挂起和恢複、cas  LockSupport類的park()主要就是用了Unsafe.park()
        Thread t = new Thread(() -> {
            long start = System.currentTimeMillis();
            //納秒,相對時間
            unsafe.park(false, 5000000000L);
            System.out.println(System.currentTimeMillis() - start + "ms");
        });
        t.start();
        TimeUnit.SECONDS.sleep(3);
        //阻塞5秒,3s提前喚醒,結束線程
        unsafe.unpark(t);

        Thread t1 = new Thread(() -> {
            long start = System.currentTimeMillis();
            //納秒,相對時間
            unsafe.park(false, 5000000000L);
            System.out.println(System.currentTimeMillis() - start + "ms");
        });
        t1.start();
        TimeUnit.SECONDS.sleep(10);
        //阻塞5秒,睡10s,輸出結果,等10s完成才結束線程
        unsafe.unpark(t1);



        //現在3的位置存的是998  把a的偏移量three 的 998 換成 100
        //如果我提前修改了裡面的值,改稱為250,那麼這個b值應該是:false
        //a[2] = 250;
        boolean b = unsafe.compareAndSwapInt(a, three, 998, 100);
        System.out.println(b);
        System.out.println(a[2]);
    }
}