1. sun.misc.Unsafe包下载
2. 实例化私有类
正常情况下没法实例化一个私有构造函数的类,但是Unsafe可以做到。
- import java.lang.reflect.Field;
- import sun.misc.Unsafe;
- public class UnsafePlayer {
- public static void main(String[] args) throws Exception {
- //通过反射实例化Unsafe
- Field f = Unsafe.class.getDeclaredField("theUnsafe");
- f.setAccessible(true);
- Unsafe unsafe = (Unsafe) f.get(null);
- //实例化Player
- Player player = (Player) unsafe.allocateInstance(Player.class);
- player.setName("li lei");
- System.out.println(player.getName());
- }
- }
- class Player{
- private String name;
- private Player(){}
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- }
3. cas原子级操作&&通过内存偏移地址修改变量值
- import java.lang.reflect.Field;
- import sun.misc.Unsafe;
- public class UnsafePlayer {
- public static void main(String[] args) throws Exception {
- //通过反射实例化Unsafe
- Field f = Unsafe.class.getDeclaredField("theUnsafe");
- f.setAccessible(true);
- Unsafe unsafe = (Unsafe) f.get(null);
- //实例化Player
- Player player = (Player) unsafe.allocateInstance(Player.class);
- player.setAge(18);
- player.setName("li lei");
- for(Field field:Player.class.getDeclaredFields()){
- System.out.println(field.getName()+":对应的内存偏移地址"+unsafe.objectFieldOffset(field));
- }
- System.out.println("-------------------");
- int ageOffset= 8;
- //修改内存偏移地址为8的值(age),返回true,说明通过内存偏移地址修改age的值成功
- System.out.println(unsafe.compareAndSwapInt(player, ageOffset, 18, 20));
- System.out.println("age修改后的值:"+player.getAge());
- System.out.println("-------------------");
- //修改内存偏移地址为8的值,但是修改后不保证立马能被其他的线程看到。
- unsafe.putOrderedInt(player, 8, 33);
- System.out.println("age修改后的值:"+player.getAge());
- System.out.println("-------------------");
- //修改内存偏移地址为12的值,volatile修饰,修改能立马对其他线程可见
- unsafe.putObjectVolatile(player, 12, "han mei");
- System.out.println("name修改后的值:"+unsafe.getObjectVolatile(player, 12));
- }
- }
- class Player{
- private int age;
- private String name;
- private Player(){}
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- }
3. 创建超级数组
java中数组的最大长度为
Integer.MAX_VALUE,正常情况下如果想创建一个大于Integer.MAX_VALUE的数组是做不到的,但是Unsafe可以,通过对内存进行直接分配实现。
- import java.lang.reflect.Field;
- import sun.misc.Unsafe;
- public class SuperArray {
- public static void main(String[] arg) throws Exception{
- //通过反射实例化Unsafe
- Field f = Unsafe.class.getDeclaredField("theUnsafe");
- f.setAccessible(true);
- Unsafe unsafe = (Unsafe) f.get(null);
- //只要内存够大,可以把这个调大,大于Integer.MAX_VALUE
- long size = (long)Integer.MAX_VALUE/2 ;
- long addr = unsafe.allocateMemory(size);
- System.out.println("unsafe address :"+addr);
- for (int i = 0; i < size; i++) {
- unsafe.putByte(addr+i, (byte)6);
- if(unsafe.getByte(addr+i) !=6){
- System.out.println("failed at offset");
- }
- }
- }
- }
- unsafe address :15817328
- #
- # A fatal error has been detected by the Java Runtime Environment:
- #
- # EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x61cc0350, pid=31240, tid=31324
- #
- # JRE version: Java(TM) SE Runtime Environment (8.0_45-b14) (build 1.8.0_45-b14)
- # Java VM: Java HotSpot(TM) Client VM (25.45-b02 mixed mode windows-x86 )
- # Problematic frame:
- # V[thread 30484 also had an error]
- [jvm.dll+0x40350]
- #
- # Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
- #
- # An error report file with more information is saved as:
- # C:\welab\workspace\Person\hs_err_pid31240.log
4.线程挂起与恢复
将一个线程进行挂起是通过park方法实现的,调用 park后,线程将一直阻塞直到超时或者中断等条件出现。unpark可以终止一个挂起的线程,使其恢复正常。整个并发框架中对线程的挂起操作被封装在 LockSupport类中,LockSupport类中有各种版本pack方法,但最终都调用了Unsafe.park()方法。
- public class LockSupport {
- /**
- * 恢复阻塞线程
- */
- public static void unpark(Thread thread) {
- if (thread != null)
- unsafe.unpark(thread);
- }
- /**
- * 一直阻塞当前线程,调用Unsafe.park()方法
- */
- public static void park(Object blocker) {
- Thread t = Thread.currentThread();
- setBlocker(t, blocker);
- unsafe.park(false, 0L);
- setBlocker(t, null);
- }
- /**
- * 阻塞当前线程nanos纳秒
- */
- public static void parkNanos(Object blocker, long nanos) {
- if (nanos > 0) {
- Thread t = Thread.currentThread();
- setBlocker(t, blocker);
- unsafe.park(false, nanos);
- setBlocker(t, null);
- }
- }
- public static void parkUntil(Object blocker, long deadline) {
- Thread t = Thread.currentThread();
- setBlocker(t, blocker);
- unsafe.park(true, deadline);
- setBlocker(t, null);
- }
- /**
- * 一直阻塞当前线程
- */
- public static void park() {
- unsafe.park(false, 0L);
- }
- /**
- * 阻塞当前线程nanos纳秒
- */
- public static void parkNanos(long nanos) {
- if (nanos > 0)
- unsafe.park(false, nanos);
- }
- public static void parkUntil(long deadline) {
- unsafe.park(true, deadline);
- }
- }
- import java.util.concurrent.locks.LockSupport;
- public class Lock {
- public static void main(String[] args) throws InterruptedException {
- ThreadPark threadPark = new ThreadPark();
- threadPark.start();
- ThreadUnPark threadUnPark = new ThreadUnPark(threadPark);
- threadUnPark.start();
- //等待threadUnPark执行成功
- threadUnPark.join();
- System.out.println("运行成功....");
- }
- static class ThreadPark extends Thread{
- public void run(){
- System.out.println(Thread.currentThread() +"我将被阻塞在这了60s....");
- //阻塞60s,单位纳秒 1s = 1000000000
- LockSupport.parkNanos(1000000000l*60);
- System.out.println(Thread.currentThread() +"我被恢复正常了....");
- }
- }
- static class ThreadUnPark extends Thread{
- public Thread thread = null;
- public ThreadUnPark(Thread thread){
- this.thread = thread;
- }
- public void run(){
- System.out.println("提前恢复阻塞线程ThreadPark");
- //恢复阻塞线程
- LockSupport.unpark(thread);
- }
- }
- }