前段时间因为看JUC的源码,里面有大量关于unsafe的操作,所以就来看看了.写点笔记总结下(本文基于jdk1.8):

unsafe可以帮我们直接去操作硬件资源,当然了是借助java的jit来进行的,官方不推荐使用,因为不安全,例如你使用unsafe创建一个超级大的数组,但是这个数组jvm是不管理的,只能你自己操作,容易oom,也不利于资源的回收.

好了,下面我们来看代码,

1.获取unsafe

//1.最简单的使用方式是基于反射获取Unsafe实例
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
Unsafe unsafe = (Unsafe) f.get(null);

2.获取unsafe

private static Unsafe unsafe = null;
private static Field getUnsafe = null;static {try {getUnsafe = Unsafe.class.getDeclaredField("theUnsafe");getUnsafe.setAccessible(true);unsafe = (Unsafe) getUnsafe.get(null);} catch (NoSuchFieldException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}
}

随便只要你高兴,都可以获取到unsafe,因为涉及到unsafe 的权限问题,所以,我们只能使用这种方式获取,不然就是权限异常,

操作方法:

/*** 操作数组:* 可以获取数组的在内容中的基本偏移量(arrayBaseOffset),获取数组内元素的间隔(比例),* 根据数组对象和偏移量获取元素值(getObject),设置数组元素值(putObject),示例如下。*/
String[] strings = new String[]{"1", "2", "3"};
long i = unsafe.arrayBaseOffset(String[].class);
System.out.println("string[] base offset is :" + i);//every index scale
long scale = unsafe.arrayIndexScale(String[].class);
System.out.println("string[] index scale is " + scale);//print first string in strings[]
System.out.println("first element is :" + unsafe.getObject(strings, i));//set 100 to first string
unsafe.putObject(strings, i + scale * 0, "100");//print first string in strings[] again
System.out.println("after set ,first element is :" + unsafe.getObject(strings, i + scale * 0));
/*** 对象操作* 实例化Data** 可以通过类的class对象创建类对象(allocateInstance),获取对象属性的偏移量(objectFieldOffset)* ,通过偏移量设置对象的值(putObject)** 对象的反序列化* 当使用框架反序列化或者构建对象时,会假设从已存在的对象中重建,你期望使用反射来调用类的设置函数,* 或者更准确一点是能直接设置内部字段甚至是final字段的函数。问题是你想创建一个对象的实例,* 但你实际上又不需要构造函数,因为它可能会使问题更加困难而且会有副作用。**/
//调用allocateInstance函数避免了在我们不需要构造函数的时候却调用它
Data data = (Data) unsafe.allocateInstance(Data.class);
data.setId(1L);
data.setName("unsafe");
System.out.println(data);//返回成员属性在内存中的地址相对于对象内存地址的偏移量
Field nameField = Data.class.getDeclaredField("name");
long fieldOffset = unsafe.objectFieldOffset(nameField);
//putLong,putInt,putDouble,putChar,putObject等方法,直接修改内存数据(可以越过访问权限)
unsafe.putObject(data,fieldOffset,"这是新的值");
System.out.println(data.getName());/*** 我们可以在运行时创建一个类,比如从已编译的.class文件中。将类内容读取为字节数组,* 并正确地传递给defineClass方法;当你必须动态创建类,而现有代码中有一些代理, 这是很有用的*/
File file = new File("C:\\workspace\\idea2\\disruptor\\target\\classes\\com\\onyx\\distruptor\\test\\Data.class");
FileInputStream input = new FileInputStream(file);
byte[] content = new byte[(int)file.length()];
input.read(content);
Class c = unsafe.defineClass(null, content, 0, content.length,null,null);
c.getMethod("getId").invoke(c.newInstance(), null);/*** 内存操作* 可以在Java内存区域中分配内存(allocateMemory),设置内存(setMemory,用于初始化),* 在指定的内存位置中设置值(putInt\putBoolean\putDouble等基本类型)*/
//分配一个8byte的内存
long address = unsafe.allocateMemory(8L);
//初始化内存填充1
unsafe.setMemory(address, 8L, (byte) 1);
//测试输出
System.out.println("add byte to memory:" + unsafe.getInt(address));
//设置0-3 4个byte为0x7fffffff
unsafe.putInt(address, 0x7fffffff);
//设置4-7 4个byte为0x80000000
unsafe.putInt(address + 4, 0x80000000);
//int占用4byte
System.out.println("add byte to memory:" + unsafe.getInt(address));
System.out.println("add byte to memory:" + unsafe.getInt(address + 4));
/*** CAS操作* Compare And Swap(比较并交换),当需要改变的值为期望的值时,那么就替换它为新的值,是原子* (不可在分割)的操作。很多并发框架底层都用到了CAS操作,CAS操作优势是无锁,可以减少线程切换耗费* 的时间,但CAS经常失败运行容易引起性能问题,也存在ABA问题。在Unsafe中包含compareAndSwapObject、* compareAndSwapInt、compareAndSwapLong三个方法,compareAndSwapInt的简单示例如下。*/
Data data = new Data();
data.setId(1L);
Field id = data.getClass().getDeclaredField("id");
long l = unsafe.objectFieldOffset(id);
id.setAccessible(true);
//比较并交换,比如id的值如果是所期望的值1,那么就替换为2,否则不做处理
unsafe.compareAndSwapLong(data,1L,1L,2L);
System.out.println(data.getId());
/*** 常量获取** 可以获取地址大小(addressSize),页大小(pageSize),基本类型数组的偏移量* (Unsafe.ARRAY_INT_BASE_OFFSET\Unsafe.ARRAY_BOOLEAN_BASE_OFFSET等)、* 基本类型数组内元素的间隔(Unsafe.ARRAY_INT_INDEX_SCALE\Unsafe.ARRAY_BOOLEAN_INDEX_SCALE等)*/
//get os address size
System.out.println("address size is :" + unsafe.addressSize());
//get os page size
System.out.println("page size is :" + unsafe.pageSize());
//int array base offset
System.out.println("unsafe array int base offset:" + Unsafe.ARRAY_INT_BASE_OFFSET);/*** 线程许可* 许可线程通过(park),或者让线程等待许可(unpark),*/
Thread packThread = new Thread(() -> {long startTime = System.currentTimeMillis();//纳秒,相对时间parkunsafe.park(false,3000000000L);//毫秒,绝对时间park//unsafe.park(true,System.currentTimeMillis()+3000);System.out.println("main thread end,cost :"+(System.currentTimeMillis()-startTime)+"ms");
});
packThread.start();
TimeUnit.SECONDS.sleep(1);
//注释掉下一行后,线程3秒数后进行输出,否则在1秒后输出
unsafe.unpark(packThread);
/*** Java数组大小的最大值为Integer.MAX_VALUE。使用直接内存分配,我们创建的数组大小受限于堆大小;* 实际上,这是堆外内存(off-heap memory)技术,在java.nio包中部分可用;** 这种方式的内存分配不在堆上,且不受GC管理,所以必须小心Unsafe.freeMemory()的使用。* 它也不执行任何边界检查,所以任何非法访问可能会导致JVM崩溃*/
public class SuperArray {private static Unsafe unsafe = null;private static Field getUnsafe = null;static {try {getUnsafe = Unsafe.class.getDeclaredField("theUnsafe");getUnsafe.setAccessible(true);unsafe = (Unsafe) getUnsafe.get(null);} catch (NoSuchFieldException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}private final static int BYTE = 1;private long size;private long address;public SuperArray(long size) {this.size = size;address = unsafe.allocateMemory(size * BYTE);}public void set(long i, byte value) {unsafe.putByte(address + i * BYTE, value);}public int get(long idx) {return unsafe.getByte(address + idx * BYTE);}public long size() {return size;}public static void main(String[] args) {long SUPER_SIZE = (long)Integer.MAX_VALUE * 2;SuperArray array = new SuperArray(SUPER_SIZE);System.out.println("Array size:" + array.size()); // 4294967294int sum=0;for (int i = 0; i < 100; i++) {array.set((long)Integer.MAX_VALUE + i, (byte)3);sum += array.get((long)Integer.MAX_VALUE + i);}System.out.println(sum);}}

如果您觉得写得不多, 可以点个赞吗?

java中Unsafe使用讲解相关推荐

  1. Java中Unsafe类详解

    http://www.cnblogs.com/mickole/articles/3757278.html java不能直接访问操作系统底层,而是通过本地方法来访问.Unsafe类提供了硬件级别的原子操 ...

  2. C语言变量unsafe,Java中Unsafe使用详解

    Unsafe介绍 Unsafe是位于sun.misc包下的一个类,主要提供一些用于执行低级别.不安全操作的方法,如直接访问系统内存资源.自主管理内存资源等,这些方法在提升Java运行效率.增强Java ...

  3. Java中Unsafe类的原理详解与使用案例

    点击关注公众号,利用碎片时间学习 1 概述 本文基于JDK1.8. Unsafe类位于rt.jar包,Unsafe类提供了硬件级别的原子操作,类中的方法都是native方法,它们使用JNI的方式访问本 ...

  4. java中的装饰模式讲解,java 中设计模式(装饰设计模式)的实例详解

    搜索热词 java 中设计模式(装饰设计模式)的实例详解 应用场景: 在不对原有对象类进行修改的基础上,给一个或多个已有的类对象提供增强额外的功能. 我觉得可以从字面理解,装饰,装饰房子.房子可以看成 ...

  5. Java JDK Unsafe

    最近看java.util.concurrent.atomic包,发现其中大量的用到Unsafe这个类.就在网上查了一下这个类到底是来干嘛的.java不能直接访问操作系统底层,而是通过本地方法来访问.U ...

  6. java unsafe获取指针_【实战Java高并发程序设计 1】Java中的指针:Unsafe类

    是<实战Java高并发程序设计>第4章的几点. 如果你对技术有着不折不挠的追求,应该还会特别在意incrementAndGet() 方法中compareAndSet()的实现.现在,就让我 ...

  7. java 中向文本写入和读取hashmap_就靠这一篇HashMap的讲解,我与头条面试官聊了一个小时。...

    预备知识 位运算知识(更多资料私信"学习"免费获取) 位运算操作是由处理器支持的底层操作,底层硬件只支持01这样的数字,因此位运算运行速度很快.尽管现代计算机处理器拥有了更长的指令 ...

  8. JAVA中希尔排序去的讲解_java 中基本算法之希尔排序的实例详解

    java 中基本算法之希尔排序的实例详解 希尔排序(Shell Sort)是插入排序的一种.也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本.希尔排序是非稳定排序算法.该方法因DL.Shel ...

  9. MySQL 数据类型讲解 和Java中所对应的数据类型讲解

    MySQL 数据类型讲解 和Java中所对应的数据类型讲解 Mysql数据类型分类 在Mysql中常用数据类型一共有四种字符串数据类型.日期/时间数据类型.数值数据类型以及二进制数据类型. 一.字符串 ...

最新文章

  1. .NET新手系列(八)
  2. 结对-贪吃蛇游戏-开发过程
  3. SpringMVC介绍之Validation
  4. 读书笔记:软件人才-管理的艺术
  5. C# WebApi 返回JSON类型
  6. java怎么使异常不起作用_java – @Test(expected = Exception.class)对我不起作用,我错过了什么?...
  7. JAVA牛客专项练习2020.12.31
  8. java kafka 分区_Java kafka如何实现自定义分区类和拦截器
  9. 在FIREBUG控制台中输入 jQuery() 返回 []
  10. 红包不是你想送就能送 摩拜物联网技术成行业壁垒
  11. Linux内存映射实现框架
  12. 记录一次 CPU sy 过高的排查经历
  13. Vagrant + VMBox 踩坑记录
  14. 逃跑吧少年维护服务器,逃跑吧少年11月19日PC端更新公告
  15. 用python赚零花钱_买不起猪肉了?用Python炒股赚点零花钱吧
  16. cocos2d-x 中添加显示文字的三种方式 LabelTTF 、LabelBMFont 和 LabelAtlas
  17. RN:React Native原理以及新架构JSI、Fabric等概念
  18. 牛津大学出品:随机噪声对抗训练
  19. 计算机硬件技术基础课程主要内容,计算机硬件技术基础课程设计.doc
  20. 【程序人生】程序员成长历程的四个阶段

热门文章

  1. 好可怕!情侣住酒店凌晨被人开门闯入
  2. 电脑删除一些流氓软件/病毒
  3. [福大软工] Z班——个人技术博客评分
  4. 在Microsoft outlook(家用版)利用日曆及To-do list
  5. 使用Arduino制作智能餐厅菜单点餐系统
  6. 数据集:自杀率,目标:分析数据
  7. c语言strdup函数_在C / C ++中使用strdup()函数的指南
  8. 60岁大爷开甜品店,成功解决甜品店的客流和营业额下滑的问题!
  9. SpringBoot @Cacheable Redis 设置缓存过期时间
  10. 网站地图(站点地图)详细介绍以及如何制作