在jdk源码中,经常能够看到sun.misc.Unsafe的使用,通过Unsafe可以操作内存管理等相关操作。
1.怎么使用Unsafe?
public final class Unsafe{ private static final Unsafe theUnsafe; private Unsafe(){} public static Unsafe getUnsafe(){ Class cc = sun.reflect.Reflection.getCallerClass(2); if (cc.getClassLoader() != null) throw new SecurityException("Unsafe"); return theUnsafe; } }
从Unsafe类中可以看出该类并不推荐让外部用户来使用,首先构造函数为私有的,外部无法通过new实例来使用该类,其次静态的getUnsafe方法的使用也有局限,类加载器必须是bootstrap时,才会返回对应实例。
那该怎么办?还好可以通过反射来获取Unsafe的实例,代码如下:
Field field = Unsafe.class.getDeclaredField("theUnsafe"); field.setAccessible(true); Unsafe unsafe = (Unsafe)field.get(null);
2.获取到unsafe实例后,下面主要介绍常用的功能
(1)修改对象的属性值
这个在开发过程中经常会用到,通常的做法是通过反射来进行设置,现在使用unsafe也可以做到这一点。具体操作用到unsafe的objectFieldOffset方法,它返回成员属性在内存中的地址相对于对象内存地址的偏移量。通过该方法可以计算一个对象在内存中的空间大小,找出Field中偏移量最大值,然后对该最大偏移值填充字节数即为对象大小。下面比较反射以及unsafe在修改对象属性值的性能
import sun.misc.Unsafe; import java.lang.reflect.Field; /** * Created by yuanchen.xuyc on 2016/7/8. * 测试反射和unsafe */ public class TestUnsafe { static Field fieldA; static Field fieldB; static long aFieldOffset; static long bFieldOffset; static Unsafe unsafe; static long loopSize = 50000000; static long preHot = 3000; static { try { //1.反射 fieldA = Bean.class.getDeclaredField("a"); fieldB = Bean.class.getDeclaredField("b"); fieldA.setAccessible(true); fieldB.setAccessible(true); //获取unsafe实例 Field field = Unsafe.class.getDeclaredField("theUnsafe"); field.setAccessible(true); unsafe = (Unsafe)field.get(null); //获取属性a,b的偏移量 aFieldOffset = unsafe.objectFieldOffset(fieldA); bFieldOffset = unsafe.objectFieldOffset(fieldB); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } public static void main(String args[]) throws IllegalAccessException { testReflection(); testUnsafe(); testDirect(); } static class Bean{ private int a; private int b; } private static void testReflection() throws IllegalAccessException { Bean bean = new Bean(); //预热 for(int i=0; i<preHot;i++){ fieldA.set(bean,i); fieldB.set(bean,i); } long start = System.currentTimeMillis(); for(int i=0; i<loopSize;i++){ fieldA.set(bean,i); fieldB.set(bean,i); } long end = System.currentTimeMillis(); System.out.println("反射值set耗费:"+(end-start)+"ms"); } private static void testUnsafe(){ Bean bean = new Bean(); //预热 for(int i=0; i<preHot;i++){ unsafe.putInt(bean, aFieldOffset, i); unsafe.putInt(bean, bFieldOffset, i); } long start = System.currentTimeMillis(); for(int i=0; i<loopSize;i++){ unsafe.putInt(bean, aFieldOffset, i); unsafe.putInt(bean, bFieldOffset, i); } long end = System.currentTimeMillis(); System.out.println("unsafe set耗费:"+(end-start)+"ms"); } private static void testDirect(){ Bean bean = new Bean(); for(int i=0; i<preHot;i++){ bean.a = i; bean.b = i; } long start = System.currentTimeMillis(); for(int i=0; i<loopSize;i++){ bean.a = i; bean.b = i; } long end = System.currentTimeMillis(); System.out.println("direct set耗费:"+(end-start)+"ms"); } }
在x240机器上测试的结果如下:
反射值set耗费:2697ms
unsafe set耗费:164ms
direct set耗费:100ms
从数据上可以看出,unsafe的耗时接近于直接赋值,而反射的性能和unsafe比起来不在一个数量级上。
(2)提供了compareAndSwap,用于实现无锁计数功能
直接上代码,比较几种计数的效率
import sun.misc.Unsafe; import java.lang.reflect.Field; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * Created by yuanchen.xuyc on 2016/7/8. */ public class TestCouter { private static int threadNum = 500; private static int num_to_increment = 1000000; public static void main(String args[]) throws InterruptedException { ExecutorService executorService = Executors.newFixedThreadPool(threadNum); MyCounter synCounter = new SyncCounter(); MyCounter lockCounter = new LockCounter(); MyCounter atomicCounter = new AtomicCounter(); MyCounter unsafeCounter = new UnsafeCounter(); long startTime = System.currentTimeMillis(); for(int i=0;i<threadNum;i++){ executorService.submit(new Count(synCounter,num_to_increment)); } executorService.shutdown(); executorService.awaitTermination(1, TimeUnit.MINUTES); long endTime = System.currentTimeMillis(); System.out.println("计数到:"+synCounter.getCounter()); System.out.println("计数耗时:"+(endTime-startTime) + "ms"); } } class Count implements Runnable{ private MyCounter myCounter; private int count; Count(MyCounter myCounter,int count){ this.myCounter = myCounter; this.count = count; } public long getCounter(){ return myCounter.getCounter(); } public void run() { for(int i=0;i<count;i++) { myCounter.increment(); } } } /** * 利用synchronized加锁实现同步 */ class SyncCounter extends MyCounter{ private long counter = 0l; public synchronized void increment(){ counter++; } public long getCounter(){ return counter; } } /** * 使用读写锁实现 */ class LockCounter extends MyCounter{ private ReentrantReadWriteLock.WriteLock lock = new ReentrantReadWriteLock().writeLock(); private long counter = 0l; public void increment(){ try{ lock.lock(); counter++; }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock(); } } public long getCounter(){ return counter; } } /** * 使用原子类 */ class AtomicCounter extends MyCounter{ private AtomicLong atomicLong = new AtomicLong(0); public void increment(){ atomicLong.incrementAndGet(); } public long getCounter(){ return atomicLong.get(); } } /** * 使用unsafe */ class UnsafeCounter extends MyCounter{ private volatile long counter = 0l; private Unsafe unsafe; private long offset; private Unsafe getUnsafe(){ try { Field field = Unsafe.class.getDeclaredField("theUnsafe"); field.setAccessible(true); unsafe = (Unsafe)field.get(null); } catch (Exception e) { e.printStackTrace(); } return unsafe; } UnsafeCounter(){ unsafe = getUnsafe(); try { offset = unsafe.objectFieldOffset(UnsafeCounter.class.getDeclaredField("counter")); } catch (NoSuchFieldException e) { e.printStackTrace(); } } public void increment(){ long before = counter; while(!unsafe.compareAndSwapLong(this,offset,before,before+1)){ before = counter; } } public long getCounter(){ return counter; } } abstract class MyCounter{ abstract void increment(); abstract long getCounter(); }
相关推荐
CS使用Unsafe的方法向DLL传参 由一个实例开始: c++中函数声明如下: bool Test(float** arr,int rows,int cols); 这个函数在C#中怎么使用,直接传入single[,]出现错误”尝试读取或写入受保护的内存",那到底...
JDK8中sun.misc下UnSafe类源代码 UnSafe.java JDK8中sun.misc下UnSafe类源代码 UnSafe.java
对Netty中的Unsafe做了简单的总结,构建自己的知识网!!!
并发作为 Java 中非常重要的一部分,其内部大量使用了 Unsafe 类,它为 java.util.concurrent 包中的类提供了底层支持。
unsafe-helper-包含一些简单的方法,这些方法使使用sun.misc.Unsafe更容易。 unsafe-collection-在ArrayList上建模的示例列表,该列表不存储对集合内对象的引用,而是直接将元素复制到列表中。 这有一些有趣的特性...
CAS算法的出现使得在不使用synchronize这种“悲观锁”依然可以实现数据的安全访问,CAS算法是指先读取要修改的变量值,对它进行计算,然后执行检查并更新这个步骤(更新前判断那个值是否是之前那个读到的值),检查...
sun.misc.Unsafe源码文件,需要学习的带走。希望能够帮助到大家。
JDK8中sun.misc包下的UnSafe类,想查看源码的就拿走,没积分的请与我联系!xtfggef@gmail.com
解决VS中This function or variable may be unsafe的安全检查错误
但是究竟是什么取代Unsafe不得而知,个人推测会有不止一样来取代它,那么问题来了,到底为什么要使用Unsafe? 做一些Java语言不允许但是又十分有用的事情 很多低级语言中可用的技巧在Java中都是不被允许的。对...
解决VS中This function or variable may be unsafe的安全检查错误
Java Unsafe类1
以后已修复此问题(版本> = 0.2.2.0),但是这也意味着一直通过DotNetCross.Memory.Unsafe.dll引用该程序包的DotNetCross.Memory.Unsafe.dll可能不知道将其更改为DotNetCross.Memory.Unsafe 。 不幸的是,无法...
go官方是不推荐使用unsafe的操作因为它是不安全的,它绕过了golang的内存安全原则,容易使你的程序出现莫名其妙的问题,不利于程序的扩展与维护。但是在很多地方却是很实用。在一些go底层的包中unsafe包被很频繁的...
过度的使用Unsafe类会使得出错的几率变大,因此Java官方并不建议使用的,官方文档也几乎没有。Oracle正在计划从Java 9中去掉Unsafe类,如果真是如此影响就太大了。 Unsafe类提供了以下这些功能: 一、内存管理。包括...
仍然坚持使用Ruby? 这个给你。 一颗宝石中的所有善良 没有垃圾收集器 空指针 不确定。 用法 #!/usr/bin/env ruby # -- encoding: utf-8 -- require 'unsafe/unsafe' CHANCE_OF_DOOM = 0.5 unsafe { ( 1 .. 10 ) ...
Unsafe code是一种绕过go类型安全和内存安全检查的Go代码。这篇文章主要介绍了go中的unsafe包,需要的朋友可以参考下
java魔法类:Unsafe应用
要使用unsafe包需要先了解内存对齐,对有c使用经验的朋友就比较简单了。数据在内存的存储并不是连续按着存放的,而是按照一定的对齐规则。使用对齐规则有一个最大的好处是避免cpu的二次读取,也就是说对齐后的数据...
Unsafe为我们提供了访问底层的机制,这种机制仅供java核心类库使用,而不应该被普通用户使用。但是,为了更好地了解java的生态体系,我们应该去学习它,去了解它,不求深入到底层的C/C++代码,但求能了解它的基本...