这篇文章将为大家详细讲解有关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); } } @Data class 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; AtomicIntegerFieldUpdater<BankAccount> fieldUpdater = 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类”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。