16、Java并发 Java ThreadLocalRandom

news/2024/10/19 6:20:42/

随机数生成是一个非常常见的操作,而且 Java 也提供了 java.util.Random 类用于生成随机数,而且呢,这个类也是线程安全的,就是有一点不好,在多线程下,它的性能不佳。

为什么多线程下,Random 的性能不佳?

因为,它采用了多个线程共享一个 Random 实例。这样就会导致多个线程争用。

为了解决这个问题,Java 7 引入了 java.util.concurrent.ThreadLocalRandom 类,用于在多线程环境中生成随机数。

本文接下来的部分,就来看看如何 ThreadLocalRandom 如何执行以及如何在实际应用程序中使用它。

ThreadLocalRandom Via Random

ThreadLocalRandom 是 ThreadLocal 类和 Random 类的组合,它与当前线程隔离,通过简单地避免对 Random 对象的任何并发访问,在多线程环境中实现了更好的性能。

也就是说,相比于 java.util.Random 类全局的提供随机数生成, 使用 ThreadLocalRandom,一个线程获得的随机数不受另一个线程的影响。

另一个与 Random 类不同的是,ThreadLocalRandom 不支持显式设置种子。因为它重写了从 Random 继承的 setSeed(long seed) 方法,会在调用时始终抛出 UnsupportedOperationException。

接下来我们看看如何使用 ThreadLocalRandom 生成随机 int、long 和 double 值。

使用 ThreadLocalRandom 生成随机数

根据Oracle 文档,我们只需要调用 ThreadLocalRandom.current() 方法,就能返回当前线程的 ThreadLocalRandom 实例。然后,我们可以通过实例的相关方法来生成随机值。

比如下面的代码,生成一个没有任何边界的随机 int 值

int unboundedRandomValue = ThreadLocalRandom.current().nextInt());

其实是有边界的,它的边界就是 int 的边界。

接下来,我们看看如何生成有边界的随机 int 值,这意味着我们需要传递边界下限和边界上限作为参数

int boundedRandomValue = ThreadLocalRandom.current().nextInt(0, 100);

请注意,这是一个左闭右开区间,也就是说,上面的实例生成的随机数在 [0,100) 之间,包含了 0 但不包含 100。

同样的,我们可以通过调用 nextLong() 和 nextDouble() 方法生成 long 和 double 类型的随机值,调用方式与上面示例中 nextInt() 类似。

Java 8 还添加了 nextGaussian() 方法从生成器序列中生成下一个正态分布的值,其值范围在 0.0 和 1.0 之间。

与Random 方法类似,ThreadLocalRandom 也提供了 doubles() 、ints() 和 longs() 方法生成一序列流式 ( stream ) 的随机值。

使用 JMH 比较 ThreadLocalRandom 和 Random

记下来,我们看看如何在多线程环境中分别使用这两个类生成随机值,然后再使用 JMH 比较它们的性能。

首先,我们创建一个示例,其中所有线程共享一个 Random 实例。

ExecutorService executor = Executors.newWorkStealingPool();
List<Callable<Integer>> callables = new ArrayList<>();
Random random = new Random();
for (int i = 0; i < 1000; i++) {callables.add(() -> {return random.nextInt();});
}
executor.invokeAll(callables);

上面的代码中,我们把使用 Random 实例生成随机值的任务提交给 ExecutorService 。

然后,我们使用 JMH 基准测试来检查上面代码的性能

# Run complete. Total time: 00:00:36
Benchmark                                            Mode Cnt Score    Error    Units
ThreadLocalRandomBenchMarker.randomValuesUsingRandom avgt 20  771.613 ± 222.220 us/op

接着,类似地,我们使用 ThreadLocalRandom 而不是 Random 实例

ExecutorService executor = Executors.newWorkStealingPool();
List<Callable<Integer>> callables = new ArrayList<>();
for (int i = 0; i < 1000; i++) {callables.add(() -> {return ThreadLocalRandom.current().nextInt();});
}
executor.invokeAll(callables);

上面的代码,为线程池中的每个线程单独使用了一个 ThreadLocalRandom 实例。

下面是使用 JMH 对 ThreadLocalRandom 的测试结果

# Run complete. Total time: 00:00:36
Benchmark                                                       Mode Cnt Score    Error   Units
ThreadLocalRandomBenchMarker.randomValuesUsingThreadLocalRandom avgt 20  624.911 ± 113.268 us/op

通过JMH 的测试结果中可以看出,使用 Random 生成 1000 个随机值所花费的平均时间是 772 微秒,但使用 ThreadLocalRandom 只花了 625 微秒。嗯,差距不是很大,但好歹也是有差距的,因为生成 1000 个随机数是瞬间的事情。

因此,我们可以得出结论,ThreadLocalRandom 在高度并发的环境中更有效。


http://www.ppmy.cn/news/11127.html

相关文章

嵌入式 LINUX 驱动开发 day02 字符设备驱动 字符设备驱动 虚拟串口, 一个驱动支持多个设备

1. 驱动开发 字符设备驱动 代码&#xff1a; vser.c #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h>#include <linux/fs.h> /***** 设备相关信息 ******/ static unsigned int VSER_MAJOR 256; //主设备号…

Redis哨兵模式搭建

以下配置机器部署ip为 a、b、c&#xff0c;其中a为master节点 需提前创建 /app/user/oms/redis/data 目录 1.1上传 redis-5.0.5.zip 到对应目录&#xff0c;解压 unzip redis-5.0.5.zip # 生成 redis-5.0.5 目录 1.2 修改配置文件 maxclients 10000 #20000 &#xff0…

MATLAB-样条插值运算

MATLAB中不仅提供了一维插值、二维插值和三维插值方法&#xff0c;还提供了样条插值的方法。其主要思想是:假定有一组已知的数据点&#xff0c;希望找到该组数据的拟合多项式。在多项式的拟合过程中&#xff0c;对于每组相邻的样本数据点&#xff0c;存在一条曲线&#xff0c;该…

jvm运行过程

VM是Java程序运行的环境,同时是一个操作系统的一个应用程序进程,因此它有自己的生命周期,也有自己的代码和数据空间. JVM体系主要是两个JVM的内部体系结构分为三个子系统和两大组件&#xff0c;分别是&#xff1a;类装载器&#xff08;ClassLoader&#xff09;子系统、执行引擎…

仿抖音视频双指缩放和单指滑动效果

最近刷抖音看视频时&#xff0c;对一个视频某个位置比较感兴趣&#xff0c;采用双指放大查看细节&#xff0c;然后还可以随意滑动到任何位置&#xff0c;比较感兴趣&#xff0c;决定自己来实现此效果&#xff1b;分析效果&#xff1a;ViewPager左右滑动&#xff0c;视频列表上下…

FFmpeg功能命令汇总

前言 如此强大的FFmpeg&#xff0c;能够实现视频采集、视频格式转化、视频截图、视频添加水印、视频切片、视频录制、视频推流、更改音视频参数功能等。通过终端命令如何实现这些功能&#xff0c;Richy在本文做一记录&#xff0c;以备之后查阅。 注意&#xff1a;下面一一列举…

Linux常用命令——nethogs命令

在线Linux命令查询工具(http://www.lzltool.com/LinuxCommand) nethogs 终端下的网络流量监控工具 补充说明 有很多适用于Linux系统的开源网络监视工具。比如说&#xff0c;你可以用命令iftop来检查带宽使用情况。netstat用来查看接口统计报告&#xff0c;还有top监控系统当…

【自学Python】Python input()函数

Python input()函数 Python input()函数教程 在 Python 中&#xff0c;input() 函数用于获取用于的输入&#xff0c;并给出提示。input() 函数&#xff0c;总是返回 string 类型&#xff0c;因此&#xff0c;我们可以使用 input() 函数&#xff0c;获取用户输入的任何数据类型…