jdk源码解析--Unsafe类
Posted 我的IT技术路
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jdk源码解析--Unsafe类相关的知识,希望对你有一定的参考价值。
在之前我们描述的很多原子类操作的时候,看到好多CAS操作。CAS(compare 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(-1, 0, 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, (byte) 0);//设置内存初始化值
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(this, new 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. 返回内存页的大小,在nio的bits类有使用:
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中有park和unpark的实现
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中有较多的使用,但是一般情况 下,如果我们对jvm,jmm不是特别熟练的话,不建议使用这些类,可能会导致一些不可预料的事情发现。
以上是关于jdk源码解析--Unsafe类的主要内容,如果未能解决你的问题,请参考以下文章