java不能直接访问操作系统底层,而是通过本地方法来访问。Unsafe类提供了硬件级别的原子操作,主要提供了以下功能:

1、通过Unsafe类可以分配内存,可以释放内存;

类中提供的3个本地方法allocateMemory、reallocateMemory、freeMemory分别用于分配内存,扩充内存和释放内存,与C语言中的3个方法对应。

2、可以定位对象某字段的内存位置,也可以修改对象的字段值,即使它是私有的;

  1. public native long allocateMemory(long l);
  2. public native long reallocateMemory(long l, long l1);
  3. public native void freeMemory(long l);
字段的定位:
JAVA中对象的字段的定位可能通过staticFieldOffset方法实现,该方法返回给定field的内存地址偏移量,这个值对于给定的filed是唯一的且是固定不变的。
getIntVolatile方法获取对象中offset偏移地址对应的整型field的值,支持volatile load语义。
getLong方法获取对象中offset偏移地址对应的long型field的值
数组元素定位:
Unsafe类中有很多以BASE_OFFSET结尾的常量,比如ARRAY_INT_BASE_OFFSET,ARRAY_BYTE_BASE_OFFSET等,这些常量值是通过arrayBaseOffset方法得到的。arrayBaseOffset方法是一个本地方法,可以获取数组第一个元素的偏移地址。Unsafe类中还有很多以INDEX_SCALE结尾的常量,比如 ARRAY_INT_INDEX_SCALE
, ARRAY_BYTE_INDEX_SCALE等,这些常量值是通过arrayIndexScale方法得到的。arrayIndexScale方法也是一个本地方法,可以获取数组的转换因子,也就是数组中元素的增量地址。将arrayBaseOffset与arrayIndexScale配合使用,可以定位数组中每个元素在内存中的位置。
  1. public final class Unsafe {
  2. public static final int ARRAY_INT_BASE_OFFSET;
  3. public static final int ARRAY_INT_INDEX_SCALE;
  4. public native long staticFieldOffset(Field field);
  5. public native int getIntVolatile(Object obj, long l);
  6. public native long getLong(Object obj, long l);
  7. public native int arrayBaseOffset(Class class1);
  8. public native int arrayIndexScale(Class class1);
  9. static
  10. {
  11. ARRAY_INT_BASE_OFFSET = theUnsafe.arrayBaseOffset([I);
  12. ARRAY_INT_INDEX_SCALE = theUnsafe.arrayIndexScale([I);
  13. }
  14. }

3、挂起与恢复

将一个线程进行挂起是通过park方法实现的,调用 park后,线程将一直阻塞直到超时或者中断等条件出现。unpark可以终止一个挂起的线程,使其恢复正常。整个并发框架中对线程的挂起操作被封装在 LockSupport类中,LockSupport类中有各种版本pack方法,但最终都调用了Unsafe.park()方法。
  1. public class LockSupport {
  2. public static void unpark(Thread thread) {
  3. if (thread != null)
  4. unsafe.unpark(thread);
  5. }
  6. public static void park(Object blocker) {
  7. Thread t = Thread.currentThread();
  8. setBlocker(t, blocker);
  9. unsafe.park(false, 0L);
  10. setBlocker(t, null);
  11. }
  12. public static void parkNanos(Object blocker, long nanos) {
  13. if (nanos > 0) {
  14. Thread t = Thread.currentThread();
  15. setBlocker(t, blocker);
  16. unsafe.park(false, nanos);
  17. setBlocker(t, null);
  18. }
  19. }
  20. public static void parkUntil(Object blocker, long deadline) {
  21. Thread t = Thread.currentThread();
  22. setBlocker(t, blocker);
  23. unsafe.park(true, deadline);
  24. setBlocker(t, null);
  25. }
  26. public static void park() {
  27. unsafe.park(false, 0L);
  28. }
  29. public static void parkNanos(long nanos) {
  30. if (nanos > 0)
  31. unsafe.park(false, nanos);
  32. }
  33. public static void parkUntil(long deadline) {
  34. unsafe.park(true, deadline);
  35. }
  36. }

4、CAS操作

是通过compareAndSwapXXX方法实现的
  1. /**
  2. * 比较obj的offset处内存位置中的值和期望的值,如果相同则更新。此更新是不可中断的。
  3. *
  4. * @param obj 需要更新的对象
  5. * @param offset obj中整型field的偏移量
  6. * @param expect 希望field中存在的值
  7. * @param update 如果期望值expect与field的当前值相同,设置filed的值为这个新值
  8. * @return 如果field的值被更改返回true
  9. */
  10. public native boolean compareAndSwapInt(Object obj, long offset, int expect, int update);
CAS操作有3个操作数,内存值M,预期值E,新值U,如果M==E,则将内存值修改为B,否则啥都不做。

参考资料:

JAVA并发编程学习笔记之Unsafe类的更多相关文章

  1. [转]JAVA并发编程学习笔记之Unsafe类

    1.通过Unsafe类可以分配内存,可以释放内存:类中提供的3个本地方法allocateMemory.reallocateMemory.freeMemory分别用于分配内存,扩充内存和释放内存,与C语 ...

  2. Java并发编程学习笔记

    Java编程思想,并发编程学习笔记. 一.基本的线程机制 1.定义任务:Runnable接口 线程可以驱动任务,因此需要一种描述任务的方式,这可以由Runnable接口来提供.要想定义任务,只需实现R ...

  3. Java 并发编程学习笔记 理解CLH队列锁算法

    CLH算法实现 CLH队列中的结点QNode中含有一个locked字段,该字段若为true表示该线程需要获取锁,且不释放锁,为false表示线程释放了锁.结点之间是通过隐形的链表相连,之所以叫隐形的链 ...

  4. Java并发编程学习笔记 深入理解volatile关键字的作用

    引言:以前只是看过介绍volatile的文章,对其的理解也只是停留在理论的层面上,由于最近在项目当中用到了关于并发方面的技术,所以下定决心深入研究一下java并发方面的知识.网上关于volatile的 ...

  5. Java并发编程学习笔记(一)——线程安全性

    主要概念:线程安全性.原子性.原子变量.原子操作.竟态条件.复合操作.加锁机制.重入.活跃性与性能. 1.当多个线程访问某个状态变量并且其中有一个线程执行写入操作时,必须采用同步机制来协同这些线程对变 ...

  6. JAVA并发编程学习笔记------多线程调优

    1. 多线程场景下尽量使用并发容器代替同步容器 (如ConcurrentHashMap代替同步且基于散列的Map, 遍历操作为主要操作的情况下用CopyOnWriteArrayList代替同步的Lis ...

  7. JAVA并发编程学习笔记------基础构建模块

    一.并发容器:ConcurrentHashMap:1.分段锁机制: 任意数量的读取线程可以并发的访问map,执行读取操作的线程和执行写入操作的线程可以并发的访问Map,并且一定数量的写入线程可以并发的 ...

  8. JAVA并发编程学习笔记------对象的可见性及发布逸出

    一.非原子的64位操作: 当线程在没有同步的情况下读取变量时,可能会得到一个失效值,但至少这个值是由之前某个线程设置的值,而不是一个随机值,这种安全性保证被称为最低安全性.最低安全性适用于绝大多数变量 ...

  9. Java并发编程学习笔记(三)——对象的组合

    重要概念: 1.在设计线程安全类的过程中,需要包含以下三个基本要素: (1)找出构成对象状态的所有变量. (2)找出约束状态变量的不变性条件. (3)建立对象状态的并发访问管理策略. 2.

  10. Java并发编程学习笔记(二)——对象的共享

    主要概念:可见性.重排序.失效数据.最低安全性.发布.逸出.线程封闭(Ad-hoc.栈封闭.ThreadLocal类).不变性.Final域.事实不可变对象. 1.在没有同步的情况下,编译器.处理器以 ...

随机推荐

  1. 【YashanDB知识库】yasdb jdbc驱动集成BeetISQL中间件,业务(java)报autoAssignKey failure异常

    问题现象 BeetISQL中间件版本:2.13.8.RELEASE 客户在调用BeetISQL提供的api向yashandb的表中执行batch insert并将返回sequence设置到传入的jav ...

  2. FirewallD, iptables, Docker

    firewalld 是之前 iptables 的前端.命令更好用 FirewallD 将配置储存在 /usr/lib/firewalld/ 和 /etc/firewalld/ 中的各种 XML 文件 ...

  3. Vue3 插槽技巧

    最近想着使用Vue3+ElementPlus封装一个后台管理常用的Table组件,设计之初考虑到高自定义性,所以便延伸出以下的代码 使用技术栈: Vue3.x ElementPlus Jsx Jsx ...

  4. canvas图片旋转扩展出原生JS实现移动端横竖屏手写签名示例

    前提知识 canvas是提供了各种各样的接口去控制画布,比如旋转rotate方法. 这里的旋转并不是真的把这个画布旋转了,例如ctx.rotate(90 * Math.PI / 180)顺时针旋转90 ...

  5. 小tips:postMessage处理iframe跨域通信

    实例 父页面发消息给子页面,子页面接收消息后回复父页面. 父页面代码: <body> 父级页面: <button id="btn">给iframe子页面传递 ...

  6. Angular 18+ 高级教程 – Component 组件 の Control Flow

    前言 Control Flow 是 Angular v17 版本后推出的新模板语法,用来取代 NgIf.NgForOf.NgSwitch 这 3 个 Structure Directive. Stru ...

  7. ASP.NET Core – Minimal API

    介绍 Minimal API 是 .NET 6 才开始有的功能. 它是一个简化版本的 Web API. 我还没有认真的去学习它, 感觉它走的是 Node.js Express 的路线. 目前用它来写小 ...

  8. JavaScript – 解构赋值 Destructuring Assignment

    参考 阮一峰 – 变量的解构赋值 Array Destructuring Assignment old school const items = [1, 2, 3]; const item1 = it ...

  9. Parquet.Net: 将 Apache Parquet 移植到 .NET

    Parquet.Net 是一个用于读取和写入 Apache Parquet 文件的纯 .NET 库,使用MIT协议开源,github仓库:https://github.com/aloneguid/pa ...

  10. Shiro-550—漏洞分析(CVE-2016-4437)

    目录 漏洞原理 源码分析 加密过程 解密过程 漏洞复现 漏洞原理 Shiro-550(CVE-2016-4437)反序列化漏洞 在调试cookie加密过程的时候发现开发者将AES-CBC用来加密的密钥 ...