Unsafe学习

一 介绍

  1. 一个管理内存的类
  2. Unsafe类是"final"的,不允许继承。且构造函数是private的
  3. 使用单列模式模式获取类对象

1.1 测试的类

public class UnsafeBean {
    private static int staticInt = 5;
    private final int finalInt = 5;
}

二 代码

package sun.misc;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.security.ProtectionDomain;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;

//final修饰,该类不能被继承
public final class Unsafe {
	//定义一个唯一的实体类
	private static final Unsafe theUnsafe;

	public static final int INVALID_FIELD_OFFSET = -1;
	public static final int ARRAY_BOOLEAN_BASE_OFFSET;
	public static final int ARRAY_BYTE_BASE_OFFSET;
	public static final int ARRAY_SHORT_BASE_OFFSET;
	public static final int ARRAY_CHAR_BASE_OFFSET;
	public static final int ARRAY_INT_BASE_OFFSET;
	public static final int ARRAY_LONG_BASE_OFFSET;
	public static final int ARRAY_FLOAT_BASE_OFFSET;
	public static final int ARRAY_DOUBLE_BASE_OFFSET;
	public static final int ARRAY_OBJECT_BASE_OFFSET;
	public static final int ARRAY_BOOLEAN_INDEX_SCALE;
	public static final int ARRAY_BYTE_INDEX_SCALE;
	public static final int ARRAY_SHORT_INDEX_SCALE;
	public static final int ARRAY_CHAR_INDEX_SCALE;
	public static final int ARRAY_INT_INDEX_SCALE;
	public static final int ARRAY_LONG_INDEX_SCALE;
	public static final int ARRAY_FLOAT_INDEX_SCALE;
	public static final int ARRAY_DOUBLE_INDEX_SCALE;
	public static final int ARRAY_OBJECT_INDEX_SCALE;
	public static final int ADDRESS_SIZE;

	private static native void registerNatives();
	//构造函数是private,不能new 构造
	private Unsafe() {
	}

	//单例模式获取对象
	@CallerSensitive
	public static Unsafe getUnsafe() {
		Class var0 = Reflection.getCallerClass();
		if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
			throw new SecurityException("Unsafe");
		} else {
			return theUnsafe;
		}
	}

	public native int getInt(Object var1, long var2);

	public native void putInt(Object var1, long var2, int var4);

	public native Object getObject(Object var1, long var2);

	public native void putObject(Object var1, long var2, Object var4);

	public native boolean getBoolean(Object var1, long var2);

	public native void putBoolean(Object var1, long var2, boolean var4);

	public native byte getByte(Object var1, long var2);

	public native void putByte(Object var1, long var2, byte var4);

	public native short getShort(Object var1, long var2);

	public native void putShort(Object var1, long var2, short var4);

	public native char getChar(Object var1, long var2);

	public native void putChar(Object var1, long var2, char var4);

	public native long getLong(Object var1, long var2);

	public native void putLong(Object var1, long var2, long var4);

	public native float getFloat(Object var1, long var2);

	public native void putFloat(Object var1, long var2, float var4);

	public native double getDouble(Object var1, long var2);

	public native void putDouble(Object var1, long var2, double var4);

	/** @deprecated */
	@Deprecated
	public int getInt(Object var1, int var2) {
		return this.getInt(var1, (long)var2);
	}

	/** @deprecated */
	@Deprecated
	public void putInt(Object var1, int var2, int var3) {
		this.putInt(var1, (long)var2, var3);
	}

	/** @deprecated */
	@Deprecated
	public Object getObject(Object var1, int var2) {
		return this.getObject(var1, (long)var2);
	}

	/** @deprecated */
	@Deprecated
	public void putObject(Object var1, int var2, Object var3) {
		this.putObject(var1, (long)var2, var3);
	}

	/** @deprecated */
	@Deprecated
	public boolean getBoolean(Object var1, int var2) {
		return this.getBoolean(var1, (long)var2);
	}

	/** @deprecated */
	@Deprecated
	public void putBoolean(Object var1, int var2, boolean var3) {
		this.putBoolean(var1, (long)var2, var3);
	}

	/** @deprecated */
	@Deprecated
	public byte getByte(Object var1, int var2) {
		return this.getByte(var1, (long)var2);
	}

	/** @deprecated */
	@Deprecated
	public void putByte(Object var1, int var2, byte var3) {
		this.putByte(var1, (long)var2, var3);
	}

	/** @deprecated */
	@Deprecated
	public short getShort(Object var1, int var2) {
		return this.getShort(var1, (long)var2);
	}

	/** @deprecated */
	@Deprecated
	public void putShort(Object var1, int var2, short var3) {
		this.putShort(var1, (long)var2, var3);
	}

	/** @deprecated */
	@Deprecated
	public char getChar(Object var1, int var2) {
		return this.getChar(var1, (long)var2);
	}

	/** @deprecated */
	@Deprecated
	public void putChar(Object var1, int var2, char var3) {
		this.putChar(var1, (long)var2, var3);
	}

	/** @deprecated */
	@Deprecated
	public long getLong(Object var1, int var2) {
		return this.getLong(var1, (long)var2);
	}

	/** @deprecated */
	@Deprecated
	public void putLong(Object var1, int var2, long var3) {
		this.putLong(var1, (long)var2, var3);
	}

	/** @deprecated */
	@Deprecated
	public float getFloat(Object var1, int var2) {
		return this.getFloat(var1, (long)var2);
	}

	/** @deprecated */
	@Deprecated
	public void putFloat(Object var1, int var2, float var3) {
		this.putFloat(var1, (long)var2, var3);
	}

	/** @deprecated */
	@Deprecated
	public double getDouble(Object var1, int var2) {
		return this.getDouble(var1, (long)var2);
	}

	/** @deprecated */
	@Deprecated
	public void putDouble(Object var1, int var2, double var3) {
		this.putDouble(var1, (long)var2, var3);
	}

	public native byte getByte(long var1);

	public native void putByte(long var1, byte var3);

	public native short getShort(long var1);

	public native void putShort(long var1, short var3);

	public native char getChar(long var1);

	public native void putChar(long var1, char var3);

	public native int getInt(long var1);

	public native void putInt(long var1, int var3);

	public native long getLong(long var1);

	public native void putLong(long var1, long var3);

	public native float getFloat(long var1);

	public native void putFloat(long var1, float var3);

	public native double getDouble(long var1);

	public native void putDouble(long var1, double var3);

	public native long getAddress(long var1);

	public native void putAddress(long var1, long var3);

	public native long allocateMemory(long var1);

	public native long reallocateMemory(long var1, long var3);

	public native void setMemory(Object var1, long var2, long var4, byte var6);

	public void setMemory(long var1, long var3, byte var5) {
		this.setMemory((Object)null, var1, var3, var5);
	}

	public native void copyMemory(Object var1, long var2, Object var4, long var5, long var7);

	public void copyMemory(long var1, long var3, long var5) {
		this.copyMemory((Object)null, var1, (Object)null, var3, var5);
	}

	public native void freeMemory(long var1);

	/** @deprecated */
	@Deprecated
	public int fieldOffset(Field var1) {
		return Modifier.isStatic(var1.getModifiers()) ? (int)this.staticFieldOffset(var1) : (int)this.objectFieldOffset(var1);
	}

	/** @deprecated */
	@Deprecated
	public Object staticFieldBase(Class<?> var1) {
		Field[] var2 = var1.getDeclaredFields();

		for(int var3 = 0; var3 < var2.length; ++var3) {
			if (Modifier.isStatic(var2[var3].getModifiers())) {
				return this.staticFieldBase(var2[var3]);
			}
		}

		return null;
	}

	public native long staticFieldOffset(Field var1);

	public native long objectFieldOffset(Field var1);

	public native Object staticFieldBase(Field var1);

	public native boolean shouldBeInitialized(Class<?> var1);

	public native void ensureClassInitialized(Class<?> var1);

	public native int arrayBaseOffset(Class<?> var1);

	public native int arrayIndexScale(Class<?> var1);

	public native int addressSize();

	public native int pageSize();

	public native Class<?> defineClass(String var1, byte[] var2, int var3, int var4, ClassLoader var5, ProtectionDomain var6);

	public native Class<?> defineAnonymousClass(Class<?> var1, byte[] var2, Object[] var3);

	public native Object allocateInstance(Class<?> var1) throws InstantiationException;

	public native void monitorEnter(Object var1);

	public native void monitorExit(Object var1);

	public native boolean tryMonitorEnter(Object var1);

	public native void throwException(Throwable var1);

	public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);

	public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

	public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);

	public native Object getObjectVolatile(Object var1, long var2);

	public native void putObjectVolatile(Object var1, long var2, Object var4);

	public native int getIntVolatile(Object var1, long var2);

	public native void putIntVolatile(Object var1, long var2, int var4);

	public native boolean getBooleanVolatile(Object var1, long var2);

	public native void putBooleanVolatile(Object var1, long var2, boolean var4);

	public native byte getByteVolatile(Object var1, long var2);

	public native void putByteVolatile(Object var1, long var2, byte var4);

	public native short getShortVolatile(Object var1, long var2);

	public native void putShortVolatile(Object var1, long var2, short var4);

	public native char getCharVolatile(Object var1, long var2);

	public native void putCharVolatile(Object var1, long var2, char var4);

	public native long getLongVolatile(Object var1, long var2);

	public native void putLongVolatile(Object var1, long var2, long var4);

	public native float getFloatVolatile(Object var1, long var2);

	public native void putFloatVolatile(Object var1, long var2, float var4);

	public native double getDoubleVolatile(Object var1, long var2);

	public native void putDoubleVolatile(Object var1, long var2, double var4);

	public native void putOrderedObject(Object var1, long var2, Object var4);

	public native void putOrderedInt(Object var1, long var2, int var4);

	public native void putOrderedLong(Object var1, long var2, long var4);

	public native void unpark(Object var1);

	public native void park(boolean var1, long var2);

	public native int getLoadAverage(double[] var1, int var2);

	public final int getAndAddInt(Object var1, long var2, int var4) {
		int var5;
		do {
			var5 = this.getIntVolatile(var1, var2);
		} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

		return var5;
	}

	public final long getAndAddLong(Object var1, long var2, long var4) {
		long var6;
		do {
			var6 = this.getLongVolatile(var1, var2);
		} while(!this.compareAndSwapLong(var1, var2, var6, var6 + var4));

		return var6;
	}

	public final int getAndSetInt(Object var1, long var2, int var4) {
		int var5;
		do {
			var5 = this.getIntVolatile(var1, var2);
		} while(!this.compareAndSwapInt(var1, var2, var5, var4));

		return var5;
	}

	public final long getAndSetLong(Object var1, long var2, long var4) {
		long var6;
		do {
			var6 = this.getLongVolatile(var1, var2);
		} while(!this.compareAndSwapLong(var1, var2, var6, var4));

		return var6;
	}

	public final Object getAndSetObject(Object var1, long var2, Object var4) {
		Object var5;
		do {
			var5 = this.getObjectVolatile(var1, var2);
		} while(!this.compareAndSwapObject(var1, var2, var5, var4));

		return var5;
	}

	public native void loadFence();

	public native void storeFence();

	public native void fullFence();

	private static void throwIllegalAccessError() {
		throw new IllegalAccessError();
	}

	static {
		registerNatives();
		Reflection.registerMethodsToFilter(Unsafe.class, new String[]{"getUnsafe"});
		theUnsafe = new Unsafe();
		ARRAY_BOOLEAN_BASE_OFFSET = theUnsafe.arrayBaseOffset(boolean[].class);
		ARRAY_BYTE_BASE_OFFSET = theUnsafe.arrayBaseOffset(byte[].class);
		ARRAY_SHORT_BASE_OFFSET = theUnsafe.arrayBaseOffset(short[].class);
		ARRAY_CHAR_BASE_OFFSET = theUnsafe.arrayBaseOffset(char[].class);
		ARRAY_INT_BASE_OFFSET = theUnsafe.arrayBaseOffset(int[].class);
		ARRAY_LONG_BASE_OFFSET = theUnsafe.arrayBaseOffset(long[].class);
		ARRAY_FLOAT_BASE_OFFSET = theUnsafe.arrayBaseOffset(float[].class);
		ARRAY_DOUBLE_BASE_OFFSET = theUnsafe.arrayBaseOffset(double[].class);
		ARRAY_OBJECT_BASE_OFFSET = theUnsafe.arrayBaseOffset(Object[].class);
		ARRAY_BOOLEAN_INDEX_SCALE = theUnsafe.arrayIndexScale(boolean[].class);
		ARRAY_BYTE_INDEX_SCALE = theUnsafe.arrayIndexScale(byte[].class);
		ARRAY_SHORT_INDEX_SCALE = theUnsafe.arrayIndexScale(short[].class);
		ARRAY_CHAR_INDEX_SCALE = theUnsafe.arrayIndexScale(char[].class);
		ARRAY_INT_INDEX_SCALE = theUnsafe.arrayIndexScale(int[].class);
		ARRAY_LONG_INDEX_SCALE = theUnsafe.arrayIndexScale(long[].class);
		ARRAY_FLOAT_INDEX_SCALE = theUnsafe.arrayIndexScale(float[].class);
		ARRAY_DOUBLE_INDEX_SCALE = theUnsafe.arrayIndexScale(double[].class);
		ARRAY_OBJECT_INDEX_SCALE = theUnsafe.arrayIndexScale(Object[].class);
		ADDRESS_SIZE = theUnsafe.addressSize();
	}
}

三 方法

在这里插入图片描述

1 线程调度

1. public native void unpark(Object var1) :恢复被挂起的线程

1. var1:被挂起的线程

2. public native void park(boolean var1, long var2) :挂起当前线程

1. var1:boolean 类型,表示挂起时间的单位,true表示毫秒,false表示纳秒。
2. var2:挂起多少时间,var2为0表示永不过期 
3. 阻塞一个线程直到unpark被调用或者线程被中断或者timeout时间到期。



	    @Test
	    public void parkOrUnpark() throws InterruptedException {
	        Thread packThread = new Thread(() -> {
	            long startTime = System.currentTimeMillis();
	            //纳秒,定义3秒堵塞时间
	            unsafe.park(false,3000000000L);
	            System.out.println("堵塞时间 :"+(System.currentTimeMillis()-startTime)+"毫秒");
	        });
	        packThread.start();
	        //堵塞1秒
	        TimeUnit.SECONDS.sleep(1);
	        //注释掉下一行后,线程3秒数后进行输出,否则在1秒后输出
	        unsafe.unpark(packThread);//解除packThread的堵塞状态
	        //堵塞时间 :1000毫秒
	    }

在这里插入图片描述

3public native void monitorEnter(Object o):锁定对象,必须是没有被锁的

4public native void monitorExit(Object o):解锁对象

5public native boolean tryMonitorEnter(Object o):试图锁定对象,返回true或false是否锁定成功,如果锁定,必须用monitorExit解锁

    @Test
    public void monitorEnterOrmonitorExit() throws InterruptedException {

        UnSafeBean unSafeBean = new UnSafeBean();
        unSafeBean.setAge(20);
        //锁定对象
        unsafe.monitorEnter(unSafeBean);

        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                //锁定对象后,线程堵塞在这里,只有释放锁才可以设置值

                //试图锁定对象,返回true或false是否锁定成功
                while (!unsafe.tryMonitorEnter(unSafeBean)) {

                }
                System.out.println("tryMonitorEnter:" + unsafe.tryMonitorEnter(unSafeBean));
                //只有释放锁才可以设置值
                unSafeBean.setAge(100);
                System.out.println("解锁对象后age值:" + unSafeBean.getAge());

            }
        });
        thread1.start();

        Thread.sleep(2 * 1000);

        System.out.println("锁定对象后age值:" + unSafeBean.getAge());

        //解锁对象
        unsafe.monitorExit(unSafeBean);

//        锁定对象后age值:20
//        tryMonitorEnter:true
//        解锁对象后age值:100
    }
		
		---------------------------------------------------------
		public class UnSafeBean {
		   private  int age;
		
		
		
		    public  int getAge() {
		        return age;
		    }
		
		    public void setAge(int age) {
		        this.age = age;
		    }
		}

2 CAS相关:比较及替换值

2.1 compareAndSwapXXX(Object var1, long var2, XXX var4, XXX var5)

  1. 参数1:被替换的对象

  2. 参数2:为值的内存地址

  3. 参数3:变量的预期值

  4. 参数4:变量要换的值

  5. 如果变量(参数1)目前的值等于预期值(参数3),则会将变量(参数1)的值换成新值(参数4),返回 true,如果不等于预期,则不会改变,并返回 false

     public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);
     
     public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
     
     public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);
    
     ----------------------------
     @Test
     public void CAS() throws NoSuchFieldException {
         //创建一个 Integer 对象,value 为 1
         Integer i = 1;
    
         //获取到内部变量 value,这个变量用于存放值
         Field valueField = Integer.class.getDeclaredField("value");
         valueField.setAccessible(true);
    
         //获取到内存地址
         long valueAddress = unsafe.objectFieldOffset(valueField);
    
        
         //参数1:被替换的对象
         //参数2:为值的内存地址
         //参数3:变量的预期值
         //参数4:变量要换的值
         //如果变量(参数1)目前的值等于预期值(参数3),则会将变量(参数1)的值换成新值(参数4),返回 true
         //如果不等于预期,则不会改变,并返回 false
         boolean isOk = unsafe.compareAndSwapInt(i,valueAddress,1,5);
    
         System.out.println("isOk:"+isOk+",i=: "+i);
         //isOk:true,i=: 5
         i=unsafe.getIntVolatile(Integer.class,valueAddress);
         isOk = unsafe.compareAndSwapInt(i,valueAddress,1,5);
         System.out.println("isOk:"+isOk+",i=: "+i);
         //isOk:false,i=: 0
    
     }
    

3 直接内存操作

3.1 public native long allocateMemory(long var1);

  1. var1:申请的内存的大小,单位为 byte

  2. 返回这块内存的long 类型地址

     @Test
     public void allocateMemory() {
     	//申请8字节的内存
     	//返回当前申请内存的地址
     	long memoryAddress = unsafe.allocateMemory(8);
     	System.out.println("memoryAddress: "+memoryAddress);
     	//memoryAddress: 534459264
     }
    

3.2 public native void freeMemory(long var1);

  1. 释放var1地址对应的内存

  2. Unsafe 申请的内存不在jvm管辖范围内,需要手动释放

  3. 生产中尽量在finally区域里进行内存的释放操作。

     @Test
     public void freeMemory() {
         //释放var1地址对应的内存
         //Unsafe 申请的内存不在jvm管辖范围内,需要手动释放
         //生产中尽量在finally区域里进行内存的释放操作。
           unsafe.freeMemory(534459264L);
     }
    

3.3 public native long reallocateMemory(long var1, long var3)

  1. 此方法会释放var1内存地址的内存,然后重新申请一块var3大小的内存,并返回新的内存地址

  2. 如果之前那块内存上已经存在对象了,会被拷贝到新的内存上

  3. 考虑:如果新内存大小小于旧内存大小会怎么样呢?

     @Test
     public void reallocateMemory() {
         //此方法会释放var1内存地址的内存,然后重新申请一块var3大小的内存,并返回新的内存地址
         //如果之前那块内存上已经存在对象了,会被拷贝到新的内存上
         //考虑:如果新内存大小小于旧内存大小会怎么样呢?
         long memoryAddress = unsafe.allocateMemory(8);
         long newMemoryAddress = unsafe.reallocateMemory(memoryAddress, 1);
         System.out.println("memoryAddress: "+memoryAddress);
         System.out.println("newMemoryAddress: "+newMemoryAddress);
         //memoryAddress: 544816560
         //newMemoryAddress: 536527360
     }
    

3.4 public native void copyMemory(Object var1, long var2, Object var4, long var5, long var7);内存复制

  1. srcBase:源数据

  2. srcOffset:源内存地址

  3. destBase:目的数据

  4. destOffset:目的地址

  5. bytes:复制大小

         @Test
     public void copyMemory() throws NoSuchFieldException {
    
         //分配100字节内存  返回初始地址
         long address = unsafe.allocateMemory(100);
         //往分配的内存地址写入值
         unsafe.putInt(address, 55);
    
    
         //打印
         System.out.println("address:"+unsafe.getInt(address));
    
         //分配100字节内存  返回初始地址
         long address1 = unsafe.allocateMemory(100);
    
         //内存复制,将内存地址address复制到内存地址address1中,复制大小为8个字节
         unsafe.copyMemory(null,address, null,address1, 8);
    
         System.out.println("address1:"+unsafe.getInt(address1));
    

    // address:55
    // address1:55
    }

3.5 public native void setMemory(long var1, long var3, byte var5);将内存块中的所有字节设置为固定值

  1. var1:被操作的对象

  2. var2:被操作对象的内存地址

  3. var4,var6:2个参数一起决定固定值大小

         @Test
         public void setMemory() {
     
     
             //分配一个8byte的内存
             long address = unsafe.allocateMemory(8L);
             //  //将内存块中的所有字节设置为固定值,初始化内存填充值为1
             unsafe.setMemory(null,address, 1L, (byte) 1);
             //获取内存地址对应的值
             System.out.println("address value1:" + unsafe.getInt(address));
     
     
     
             unsafe.setMemory(null,address, 2L, (byte) 1);
             //获取内存地址对应的值
             System.out.println("address value2:" + unsafe.getInt(address));
     
     
             unsafe.setMemory(null,address, 3L, (byte) 1);
             //获取内存地址对应的值
             System.out.println("address value3:" + unsafe.getInt(address));
         }
     	
     	//address value1:1
     	//address value2:257
     	//address value3:65793
    

4 普通读写

4.1直接在一个地址上读写

####4.1.1 getXXX(long var1):获取var1内存地址的值
####4.1.2 putXXX(long var1, byte var3):在var1的内存地址设置值为var3
public native byte getByte(long var1);

	public native void putByte(long var1, byte var3);

	public native short getShort(long var1);

	public native void putShort(long var1, short var3);

	public native char getChar(long var1);

	public native void putChar(long var1, char var3);

	public native int getInt(long var1);

	public native void putInt(long var1, int var3);

	public native long getLong(long var1);

	public native void putLong(long var1, long var3);

	public native float getFloat(long var1);

	public native void putFloat(long var1, float var3);

	public native double getDouble(long var1);

	public native void putDouble(long var1, double var3);


	-------------------------

    @Test
    public void getOrPutInt() {
        //申请4字节的内存
        long memoryAddress = unsafe.allocateMemory(4);
        //将5存入到指定的内存地址中
        unsafe.putInt(memoryAddress,5);
        //根据内存地址获取到整数
        int a = unsafe.getInt(memoryAddress);
        System.out.println("a: "+a);
        //a: 5
    }

4.2 Object属性的读写

4.2.1 getXXX(Object var1, long var2):获取指定对象var1的指定内存地址var2对应的值

4.2.2 putXXX(Object var1, long var2, int var4):修改指定对象var1的指定内存地址var2对应的值

	public native int getInt(Object var1, long var2);

	public native void putInt(Object var1, long var2, int var4);

	public native Object getObject(Object var1, long var2);

	public native void putObject(Object var1, long var2, Object var4);

	public native boolean getBoolean(Object var1, long var2);

	public native void putBoolean(Object var1, long var2, boolean var4);

	public native byte getByte(Object var1, long var2);

	public native void putByte(Object var1, long var2, byte var4);

	public native short getShort(Object var1, long var2);

	public native void putShort(Object var1, long var2, short var4);

	public native char getChar(Object var1, long var2);

	public native void putChar(Object var1, long var2, char var4);

	public native long getLong(Object var1, long var2);

	public native void putLong(Object var1, long var2, long var4);

	public native float getFloat(Object var1, long var2);

	public native void putFloat(Object var1, long var2, float var4);

	public native double getDouble(Object var1, long var2);

	public native void putDouble(Object var1, long var2, double var4);


	-------------------------

    @Test
    public void getOrPutInt2() throws NoSuchFieldException {
        //先通过变量名反射获取到该变量
        Field staticIntField = UnsafeBean.class.getDeclaredField("staticInt");
        //无视权限
        staticIntField.setAccessible(true);

        //够获取到类中的 static 修饰的变量
        long staticIntAddress = unsafe.staticFieldOffset(staticIntField);
        //修改指定对象的指定内存地址对应的值
        unsafe.putInt(UnsafeBean.class,staticIntAddress,10);
        //获取指定对象的指定内存地址对应的值
        int stiatcIntTest = unsafe.getInt(UnsafeBean.class,staticIntAddress);
        //此处输出为 10
        System.out.println("stiatcIntTest:"+stiatcIntTest);
        //stiatcIntTest:10
    }

5 偏移量相关

  1. staticFieldOffset(Field var1):获取静态字段在对象实例中内存地址值

  2. objectFieldOffset(Field var1):获取非静态字段在对象实例中的内存地址值

    public native long staticFieldOffset(Field var1);
    
    public native long objectFieldOffset(Field var1);
    
    -----------------------------
    
    @Test
    public void getXXXFieldOffset() throws NoSuchFieldException {
        //先通过变量名反射获取到该变量
        Field staticIntField = UnsafeBean.class.getDeclaredField("staticInt");
        //无视权限
        staticIntField.setAccessible(true);
        //获取到类中的 static 修饰的变量的地址值
        long staticIntAddress = unsafe.staticFieldOffset(staticIntField);
        System.out.println("staticIntAddress:"+staticIntAddress);
        //staticIntAddress:96
    
        //获取finnal修饰的变量
        Field finalIntField = UnsafeBean.class.getDeclaredField("finalInt");
        finalIntField.setAccessible(true);
        long finalIntAddress = unsafe.objectFieldOffset(finalIntField);
        System.out.println("finalIntAddress:"+finalIntAddress);
        //finalIntAddress:12
    }
    
  3. public native Object staticFieldBase(Field var1):用于返回Field所在的对象

     @Test
     public void staticFieldBase() throws NoSuchFieldException {
     	//先通过变量名反射获取到该变量
     	Field staticIntField = UnsafeBean.class.getDeclaredField("staticInt");
     	//无视权限
     	staticIntField.setAccessible(true);
     	//获取Field所在的对象
     	Object o = unsafe.staticFieldBase(staticIntField);
     	System.out.println("Object:"+o.toString());
     	//Object:class com.feizhou.example.demo.UnsafeBean
     }
    
  4. arrayBaseOffset:返回一个数组第一个元素的内存地址

  5. arrayIndexScale:数组中第一个元素所占用的内存空间大小。

     	 @Test
         public void arrayBaseOffsetOrArrayIndexScale() {
     
             String[] strings = new String[]{"1", "2", "3"};
             //这个方法是返回一个数组第一个元素的内存地址
             long i = unsafe.arrayBaseOffset(String[].class);
             System.out.println("数组第一个元素的内存地址 :" + i);
     
             //every index scale
             //数组中第一个元素所占用的内存空间大小。也就是每个元素分配的内存空间大小
             long scale = unsafe.arrayIndexScale(String[].class);
             System.out.println("数组中第一个元素所占用的内存空间大小 :" + scale);
     
             //print first string in strings[]
             System.out.println("第一个元素 :" + unsafe.getObject(strings, i));
     
             //第一个元素设置为100
             unsafe.putObject(strings, i + scale * 0, "100");
     
     
             System.out.println("第1个元素 : :" + unsafe.getObject(strings, i + scale * 0));
             System.out.println("第2个元素 : :" + unsafe.getObject(strings, i + scale * 1));
             System.out.println("第3个元素 : :" + unsafe.getObject(strings, i + scale * 2));
     
     //        数组第一个元素的内存地址 :16
     //        数组中第一个元素所占用的内存空间 :4
     //        第一个元素 :1
     //        第1个元素 : :100
     //        第2个元素 : :2
     //        第3个元素 : :3
     
         }	
    

6 volatile读写:可以保证可见性和有序性。

  1. getXXXVolatile(Object var1, long var2):用于在对象var1指定偏移地址处var2,volatile读取一个值

  2. putXXXVolatile(Object var1, long var2, XXX var4):在对象var1指定偏移地址处var2,volatile写入一个值var4
    public native Object getObjectVolatile(Object var1, long var2);

    public native void putObjectVolatile(Object var1, long var2, Object var4);
    
    public native int getIntVolatile(Object var1, long var2);
    
    public native void putIntVolatile(Object var1, long var2, int var4);
    
    public native boolean getBooleanVolatile(Object var1, long var2);
    
    public native void putBooleanVolatile(Object var1, long var2, boolean var4);
    
    public native byte getByteVolatile(Object var1, long var2);
    
    public native void putByteVolatile(Object var1, long var2, byte var4);
    
    public native short getShortVolatile(Object var1, long var2);
    
    public native void putShortVolatile(Object var1, long var2, short var4);
    
    public native char getCharVolatile(Object var1, long var2);
    
    public native void putCharVolatile(Object var1, long var2, char var4);
    
    public native long getLongVolatile(Object var1, long var2);
    
    public native void putLongVolatile(Object var1, long var2, long var4);
    
    public native float getFloatVolatile(Object var1, long var2);
    
    public native void putFloatVolatile(Object var1, long var2, float var4);
    
    public native double getDoubleVolatile(Object var1, long var2);
    
    
    -------------------------
    
    
    @Test
    public void getOrPutIntVolatile() throws NoSuchFieldException {
        //先通过变量名反射获取到该变量
        Field staticIntField = UnsafeBean.class.getDeclaredField("staticInt");
        //无视权限
        staticIntField.setAccessible(true);
        //获取到类中 static修饰的变量的地址值
        long staticIntAddress = unsafe.staticFieldOffset(staticIntField);
        //修改指定对象的指定内存地址对应的值
        unsafe.putIntVolatile(UnsafeBean.class,staticIntAddress,10);
        //获取指定对象的指定内存地址对应的值
        int stiatcIntTest = unsafe.getIntVolatile(UnsafeBean.class,staticIntAddress);
        //此处输出为 10
        System.out.println("stiatcIntTest:"+stiatcIntTest);
        //stiatcIntTest:10
    }
    

7 有序写入:保证写入的有序性,不保证可见性

  1. putOrderedXXX(Object var1, long var2, XXX var4):在对象var1指定偏移地址处var2,有序写入一个值var4

     public native void putOrderedObject(Object var1, long var2, Object var4);
    
     public native void putOrderedInt(Object var1, long var2, int var4);
    
     public native void putOrderedLong(Object var1, long var2, long var4);
    
     -------------------------------
    
     @Test
     public void putOrderedXXX() throws NoSuchFieldException {
         Integer i = 1;
         //获取到内部变量 value,这个变量用于存放值
         Field valueField = Integer.class.getDeclaredField("value");
         //无视权限
         valueField.setAccessible(true);
    
         //获取到内存地址
         long valueAddress = unsafe.objectFieldOffset(valueField);
    
         ////将5存入到指定地址中
         unsafe.putOrderedInt(Integer.class,valueAddress,5);
    
         //根据地址获取到整数
         int a = unsafe.getIntVolatile(Integer.class,valueAddress);
         System.out.println("a: "+a);
         //a: 5
     }
    

8 线程调度

1public native void monitorEnter(Object o):锁定对象,必须是没有被锁的

2public native void monitorExit(Object o):解锁对象

3public native boolean tryMonitorEnter(Object o):试图锁定对象,返回true或false是否锁定成功,如果锁定,必须用monitorExit解锁

    @Test
    public void monitorEnterOrmonitorExit() throws InterruptedException {

        UnSafeBean unSafeBean = new UnSafeBean();
        unSafeBean.setAge(20);
        //锁定对象
        unsafe.monitorEnter(unSafeBean);

        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                //锁定对象后,线程堵塞在这里,只有释放锁才可以设置值

                //试图锁定对象,返回true或false是否锁定成功
                while (!unsafe.tryMonitorEnter(unSafeBean)) {

                }
                System.out.println("tryMonitorEnter:" + unsafe.tryMonitorEnter(unSafeBean));
                //只有释放锁才可以设置值
                unSafeBean.setAge(100);
                System.out.println("解锁对象后age值:" + unSafeBean.getAge());

            }
        });
        thread1.start();

        Thread.sleep(2 * 1000);

        System.out.println("锁定对象后age值:" + unSafeBean.getAge());

        //解锁对象
        unsafe.monitorExit(unSafeBean);

//        锁定对象后age值:20
//        tryMonitorEnter:true
//        解锁对象后age值:100
    }
		
		---------------------------------------------------------
		public class UnSafeBean {
		   private  int age;
		
		
		
		    public  int getAge() {
		        return age;
		    }
		
		    public void setAge(int age) {
		        this.age = age;
		    }
		}

9 内存屏障相关

1 public native void loadFence():保证在这个屏障之前的所有读操作都已经完成

2 public native void storeFence():保证在这个屏障之前的所有写操作都已经完成。

3 public native void fullFence():保证在这个屏障之前的所有读写操作都已经完成。

10类加载

1 public native Class<?> defineClass(String var1, byte[] var2, int var3, int var4, ClassLoader var5, ProtectionDomain var6)

定义一个类,用于动态地创建类。

2 public native Class<?> defineAnonymousClass(Class<?> var1, byte[] var2, Object[] var3)

用于动态的创建一个匿名内部类。

3 public native Object allocateInstance(Class<?> var1) throws InstantiationException

方法用于创建一个类的实例,但是不会调用这个实例的构造方法,如果这个类还未被初始化,则初始化这个类。

4 public native boolean shouldBeInitialized(Class<?> var1)

方法用于判断是否需要初始化一个类

5 public native void ensureClassInitialized(Class<?> var1)

方法用于保证已经初始化过一个类
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章