Java如何使用Unsafe类
发表于:2025-02-02 作者:千家信息网编辑
千家信息网最后更新 2025年02月02日,这篇文章将为大家详细讲解有关Java如何使用Unsafe类,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。Unsafe 对象提供了非常底层的,操作内存、线程的方法,相
千家信息网最后更新 2025年02月02日Java如何使用Unsafe类
这篇文章将为大家详细讲解有关Java如何使用Unsafe类,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。
Unsafe 对象提供了非常底层的,操作内存、线程的方法,相当于开了后门。
在atomic类中CAS实现、LockSupport中park unpark的底层都调用了UnSafe中的方法。
UnSafe并不是说线程不安全,而是说操作内存有可能会造成不安全问题。
当然对于开发人员来说
Unsafe 对象不能直接调用,只能通过反射获得
通过反射获得Unsafe对象
package com.dongguo.unsafe;import sun.misc.Unsafe;import java.lang.reflect.Field;/** * @author Dongguo * @date 2021/9/12 0012-21:32 * @description: */public class UnsafeAccessor { static Unsafe unsafe; static { try { Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); theUnsafe.setAccessible(true); unsafe = (Unsafe) theUnsafe.get(null); } catch (NoSuchFieldException | IllegalAccessException e) { throw new Error(e); } } static Unsafe getUnsafe() { return unsafe; } public static void main(String[] args) { Unsafe unsafe = getUnsafe(); System.out.println(unsafe); }}
运行结果
sun.misc.Unsafe@7ea987ac
使用Unsafe实现 CAS 操作
package com.dongguo.unsafe;import lombok.Data;import sun.misc.Unsafe;import java.lang.reflect.Field;/** * @author Dongguo * @date 2021/9/12 0012-21:32 * @description: */public class UnsafeAccessor { static Unsafe unsafe; static { try { Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); theUnsafe.setAccessible(true); unsafe = (Unsafe) theUnsafe.get(null); } catch (NoSuchFieldException | IllegalAccessException e) { throw new Error(e); } } static Unsafe getUnsafe() { return unsafe; } public static void main(String[] args) throws NoSuchFieldException { Unsafe unsafe = getUnsafe(); System.out.println(unsafe); Field id = Student.class.getDeclaredField("id"); Field name = Student.class.getDeclaredField("name"); // 获得成员变量的偏移量 long idOffset = unsafe.objectFieldOffset(id); long nameOffset = unsafe.objectFieldOffset(name); Student student = new Student(); // 使用 cas 方法替换成员变量的值 unsafe.compareAndSwapInt(student, idOffset, 0, 20); // 返回 true 0为旧值 20为新值 unsafe.compareAndSwapObject(student, nameOffset, null, "张三"); // 返回 true 旧值为null,新值为张三 System.out.println(student); }}@Dataclass Student { volatile int id; volatile String name;}
运行结果
sun.misc.Unsafe@7ea987ac
Student(id=20, name=张三)
直接使用Unsafe类实现之前AtomicIntegerFieldUpdater中线程安全的原子整数 BankAccount
在atomic中使用AtomicIntegerFieldUpdater实现money线程安全的原子整数
package com.dongguo.unsafe;import java.util.concurrent.TimeUnit;import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;/** * @author Dongguo * @date 2021/9/7 0007-14:41 * 以一种线程安全的方式操作非线程安全对象的某些字段。 * 需求: * 1000个人同时向一个账号转账一元钱,那么累计应该增加1000元, * 除了synchronized和CAS,还可以使用AtomicIntegerFieldUpdater来实现。 */class BankAccount { private String bankName = "ACBC"; public volatile int money = 0; AtomicIntegerFieldUpdaterfieldUpdater = AtomicIntegerFieldUpdater.newUpdater(BankAccount.class, "money"); public void transferMoney(BankAccount bankAccount) { fieldUpdater.incrementAndGet(bankAccount); }}public class AtomicIntegerFieldUpdaterDemo { public static void main(String[] args) { BankAccount bankAccount = new BankAccount(); for (int i = 1; i <= 1000; i++) { new Thread(() -> { bankAccount.transferMoney(bankAccount); }, String.valueOf(i)).start(); } //暂停毫秒 try { TimeUnit.MILLISECONDS.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(bankAccount.money); }}
改为使用UnSafe实现money线程安全的原子整数
package com.dongguo.unsafe;import sun.misc.Unsafe;import java.util.concurrent.TimeUnit;import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;/** * @author Dongguo * @date 2021/9/7 0007-14:41 */class BankAccount { private String bankName = "ACBC"; public volatile int money; static final Unsafe unsafe; static final long DATA_OFFSET; static { unsafe = UnsafeAccessor.getUnsafe(); try { // money 属性在 BankAccount 对象中的偏移量,用于 Unsafe 直接访问该属性 DATA_OFFSET = unsafe.objectFieldOffset(BankAccount.class.getDeclaredField("money")); } catch (NoSuchFieldException e) { throw new Error(e); } } public BankAccount(int money) { this.money = money; } public void transferMoney(int amount) { int oldValue; while (true) { // 获取共享变量旧值,可以在这一行加入断点,修改 data 调试来加深理解 oldValue = money; // cas 尝试修改 data 为 旧值 + amount,如果期间旧值被别的线程改了,返回 false if (unsafe.compareAndSwapInt(this, DATA_OFFSET, oldValue, oldValue + amount)) { return; } } }}public class AtomicIntegerFieldUpdaterDemo { public static void main(String[] args) { BankAccount bankAccount = new BankAccount(0); for (int i = 1; i <= 1000; i++) { new Thread(() -> { bankAccount.transferMoney(1); }, String.valueOf(i)).start(); } //暂停毫秒 try { TimeUnit.MILLISECONDS.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(bankAccount.money); }}运行结果1000/暂停毫秒 try { TimeUnit.MILLISECONDS.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(bankAccount.money); }}
运行结果
1000
关于"Java如何使用Unsafe类"这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。
线程
安全
对象
结果
运行
原子
变量
整数
方法
篇文章
张三
内存
属性
底层
成员
更多
偏移
反射
不错
实用
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
网络安全防护工作机制网络
中国林业数据库2.0
无锡培训软件开发机构
软件开发项目的财务风险
移动协同服务器不支持客户端
跨平台软件开发 unity
服务器文件管理软件
网络安全硬件怎么选
数据库 手机
合肥宁通互联网科技
ug服务器自动启动教程
服务器忘记密码怎样登录
安卓软件开发工作室
青少年的网络安全教案
如何将电脑变为服务器
鹰皇金佰仕网络技术
我们如何保护国家网络安全
怎么把文章存到数据库显示
windows 数据库
生态环境局网络安全工作会议
济宁城管通软件开发
软件开发模板功能
城北网络技术
宿迁云服务器供货厂
服务器忘记密码怎样登录
医疗器械软件开发用sdk吗
江苏web前端软件开发机构
山西网络技术应用会考
世纪佳缘网络安全部
ktv服务器授权两天到期