Java并发29:ThreadLocalRandom学习笔记-随机数的三种使用方法
本章主要对ThreadLocalRandom进行学习。
1.ThreadLocalRandom简介
ThreadLocalRandom是Java提供的用于并发产生伪随机数的工具类,出现于JDK1.7版本中。
ThreadLocalRandom可以看做Math.random()的并发升级类。
ThreadLocalRandom不是直接用new实例化,而是第一次使用其静态方法current()。
ThreadLocalRandom的优势类似于上章的ThreadLocal:每个线程单独一个变量副本,不再产生数据争用。
2.伪随机
所谓伪随机,即不是真正的随机:当使用同样的种子(seed)时,随机工具类会产生一样的随机数序列。
下面通过代码进行伪随机的学习:
- 分别进行两次随机数循环打印
- 两次随机数使用的种子相同
代码如下:
//获取种子 Long seed = System.currentTimeMillis(); /// 伪随机 示例 /// System.out.println("================伪随机:种子相同,生成的随机数序列一致。"); random = new Random(seed); System.out.println("第一次生成:"); for (int i = 0; i < 10; i++) { System.out.print(random.nextInt() + " "); } random = new Random(seed); System.out.println("\n重置种子\n第一次生成:"); for (int i = 0; i < 10; i++) { System.out.print(random.nextInt() + " "); }
运行结果:
================伪随机:种子相同,生成的随机数序列一致。 第一次生成: 382893898 101358198 2106535064 -1939200049 2065597289 383574374 25675075 1140022109 1563937615 -640309302 重置种子 第一次生成: 382893898 101358198 2106535064 -1939200049 2065597289 383574374 25675075 1140022109 1563937615 -640309302
从结果看,种子相同,生成的随机数序列一致,并不是真正的随机。
3.三种随机数实例
生成随机数有很多种方式,下面以三种方式进行练习:
- Random:线程共享随机变量
- ThreadLocalRandom:线程本地随机变量
- ThreadLocal<Random>:线程本地随机变量
采取两种策略:
- 相同种子
- 不同种子
实例代码:
//java.util.Random 多线程-共享 伪随机 相同种子 System.out.println("================java.util.Random的多线程共享伪随机数"); //不同种子 System.out.println("----------------不同种子"); for (int i = 0; i < 2; i++) { Thread.sleep(100); new Thread(() -> { random = new Random(System.currentTimeMillis()); System.out.print(Thread.currentThread().getName() + ":"); for (int j = 0; j < 10; j++) { System.out.print(random.nextInt() + " "); } System.out.println(); }).start(); } Thread.sleep(100); System.out.println("----------------相同种子-->证明Random的伪随机性"); for (int i = 0; i < 2; i++) { Thread.sleep(100); new Thread(() -> { random = new Random(seed); System.out.print(Thread.currentThread().getName() + ":"); for (int j = 0; j < 10; j++) { System.out.print(random.nextInt() + " "); } System.out.println(); }).start(); } Thread.sleep(1000); //java.util.concurrent.ThreadLocalRandom 多线程-并发 伪随机 System.out.println("\n================java.util.concurrent.ThreadLocalRandom的多线程并发伪随机数"); //不同种子 System.out.println("----------------不同种子"); for (int i = 0; i < 2; i++) { Thread.sleep(100); new Thread(() -> { threadLocalRandom = ThreadLocalRandom.current(); System.out.print(Thread.currentThread().getName() + ":"); for (int j = 0; j < 10; j++) { System.out.print(threadLocalRandom.nextInt() + " "); } System.out.println(); }).start(); } Thread.sleep(100); //相同种子-->证明Random的伪随机性 threadLocalRandom = ThreadLocalRandom.current(); System.out.println("----------------相同种子-->证明Random的伪随机性"); for (int i = 0; i < 2; i++) { Thread.sleep(100); new Thread(() -> { System.out.print(Thread.currentThread().getName() + ":"); for (int j = 0; j < 10; j++) { System.out.print(threadLocalRandom.nextInt() + " "); } System.out.println(); }).start(); } Thread.sleep(1000); //java.util.concurrent.ThreadLocal<Random> 多线程-并发 伪随机 System.out.println("\n================java.util.concurrent.ThreadLocal<Random>的多线程并发伪随机数"); Thread.sleep(100); //不同种子 System.out.println("----------------不同种子"); for (int i = 0; i < 2; i++) { Thread.sleep(100); new Thread(() -> { tlRandom.set(new Random(System.currentTimeMillis())); System.out.print(Thread.currentThread().getName() + ":"); for (int j = 0; j < 10; j++) { System.out.print(tlRandom.get().nextInt() + " "); } System.out.println(); }).start(); } Thread.sleep(100); //相同种子-->证明Random的伪随机性 System.out.println("----------------相同种子-->证明Random的伪随机性"); for (int i = 0; i < 2; i++) { Thread.sleep(100); new Thread(() -> { tlRandom.set(new Random(seed)); System.out.print(Thread.currentThread().getName() + ":"); for (int j = 0; j < 10; j++) { System.out.print(tlRandom.get().nextInt() + " "); } System.out.println(); }).start(); }
运行结果:
================java.util.Random的多线程共享伪随机数 ----------------不同种子 Thread-0:1209719284 -543898451 599398397 -16150711 -378920972 1585446581 -488873971 -829205970 -938436680 -45641360 Thread-1:1269740112 -410865868 -1328723315 109456979 -234600411 -307908712 -642144215 1188318491 123033431 143423699 ----------------相同种子-->证明Random的伪随机性 Thread-2:382893898 101358198 2106535064 -1939200049 2065597289 383574374 25675075 1140022109 1563937615 -640309302 Thread-3:382893898 101358198 2106535064 -1939200049 2065597289 383574374 25675075 1140022109 1563937615 -640309302 ================java.util.concurrent.ThreadLocalRandom的多线程并发伪随机数 ----------------不同种子 Thread-4:-1076900907 1413014134 61153437 -391967598 -1288519279 -1610817129 -1180393198 60726166 1036092966 -987557314 Thread-5:1839222654 -1020613466 1431620360 746873003 -436040442 -1615521969 -2094704589 -113489507 1594492864 -1186578140 ----------------相同种子-->证明Random的伪随机性 Thread-6:-1667209487 -754252478 -672050859 1793377410 580216652 595758109 1042779594 1039129943 -125685422 -1698765474 Thread-7:-1667209487 -754252478 -672050859 1793377410 580216652 595758109 1042779594 1039129943 -125685422 -1698765474 ================java.util.concurrent.ThreadLocal<Random>的多线程并发伪随机数 ----------------不同种子 Thread-8:-413521001 545178108 306926326 1860102961 973724015 -317981950 -353356762 -1257712729 1551816344 88775054 Thread-9:-365812138 -1000988543 205972525 418161839 -2105253272 -1052065104 -365059589 -2076841504 1955039530 -862216129 ----------------相同种子-->证明Random的伪随机性 Thread-10:382893898 101358198 2106535064 -1939200049 2065597289 383574374 25675075 1140022109 1563937615 -640309302 Thread-11:382893898 101358198 2106535064 -1939200049 2065597289 383574374 25675075 1140022109 1563937615 -640309302