Java中的Unsafe工具类使用详解

 更新时间:2023年12月16日 09:30:31   作者:小晨想好好学习  
这篇文章主要介绍了Java中的Unsafe工具类使用详解,Unsafe是jdk提供的一个直接访问操作系统资源的工具类(底层c++实现),它可以直接分配内存,内存复制,copy,提供cpu级别的CAS乐观锁等操作,需要的朋友可以参考下

一、Unsafe是什么?

Unsafe是jdk提供的一个直接访问操作系统资源的工具类(底层c++实现),它可以直接分配内存,内存复制,copy,提供cpu级别的CAS乐观锁等操作。

Unsafe位于sun.misc包下,jdk中的并发编程包juc(java.util.concurrent)基本全部靠Unsafe实现,由此可见其重要性。

二、Unsafe对象的获取

查看源码:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

结论:

  • Unsafe是饿汉式的单例模式
  • 只允许被引导类加载器(BootstrapClassLoader)加载的类使用,查看源码可以看到在获取unsafe对象时会判断调用类是否是系统类加载器加载的,所以我们无法在自己的类中直接通过Unsafe.getUnsafe()获取unsafe对象。所以只能通过反射直接new一个或者将其内部静态成员变量theUnsafe获取出来
public static void main(String[] args) throws Exception{
    Class<Unsafe> unsafeClass = Unsafe.class;
    //方法一:通过反射构造一个Unsafe对象
    Constructor<Unsafe> constructor = unsafeClass.getDeclaredConstructor();
    constructor.setAccessible(true);
    Unsafe unsafe1 = constructor.newInstance();
    System.out.println(unsafe1);
    //方法二:获取内部静态成员变量
    Field theUnsafe = unsafeClass.getDeclaredField("theUnsafe");
    theUnsafe.setAccessible(true);
    Unsafe unsafe2 = (Unsafe) theUnsafe.get(null);
    System.out.println(unsafe2);
}

三、CAS

CAS译为Compare And Swap,它是乐观锁的一种实现。假设主存值为pre,预期值为expect,想要更新成得值为update,当且仅当主存值pre等预期值expect时,才将pre更新为update。

1、相关方法

在unsafe中,实现CAS算法通过cpu的原子指令cmpxchg实现,它对应的方法如下:

在这里插入图片描述

简单介绍下它使用的参数:

  • 第一个参数 var1为内存中要操作的对象
  • 第二个参数 var2为要操作的值的内存地址偏移量
  • 第三个参数 var4为预期值
  • 第四个参数 var5 为想要更新成的值

为了方便理解,举个栗子。类User有一个成员变量name。我们new了一个对象User后,就知道了它(User对象)在内存中的起始值,而员变量name在对象中的位置偏移是固定的。这样通过这个起始值和这个偏移量就能够定位到成员变量name在内存中的具体位置。

如何得出name在对象User中的偏移量,Unsafe自然也提供了相应的方法:

在这里插入图片描述

2、demo

import sun.misc.Unsafe;
import java.lang.reflect.*;
public class UnsafeDemo {
    public static void main(String[] args) throws Exception {
        Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
        theUnsafe.setAccessible(true);
        Unsafe unsafe = (Unsafe) theUnsafe.get(null);
        User user = new User("jsbintask");
        long nameOffset = unsafe.objectFieldOffset(User.class.getDeclaredField("name"));
        boolean res1 = unsafe.compareAndSwapObject(user, nameOffset, "jsbintask1", "jsbintask2");
        System.out.println(res1+", 第一次更新后的值:" + user.getName());
        boolean res2 = unsafe.compareAndSwapObject(user, nameOffset, "jsbintask", "jsbintask2");
        System.out.println(res2+", 第二次更新后的值:" + user.getName());
    }
    public static class User {
        private String name;
            public User(String name) {
            this.name = name;
        }
        public String getName() {
            return name;
        }
    }  
}

在这里插入图片描述

因为内存中name的值为"jsbintask",而第一次使用compareAndSwapObject方法预期值为"jsbintask1",这显然是不相等的,所以第一次更新失败,返回false。第二次我们传入了正确的预期值,返回true,更新成功!

四、内存分配

Unsafe还给我们提供了直接分配内存,释放内存,拷贝内存,内存设置等方法,值得注意的是,这里的内存指的是堆外内存!它是不受jvm内存模型掌控的,所以使用需要及其小心

在这里插入图片描述

之后用到的时候再进行补充

五、线程调度

通过Unsafe还可以直接将某个线程挂起,这和调用Object.wait()方法作用是一样的,但是效率确更高!

在这里插入图片描述

我们熟知的AQS(AbstractQueuedSynchronizer)内部挂起线程使用了LockSupport,而LockSupport内部依旧使用的是Unsafe:

到此这篇关于Java中的Unsafe工具类使用详解的文章就介绍到这了,更多相关Unsafe工具类内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java实现简单猜数字

    java实现简单猜数字

    这篇文章主要为大家详细介绍了java实现简单猜数字,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-05-05
  • SpringBoot2.3定制错误页面的方法示例

    SpringBoot2.3定制错误页面的方法示例

    这篇文章主要介绍了SpringBoot2.3定制错误页面的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • IDEA x64 exe文件打不开,bat能打开问题

    IDEA x64 exe文件打不开,bat能打开问题

    这篇文章主要介绍了IDEA x64 exe文件打不开,bat能打开问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11
  • Intellij IDEA 2017.3使用Lombok及常用注解介绍

    Intellij IDEA 2017.3使用Lombok及常用注解介绍

    这篇文章主要介绍了Intellij IDEA 2017.3使用Lombok及常用注解介绍,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-09-09
  • springboot中手动提交事务的实现方法

    springboot中手动提交事务的实现方法

    手动提交事务可以提供更灵活的控制,以便在分布式环境中处理事务的提交和回滚,本文就来介绍一下springboot中手动提交事务的实现方法,感兴趣的可以了解一下
    2024-01-01
  • Java中InputSteam怎么转String

    Java中InputSteam怎么转String

    面了一位实习生,叫他给我说一下怎么把InputStream转换为String,这种常规的操作,他竟然都没有用过我准备结合工作经验,整理汇集出了InputStream 到String 转换的十八般武艺,助大家闯荡 Java 江湖一臂之力,需要的朋友可以参考下
    2021-06-06
  • 浅谈Java锁的膨胀过程以及一致性哈希对锁膨胀的影响

    浅谈Java锁的膨胀过程以及一致性哈希对锁膨胀的影响

    本文主要介绍了Java锁的膨胀过程以及一致性哈希对锁膨胀的影响,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • Java使用反射获取list泛型过程浅析

    Java使用反射获取list泛型过程浅析

    这篇文章主要介绍了Java使用反射获取list泛型过程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
    2023-02-02
  • 关于java数组与字符串相互转换的问题

    关于java数组与字符串相互转换的问题

    这篇文章主要介绍了java数组与字符串相互转换的问题,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-10-10
  • Spring Security安全框架之记住我功能

    Spring Security安全框架之记住我功能

    这篇文章主要介绍了Spring Security安全框架之记住我,本次就来探究如何实现这种自动登录、记住我的功能,通过实例代码图文相结合给大家介绍的非常详细,需要的朋友可以参考下
    2022-02-02

最新评论