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)

方法用於保證已經初始化過一個類
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章