服务器之家

服务器之家 > 正文

Java使用Unsafe类的示例详解

时间:2022-01-18 16:47     来源/作者:Dongguo丶

Unsafe 对象提供了非常底层的,操作内存、线程的方法,相当于开了后门。

在atomic类中CAS实现、LockSupport中park unpark的底层都调用了UnSafe中的方法。

UnSafe并不是说线程不安全,而是说操作内存有可能会造成不安全问题。

当然对于开发人员来说

Unsafe 对象不能直接调用,只能通过反射获得

Java使用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类的文章就介绍到这了,更多相关Java使用Unsafe类内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/m0_37450089/article/details/120462281

标签:

相关文章

热门资讯

蜘蛛侠3英雄无归3正片免费播放 蜘蛛侠3在线观看免费高清完整
蜘蛛侠3英雄无归3正片免费播放 蜘蛛侠3在线观看免费高清完整 2021-08-24
yue是什么意思 网络流行语yue了是什么梗
yue是什么意思 网络流行语yue了是什么梗 2020-10-11
背刺什么意思 网络词语背刺是什么梗
背刺什么意思 网络词语背刺是什么梗 2020-05-22
2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全
2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全 2019-12-26
2021年耽改剧名单 2021要播出的59部耽改剧列表
2021年耽改剧名单 2021要播出的59部耽改剧列表 2021-03-05
返回顶部