背景

前言

最近在写一些业务代码时遇到一个需要产生随机数的场景,这时自然想到 jdk 包里的 Random 类。但出于对性能的极致追求,就考虑使用 ThreadLocalRandom 类进行优化,在查看 ThreadLocalRandom 实现的过程中,又追了下 Unsafe 有部分代码,整个流程下来,学到了不少东西,也通过搜索和提问解决了很多疑惑,于是总结成本文。

Random 的性能问题

使用 Random 类时,为了避免重复创建的开销,我们一般将实例化好的 Random 对象设置为我们所使用服务对象的属性或静态属性,这在线程竞争不激烈的情况下没有问题,但在一个高并发的 web 服务内,使用同一个 Random 对象可能会导致线程阻塞。

Random 的随机原理是对一个”随机种子”进行固定的算术和位运算,得到随机结果,再使用这个结果作为下一次随机的种子。在解决线程安全问题时,Random 使用 CAS 更新下一次随机的种子 ,失败的线程则需要自旋重试 。可以想到,如果多个线程同时使用这个对象,就肯定会有一些线程执行 CAS 连续失败,进而导致线程阻塞。

ThreadLocalRandom

jdk 的开发者自然考虑到了这个问题,在 concurrent 包内添加了 ThreadLocalRandom 类,第一次看到这个类名,我以为它是通过 ThreadLocal 实现的,进而想到恐怖的内存泄漏问题,但点进源码却没有 ThreadLocal 的影子,而是存在着大量 Unsafe 相关的代码。

我们来看一下它的核心代码:

UNSAFE.putLong(t = Thread.currentThread(), SEED, r = UNSAFE.getLong(t, SEED) + GAMMA);

翻译成更直观的 Java 代码就像:

Thread t = Thread.currentThread();
long r = UNSAFE.getLong(t, SEED) + GAMMA;
UNSAFE.putLong(t, SEED, r);

看上去非常眼熟,像我们平常往 Map 里 get/set 一样,以 Thread.currentThread() 获取到的当前对象里 key,以 SEED 随机种子作为 value。

但是以对象作为 key 是可能会造成内存泄漏的啊,由于 Thread 对象可能会大量创建,在回收时不 remove Map 里的 value 时会导致 Map 越来越大,最后内存溢出。

示例代码 :

import java.util.concurrent.ThreadLocalRandom;public class ThreadLocalRandomDemo {public static void main(String[] args) {for (int i = 0; i < 10; i++) {new Player().start();}}private static class Player extends Thread {@Overridepublic void run() {System.out.println(getName() + ": " + ThreadLocalRandom.current().nextInt(100));}}
}

多线程下获取随机数的王者-ThreadLocalRandom相关推荐

  1. 干掉Random:这个类已经成为获取随机数的王者

    欢迎关注方志朋的博客,回复"666"获面试宝典 来源:zhenbianshu.github.io 背景 ThreadLocalRandom Unsafe 疑问 小结 背景 前言 最 ...

  2. 干掉 Random!它已经成为获取随机数的王者

    点击关注公众号,回复"1024"获取2TB学习资源! 前言 最近在写一些业务代码时遇到一个需要产生随机数的场景,这时自然想到 jdk 包里的 Random 类.但出于对性能的极致追 ...

  3. 【小家java】Java中Random ThreadLocalRandom 设置随机种子获取随机数精讲

    相关阅读 [小家java]java5新特性(简述十大新特性) 重要一跃 [小家java]java6新特性(简述十大新特性) 鸡肋升级 [小家java]java7新特性(简述八大新特性) 不温不火 [小 ...

  4. linux获取随机数脚本,Linux下对拍脚本与随机数生成器

    对拍脚本 新建一个文档 check.sh 作为对拍脚本. #!/bin/bash while(true)do #死循环 ./data > .in #运行数据生成器,将数据输出到1.in ./st ...

  5. Java获取随机数的实现方法

    在实际开发工作中经常需要用到随机数.如有些系统中创建用户后会给用户一个随机的初始化密码.这个密码由于是随机的,为此往往只有用户自己知道.他们获取了这个随机密码之后,需要马上去系统中更改.这就是利用随机 ...

  6. Linux下生成随机数与字符串

    日常生活中,会经常用到随机数,使用场景非常广泛,例如买彩票.丢骰子.抽签.年会抽奖等. Shell 下如何生成随机数呢,米扑博客特意写了本文,总结 Linux Shell 产生随机数的多种方法. 本文 ...

  7. java 多线程缓存_[Java教程]【JAVA并发编程实战】12、使用condition实现多线程下的有界缓存先进先出队列...

    [Java教程][JAVA并发编程实战]12.使用condition实现多线程下的有界缓存先进先出队列 0 2016-11-29 17:00:10 package cn.study.concurren ...

  8. 线程基础知识_线程生命周期_从JVM内存结构看多线程下的共享资源

    线程生命周期 线程状态 New: 线程创建(new Thread()) Runnable: 线程可运行(thread.start()), 注: 调用start并不一定是运行状态, 可能在等待CPU调度 ...

  9. java如何实取随机数_java - 如何在Kotlin中获取随机数?

    java - 如何在Kotlin中获取随机数? 可以在2个参数之间返回随机整数的通用方法,如ruby,可以使用rand(0..n). 有什么建议吗? 16个解决方案 208 votes 我的建议是In ...

最新文章

  1. 【C++】C/C++ 中default/delete特性
  2. 调整屏幕亮度,调整字体大小
  3. Python class 类中 __init__ 函数
  4. 机器学习:使用numpy实现数据增强(Data Augmentation)
  5. 【Python3】Tensorflow_Fasterrcnn训练自己数据集,Keras_Yolov3_GPU训练自己数据集
  6. swift5以上版本的代理的实现,详细教你书写代理
  7. windows 下架设svn服务器
  8. jQuery中的跨域问题
  9. druid链接mysql-proxy_MySQL读写分离之mysql-proxy
  10. xmlhttp的状态码收集
  11. c# 调用服务返回结果模板化
  12. 重写description方法
  13. 测绘——AutoCAD教育版打印戳去除
  14. 《现代操作系统(中文第三版)》课后习题——第六章 死锁
  15. Red Hat Enterprise Linux 8.0 安装(全网最详细版)
  16. 【微信小程序】(一)开发工具下载与界面介绍
  17. Java课程设计报告——学生成绩管理系统
  18. 光学中你遇到过哪些问题?
  19. VirtualBox 6.0.10
  20. 让curl支持IE代理

热门文章

  1. Cell:损伤和微生物模式的共同作用控制着根部的局部免疫反应
  2. MPB:中南大学刘学端、马丽媛组-基于16S测序和RT-qPCR的硫化矿物表面微生物群落组成分析...
  3. Microbiome:掠食性粘细菌通过调节土壤微生物群落来控制黄瓜枯萎病
  4. 这是入门生信,学习生信分析思路和数据可视化的首选?
  5. 植物微生物组培养与重组技术:从描述性研究走向功能性研究
  6. R语言可视化dataframe数据、并自定义设置坐标轴各个标签使用不同的色彩
  7. R语言使用integrate函数进行函数积分计算实战
  8. Pandas判断dataframe是否为空
  9. R语言dir函数获取目录中文件或者文件夹名称实战
  10. CRISP-DM (cross-industry standard process for data mining)跨行业数据挖掘过程标准