JUC-ThreadLocalRandom
这个类是在JDK7中新增的随机数生成器,它弥补了Random类在多线程下的缺陷。
Radndom类的局限性
在JDK7之前包括现在java.util.Random都是使用比较广泛的随机数生成工具。为什么说它在多线程中有缺陷,看下面一个例子:
public class RandomTest {
public static void main(String[] args) {
Random random=new Random();
for (int i = 0; i <10 ; i++) {
System.out.println(random.nextInt(5));
}
}
}

这是生成随机数常用的一种方法。随机数的生成需要一个默认的种子,这个种子其实是一个long类型的数字,你可以在创建Random对象的时候通过内部的构造函数指定。如果不指定内部将生成一个默认的随机数种子。
有了种子怎么生成随机数呢?
public int nextInt(int bound) {
if (bound <= 0)
throw new IllegalArgumentException(BadBound);
int r = next(31);
int m = bound - 1;
if ((bound & m) == 0) // i.e., bound is a power of 2
r = (int)((bound * (long)r) >> 31);
else {
for (int u = r;
u - (r = u % bound) + m < 0;
u = next(31))
;
}
return r;
}
由此可见生成随机数需要两步:
- 首先根据老的种子来生成新的种子
- 然后根据新的种子来计算新的随机数
但是在多线程环境中,有可能多个线程同时拿到同一个老种子来计算新种子,这样多线程会产生相同值得随机数。
要解决这个问题,首先我们得保证原子性,也就是说当多个线程去拿老种子的时候,第一个线程的新种子被计算出来后,第二个线程要丢弃自己的老种子,使用第一个线程的新种子来计算自己的新种子。
Random函数使用了一个原子变量达到了这个效果。
private final AtomicLong seed;
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));
}
while (!seed.compareAndSet(oldseed, nextseed))这一步使用CAS操作,它使用新种子来更新老种子,但是可能有多个线程同时拿到了老种子,然后根据nextseed = (oldseed * multiplier + addend) & mask;算出来的新种子也是一样的。但是在while操作中由于是CAS操作那么只会有一个线程更新种子成功,失败的线程会通过循环重新去获取更新过后的种子,这样通过原子变量和CAS操作就解决了上诉问题。保证了随机数的随机性。但是我们都知道CAS操作在多线程中必然会造成自旋重试,这将会降低并发性能,所以ThreadLocalRandom应运而生。
ThreadLocalRandom
public class ThreadLocalRandomTest {
static void random(){
ThreadLocalRandom random=ThreadLocalRandom.current();
for (int i = 0; i <10 ; i++) {
System.out.println(random.nextInt(5));
}
System.out.println("--------------");
}
public static void main(String[] args) throws Exception{
Thread thread1=new Thread(() -> {
random();
});
Thread thread2=new Thread(() -> {
random();
});
Thread thread3=new Thread(() -> {
random();
});
Thread thread4=new Thread(() -> {
random();
});
thread1.start();
Thread.sleep(3000);
thread2.start();
Thread.sleep(3000);
thread3.start();
Thread.sleep(3000);
thread4.start();
}
}
其实从名字上我们可以联想到ThreadLocal这个类,实际上这个类也是这个原理,Random的缺点是多个线程会使用同一个原子变量,从而导致对原子变量的更新竞争,导致大量的自旋重试。
那么我们可以让每一个线程维护一个种子变量,每个线程生成随机数的时候根据自己老的种子来计算新的种子。就不会存在竞争问题了,这会大大提高并发性能。
JUC-ThreadLocalRandom的更多相关文章
- JUC源码分析-其它工具类(一)ThreadLocalRandom
JUC源码分析-其它工具类(一)ThreadLocalRandom ThreadLocalRandom 是 JDK7 在 JUC 包下新增的随机数生成器,它解决了 Random 在多线程下多个线程竞争 ...
- Random在高并发下的缺陷以及JUC对其的优化
Random可以说是每个开发都知道,而且都用的很6的类,如果你说,你没有用过Random,也不知道Random是什么鬼,那么你也不会来到这个技术类型的社区,也看不到我的博客了.但并不是每个人都知道Ra ...
- Java并发编程笔记之ThreadLocalRandom源码分析
JDK 并发包中 ThreadLocalRandom 类原理剖析,经常使用的随机数生成器 Random 类的原理是什么?及其局限性是什么?ThreadLocalRandom 是如何利用 ThreadL ...
- JUC包中的分而治之策略-为提高性能而生
一.前言 本次分享我们来共同探讨JUC包中一些有意思的类,包含AtomicLong & LongAdder,ThreadLocalRandom原理. 二.AtomicLong & Lo ...
- ThreadLocalRandom原理
原文链接:https://www.jianshu.com/p/9c2198586f9b 2.2. 并发包中ThreadLocalRandom类原理剖析 ThreadLocalRandom类是JDK7在 ...
- JUC源码分析-集合篇(十)LinkedTransferQueue
JUC源码分析-集合篇(十)LinkedTransferQueue LinkedTransferQueue(LTQ) 相比 BlockingQueue 更进一步,生产者会一直阻塞直到所添加到队列的元素 ...
- JUC源码分析-集合篇(一)ConcurrentHashMap
JUC源码分析-集合篇(一)ConcurrentHashMap 1. 概述 <HashMap 源码详细分析(JDK1.8)>:https://segmentfault.com/a/1190 ...
- JUC中的原子操作类及其原理
昨天简单的看了看Unsafe的使用,今天我们看看JUC中的原子类是怎么使用Unsafe的,以及分析一下其中的原理! 一.简单使用AtomicLong 还记的上一篇博客中我们使用了volatile关键字 ...
- ThreadLocalRandom ---- 提升Random在大并发下的效率
本博客系列是学习并发编程过程中的记录总结.由于文章比较多,写的时间也比较散,所以我整理了个目录贴(传送门),方便查阅. 并发编程系列博客传送门 随机数 随机数在科学研究与工程实际中有着极其重要的应用! ...
- JUC——检视阅读
JUC--检视阅读 参考资料 JUC知识图参考 JUC框架学习顺序参考 J.U.C学习总结参考,简洁直观 易百并发编程,实践操作1,不推荐阅读,不及格 JUC文章,带例子讲解,可以学习2 Doug L ...
随机推荐
- vs中python包安装教程
vs安装python很简单,只需要在vs安装包中选择python就可以了,这里使用的python3.7: 如果有了解,都知道安装python包的指令:"pip install xxx&quo ...
- Codeforces Round #589 (Div. 2) D. Complete Tripartite(模拟)
题意:给你n个点 和 m条边 问是否可以分成三个集合 使得任意两个集合之间的任意两个点都有边 思路:对于其中一个集合v1 我们考虑其中的点1 假设点u和1无边 那么我们可以得到 u一定和点1在一个集合 ...
- LaTeX 环境安装&编译器配置
推荐网站:https://www.latexstudio.net/articles/ (基本所有的latex疑惑都可以在这里得到解决) 入门视频:两小时短小精悍,让你轻松入门,https://www. ...
- Codeforces Global Round 12 D. Rating Compression (思维,双指针)
题意:给你一长度为\(n\)的数组,有一长度为\(k\ (1\le k \le n)\)的区间不断从左往右扫过这个数组,总共扫\(n\)次,每次扫的区间长度\(k=i\),在扫的过程中,每次取当前区间 ...
- hdu5534 Partial Tree
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others) Total Submissi ...
- Milk Patterns POJ - 3261 后缀数组
Farmer John has noticed that the quality of milk given by his cows varies from day to day. On furthe ...
- HDU-6608 Fansblog(威尔逊定理+素数间隔+逆元)
参考博客:https://blog.csdn.net/birdmanqin/article/details/97750844 题目链接:链接:http://acm.hdu.edu.cn/showpro ...
- poj 2566 Bound Found 尺取法
一.首先介绍一下什么叫尺取 过程大致分为四步: 1.初始化左右端点,即先找到一个满足条件的序列. 2.在满足条件的基础上不断扩大右端点. 3.如果第二步无法满足条件则到第四步,否则更新结果. 4.扩大 ...
- 在kubernetes集群里集成Apollo配置中心(6)之实战使用apollo分环境管理dubbo服务
生产实践 1.迭代新需求/修复BUG(编码--->提git) 2.测试环境发版,测试(应用通过编译打包发布至test命名空间) 3.测试通过,上线(应用镜像直接发布至prod命名空间) 系统架构 ...
- 数据库之postgreSQL入门操作指南
一.增 二.删 三.改 四.查 五.SQL操作表 1.增加列 ALTER TABLE table_name ADD column_name datatype; 2.删除一列 ALTER TABLE t ...