这个类是在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的更多相关文章

  1. JUC源码分析-其它工具类(一)ThreadLocalRandom

    JUC源码分析-其它工具类(一)ThreadLocalRandom ThreadLocalRandom 是 JDK7 在 JUC 包下新增的随机数生成器,它解决了 Random 在多线程下多个线程竞争 ...

  2. Random在高并发下的缺陷以及JUC对其的优化

    Random可以说是每个开发都知道,而且都用的很6的类,如果你说,你没有用过Random,也不知道Random是什么鬼,那么你也不会来到这个技术类型的社区,也看不到我的博客了.但并不是每个人都知道Ra ...

  3. Java并发编程笔记之ThreadLocalRandom源码分析

    JDK 并发包中 ThreadLocalRandom 类原理剖析,经常使用的随机数生成器 Random 类的原理是什么?及其局限性是什么?ThreadLocalRandom 是如何利用 ThreadL ...

  4. JUC包中的分而治之策略-为提高性能而生

    一.前言 本次分享我们来共同探讨JUC包中一些有意思的类,包含AtomicLong & LongAdder,ThreadLocalRandom原理. 二.AtomicLong & Lo ...

  5. ThreadLocalRandom原理

    原文链接:https://www.jianshu.com/p/9c2198586f9b 2.2. 并发包中ThreadLocalRandom类原理剖析 ThreadLocalRandom类是JDK7在 ...

  6. JUC源码分析-集合篇(十)LinkedTransferQueue

    JUC源码分析-集合篇(十)LinkedTransferQueue LinkedTransferQueue(LTQ) 相比 BlockingQueue 更进一步,生产者会一直阻塞直到所添加到队列的元素 ...

  7. JUC源码分析-集合篇(一)ConcurrentHashMap

    JUC源码分析-集合篇(一)ConcurrentHashMap 1. 概述 <HashMap 源码详细分析(JDK1.8)>:https://segmentfault.com/a/1190 ...

  8. JUC中的原子操作类及其原理

    昨天简单的看了看Unsafe的使用,今天我们看看JUC中的原子类是怎么使用Unsafe的,以及分析一下其中的原理! 一.简单使用AtomicLong 还记的上一篇博客中我们使用了volatile关键字 ...

  9. ThreadLocalRandom ---- 提升Random在大并发下的效率

    本博客系列是学习并发编程过程中的记录总结.由于文章比较多,写的时间也比较散,所以我整理了个目录贴(传送门),方便查阅. 并发编程系列博客传送门 随机数 随机数在科学研究与工程实际中有着极其重要的应用! ...

  10. JUC——检视阅读

    JUC--检视阅读 参考资料 JUC知识图参考 JUC框架学习顺序参考 J.U.C学习总结参考,简洁直观 易百并发编程,实践操作1,不推荐阅读,不及格 JUC文章,带例子讲解,可以学习2 Doug L ...

随机推荐

  1. 2020第十一届蓝桥杯第二场省赛C++A组【A-H】

    A. 门牌制作 答案 624 代码 #include <bits/stdc++.h> using namespace std; int main() { ios::sync_with_st ...

  2. HDU6504 Problem E. Split The Tree【dsu on tree】

    Problem E. Split The Tree Problem Description You are given a tree with n vertices, numbered from 1 ...

  3. BZOJ2882 工艺【SAM】 最小循环串

    BZOJ2882 工艺 给出一个串,要求其循环同构串中字典序最小的那个 串翻倍建\(SAM\)然后从起点开始贪心的跑\(n\)次即可 当然也能用最小表示法来做 #include<bits/std ...

  4. Codeforces 1355 C. Count Triangles

    传送门:C - Count Triangles  题意:给你四个数A,B,C,D,求有多少个三边为x,y,z (A ≤ x ≤ B ≤ y ≤ C ≤ z ≤ D)的三角形. 题解:枚举 x=A~B, ...

  5. HDU - 4300 Clairewd’s message (拓展kmp)

    HDU - 4300 题意:这个题目好难读懂,,先给你一个字母的转换表,然后给你一个字符串密文+明文,密文一定是全的,但明文不一定是全的,求最短的密文和解密后的明文: 题解:由于密文一定是全的,所以他 ...

  6. .net core面试题

    第1题,什么是ASP net core? 首先ASP net core不是 asp net的升级版本.它遵循了dot net的标准架构, 可以运行于多个操作系统上.它更快,更容易配置,更加模块化,可扩 ...

  7. Spring中AOP学习笔记

    AOP 描述(摘抄百度百科) AOP开发中的相关操作术语 实例(xml方式) 通知的类型 切入点表达式的写法: 实例(注解方式) 描述(摘抄百度百科) AOP(面向切面编程):Aspect Orien ...

  8. Nginx 动静分离概述

    目录 Nginx 动静分离是什么 Nginx 动静分离配置 Nginx 动静分离是什么 Nginx 动静分离,指的是静态资源请求由 Nginx 处理,动态资源请求由 php-fpm 处理或 tomca ...

  9. Automatic merge failed; fix conflicts and then commit the result.解决方法

    产生原因: git pull 的时候会分为两步,第一步先从远程服务器上拉下代码,第二步进行merge.当你merge时候失败了就会产生Automatic merge failed; fix confl ...

  10. mysql 索引类型以及创建

    明天就去面浦发了,感觉对数据库有些忘了,时间紧迫,就直接把链接贴这了,有空再整理. 参考: 1. https://www.cnblogs.com/crazylqy/p/7615388.html