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]);
}
}