JAVA中生成随机数Random VS ThreadLocalRandom性能比较

news2024/11/22 10:05:11

前言

大家项目中如果有生成随机数的需求,我想大多都会选择使用Random来实现,它内部使用了CAS来实现。 实际上,JDK1.7之后,提供了另外一个生成随机数的类ThreadLocalRandom,那么他们二者之间的性能是怎么样的呢?

Random的使用

Random类是JDK提供的生成随机数的类, 这个类不是随机的,而是伪随机的。什么是伪随机呢? 伪随机是指生成的随机数是有一定规律的,这个规律出现的周期因伪随机算法的优劣而异。 一般来说,周期比较长,但可以预见。 我们可以通过以下代码简单地使用 Random:

Random中有很多方法。 这里我们就分析比较常见的nextInt()nextInt(int bound)方法。

  • nextInt()会计算int范围内的随机数,
  • nextInt(int bound)会计算[0,bound) 之间的随机数,左闭右开。

实现原理

Random类的构造函数如下图所示:

  • 可以看到在构造方法中,根据当前时间seed生成了一个AtomicLong类型的seed
public int nextInt() {
    return next(32);
}
复制代码
  • 这里面直接调用了next()方法,传入了32,这里的32是指Int的位数。
protected int next(int bits) {
    long oldseed, nextseed;
    AtomicLong seed = this.seed;
    do {
        oldseed = seed.get();
        nextseed = (oldseed * multiplier + addend) & mask;
    } while (!seed.compareAndSet(oldseed, nextseed));
    return (int)(nextseed >>> (48 - bits));
}
复制代码
  • 这里会根据seed的当前值,通过一定的规则(伪随机)计算出下一个seed,然后进行CAS。 如果CAS失败,继续循环上述操作。 最后根据我们需要的位数返回。

小结:可以看出在next(int bits)方法中,对AtomicLong进行了CAS操作,如果失败则循环重试。 很多人一看到CAS,因为不需要加锁,第一时间就想到了高性能、高并发。 但是在这里,却成为了我们多线程并发性能的瓶颈。 可以想象,当我们有多个线程执行CAS时,只有一个线程一定会失败,其他的会继续循环执行CAS操作。 当并发线程较多时,性能就会下降。

ThreadLocalRandom的使用

JDK1.7之后,提供了一个新类ThreadLocalRandom来替代Random

实现原理

我们先来看下current()方法。

public static ThreadLocalRandom current() {
    if (UNSAFE.getInt(Thread.currentThread(), PROBE) == 0)
        localInit();
    return instance;
}
static final void localInit() {
    int p = probeGenerator.addAndGet(PROBE_INCREMENT);
    int probe = (p == 0) ? 1 : p; // skip 0
    long seed = mix64(seeder.getAndAdd(SEEDER_INCREMENT));
    Thread t = Thread.currentThread();
    UNSAFE.putLong(t, SEED, seed);
    UNSAFE.putInt(t, PROBE, probe);
}
复制代码
  • 如果没有初始化,先进行初始化,这里我们的seed不再是全局变量了。 我们的线程中有三个变量:
/** The current seed for a ThreadLocalRandom */
@sun.misc.Contended("tlr")
long threadLocalRandomSeed;

/** Probe hash value; nonzero if threadLocalRandomSeed initialized */
@sun.misc.Contended("tlr")
int threadLocalRandomProbe;

/** Secondary seed isolated from public ThreadLocalRandom sequence */
@sun.misc.Contended("tlr")
int threadLocalRandomSecondarySeed;
复制代码
  • threadLocalRandomSeed:这是我们用来控制随机数的种子。
  • threadLocalRandomProbe:这个就是ThreadLocalRandom,用来控制初始化。
  • threadLocalRandomSecondarySeed:这是二级种子。

关键代码如下:

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

可以看出,由于每个线程都维护自己的seed,所以此时不需要CAS,直接进行put。 这里通过线程间的隔离来减少并发冲突,所以ThreadLocalRandom的性能非常高。

性能对比

通过基准工具JMH测试:

@BenchmarkMode({Mode.AverageTime})
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations=3, time = 5, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations=3,time = 5)
@Threads(4)
@Fork(1)
@State(Scope.Benchmark)
public class Myclass {
   Random random = new Random();
   ThreadLocalRandom threadLocalRandom = ThreadLocalRandom.current();

   @Benchmark
   public int measureRandom(){
       return random.nextInt();
   }
   @Benchmark
   public int threadLocalmeasureRandom(){
       return threadLocalRandom.nextInt();
   }
	
}
复制代码

运行结果如下图所示,最左边是并发线程的数量:

显而易见,无论线程数量是多少,ThreadLocalRandom性能是远高于Random

总结

本文讲解了JDK中提供的两种生成随机数的方式,一个是JDK 1.0引入的Random类,另外一个是JDK1.7引入的ThreadLocalRandom类,由于底层的实现机制不同,ThreadLocalRandom的性能是远高于Random,建议后面大家在技术选型的时候优先使用ThreadLocalRandom

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/91663.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

用JavaScript写代码将硬盘序列号从16进制字符串转换为ASCII字符串,兼谈EditPlus和Edge浏览器对JavaScript脚本支持的一点差别

之前写的系统信息收集报告程序SysInfo的一个功能就是收集并报告系统中的硬盘序列号。在之前的测试中这项功能表现不错,但前两天用SysInfo收集一台电脑的信息时,显示的硬盘序列号与其它硬盘序列号读取程序显示的顺序不一样。于是着手对SysInfo的相关代码进…

网络爬虫爬取数据并制作词云全过程【内附可执行代码注释完整】

文章目录前言网络爬取数据部分小知识点利用正则表达式在字符串中提取到url(https以及http)仅仅只保存字符串中的中文字符爬取数据生成词云jieba分词生成词云生成词云最终版代码总结前言 快期末了,有个数据挖掘的大作业需要用到python的相关知…

Json字符串转成对象

Json字符串转成对象 Hello吖😊,我是孤音(一个你理解不了的程序猿),今天来分享一个小技巧,能够大大滴提高效率额 问题😵 接收到一串JSON格式的字符串,需要获取其中某些字段的值 思路…

一天梳理完React所有面试考察知识点

性能优化 性能优化,永远是面试的重点,性能优化对于 React 更加重要 在页面中使用了setTimout()、addEventListener()等,要及时在componentWillUnmount()中销毁使用异步组件使用 React-loadable 动态加载组件shouldComponentUpdate(简称SCU …

更高效、更精确的预测性维护方案是如何实现的?

一、预测性维护的必要性 设备维护一般有三种模式:事后维护、预防性维护和预测性维护。事后维护通常是在设备产生故障后采取措施进行维护,是一种成本较大的维护方式。预防性维护属于事先维护,是一种基于时间、性能等条件,对设备进…

A_A05_003 STC-ISP串口调试助手使用

目录 一、软件获取 二、软件基本功能介绍 1、接收缓冲区 2、串口通信参数配置区串口打开关闭其他设置区域 3、发送缓冲区 4、多字符发送区 三、注意事项 一、软件获取 网盘链接 直戳跳转 二、软件基本功能介绍 1、接收缓冲区 注:先选中串口助手切换到上图界…

OneNav Extend网址导航书签系统源码魔改版

内容目录一、详细介绍二、效果展示1.部分代码2.效果图展示三、学习资料下载一、详细介绍 OneNav Extend 是一款功能强大的书签(导航)管理程序,使用PHP SQLite 3开发,界面简洁,安装简单,使用方便。 OneNa…

通达信下单接口如何执行量化策略?

在量化市场上,有很多交易系统就是通过执行量化策略来进行盈利,比如像通达信下单接口系统,其中就包括开仓、买入、止盈、止损方法与策略执行主函数等,那么执行这些策略呢? 想要了解清楚这个问题也很简单,通…

ssm+Vue计算机毕业设计校园疫情信息管理系统(程序+LW文档)

ssmVue计算机毕业设计校园疫情信息管理系统(程序LW文档) 项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项…

linux下gcc编程12-window下clion编译调试redis7.0

redis介绍 Redis 通常被称为数据结构服务器。这意味着 Redis 通过一组命令提供对可变数据结构的访问,这些命令使用具有 TCP 套接字和简单协议的服务器-客户机模型发送。因此,不同的进程可以以共享的方式查询和修改相同的数据结构。 在 Redis 中实现的数…

WebDAV之葫芦儿·派盘 + Enpass

Enpass 支持WebDAV方式连接葫芦儿派盘。 想找一款加密软件把原来本地存储的明文密码,经过加密后存储到自己的电脑上。同时要具备云同步功能,有些安全级别没那么高的内容,可以同步到各端,以供快速查看、编辑。那您选择Enpass准没错了,还可以同步备份到个人私有派盘,跨平…

【vue】插槽,Provided/inject和vue3生命周期

&#xff08;1&#xff09;第一部分&#xff0c;关于插槽 插槽的作用是再子组件模板里面预留出位置&#xff0c;可以插入父组件的东西例如 <template> 下面是插槽展示的内容和&#xff1a;<slot/> </template>//父组件调用子组件布局的时候 <content>…

电竞蓝牙耳机什么牌子好?2022游戏蓝牙耳机推荐

随着玩游戏的人越来越多&#xff0c;随之而来的是越来越多的电竞蓝牙耳机的出现。在游戏中能够精准获取人物周围的声音变化&#xff0c;音效的同步汇入&#xff0c;这是喜欢戴蓝牙耳机玩游戏的用户所追求的听声辨位。那么&#xff0c;在众多的电竞蓝牙耳机当中&#xff0c;什么…

【复习笔记】计算机组成原理复习重点——篇五

计算机组成原理复习重点笔记 第&#xff15;章 输入输出系统 5.1 概述 外部设备&#xff1a;包括输入/输出设备及通过输入/输出接口才能访问的外存储设备。接口&#xff1a;外设与主机之间数据传输时完成速度匹配、格式转换等工作的逻辑部件。输入设备&#xff1a;键盘鼠标输出…

制造业ERP管理系统如何帮助企业解决委外加工管理难题?

当制造企业自身的生产能力不足或者缺乏某种技术的话&#xff0c;就需要把某个工艺甚至整个产品交给外面的制造厂商去进行生产&#xff0c;这就会触发委外加工作业。 委外加工是制造企业管理流程中&#xff0c;非常常见的一个环节&#xff0c;可以有效地减少因公司产能不足&…

qcustomplot单游标在多个坐标系中切换

1. 多坐标系—单个游标—游标在多个坐标系切换 在某些场景下&#xff0c;需要动态的添加多个坐标系&#xff0c;而游标只能在一个坐标系中显示&#xff0c;这时就需要将游标从默认的坐标系切换到指定坐标系&#xff0c;实现很简单&#xff0c;就不贴图了。代码如下&#xff1a…

docker中的c++ ROS节点中使用Matplotlib-cpp

背景 有时debug算法问题&#xff0c;想把算法&#xff0c;代码的中间量快速可视化出来&#xff0c;目前采用rviz或者qt_ros可以实现&#xff0c;但都不是很方便&#xff0c;代码开发量较大&#xff0c;常常会想要是能在ros c中也能像Matlab一样直接plot绘图就好了&#xff0c;…

英飞凌-AURIX-TC3XX 片上总线通信架构

目录1、英飞凌-AURIX-TC3XX 片上总线通信架构1.1、SRI-系统资源互连结构1.1.1、SRI简介1.1.2、SRI 的特征&#xff1a;1.1.3、SRI 结构相比于前一代产品主要的区别&#xff1a;1.1.4、SRI Crossbar 点对点连接机制1.1.5、SRI主机和SRI从机的连接情况1.2、系统外设总线1.3、BBB-…

Windows Qt连接达梦数据库

下载达梦数据库 首先可以在达梦数据库的官网下载达梦数据库&#xff1a;https://www.dameng.com/list_103.html 如果你的QT程序是64位的&#xff0c;那么就下载win64 的达梦数据库&#xff0c;相应的32位的QT程序要下载win32的达梦数据库。否则&#xff0c;程序在连接数据库时…

【图像分割】各向异性热扩散方程SAR图像分割【含Matlab源码 1879期】

⛄一、各向异性热扩散方程简介&#xff08;具体理论见参考文献&#xff09; 1 前言 图像分割是 图像解译的一个关键步骥。 图像分割属于图像解译的早期处理 &#xff0c; 目的是为更高水平的后续处理提供输人。 因此图像分割的好坏对后续 解译性能有较大的影响。 相对于光学图…