jdk源码解析--Unsafe类

Posted 我的IT技术路

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jdk源码解析--Unsafe类相关的知识,希望对你有一定的参考价值。

在之前我们描述的很多原子类操作的时候,看到好多CAS操作。CAScompare and set)翻译过来是比较设值,就是说他会先进行比较是否是预期值,如果是预期值的话,那么就认为没人动过这个值,就可以设值。这个是我们之前描述的一种乐观锁的概念,在java中,unsafe类提供了大量的CAS操作来保证无锁并发。很多人会评价Unsafe类是一个双刃剑,它里面提供了太多操作底层的东西,如果使用不当会造成很多奇怪的问题。Unsafe主要的功能有操作底层的内存,操作线程,当然这些都是一些native方法,本身通过调用底层的c++实现。本文就介绍一下unsafe类的具体实现函数的功能,并通过一些例子说明一下该类的部分功能使用。

我们先看下这个类提供了哪些功能函数:

1.  //获取字段的内存位置,设置相应的值  

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

3.   

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

5.   

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

7.   

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

9.   

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

11.   

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

13.   

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

15.   

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

17.   

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

19.   

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

21.   

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

23.   

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

25.   

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

27.   

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

29.   

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

31.   

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

33.   

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

35.   

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

37.    

38.   

40.  public native long getAddress(long var1);  

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

42.  //申请内存单元 以下是和内存有关的,这个内存不是jvm管理的内存  

43.  public native long allocateMemory(long var1);  

44.   

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

46.   

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

48.   

49.  public void setMemory(long var1, long var3, byte var5) {  

50.      this.setMemory((Object)null, var1, var3, var5);  

51.  }  

52.   

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

54.   

55.  public void copyMemory(long var1, long var3, long var5) {  

56.      this.copyMemory((Object)null, var1, (Object)null, var3, var5);  

57.  }  

58.   

59.  public native void freeMemory(long var1);  

60.    

61. //获取系统指针大小  

62. public native int addressSize();  

63. // 获取内存页的大小  

64.  public native int pageSize();  

65.  //类操作,定义类和获取类  

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

67.   

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

69.   

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

71.  //对象监视器,加锁使用  

72.  public native void monitorEnter(Object var1);  

73.   

74.  public native void monitorExit(Object var1);  

75.   

76.  public native boolean tryMonitorEnter(Object var1);  

77.    

78.  //CAS操作使用  

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

80.   

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

82.   

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

84.  //线程的暂停和恢复  

85.  public native void unpark(Object var1);  

86.   

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

88.  //加载和使用内存屏障  

89.  public native void loadFence();  

90.   

91.  public native void storeFence();  

92.   

93.  public native void fullFence();  

当然里面还有些其他的功能类的,平时可能用到的大概就这么多,下面我们通过例子说明一下这个函数的具体使用方法。

1. 申请堆外内存,即直接内存

1. DirectByteBuffer(int cap) {                     

2.   

3.         super(-10, cap, cap);  

4.         boolean pa = VM.isDirectMemoryPageAligned();  

5.         int ps = Bits.pageSize();  

6.         long size = Math.max(1L, (long)cap + (pa ? ps : 0));  

7.         Bits.reserveMemory(size, cap);  

8.   

9.         long base = 0;  

10.         try {  

11.             base = unsafe.allocateMemory(size);//申请内存  

12.         } catch (OutOfMemoryError x) {  

13.             Bits.unreserveMemory(size, cap);  

14.             throw x;  

15.         }  

16.         unsafe.setMemory(base, size, (byte0);//设置内存初始化值  

17.         if (pa && (base % ps != 0)) {  

18.             // Round up to page boundary  

19.             address = base + ps - (base & (ps - 1));  

20.         } else {  

21.             address = base;  

22.         }  

23.         cleaner = Cleaner.create(thisnew Deallocator(base, size, cap));  

24.         att = null;  

25.   

26.   

27.   

28.     }  

2. 获取内存中某个位置的值,LockSupport

1. static final int nextSecondarySeed() {  

2.         int r;  

3.         Thread t = Thread.currentThread();  

5.             r ^= r << 13;   // xorshift  

6.             r ^= r >>> 17;  

7.             r ^= r << 5;  

8.         }  

9.         else if ((r = java.util.concurrent.ThreadLocalRandom.current().nextInt()) == 0)  

10.             r = 1// avoid zero  

11.         UNSAFE.putInt(t, SECONDARY, r);//设置第二的值  

12.         return r;  

13.     }  

3. 返回内存页的大小,在niobits类有使用:

1. static int pageSize() {  

2.         if (pageSize == -1)  

3.             pageSize = unsafe().pageSize();//获取系统的分页大小  

4.         return pageSize;  

5.     }  

4. 获取类的实例:

1. static Object allocateInstance(Object mh) throws InstantiationException {  

2.         Constructor dmh = (Constructor)mh;//通过构造函数  

3.         return UNSAFE.allocateInstance(dmh.instanceClass);//获取对应的类  

4.     }  

5. cas替换:

1. public final boolean compareAndSet(boolean expect, boolean update) {  

2.         int e = expect ? 1 : 0;  

3.         int u = update ? 1 : 0;  

4.         return unsafe.compareAndSwapInt(this, valueOffset, e, u);//比较对比设置,预期值是e  

5.     }  

6. 线程的暂停:在locksupport中有parkunpark的实现

1. public static void park(Object blocker) {  

2.         Thread t = Thread.currentThread();  

3.         setBlocker(t, blocker);  

4.         UNSAFE.park(false, 0L);//设置线程阻塞  

5.         setBlocker(t, null);  

6.     }  

7. 加内存屏障,防止指令重排序,在stampedLock中有使用

1. public boolean validate(long stamp) {  

2.         U.loadFence();//加上内存屏障,防止获取数据和校验数据重新排序  

3.         return (stamp & SBITS) == (state & SBITS);  

4.     }  

如果要使用unsafe类,我们自己时无法创建的,但是可以通过反射来使用,我们看下jdk默认提供的方法:

1. public static Unsafe getUnsafe() {  

2.         Class var0 = Reflection.getCallerClass();  

3.         if (!VM.isSystemDomainLoader(var0.getClassLoader())) {//是否是启动类,否则异常,换句话说只有jdk自己提供的类可以通过该方法创建  

4.             throw new SecurityException("Unsafe");  

5.         } else {  

6.             return theUnsafe;  

7.         }  

8.     }  

所以如果要使用的话,我们得跳过这个,如下:

1. import sun.misc.Unsafe;  

2. import java.lang.reflect.Field;  

3. public  class CASInt implements java.io.Serializable {  

4.     private static final long serialVersionUID = 6214790243416807051L;  

5.     private static final Unsafe unsafe;  

6.     private static final long valueOffset ;  

7.     static {  

8.         try {  

9.             Field field = Unsafe.class.getDeclaredField("theUnsafe");//通过反射获取  

10.             field.setAccessible(true);//并且设置为可访问  

11.             unsafe= (Unsafe) field.get(null);//返回这个实例  

12.             valueOffset = unsafe.objectFieldOffset  

13.                     (CASInt.class.getDeclaredField("data"));  

14.         } catch (Exception e) {throw new Error(e);}  

15.     }  

16.     private volatile int data ;  

17.   

18.     public CASInt (int i){  

19.   

20.         this.data = i;  

21.     }  

22.     public CASInt (){  

23.         this.data = 0;  

24.     }  

25.     public int add(int k){  

26.         return unsafe.getAndAddInt(this,valueOffset,k);  

27.     }  

28.   

29. }  

Unsafe类确实在jdk中有较多的使用,但是一般情况 下,如果我们对jvmjmm不是特别熟练的话,不建议使用这些类,可能会导致一些不可预料的事情发现。


以上是关于jdk源码解析--Unsafe类的主要内容,如果未能解决你的问题,请参考以下文章

jdk源码解析--LongAdder类

jdk源码解析--String 类

jdk源码解析--BitSet类

jdk源码解析--WeakReference/softReference类

jdk源码解析--Writer类

JDK1.8 动态代理机制及源码解析