Java ThreadLocalRandom 类
上次修改:2025 年 4 月 26 日
ThreadLocalRandom 类是 Java 并发实用程序的一部分,它生成针对多线程环境优化的伪随机数。 它提供了高效的方法来生成随机整数、双精度浮点数和长整数。
随机数生成在并发应用程序(如游戏、模拟和负载测试)中至关重要。 ThreadLocalRandom 通过为每个线程维护单独的随机数生成器来避免竞争。
ThreadLocalRandom 类概述
ThreadLocalRandom 在 Java 7 中引入,是一个高性能的随机数生成器,专为并发应用程序而设计。 与 Random 相比,由于共享状态,Random 可能会在线程之间产生竞争,而 ThreadLocalRandom 通过为每个线程提供其自身隔离的随机数生成器来消除同步开销。 这显著提高了多线程环境中的性能。
可以通过静态方法 ThreadLocalRandom.current 访问,此类提供了各种便捷方法,包括 nextInt、nextDouble、nextLong 及其支持指定范围的重载版本。 这些方法本质上是线程安全的,因为每个线程管理其自身的 ThreadLocalRandom 实例,从而确保在高并发下的效率和可靠性。
除了并发优势之外,ThreadLocalRandom 简化了在指定范围内生成随机值的过程,使其成为现代多线程应用程序的首选。 它的设计符合 Java 强调为并行处理提供强大而高效的工具的理念。
基本随机数生成
此示例演示了 ThreadLocalRandom 的基本用法,以并发友好的方式生成随机整数、双精度浮点数和长整数。
package com.zetcode;
import java.util.concurrent.ThreadLocalRandom;
public class BasicThreadLocalRandom {
public static void main(String[] args) {
ThreadLocalRandom random = ThreadLocalRandom.current();
// Generate random integer
int randInt = random.nextInt();
System.out.println("Random integer: " + randInt);
// Generate random integer between 0 and 100 (exclusive)
int randIntRange = random.nextInt(100);
System.out.println("Random integer (0-99): " + randIntRange);
// Generate random double between 0.0 and 1.0
double randDouble = random.nextDouble();
System.out.println("Random double: " + randDouble);
// Generate random long
long randLong = random.nextLong();
System.out.println("Random long: " + randLong);
}
}
该程序使用 ThreadLocalRandom.current 获取特定于线程的随机生成器。 它生成四个随机值,展示了该类的核心方法。
每次运行都会产生不同的结果,因为每个线程的生成器都以唯一的方式播种。 这些值均匀分布,非常适合并发应用程序。
自定义范围内的随机数
此示例展示了如何使用 ThreadLocalRandom 在特定范围内生成随机数,适用于需要有界值的任务。
package com.zetcode;
import java.util.concurrent.ThreadLocalRandom;
public class RandomRange {
public static void main(String[] args) {
ThreadLocalRandom random = ThreadLocalRandom.current();
int min = 10;
int max = 20;
// Generate random integer in range [min, max)
int randInt = random.nextInt(min, max);
System.out.println("Random int (" + min + "-" + (max-1) + "): " + randInt);
// Generate random double in range [min, max)
double randDouble = random.nextDouble(min, max);
System.out.println("Random double (" + min + "-" + max + "): " + randDouble);
// Generate random long in range [min, max)
long randLong = random.nextLong(min, max);
System.out.println("Random long (" + min + "-" + (max-1) + "): " + randLong);
}
}
该程序使用重载方法直接在指定范围内生成数字。 例如,nextInt(min, max) 方法生成从 min 到 max-1 的整数。
与 Random 相比,这种方法简化了范围生成,使其对于模拟或游戏机制等并发任务非常有效。
并发随机数生成
此示例说明了在多线程环境中使用 ThreadLocalRandom,突出了其在并发设置中优于 Random 的效率。
package com.zetcode;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ConcurrentRandom {
public static void main(String[] args) {
try (ExecutorService executor = Executors.newFixedThreadPool(4)) {
for (int i = 0; i < 4; i++) {
executor.submit(() -> {
ThreadLocalRandom random = ThreadLocalRandom.current();
System.out.println(Thread.currentThread().getName() +
": " + random.nextInt(100));
});
}
executor.shutdown();
}
}
}
我们创建一个线程池并提交使用 ThreadLocalRandom 生成随机数的任务。 每个线程都使用自己的生成器,避免了竞争。
这证明了该类在并发环境中的优势,在并发环境中,多个线程可以生成随机数而无需同步开销。
生成随机流
此示例展示了如何将 ThreadLocalRandom 与 Java 流一起使用来生成随机数序列,非常适合函数式编程。
package com.zetcode;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.IntStream;
public class RandomStreams {
public static void main(String[] args) {
ThreadLocalRandom random = ThreadLocalRandom.current();
// Generate stream of random integers
System.out.println("Random integers (limit 5):");
IntStream intStream = random.ints(5);
intStream.forEach(System.out::println);
// Generate stream of random integers in range
System.out.println("\nRandom integers (50-100, limit 5):");
IntStream rangeStream = random.ints(5, 50, 100);
rangeStream.forEach(System.out::println);
// Generate stream of random doubles
System.out.println("\nRandom doubles (limit 5):");
random.doubles(5).forEach(System.out::println);
}
}
该程序使用 ints 和 doubles 方法生成随机整数和双精度浮点数的流,并提供有界范围和大小的选项。
流提供了一种生成随机数的函数式方法,使 ThreadLocalRandom 在并发设置中可用于现代 Java 应用程序。
从列表中随机选择
此示例演示了如何使用 ThreadLocalRandom 从列表中随机选择元素,这在游戏或抽样等并发应用程序中很有用。
package com.zetcode;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
public class RandomSelection {
public static void main(String[] args) {
ThreadLocalRandom random = ThreadLocalRandom.current();
List<String> items = List.of("Apple", "Banana", "Orange", "Grape", "Mango");
// Select one random item
int index = random.nextInt(items.size());
String randomItem = items.get(index);
System.out.println("Random item: " + randomItem);
// Select multiple random items
System.out.println("Three random items:");
for (int i = 0; i < 3; i++) {
index = random.nextInt(items.size());
System.out.println(items.get(index));
}
}
}
我们使用 nextInt 生成列表大小范围内的随机索引,然后检索相应的元素。 该示例包括多次替换选择。
此技术在并发环境中非常有效,因为 ThreadLocalRandom 可确保线程安全的随机数生成,而无需锁定。
性能比较
此示例比较了多线程环境中 Random 和 ThreadLocalRandom 的性能。 它强调了 ThreadLocalRandom 的效率,它专为并发应用程序而设计,优于 Random,后者需要显式处理才能保持线程安全。
package com.zetcode;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class PerformanceComparison {
static final int COUNT = 1000000;
public static void main(String[] args) {
// Test Random
try (ExecutorService executor = Executors.newFixedThreadPool(4)) {
long start = System.currentTimeMillis();
for (int i = 0; i < 4; i++) {
executor.submit(() -> {
Random random = new Random();
for (int j = 0; j < COUNT; j++) {
random.nextInt();
}
});
}
executor.shutdown();
if (!executor.awaitTermination(1, TimeUnit.MINUTES)) {
System.err.println("Random tasks did not complete within the timeout.");
}
long duration = System.currentTimeMillis() - start;
System.out.println("Random time: " + duration + "ms");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println("Execution was interrupted.");
}
// Test ThreadLocalRandom
try (ExecutorService executor = Executors.newFixedThreadPool(4)) {
long start = System.currentTimeMillis();
for (int i = 0; i < 4; i++) {
executor.submit(() -> {
ThreadLocalRandom random = ThreadLocalRandom.current();
for (int j = 0; j < COUNT; j++) {
random.nextInt();
}
});
}
executor.shutdown();
if (!executor.awaitTermination(1, TimeUnit.MINUTES)) {
System.err.println("ThreadLocalRandom tasks did not complete within the timeout.");
}
long duration = System.currentTimeMillis() - start;
System.out.println("ThreadLocalRandom time: " + duration + "ms");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println("Execution was interrupted.");
}
}
}
在此示例中,我们使用一个固定的线程池来执行使用 Random 和 ThreadLocalRandom 生成随机数的任务。 这些任务在四个线程上并发运行,每个线程生成一百万个随机数。
虽然 Random 类对于单线程应用程序来说已经足够,但在多线程环境中可能会导致竞争,因为每个线程都会创建自己的实例。 另一方面,ThreadLocalRandom 专门为并发应用程序而设计,提供更快、更高效的随机数生成,而无需同步开销。
此外,使用 try-with-resources 确保正确清理 ExecutorService,而 awaitTermination 验证所有任务是否在给定的超时时间内完成,从而提供更强大的线程池执行处理。
生成随机数组
此示例展示了如何使用 ThreadLocalRandom 使用随机数填充数组,这对于并发测试或模拟任务非常有用。
package com.zetcode;
import java.util.Arrays;
import java.util.concurrent.ThreadLocalRandom;
public class RandomArray {
public static void main(String[] args) {
ThreadLocalRandom random = ThreadLocalRandom.current();
int size = 10;
// Generate array of random integers
int[] intArray = new int[size];
for (int i = 0; i < size; i++) {
intArray[i] = random.nextInt(100);
}
System.out.println("Random integer array: " + Arrays.toString(intArray));
// Generate array of random doubles
double[] doubleArray = new double[size];
for (int i = 0; i < size; i++) {
doubleArray[i] = random.nextDouble();
}
System.out.println("Random double array: " + Arrays.toString(doubleArray));
}
}
该程序使用 ThreadLocalRandom 创建随机整数和双精度浮点数的数组。 每个元素的生成效率都很高,适合并发环境。
此类数组对于在多线程应用程序中测试算法或模拟数据很有价值,并使用 Arrays.toString 格式化输出。
来源
本教程全面探讨了 Java ThreadLocalRandom 类,涵盖了并发设置中的基本用法、范围生成、流和性能。 这对于多线程应用程序至关重要。
作者
列出所有Java教程。