您的位置:首页 > 游戏 > 手游 > 电子商务网络平台建设_暴雪中国官网_ip域名查询网站入口_最近几天的新闻

电子商务网络平台建设_暴雪中国官网_ip域名查询网站入口_最近几天的新闻

2025/1/6 12:22:58 来源:https://blog.csdn.net/weixin_44231698/article/details/144913175  浏览:    关键词:电子商务网络平台建设_暴雪中国官网_ip域名查询网站入口_最近几天的新闻
电子商务网络平台建设_暴雪中国官网_ip域名查询网站入口_最近几天的新闻

文章目录

  • 1.Unsafe中重要的方法
  • 2. 使用Unsafe
  • 3. 使用反射来获取Unsafe 实例方法


1.Unsafe中重要的方法

JDK 的rt.jar 包中的 Unsafe 类提供了硬件级别的原子性操作,Unsafe 类中的方法都是native 方法,它们使用 JNI的方式访问本地 C++ 实现库。

  • long objectFieldOffset(Field var1):返回指定的变量在所属类中的内存偏移地址,该偏移地址仅仅在该Unsafe 函数中访问指定字段时使用。如下代码使用Unsafe类获取变量value在AtomicLong对象中的内存偏移。

    	static{try{valueOffset = unsafe.objectFieldOffset(AtomicLong.class.getDeclaredField("value"));}catch(Exception ex){ throw new Error(ex);}}
    
  • int arrayBaseOffset(Class<?> var1):获取数组中第一个元素的地址。

  • int arrayIndexScale(Class<?> var1):获取数组中一个元素占用的字节。

  • boolean compareAndSwapLong(Object obj, long offset, long expect, long update):比较对象obj 中偏移量为offset 的变量的值是否与expect 相等, 相等则使用update值更新, 然后返回true,否则返回false。

  • long getLongVolatile(Object obj, long offset):获取对象obj 中偏移量为offset 的变量对应volatile 语义的值。

  • void putLongVolatile(Object obj, long offset, long value):设置obj 对象中offset偏移的类型为long 的field 的值为value ,支持volatile 语义。

  • void park(boolean isAbsolute, long time):阻塞当前线程,其中参数isAbsolute等于false且time等于0表示一直阻塞。time大于0表示等待指定的time后阻塞线程会被唤醒,这个time 是个相对值, 是个增量值, 也就是相对当前时间累加time
    后当前线程就会被唤醒。如果isAbsolute 等于true , 并且time 大于0 ,则表示阻塞的线程到指定的时间点后会被唤醒,这里time 是个绝对时间, 是将某个时间点换算为ms 后的值。另外,当其他线程调用了当前阻塞线程的interrupt 方法而中断了当前线程时, 当前线程也会返回, 而当其他线程调用了unPark 方法并且把当前线程作为参数时当前线程也会返回。

  • void unpark(Object thread):唤醒调用park 后阻塞的线程。

  • long getAndSetLong(Object obj, long offset, long update):获取对象obj 中偏移量为offset 的变量volatile 语义的当前值, 并设置变量volatile 语义的值为update 。

    public final long getAndSetLong(Object obj, long offset, long update) {long l;do {l= this.getLongVolatile(obj, offset);//(1)} while(!this.compareAndSwapLong(obj, offset, l, update));return l;
    }
    

    由以上代码可知, 首先(1) 处的getLongvolatile 获取当前变量的值, 然后使用CAS 原子操作设置新值。这里使用while 循环是考虑到,在多个线程同时调用的情况下CAS 失败时需要重试。

  • long getAndAddLong(Object obj, long offset, long addValue):获取对象obj中偏移量为offset 的变量volatile 语义的当前值, 并设置变量值为原始值+addValue 。

     public final long getAndAddLong(Object obj, long offset, long update) {long l;do {l= this.getLongVolatile(obj, offset);} while(!this.compareAndSwapLong(obj, offset, l, l+ update));return l;
    }
    

2. 使用Unsafe

public class TestUnsafe {static final Unsafe unsafe = Unsafe.getUnsafe();static final long stateOffset;private volatile long state = 0;static {try {stateOffset = unsafe.objectFieldOffset(TestUnsafe.class.getDeclaredField("state"));} catch (Exception ex) {System.out.println(ex.getLocalizedMessage());throw new Error(ex);}}public static void main(String[] args){TestUnsafe test = new TestUnsafe();Boolean sucess = unsafe.compareAndSwapInt(test, stateOffset, 0, 1);System.out.println(sucess) ;}
}

运行上面代码我们期望输出true,实际执行报错。输出如下结果。

java.lang.ExceptionInInitializerError
Caused by: java.lang.SecurityException: Unsafeat sun.misc.Unsafe.getUnsafe(Unsafe.java:90)at com.exm.collectcodenew.juc.unsafe.TestUnsafe.<clinit>(TestUnsafe.java:8)
Exception in thread "main" 

为找出原因我们看下Unsafe.getUnsafe的源码

 @CallerSensitivepublic static Unsafe getUnsafe() {Class loadClass= Reflection.getCallerClass();//(2.2.8)if (!VM.isSystemDomainLoader(loadClass.getClassLoader())) {throw new SecurityException("Unsafe");} else {return theUnsafe;}}//判断paramClassLoader是不是Bootstrap 类加载器public static boolean isSystemDomainLoader(ClassLoader paramClassLoader) {return paramClassLoader== null;}

调用getUnsafe 这个方法的对象的Class 对象,这里是TestUnSafe.class 。由于TestUnSafe.class 是使用AppClassLoader 加载的, 所以这里直接抛出了异常。
思考一下,这里为何要有这个判断?我们知道Unsafe 类是rt.jar 包提供的, rt.jar 包里面的类是使用Bootstrap 类加载器加载的,而我们的启动main 函数所在的类是使用AppClassLoader 加载的,所以在main 函数里面加载Unsafe 类时,根据委托机制, 会委托Bootstrap 去加载Unsafe 类。
如果没有代码( 2.2.8 )的限制,那么我们的应用程序就可以随意使用Unsafe 做事情了,而Unsafe 类可以直接操作内存,这是不安全的,所以JDK 开发组特意做了这个限制, 不让开发人员在正规渠道使用Unsafe 类,而是在rt.jar 包里面的核心类中使用Unsafe 功能。

3. 使用反射来获取Unsafe 实例方法

public class TestReflectUnsafe {static final Unsafe unsafe ;static final long stateOffset ;private volatile long state = 0;static {try {//使用反射获取Unsafe的成员交量theUnsafeField field = Unsafe.class.getDeclaredField("theUnsafe");//设置为可存取field.setAccessible(true);//获取该变量的值unsafe = (Unsafe) field.get(null);//获取state在TestUnSafe 中的偏移量stateOffset = unsafe.objectFieldOffset(TestUnsafe.class.getDeclaredField("state"));} catch (Exception ex) {System.out.println(ex.getLocalizedMessage());throw new Error(ex);}}public static void main(String[] args) {TestReflectUnsafe test = new TestReflectUnsafe () ;Boolean sucess = unsafe.compareAndSwapInt (test , stateOffset , 0 , 1) ;System.out.println (sucess) ;}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com