Unsafe介绍
Unsafe是位于sun.misc包下的一个类,主要提供一些用于执行低级别、不安全操作的方法,如直接访问系统内存资源、自主管理内存资源等,这些方法在提升Java运行效率、增强Java语言底层资源操作能力方面起到了很大的作用。但由于Unsafe类使得Java语言拥有了类似C语言指针一样操作内存空间的能力,这无疑也增加了程序发生相关指针问题的风险。在程序中过度、不正确使用Unsafe类会使得程序出错的概率变大,使得Java这种安全的语言变得不再“安全”,因此对Unsafe的使用一定要慎重。
java.util.concurrent.atomic包下的原子操作类,基本都是使用Unsafe实现的。
Unsafe提供的API大致可分为内存操作、CAS、Class、对象操作、线程、系统信息获取、内存屏障、数组操作等几类。
内存相关
CAS相关
java.util.concurrent.atomic包中的原子类基本都用的Unsafe
privatestaticfinal Unsafe unsafe = Unsafe.getUnsafe();
private staticfinal long valueOffset;
static{
try {
valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
publicfinalintgetAndSet(intnewValue) {
returnunsafe.getAndSetInt(this, valueOffset, newValue);
}
线程相关
LockSupport类中有应用unpark,park
publicstaticvoid park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
UNSAFE.park(false, 0L);
setBlocker(t, null);
}
publicstaticvoid unpark(Thread thread) {
if (thread != null)
UNSAFE.unpark(thread);
}
Class相关
对象操作相关
系统相关
内存屏障
loadFence:保证在这个屏障之前的所有读操作都已经完成。
storeFence:保证在这个屏障之前的所有写操作都已经完成。
fullFence:保证在这个屏障之前的所有读写操作都已经完成。
在java8中 有这个StampedLock类,该类中应用了内存屏障功能。
privatestaticfinal sun.misc.Unsafe U;
static{
try {
U = sun.misc.Unsafe.getUnsafe();
} catch (Exception e) {
throw new Error(e);
}
}
publicboolean validate(long stamp) {
U.loadFence();
return(stamp & SBITS) == (state & SBITS);
}
U.loadFence();
Unsafe.java
publicfinal class Unsafe {
private staticnative void registerNatives();
static{
registerNatives();
sun.reflect.Reflection.registerMethodsToFilter(Unsafe.class, "getUnsafe");
}
private Unsafe() {}
private staticfinal Unsafe theUnsafe = new Unsafe();
// ...
}
获取Unsafe实例
Unsafe类是final且是单例的,并且theUnsafe字段是private;通过如下方法获取实例
方法1
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe") ;
theUnsafe.setAccessible(true) ;
Unsafe unsafe = (Unsafe) theUnsafe.get(null) ;
方法2
privatestaticUnsafe unsafe =null;
static{
try {
Constructor cons = Unsafe.class.getDeclaredConstructor() ;
cons.setAccessible(true) ;
unsafe = cons.newInstance() ;
} catch (Exception e) {
e.printStackTrace();
}
}
Unsafe简单应用
inti = 0 ;
publicstaticvoid main(String[] args) throws Exception {
UnsafeDemo d = new UnsafeDemo() ;
// 获取Unsafe实例
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe") ;
theUnsafe.setAccessible(true) ;
Unsafe unsafe = (Unsafe) theUnsafe.get(null) ;
// 获取类的实例变量
Field f = UnsafeDemo.class.getDeclaredField("i") ;
// 获取字段相对Java对象的"起始地址"的偏移量
long fieldOffset = unsafe.objectFieldOffset(f) ;
System.out.println(fieldOffset) ;
// 设置值
boolean success = unsafe.compareAndSwapInt(d, fieldOffset, 0, 10) ;
System.out.println(success) ;
System.out.println(d.i) ;
}
Unsafe对象操作
privatestaticUnsafe unsafe =null;
static{
try {
Constructor cons = Unsafe.class.getDeclaredConstructor() ;
cons.setAccessible(true) ;
unsafe = cons.newInstance() ;
} catch (Exception e) {
e.printStackTrace();
}
}
publicstaticvoid allocate() {
try {
Person p = (Person)unsafe.allocateInstance(Person.class) ;
p.setId("s001");
System.out.println(p.getValue()) ;
System.out.println(p.getId()) ;
} catch (Exception e) {
e.printStackTrace();
}
}
执行结果:
对象操作2:
private Person p = new Person("1","张三") ;
publicstaticvoid main(String[] args) throws Exception {
UnSafeObjectDemo d = new UnSafeObjectDemo() ;
Field field = Unsafe.class.getDeclaredField("theUnsafe") ;
field.setAccessible(true) ;
Unsafe unsafe = (Unsafe) field.get(null) ;
Field f = d.getClass().getDeclaredField("p") ;
long offset = unsafe.objectFieldOffset(f) ;
System.out.println(offset) ;
boolean res = unsafe.compareAndSwapObject(d, offset, d.p, new Person("2","李四")) ;
System.out.println(res) ;
System.out.println(d.p.getName()) ;
}
Unsafe创建对象
当不知道即将使用的对象有何构造函数,或是不想使用现有对象的构造函数创建对象时,可以通过如下方式:
Constructor cons = (Constructor) ReflectionFactory.getReflectionFactory().newConstructorForSerialization(Teacher.class,
Object.class.getConstructor());
cons.setAccessible(true);
Teacher t = cons.newInstance() ;
System.out.println(t) ;
Unsafe简单实现原子操作类
publicclass AtomicCount {
private staticUnsafe unsafe ;
private intvalue ;
private staticlong valueOffset ;
static{
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe") ;
theUnsafe.setAccessible(true) ;
unsafe = (Unsafe) theUnsafe.get(null) ;
Field f = AtomicCount.class.getDeclaredField("value") ;
valueOffset = unsafe.objectFieldOffset(f) ;
} catch (Exception e) {
e.printStackTrace();
}
}
publicAtomicCount(intvalue) {
this.value = value ;
}
publicfinalintget() {
returnvalue;
}
publicfinalintgetAndIncrement() {
returnunsafe.getAndAddInt(this, valueOffset, 1);
}
}
完毕!!!
【编辑推荐】
【责任编辑:姜华 TEL:(010)68476606】
点赞 0