返回顶部
首页 > 资讯 > 后端开发 > Python >java并发高的情况下用ThreadLocalRandom来生成随机数
  • 704
分享到

java并发高的情况下用ThreadLocalRandom来生成随机数

2024-04-02 19:04:59 704人浏览 独家记忆

Python 官方文档:入门教程 => 点击学习

摘要

目录一:简述二:Random的性能差在哪里三:ThreadLocalRandom的简单使用四:为什么ThreadLocalRandom能在保证线程安全的情况下还能有不错的性能一:简述

一:简述

如果我们想要生成一个随机数,通常会使用Random类。但是在并发情况下Random生成随机数的性能并不是很理想,今天给大家介绍一下JUC包中的用于生成随机数的类--ThreadLocalRandom.(本文基于jdk1.8)

二:Random的性能差在哪里

Random随机数生成是和种子seed有关,而为了保证线程安全性,Random通过CAS机制来保证线程安全性。从next()方法中我们可以发现seed是通过自旋和CAS来进行修改值的。如果在高并发的场景下,那么可能会导致CAS不断失败,从而导致不断自旋,这样就可能会导致服务器CPU过高。

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));
    }

三:ThreadLocalRandom的简单使用

使用的方法很简单,通过ThreadLocalRandom.current()获取到ThreadLocalRandom实例,然后通过nextInt(),nextLong()等方法获取一个随机数。

代码:

    @Test
    void test() throws InterruptedException {
        new Thread(()->{
            ThreadLocalRandom random = ThreadLocalRandom.current();
            System.out.println(random.nextInt(100));
        }).start();
        new Thread(()->{
            ThreadLocalRandom random = ThreadLocalRandom.current();
            System.out.println(random.nextInt(100));
        }).start();

        Thread.sleep(100);
    }

运行结果:

四:为什么ThreadLocalRandom能在保证线程安全的情况下还能有不错的性能

我们可以看一下ThreadLocalRandom的代码实现。

首先我们很容易看出这是一个饿汉式的单例

    
    private ThreadLocalRandom() {
        initialized = true; // false during super() call
    }

    
    static final ThreadLocalRandom instance = new ThreadLocalRandom();

我们可以看到PROBE成员变量代表的是Thread类的threadLocalRandomProbe属性的内存偏移量,SEED成员变量代表的是Thread类的threadLocalRandomSeed属性的内存偏移量,SECONDARY成员变量代表的是Thread类的threadLocalRandomSecondarySeed属性的内存偏移量。

// Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE;
private static final long SEED;
private static final long PROBE;
private static final long SECONDARY;
static {
    try {
        UNSAFE = sun.misc.Unsafe.getUnsafe();
        Class<?> tk = Thread.class;
        SEED = UNSAFE.objectFieldOffset
            (tk.getDeclaredField("threadLocalRandomSeed"));
        PROBE = UNSAFE.objectFieldOffset
            (tk.getDeclaredField("threadLocalRandomProbe"));
        SECONDARY = UNSAFE.objectFieldOffset
            (tk.getDeclaredField("threadLocalRandomSecondarySeed"));
    } catch (Exception e) {
        throw new Error(e);
    }
}

可以看到Thread类中确实有这三个属性

Thread类:

    @sun.misc.Contended("tlr")
    //当前Thread的随机种子 默认值是0
    long threadLocalRandomSeed;

    
    @sun.misc.Contended("tlr")
    //用来标志当前Thread的threadLocalRandomSeed是否进行了初始化 0代表没有,非0代表已经初始化 默认值是0
    int threadLocalRandomProbe;

    
    @sun.misc.Contended("tlr")
    //当前Thread的二级随机种子 默认值是0
    int threadLocalRandomSecondarySeed;

接下来我们看ThreadLocalRandom.current()方法。

ThreadLocalRandom.current()

ThreadLocalRandom.current()的作用主要是初始化随机种子,并且返回ThreadLocalRandom的实例。

首先通过UNSAFE类获取当前线程的Thread对象的threadLocalRandomProbe属性,看随机种子是否已经初始化。没有初始化,那么调用localInit()方法进行初始化

public static ThreadLocalRandom current() {
        // 获取当前线程的
        if (UNSAFE.getInt(Thread.currentThread(), PROBE) == 0)
            localInit();
        return instance;
    }

localInit()

localInit()方法的作用就是初始化随机种子,可以看到代码很简单,就是通过UNSAFE类对当前Thread的threadLocalRandomProbe属性和threadLocalRandomSeed属性进行一个赋值。

static final void localInit() {
        int p = probeGenerator.addAndGet(PROBE_INCREMENT);
        int probe = (p == 0) ? 1 : p; // skip 0
        long seed = mix64(seeder.getAndAdd(SEEDER_INCREMENT));
        Thread t = Thread.currentThread();
        UNSAFE.putLong(t, SEED, seed);
        UNSAFE.putInt(t, PROBE, probe);
    }

接下来以nextInt()方法为例,看ThreadLocalRandom是如何生成到随机数的。我们可以看出随机数正是通过nextSeed()方法获取到随机种子,然后通过随机种子而生成。所以重点看nextSeed()方法是如何获取到随机种子的。

public int nextInt(int bound) {
        if (bound <= 0)
            throw new IllegalArgumentException(BadBound);
        int r = mix32(nextSeed());
        int m = bound - 1;
        if ((bound & m) == 0) // power of two
            r &= m;
        else { // reject over-represented candidates
            for (int u = r >>> 1;
                 u + m - (r = u % bound) < 0;
                 u = mix32(nextSeed()) >>> 1)
                ;
        }
        return r;
    }

nextSeed()

nextSeed()方法的作用是获取随机种子,代码很简单,就是通过UNSAFE类获取当前线程的threadLocalRandomSeed属性,并且将原来的threadLocalRandomSeed加上GAMMA设置成新的threadLocalRandomSeed。

final long nextSeed() {
        Thread t; long r; // read and update per-thread seed
        UNSAFE.putLong(t = Thread.currentThread(), SEED,
                       r = UNSAFE.getLong(t, SEED) + GAMMA);
        return r;
    }

小结:

ThreadLocalRandom为什么线程安全?是因为它将随机种子保存在当前Thread对象的threadLocalRandomSeed变量中,这样每个线程都有自己的随机种子,实现了线程级别的隔离,所以ThreadLocalRandom也并不需要像Random通过自旋锁和cas来保证随机种子的线程安全性。在高并发的场景下,效率也会相对较高。

注:各位有没有发现ThreadLocalRandom保证线程安全的方式和ThreadLocal有点像呢

需要注意的点:

1.ThreadLocalRandom是单例的。

2.我们每个线程在获取随机数之前都需要调用一下ThreadLocalRandom.current()来初始化当前线程的随机种子。

3.理解ThreadLocalRandom需要对UnSafe类有所了解,它是Java提供的一个可以直接通过内存对变量进行获取和修改的一个工具类。java的CAS也是通过这个工具类来实现的。

到此这篇关于java并发高的情况下用ThreadLocalRandom来生成随机数的文章就介绍到这了,更多相关java ThreadLocalRandom生成随机数内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: java并发高的情况下用ThreadLocalRandom来生成随机数

本文链接: https://lsjlt.com/news/148818.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • java并发高的情况下用ThreadLocalRandom来生成随机数
    目录一:简述二:Random的性能差在哪里三:ThreadLocalRandom的简单使用四:为什么ThreadLocalRandom能在保证线程安全的情况下还能有不错的性能一:简述...
    99+
    2024-04-02
  • java高并发情况下高效的随机数生成器
    前言 在代码中生成随机数,是一个非常常用的功能,并且JDK已经提供了一个现成的Random类来实现它,并且Random类是线程安全的。 下面是Random.next()生成一个随机整...
    99+
    2024-04-02
  • 高并发情况下Linux系统及kernel参数的优化方法
    这篇文章主要讲解了“高并发情况下Linux系统及kernel参数的优化方法”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“高并发情况下Linux系统及kernel参数的优化方法”吧!众所周知在...
    99+
    2023-06-15
  • Java 17 随机数生成器来了一波稳稳的增强
    目录Java 17 更新更快的 LTS 节奏 Java 17 更新后的 strictfp 关键字 这一条更新来自: JEP 356: Enhanced Pseudo-Random N...
    99+
    2024-04-02
  • 使用java怎么生成不同的随机数
    这期内容当中小编将会给大家带来有关使用java怎么生成不同的随机数,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。Java可以用来干什么Java主要应用于:1. web开发;2. Android开发;3. ...
    99+
    2023-06-14
  • JAVA 生成随机数并根据后台概率灵活生成的实例代码
    最近碰到一个大转盘的业务,奖品可根据数据后台灵活设置中奖概率,看起来挺简单的业务功能,但实现起来对我这个毫无经验的人来说并不容易,后面又碰到一个根据后台概率随机获取不同概率的档位积分,前面是两个实际中业务要用到的话不多说吧,直接上我写概率工...
    99+
    2023-05-31
    java 概率 随机数
  • 利用Java实现生成随机数的方法有哪些
    利用Java实现生成随机数的方法有哪些?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。通过System.currentTimeMillis()来获取一个当前时间毫秒数的long型...
    99+
    2023-05-31
    java 随机数生成 ava
  • 使用java在生成一个指定范围的随机整数
    使用java在生成一个指定范围的随机整数?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。Java是什么Java是一门面向对象编程语言,可以编写桌面应用程序、Web...
    99+
    2023-06-14
  • 用Java生成N个不重复的随机数,3种实例
    1、Random类和Set集合来完成 Java实现生成n个不重复的随机数可以使用Java中的Random类和Set集合来完成 具体代码如下: import java.util.HashSet;import java.util.Rand...
    99+
    2023-08-19
    java 算法 数据结构
  • 使用java怎么实现每次生成不重复的随机数
    使用java怎么实现每次生成不重复的随机数?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。Java可以用来干什么Java主要应用于:1. web开发;2. Android开发;3...
    99+
    2023-06-14
  • Java中如何使用缓存来提高数组的并发性能?
    在Java中,数组是一种常用的数据结构,它在很多场景下都被广泛使用。然而,在多线程并发的情况下,数组的性能可能会受到很大的影响,因为多个线程同时对同一个数组进行读写操作时,可能会发生数据竞争,导致数据错误或性能下降。为了解决这个问题,我们...
    99+
    2023-07-07
    缓存 数组 并发
  • java不同版本在多线程中使用随机数生成器的实现
    目录如何在多线程中使用随机数生成器(Random)Random 是通过 seed 进行同步的吗ThreadLocalRandom 生成随机数的示例如何在多线程中使用随机数生成器(Ra...
    99+
    2023-05-15
    java 随机数生成器 java多线程随机数生成
  • java web在高并发和分布式下实现订单号生成唯一的解决方案
    方案一:如果没有并发,订单号只在一个线程内产生,那么由于程序是顺序执行的,不同订单的生成时间戳正常不同,因此用时间戳+随机数(或自增数)就可以区分各个订单。如果存在并发,且订单号是由一个进程中的多个线程产生的,那么只要把线程ID添加到序列号...
    99+
    2023-05-30
    java web 高并发
  • Linux下的高并发环境:如何使用函数来处理ASP应用程序?
    随着互联网的发展,越来越多的网站需要处理高并发的访问量。而Linux作为一个稳定、高效的操作系统,被广泛应用于高并发环境中。本文将介绍如何使用函数来处理ASP应用程序,以提高网站的并发能力。 ASP是一种常用的Web应用程序开发技术,它使...
    99+
    2023-06-26
    并发 linux 函数
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作