UnSafe学习笔记
Posted 花花young
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UnSafe学习笔记相关的知识,希望对你有一定的参考价值。
前言
- 锁会导致线程上下文切换和重新调度开销
- volatile只能保证共享变量的可见性,不能解决读-改-写等的原子性问题
- CAS(Compare and Swap)是JDK提供的非阻塞原子性操作,通过硬件保证了比较-更新操作的原子性
Synchronized
又名监视器锁,释放该锁场景:
- 正常退出同步代码块
- 抛出异常后
- 同步块内调用了该内置锁资源的wait方法时
synchronized内存语义:进入synchronized内使用的共享变量从线程工作内存中清除,这样将会从主内存中去取;退出synchronized会将本地内存修改的共享变量刷新到主内存。
volatile
volatile具有可见性但不具有原子性
CAS
JDK的rt.jar包中的Unsafe类提供了硬件级别的原子性操作,内部提供了一系列原子操作方法,如:
http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/sun/misc/Unsafe.java
/*
o:对象内存地址
offset:对象中变量偏移量
expected:变量预期值
update:新更新的值
方法含义:比较对象o中偏移量为offset的变量值是否与expect相等,相等则使用update值更新,然后返回true,否则返回false
*/
public final native boolean compareAndSwapLong(Object o, long offset,
long expected,
long x);
/*
获取对象o中偏移量为offset的变量对应volatile语义的值
/*
public native long getLongVolatile(Object o, long offset);
//JDK8新增函数
/*
获取对象obj中偏移量为offset的变量volatile语义的当前值,并设置变量volatile语义的值为update
*/
public final long getAndSetLong(Object obj, long offset, long update)
/*
获取对象obj中偏移量为offset的变量volatile语义的当前值,并设置变量值为原始值+addValue
*/
public final long getAndAddLong(Object obj,long offset, long addValue)
Unsafe对象不能通过getUnsafe方法得到
public static Unsafe getUnsafe()
Class<?> caller = Reflection.getCallerClass();
//如果不是BootStrap类加载器加载则抛出异常
if (!VM.isSystemDomainLoader(caller.getClassLoader()))
throw new SecurityException("Unsafe");
return theUnsafe;
//判断paramClassLoader是不是BootStrap类加载器
public static boolean isSystemDomainLoader(ClassLoader paramClassLoader)
return paramClassLoader == null;
为什么要加这个判断?因为我们在main函数所在的类是AppClassLoader加载的,所以在main函数里面加载Unsafe类时,根据委托机制会委托BootStrap去加载Unsafe类。如果没有这个限制,我们的应用程序可以随意使用Unsafe类,而Unsafe类可以直接操作内存,这是不安全的。
当然如果要使用这个类则需要通过反射来得到,如:
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe)field.get(null);
以上是关于UnSafe学习笔记的主要内容,如果未能解决你的问题,请参考以下文章
Golang学习笔记--unsafe.Pointer和uintptr