秋招Java后端开发冲刺——基础篇4(Unsafe类详解)

本文对Java中的Unsafe类及其常见功能进行总结。

一、介绍

Unsafe类主要用于执行低级别、不安全操作的方法,如直接访问系统内存资源、自主管理内存资源等,其实现依赖于本地方法(Native method,用其他语言(如C/C++/汇编)编写的)

二、Unsafe类的使用

  1. Unsafe 类为一单例实现,提供静态方法 getUnsafe 获取 Unsafe实例。但由于其操作非常底层,为了保证安全性,只有通过启动类加载器加载的类才能够调用 Unsafe 类中的方法。
  2. 非启动类加载器加载类使用Unsafe类的方法通过反射
import sun.misc.Unsafe;
import java.lang.reflect.Field;public class UnsafeUtils {private static final Unsafe unsafe;static {try {Field field = Unsafe.class.getDeclaredField("theUnsafe");field.setAccessible(true);unsafe = (Unsafe) field.get(null);} catch (Exception e) {throw new RuntimeException("Unable to get Unsafe instance", e);}}public static Unsafe getUnsafe() {return unsafe;}
}

三、 常用功能

1. 内存操作(分配、写入、读取)
(1)Unsafe类提供的内存操作方法

  • 内存分配:使用 unsafe.allocateMemory
  • 内存写入:使用 unsafe.putByte 在指定内存地址写入字节数据
  • 内存读取:使用 unsafe.getByte 从指定内存地址读取字节数据
  • 内存释放:使用 unsafe.freeMemory

(2)示例:

import sun.misc.Unsafe;import java.lang.reflect.Field;public class UnsafeExample {private static final Unsafe unsafe;private static final long BYTE_ARRAY_BASE_OFFSET;static {try {Field field = Unsafe.class.getDeclaredField("theUnsafe");field.setAccessible(true);unsafe = (Unsafe) field.get(null);// 获取 byte[] 数组中第一个元素的偏移量BYTE_ARRAY_BASE_OFFSET = unsafe.arrayBaseOffset(byte[].class);} catch (Exception e) {throw new RuntimeException("Unable to get Unsafe instance", e);}}public static void main(String[] args) {// 分配 10 个字节的内存long memoryAddress = unsafe.allocateMemory(10L);try {// 在内存中写入值for (int i = 0; i < 10; i++) {unsafe.putByte(memoryAddress + i, (byte) (i + 1));}// 从内存中读取值for (int i = 0; i < 10; i++) {byte value = unsafe.getByte(memoryAddress + i);System.out.println("Value at index " + i + ": " + value);}// 使用 Unsafe 访问数组元素byte[] byteArray = new byte[10];for (int i = 0; i < 10; i++) {unsafe.putByte(byteArray, BYTE_ARRAY_BASE_OFFSET + i, (byte) (i + 11));}for (int i = 0; i < 10; i++) {byte value = unsafe.getByte(byteArray, BYTE_ARRAY_BASE_OFFSET + i);System.out.println("Array value at index " + i + ": " + value);}} finally {// 释放内存unsafe.freeMemory(memoryAddress);}}
}

2. 内存屏障
(1)内存屏障(Memory Barrier)是用于防止编译器和 CPU 对指令的重新排序,以确保特定的操作顺序对所有处理器和线程都是一致的。
(2) Unsafe类提供的实现内存屏障的方法如下:

  • storeFence():确保在内存屏障之前的所有存储操作在屏障之后的存储操作之前完成。
  • loadFence():确保在内存屏障之前的所有加载操作在屏障之后的加载操作之前完成。
  • fullFence():确保在内存屏障之前的所有存储和加载操作在屏障之后的存储和加载操作之前完成。

(3)示例:

public class UnsafeMemoryBarrierExample {private static final Unsafe unsafe;static {try {Field field = Unsafe.class.getDeclaredField("theUnsafe");field.setAccessible(true);unsafe = (Unsafe) field.get(null);} catch (Exception e) {throw new RuntimeException("Unable to get Unsafe instance", e);}}private volatile int sharedVar = 0;public void storeFenceExample() {// 写操作前插入 storeFenceunsafe.storeFence();sharedVar = 42;unsafe.storeFence();// 确保所有存储操作在此之前完成}public void loadFenceExample() {unsafe.loadFence();int value = sharedVar;unsafe.loadFence();// 确保所有加载操作在此之后完成}public void fullFenceExample() {unsafe.fullFence();sharedVar = 42;int value = sharedVar;unsafe.fullFence();// 确保所有存储和加载操作在此之前完成}public static void main(String[] args) {UnsafeMemoryBarrierExample example = new UnsafeMemoryBarrierExample();example.storeFenceExample();example.loadFenceExample();example.fullFenceExample();}
}

(4)Unsafe类实现内存屏障和Volatile关键字区别

特性Unsafe 类的内存屏障volatile 关键字
用途手动控制内存操作顺序确保变量的可见性和有序性
实现复杂度高,需要手动插入内存屏障低,通过关键字声明
内存屏障类型storeFence(), loadFence(), fullFence()内置,隐式插入
代码可读性低,可读性差,难以维护高,简洁明了
编译器重排序防护是,通过显式屏障是,通过内置机制
CPU重排序防护是,通过显式屏障是,通过内置机制
使用场景高性能、低延迟需求,需精准控制的场合一般并发编程,需确保变量可见性的场合
跨平台兼容性低,依赖具体 JVM 实现,不保证一致性高,由 JVM 提供保障
线程安全是,但需手动确保正确性是,由关键字保证
内存开销较低,只影响屏障附近代码较高,影响整个变量的读写
典型用法高性能并发库,如 java.util.concurrent通用多线程应用
故障风险高,不正确使用可能导致崩溃或数据损坏低,由 JVM 保证

(3)CAS 操作
(1) CAS(Compare-And-Swap)操作是一种原子操作,用于实现无锁并发编程,是一种乐观锁的形式。
(2) Unsafe 类提供了多种 CAS 方法,包括compareAndSwapInt、compareAndSwapLong 和 compareAndSwapObject。
(3)Java中的synchronized关键字和抽象队列同步器的底层实现都使用到了CAS操作。
(4)示例:

public class UnsafeCASExample {private static final Unsafe unsafe;private static final long valueOffset;static {try {Field field = Unsafe.class.getDeclaredField("theUnsafe");field.setAccessible(true);unsafe = (Unsafe) field.get(null);// 获取 value 字段的偏移量valueOffset = unsafe.objectFieldOffset(UnsafeCASExample.class.getDeclaredField("value"));} catch (Exception e) {throw new RuntimeException("Unable to get Unsafe instance", e);}}private volatile int value;public UnsafeCASExample(int initialValue) {this.value = initialValue;}public int getValue() {return value;}public boolean compareAndSwapValue(int expectedValue, int newValue) {return unsafe.compareAndSwapInt(this, valueOffset, expectedValue, newValue);}public static void main(String[] args) {UnsafeCASExample example = new UnsafeCASExample(0);// 多线程更新 valueRunnable task = () -> {for (int i = 0; i < 1000; i++) {int oldValue;int newValue;do {oldValue = example.getValue();newValue = oldValue + 1;} while (!example.compareAndSwapValue(oldValue, newValue));}};Thread thread1 = new Thread(task);Thread thread2 = new Thread(task);thread1.start();thread2.start();try {thread1.join();thread2.join();} catch (InterruptedException e) {Thread.currentThread().interrupt();}System.out.println("Final value: " + example.getValue());}
}

4. 线程调度
(1) Unsafe 类不仅提供了底层的内存操作,还提供了一些与线程操作相关的方法,包括暂停、恢复和阻塞线程等。

  • park:阻塞当前线程,直到其他线程将其唤醒
  • unpark:唤醒被阻塞的线程
    :monitorEnter、monitorExit、tryMonitorEnter方法三个方法已经被弃用
    (2)示例
public class UnsafeThreadExample {private static final Unsafe unsafe;static {try {Field field = Unsafe.class.getDeclaredField("theUnsafe");field.setAccessible(true);unsafe = (Unsafe) field.get(null);} catch (Exception e) {throw new RuntimeException("Unable to get Unsafe instance", e);}}public static void main(String[] args) {Thread parker = new Thread(() -> {System.out.println("Thread is going to park");unsafe.park(false, 0);System.out.println("Thread is unparked");});Thread unparker = new Thread(() -> {try {Thread.sleep(1000); // Sleep for a while before unparking} catch (InterruptedException e) {Thread.currentThread().interrupt();}System.out.println("Thread will unpark the parked thread");unsafe.unpark(parker);});parker.start();unparker.start();try {parker.join();unparker.join();} catch (InterruptedException e) {Thread.currentThread().interrupt();}}
}

5. 其他功能
Unsafe还提供一些其他的功能,包括:对象操作、数据操作、Class 操作、系统信息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/37681.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c进阶篇(一):数据的存储

1.数据类型介绍 char // 字符数据类型 short // 短整型 int // 整形 long // 长整型 long long // 更长的整形 float // 单精度浮点数 double // 双精度浮点数 1.1整形家族&#xff1a; char unsigned char signed char …

Transformer基础及视觉应用

文章目录 Transformer基础及视觉应用注意力机制基础(主要介绍Transformer用到的类型)Transformer的编解码器结构(Encoder and Decoder)Non-local Neural NetworksTransformer与大规模图像识别(Image Recognition at Scale)DETR-2020分割应用 Transformer基础及视觉应用 注意力…

(四)SvelteKit教程:调用外部 API 获取数据

&#xff08;四&#xff09;SvelteKit教程&#xff1a;调用 API 我们先按照如下的方式来构建api服务&#xff1a; step 1:npm i json-serverstep 2:在根目录下新建 db.json 文件&#xff0c;内部写入如下内容&#xff1a;{"users": [{"id": 1,"name…

【算法训练记录——Day36】

Day36——贪心Ⅳ 1.leetcode_452用最少数量的箭引爆气球2.leetcode_435无重叠区间3.leetcode_763划分字母区间4.leetcode_ 1.leetcode_452用最少数量的箭引爆气球 思路&#xff1a;看了眼题解&#xff0c;局部最优&#xff1a;当气球出现重叠&#xff0c;一起射&#xff0c;所用…

React@16.x(43)路由v5.x(8)常见应用场景(5)- 滚动条复位

目录 1&#xff0c;滚动条复位2&#xff0c;在 React 中的触发的3种方式2.1&#xff0c;高阶组件2.2&#xff0c;useEffect2.3&#xff0c;路由守卫 1&#xff0c;滚动条复位 因为切换路由&#xff0c;页面并不会刷新&#xff0c;所以需要手动复位滚动条。实现滚动条复位是比较…

YOLOv5改进 | 注意力机制 | 迈向高质量像素级回归的极化自注意力【全网独家】

秋招面试专栏推荐 &#xff1a;深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 &#x1f4a1;&#x1f4a1;&#x1f4a1;本专栏所有程序均经过测试&#xff0c;可成功执行&#x1f4a1;&#x1f4a1;&#x1f4a1; 专栏目录&#xff1a; 《YOLOv5入门 …

高精密机械设备中滚珠导轨的表面处理工艺有哪些?

滚珠导轨是机床传动和定位的传动元件&#xff0c;其表面处理方式对机床性能和使用寿命起着决定性的作用&#xff0c;不同的表面处理方法可以提高导轨的耐磨性、抗腐蚀性和整体性能。那么&#xff0c;滚珠导轨的表面处理方式有哪几种呢&#xff1f; 1、磨削法&#xff1a;磨削技…

AFLNet入门教学——安装(Ubuntu22.04.4)

1、AFLNet简介 AFLNet 是一种专门用于测试网络协议实现的模糊测试工具。模糊测试是一种软件测试技术&#xff0c;通过向目标程序提供大量随机或半随机数据来发现潜在的漏洞和错误。AFLNet 的设计目标是增强 AFL (American Fuzzy Lop) 的功能&#xff0c;以更有效地测试网络协议…

人事精选面试问题汇总

1.请简单介绍一下你的大学和专业&#xff0c;都开设了哪些课程&#xff0c;以及考试分数为多少&#xff1f; 答&#xff1a;高等数学、大学英语、专业英语、概率统计、离散数学、电路、模拟电子、数字电子、数据结构、操作系统、编译原理、计算机网络、数据库原理、软件工程、汇…

input子系统学习(一)

1、输入子系统框架 2、编写一个简单的设备驱动层代码 #include<linux/module.h> #include<linux/init.h> #include<linux/input.h> #include<linux/time.h>struct input_dev *my_input_dev;static void timer_function(struct timer_list *t); DEFINE…

中医背诵笔记(黄帝内经、伤寒论等)

目录 黄帝内经上古天真论今人和古人之差异&#xff08;精神内守&#xff0c;病安从来&#xff1f;&#xff09;男女每个年龄阶段身体状态至人、圣人、贤人 宣明五气篇五脏所藏 与 五脏所主七情与情绪与气的关系 天干地支天干地支与脏腑经络的关系 伤寒论六种伤寒组合及对应的药…

一款轻量级的通信协议---MQTT (内含Linux环境搭建)

目录 MQTT MQTT的关键特点&#xff1a; 应用场景 Linux环境搭建&#xff1a; 1. 安装mosquitto 2. Linux下客户端进行通信 3. PC端和Linux下进行通信 安装MQTT. fx 4. MQTT.fx的使用 1. 点击连接 ​编辑 2. 连接成功 3. 订阅主题或者给别的主题发送消息 遇到的问…

(项目实战)聚合支付系统开发环境搭建-基于VMware17安装Centos7.9

1 开发环境介绍 dtpay聚合支付系统和ecard预付卡系统&#xff0c;服务端部署在Linux环境。后续的开发环境&#xff0c;生产环境都是基于Linux进行搭建&#xff0c;系统使用到的相关中间件(RocketMQ,Redis&#xff0c;Nginx等)&#xff0c;配置中心Nacos&#xff0c;数据库MySQ…

CSS实现动画

CSS实现动画主要有三种方式&#xff1a;transition&#xff0c;transform&#xff0c;和animation1。以下是一些详细的逻辑&#xff0c;实例和注意事项&#xff1a; Transition&#xff1a;transition可以为一个元素在不同状态之间切换的时候定义不同的过渡效果。例如&#xff…

OpenCV学习之cv2.getGaussianKernel函数

OpenCV学习之cv2.getGaussianKernel函数 一、简介 cv2.getGaussianKernel 是 OpenCV 中用于生成一维高斯核&#xff08;Gaussian Kernel&#xff09;的函数。 高斯核在图像处理中主要用于图像的平滑处理、模糊处理以及作为卷积核来进行各种图像操作。生成的高斯核可以用于卷…

Emp.dll文件丢失?理解Emp.dll重要性与处理常见问题

在繁多的动态链接库&#xff08;DLL&#xff09;文件中&#xff0c;emp.dll 可能不是最广为人知的&#xff0c;但在特定软件或环境中&#xff0c;它扮演着关键角色。本文旨在深入探讨 emp.dll 的功能、重要性以及面对常见问题时的解决策略。 什么是 emp.dll&#xff1f; Emp.d…

python 第6册 辅助excel 002 批量创建非空白的 Excel 文件

---用教授的方式学习 此案例主要通过使用 while 循环以及 openpyxl. load_workbook()方法和 Workbook 的 save()方法&#xff0c;从而实现在当前目录中根据已经存在的Excel 文件批量创建多个非空白的Excel 文件。当运行此案例的Python 代码&#xff08;A002.py 文件&#xff0…

Java面试题:解释函数式编程的概念,并讨论在Java中实现函数式编程的方法

函数式编程&#xff08;Functional Programming&#xff0c;FP&#xff09;是一种编程范式&#xff0c;它将计算视为数学函数的评估&#xff0c;避免使用可变状态和副作用。函数式编程的核心理念包括&#xff1a; 函数是第一类公民&#xff1a;函数可以作为参数传递给其他函数…

【STM32】在标准库中使用定时器

1.TIM简介 STM32F407系列控制器有2个高级控制定时器、10个通用定时器和2个基本定时器。通常情况下&#xff0c;先看定时器挂在哪个总线上APB1或者APB2&#xff0c;然后定时器时钟需要在此基础上乘以2。 2.标准库实现定时中断 #ifndef __BSP_TIMER_H #define __BSP_TIMER_H#if…

Java面试题:讨论Java 8中Lambda表达式的使用,以及它们如何简化代码

Java 8引入的Lambda表达式是对Java语言的一次重要扩展&#xff0c;极大地简化了代码的书写&#xff0c;提升了代码的可读性和可维护性。下面详细讨论Lambda表达式的使用以及它们如何简化代码。 Lambda表达式的使用 Lambda表达式主要用于替代匿名内部类&#xff0c;从而简化代…