您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關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進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。