• 多线程下使用随机数ThreadLocalRandom


    目录

    1.Random类在多线程下的缺陷

    2.ThreadLocalRandom解决Random的缺陷

    3.实际使用随机数遇到了一个问题


    1.Random类在多线程下的缺陷

        Random是我们使用随机数的常用的一个类,他的原理四是根据一个老的种子生成新的种子,再根据新的种子去生成随机数。 

    在多线程的环境下,根据老的种子获得新的种子可能是同一个,这样产生的随机数不就是一样的吗?这个可不允许,所以在Random中使用一个原子类达到多线程下也是随机数的效果。用CAS把老的种子替换为新的种子,这样做以后,在竞争比较激烈的环境下,会造成大量的线程自旋,消耗CPU,因为每次CAS操作只能有一个线程能成功。 

    2.ThreadLocalRandom解决Random的缺陷

         Random的缺陷的本质就是多个线程使用同一个种子变量,而ThreadLocalRandom每个线程都有自己单独的种子变量,实现方法和ThreadLocal类似。

      使用ThreadLocalRandom很简单,ThreadLocalRandom.current()就拿到实例。

      在current方法中会有一个实例化方法localInit()

    localInit里面会为每个线程设置一个随机数种子,把变量名为threadLocalRandomSeed,存于自己的线程栈中。

     

     多线程环境下,ThreadLocalRandom的实例只会产生一个,里面只包含与线程无关的通用算法,种子存于具体线程,所以他是线程安全的。

     所以ThreadLocalRandom不能多个线程共享一个实例,不然产生的随机数会相同。

       

    3.实际使用随机数遇到了一个问题

      sonar扫描到使用Random随机函数不安全, 推荐使用SecureRandom替换之, 当使用SecureRandom.getInstanceStrong()获取SecureRandom并调用next方式时, 在生产环境(linux)产生较长时间的阻塞。

       使用SecureRandom.getInstanceStrong()是通过读取/dev/random来获得随机数,但是会导致阻塞,如果使用new 的方式来获取实例的话,是linux下从/dev/urandom读取,不会阻塞。

      读取/dev/random会阻塞的原因,是因为/dev/random中的数据来自系统的扰动, 比如键盘输入, 鼠标点击, 等等, 当系统扰动很小时, 产生的随机数不够, 导致读取/dev/random的进程会阻塞等待. 

    我们写一个小测试来验证

    1. public class TestMain {
    2. private static Random random;
    3. static {
    4. try {
    5. random = SecureRandom.getInstanceStrong();
    6. } catch (Exception e) {
    7. e.printStackTrace();
    8. }
    9. }
    10. public static void main(String[] args) throws NoSuchAlgorithmException {
    11. System.out.println("start.....");
    12. long start = System.currentTimeMillis();
    13. SecureRandom random = SecureRandom.getInstanceStrong();
    14. for(int i = 0; i < 100; i++) {
    15. System.out.println("第" + i + "个随机数.");
    16. random.nextInt(10000);
    17. }
    18. System.out.println("finish...time/ms:" + (System.currentTimeMillis() - start));
    19. }
    20. }

    放到linux上运行就卡住了   

      

       启动阿尔沙斯  看到主线程是一个非守护线程,并且是在RUNNABLE的状态

    并且我们发现这个main线程一直都是运行状态,所以我们查看线程的详细信息

    然后就找到我们代码阻塞的地方:

  • 相关阅读:
    Linux系统编程 day03 Makefile、gdb、文件IO
    基于Fomantic UI Web构建 个人导航站点网站源码 网站技术导航源码
    Spring Cloud之API网关(Gateway)
    【数据库系统概论】实验三 SQL数据定义及更新
    E. Draw a triangle(计算几何+EXGCD)
    将matlab数据导入到Python中使用
    面试系列Redis:Redis持久化的方式
    SSM美众针纺有限公司人事管理毕业设计-附源码051708
    Day51——JavaScript事件绑定,jQuery类库
    【第一阶段:java基础】第5章:数组、排序、查找
  • 原文地址:https://blog.csdn.net/weixin_37650458/article/details/126514171