返回顶部
首页 > 资讯 > 精选 >代码里的ThreadLocalRandom是否安全
  • 155
分享到

代码里的ThreadLocalRandom是否安全

2023-06-15 12:06:01 155人浏览 安东尼
摘要

这篇文章主要介绍“代码里的ThreadLocalRandom是否安全”,在日常操作中,相信很多人在代码里的ThreadLocalRandom是否安全问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”代码里的Thr

这篇文章主要介绍“代码里的ThreadLocalRandom是否安全”,在日常操作中,相信很多人在代码里的ThreadLocalRandom是否安全问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”代码里的ThreadLocalRandom是否安全”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

 代码里的ThreadLocalRandom是否安全

Random 的性能问题

使用 Random 类时,为了避免重复创建的开销,我们一般将实例化好的 Random 对象设置为我们所使用服务对象的属性或静态属性,这在线程竞争不激烈的情况下没有问题,但在一个高并发WEB 服务内,使用同一个 Random 对象可能会导致线程阻塞。

Random 的随机原理是对一个”随机种子”进行固定的算术和位运算,得到随机结果,再使用这个结果作为下一次随机的种子。在解决线程安全问题时,Random 使用 CAS 更新下一次随机的种子,可以想到,如果多个线程同时使用这个对象,就肯定会有一些线程执行 CAS 连续失败,进而导致线程阻塞。

ThreadLocalRandom

jdk开发者自然考虑到了这个问题,在 concurrent 包内添加了 ThreadLocalRandom 类,第一次看到这个类名,我以为它是通过 ThreadLocal 实现的,进而想到恐怖的内存泄漏问题,但点进源码却没有 ThreadLocal 的影子,而是存在着大量 Unsafe 相关的代码。

我们来看一下它的核心代码:

UNSAFE.putLong(t = Thread.currentThread(), SEED, r = UNSAFE.getLong(t, SEED) + GAMMA);

翻译成更直观的 Java 代码就像:

Thread t = Thread.currentThread();    long r = UNSAFE.getLong(t, SEED) + GAMMA;    UNSAFE.putLong(t, SEED, r);

看上去非常眼熟,像我们平常往 Map 里 get/set 一样,以 Thread.currentThread() 获取到的当前对象里 key,以 SEED 随机种子作为 value。

但是以对象作为 key 是可能会造成内存泄漏的啊,由于 Thread 对象可能会大量创建,在回收时不 remove Map 里的 value 时会导致 Map 越来越大,最后内存溢出。

Unsafe

功能

不过再仔细看 ThreadLocalRandom 类的核心代码,发现并不是简单的 Map 操作,它的 getLong() 方法需要传入两个参数,而 putLong() 方法需要三个参数,查看源码发现它们都是 native 方法,我们看不到具体的实现。两个方法签名分别是:

public native long getLong(Object var1, long var2);    public native void putLong(Object var1, long var2, long var4);

虽然看不到具体实现,但我们可以查得到它们的功能,下面是两个方法的功能介绍:

  •  putLong(object, offset, value) 可以将 object 对象内存地址偏移 offset 后的位置后四个字节设置为 value。

  •  getLong(object, offset) 会从 object 对象内存地址偏移 offset 后的位置读取四个字节作为 long 型返回。

不安全性

作为 Unsafe 类内的方法,它也透露着一股 “Unsafe” 的气息,具体表现就是可以直接操作内存,而不做任何安全校验,如果有问题,则会在运行时抛出 Fatal Error,导致整个虚拟机的退出。

在我们的常识里,get 方法是最容易抛异常的地方,比如空指针、类型转换等,但 Unsafe.getLong() 方法是个非常安全的方法,它从某个内存位置开始读取四个字节,而不管这四个字节是什么内容,总能成功转成 long 型,至于这个 long 型结果是不是跟业务匹配就是另一回事了。而 set 方法也是比较安全的,它把某个内存位置之后的四个字节覆盖成一个 long 型的值,也几乎不会出错。

那么这两个方法”不安全”在哪呢?

它们的不安全并不是在这两个方法执行期间报错,而是未经保护地改变内存,会引起别的方法在使用这一段内存时报错。

public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {           // Unsafe 设置了构造方法私有,getUnsafe 获取实例方法包私有,在包外只能通过反射获取            Field field = Unsafe.class.getDeclaredField("theUnsafe");             field.setAccessible(true);            Unsafe unsafe = (Unsafe) field.get(null);            // Test 类是一个随手写的测试类,只有一个 String 类型的测试类            Test test = new Test();            test.ttt = "12345";            unsafe.putLong(test, 12L, 2333L);          System.out.println(test.value);        }

运行上面的代码会得到一个 fatal error,报错信息为 “A fatal error has been detected by the Java Runtime Environment: … Process finished with exit code 134 (interrupted by signal 6: SIGABRT)”。

可以从报错信息中看到虚拟机因为这个 fatal error abort 退出了,原因也很简单,我使用 unsafe 将 Test 类 value 属性的位置设置成了 long 型值 2333,而当我使用 value 属性时,虚拟机会将这一块内存解析为 String 对象,原 String 对象对象头的结构被打乱了,解析对象失败抛出了错误,更严重的问题是报错信息中没有类名行号等信息,在复杂项目中排查这种问题真如同大海捞针。

不过 Unsafe 的其他方法可不一定像这一对方法一样,使用他们时可能需要注意另外的安全问题,之后有遇到再说。

ThreadLocalRandom 的实现

那么 ThreadLocalRandom 是不是安全的呢,再回过头来看一下它的实现。

ThreadLocalRandom 的实现需要 Thread 对象的配合,在 Thread 对象内存在着一个属性 threadLocalRandomSeed,它保存着这个线程专属的随机种子,而这个属性在 Thread 对象的 offset,是在 ThreadLocalRandom 类加载时就确定了的,具体方法是 SEED = UNSAFE.objectFieldOffset(Thread.class.getDeclaredField("threadLocalRandomSeed"));

我们知道一个对象所占用的内存大小在类被加载后就确定了的,所以使用 Unsafe.objectFieldOffset(class, fieldName) 可以获取到某个属性在类中偏移量,而在找对了偏移量,又能确定数据类型时,使用 ThreadLocalRandom 就是很安全的。

疑问

在查找这些问题的过程中,我也产生了两个疑问点。

使用场景

首先就是 ThreadLocalRandom 为什么非要使用 Unsafe 来修改 Thread 对象内的随机种子呢,在 Thread 对象内添加 get/set 方法不是更方便吗?

stackOverFlow 上有人跟我同样的疑问,why is threadlocalrandom implemented so bizarrely,被采纳的答案里解释说,对 jdk 开发者来说 Unsafe 和 get/set 方法都像普通的工具,具体使用哪一个并没有一个准则。

这个答案并没有说服我,于是我另开了一个问题,里面的一个评论我比较认同,大意是 ThreadLocalRandom 和 Thread 不在同一个包下,如果添加 get/set 方法的话,get/set 方法必须设置为 public,这就有违了类的封闭性原则。

内存布局

另一个疑问是我看到 Unsafe.objectFieldOffset 可以获取到属性在对象内存的偏移量后,自己在 idea 里使用 main 方法试了上文中提到的 Test 类,发现 Test 类的唯一一个属性 value 相对对象内存的偏移量是 12,于是比较疑惑这 12 个字节的组成。

我们知道,Java 对象的对象头是放在 Java 对象的内存起始处的,而一个对象的 MarkWord 在对象头的起始处,在 32 位系统中,它占用 4 个字节,而在 64 位系统中它占用 8 个字节,我使用的是 64 位系统,这毫无疑问会占用 8 个字节的偏移量。

紧跟 MarkWord 的应该是 Test 类的类指针和数组对象的长度,数组长度是 4 字节,但 Test 类并非数组,也没有其他属性,数据长度可以排除,但在 64 位系统下指针也应该是 8 字节的啊,为什么只占用了 4 个字节呢?

唯一的可能性是虚拟机启用了指针压缩,指针压缩只能在 64 位系统内启用,启用后指针类型只需要占用 4 个字节,但我并没有显示指定过使用指针压缩。查了一下,原来在 1.8 以后指针压缩是默认开启的,在启用时使用 -XX:-UseCompressedOops 参数后,value 的偏移量变成了 16。

到此,关于“代码里的ThreadLocalRandom是否安全”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

--结束END--

本文标题: 代码里的ThreadLocalRandom是否安全

本文链接: https://lsjlt.com/news/280196.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 代码里的ThreadLocalRandom是否安全
    这篇文章主要介绍“代码里的ThreadLocalRandom是否安全”,在日常操作中,相信很多人在代码里的ThreadLocalRandom是否安全问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”代码里的Thr...
    99+
    2023-06-15
  • go单例实现双重检测是否安全的示例代码
    目录现状改进双重检验示例:是否线程安全关于sync.Once关于atomic和metex结论今天看到项目中的kafka客户端包装结构体的获取是单例模式<br>单例的实现是...
    99+
    2024-04-02
  • php代码检测是否安装openssl
    PHP是一种流行的Web开发语言,许多Web应用程序都是用PHP编写的。在开发Web应用程序时,安全性是至关重要的。其中的一个方面是确保应用程序使用安全的加密协议和算法来处理敏感信息。OpenSSL是一种广泛使用的加密工具集,因此在使用PH...
    99+
    2023-05-23
  • NSSecureCoding是否真的安全
    这篇文章主要介绍“NSSecureCoding是否真的安全”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“NSSecureCoding是否真的安全”文章能帮助大家解决问题。NSSecureCoding...
    99+
    2023-07-05
  • 多开阿里云服务器是否安全?是否会封号?
    在云计算时代,越来越多的企业和个人开始使用云服务器来满足其业务需求。阿里云作为国内领先的云计算服务提供商,其服务器备受青睐。然而,随着技术的发展,一些用户可能会考虑通过多开阿里云服务器来获取更多的资源。本文将探讨多开阿里云服务器是否安全,...
    99+
    2024-01-16
    阿里 封号 是否会
  • 阿里云是代理的吗安全吗
    阿里云是一家提供云计算服务的公司,与阿里巴巴集团有着紧密的联系。阿里云提供了一系列安全措施,包括数据加密、防火墙、VPN、IDS/IPS等。这些措施能够保护用户的数据和网络安全。 但是,阿里云是否安全呢?答案是肯定的。阿里云提供了多种保障...
    99+
    2023-10-27
    阿里
  • TiDB的代码库中是否完全基于Go语言?
    TiDB是一个开源的分布式数据库系统,配备了分布式存储引擎 TiKV 和查询层 TiDB,旨在为用户提供高性能、高可扩展性的数据库解决方案。TiDB 代码库实现了数据库核心功能,而 T...
    99+
    2024-04-02
  • Python安全编码与代码审计是怎样的
    这篇文章给大家介绍Python安全编码与代码审计是怎样的,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。1 前言现在一般的web开发框架安全已经做的挺好的了,比如大家常用的django,但是一些不规范的开发方式还是会导致...
    99+
    2023-06-17
  • 阿里云代理安全吗是真的吗
    首先,阿里云提供了全面的安全措施来保护客户的数据和系统。这些措施包括但不限于: 数据加密:阿里云为用户提供了数据加密功能,用户可以在云端轻松地保护数据安全。 访问控制:阿里云采用了分层访问控制策略,根据用户角色的权限控制用户对资源的访问...
    99+
    2023-10-28
    阿里 吗是真
  • c语言怎么判断密码是否安全
    在C语言中,可以使用以下方法来判断密码的安全性:1. 检查密码长度:使用strlen函数获取密码的长度,然后判断其是否满足最小长度要...
    99+
    2023-10-19
    c语言
  • JavaScript 安全编码技巧:编写更安全的代码
    1. 使用严格模式 严格模式是 JavaScript 的一种语法,它可以帮助你编写更安全的代码。严格模式下,JavaScript 引擎会更加严格地执行代码,并会抛出一些在非严格模式下不会抛出的错误。例如,在严格模式下,你不能使用未声明的...
    99+
    2024-02-04
    JavaScript 安全编码 安全编码技巧 安全代码 Web 安全
  • 阿里云购买 ECS 计算器是否安全
    在当今数字化时代,云服务已经成为企业开展业务的重要工具。阿里云作为中国领先的云服务商,其旗下的 ECS计算器服务深受广大用户的喜爱。然而,近期有用户反映,阿里云购买 ECS计算器存在安全问题。那么,这个问题到底有多严重呢?本篇文章将从多个...
    99+
    2023-11-08
    阿里 计算器 ECS
  • PHP 数据库连接安全审计:检查您的代码是否存在漏洞
    数据库连接安全审计:使用安全协议(tls/ssl)保护数据库通信,防止中间人攻击。使用参数化查询,将数据与查询字符串分离,防止 sql 注入攻击。过滤用户输入,清除恶意字符和 sql 命...
    99+
    2024-05-21
    php 数据库安全 mysql 敏感数据
  • PHP 代码安全:云计算的安全隐患
    php 代码安全的云计算安全隐患包括:sql 注入攻击、xss 攻击、缓冲区溢出攻击和 rce 攻击,最佳实践包括验证用户输入、使用哈希密码、更新软件、配置安全的 web 服务器和使用安...
    99+
    2024-05-10
    安全 php 敏感数据
  • Android 判断是否是是全汉字、全字母、全数字、数字和字母等(代码)
    直接看代码吧!!! #pragma mark 判断只能为中文的 - (BOOL) zsStringInputOnlyIsChinese:(NSString*)string {...
    99+
    2022-06-06
    字母 Android
  • 阿里云 ECS 用私网 IP 连接是否安全?
    随着云计算的发展,越来越多的企业开始使用阿里云 ECS(Elastic ComputeService)进行服务器托管和应用运行。然而,一些用户可能会对使用私网 IP 连接阿里云 ECS 是否安全感到疑虑。本文将详细探讨这个问题。 阿里云 E...
    99+
    2023-11-03
    阿里 ECS IP
  • 阿里云数据库只买服务是否安全?
    简介:本文将探讨阿里云数据库只买服务的安全性问题。我们将分析数据库只买服务的风险和安全性,以及如何保护数据免受攻击。 1. 风险与安全性1.1 数据泄露风险在阿里云数据库中,只有购买了数据库实例后才能使用,但是如果只购买了数据库服务而不购买...
    99+
    2024-01-20
    阿里 数据库
  • 阿里云服务器运行是否安全可靠?
    随着互联网技术的发展,越来越多的企业和个人选择在云上运行业务。这其中,阿里云作为国内领先的云服务提供商,备受关注。本文将对阿里云服务器运行的安全性和可靠性进行深入探讨。 阿里云服务器运行是否安全可靠?阿里云是中国领先的云计算服务提供商,提供...
    99+
    2023-12-10
    阿里 可靠 服务器
  • 阿里云数据库同步备份是否安全?
    在数字化时代,数据安全成为了企业和个人关注的焦点。阿里云作为国内领先的云计算服务提供商,其数据库同步备份功能备受关注。那么,阿里云数据库同步备份是否安全呢?本文将为您详细解答。 首先,阿里云数据库同步备份是安全的。在数据安全方面,阿里云采用...
    99+
    2023-11-19
    阿里 备份 数据库
  • gitee代码是否有版权
    在程序员日益增多的今天,代码开放共享成为了一种趋势。Gitee,作为国内较知名的代码托管平台之一,自然成为了程序员们开源分享自己代码的一个重要地方。但是,在代码分享的同时,也出现了一些问题,其中一个问题就是Gitee代码是否有版权。本文将从...
    99+
    2023-10-22
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作