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