java.util.Random 源码解析

本文主要探讨了Java的Random类,详细解读了其源码,揭示了它如何实现线程安全,以及由于依赖原子类和CAS在多线程环境下的并发性能问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

java.util.Random的源码阅读

介绍

java.util.Random是Java的一个实用工具类库中的一个类,提供了产生各种类型随机数的方法

// 无参构造方法
public Random() {
    // 生成种子 seedUniquifier方法和System.nanoTime()时间进行 异或运算
    this(seedUniquifier() ^ System.nanoTime());
}

// 初始的种子
private static final AtomicLong seedUniquifier = new AtomicLong(8682522807148012L);
private static long seedUniquifier() {
    // 多线程可以会赋值失败,所以使用for循环
    for (;;) {
        // 当前预期值
        long current = seedUniquifier.get();
        // 要更新的值
        long next = current * 181783497276652981L;
        // 使用CAS操作更新seedUniquifier
        if (seedUniquifier.compareAndSet(current, next))
            return next;
    }
}

private final AtomicLong seed;
// 有参构造方法
public Random(long seed) {
    if (getClass() == Random.class)
        this.seed = new AtomicLong(initialScramble(seed));
    else {
        // 子类可以重写setSeed()方法 
        this.seed = new AtomicLong();
        setSeed(seed);
    }
}

private static final long multiplier = 0x5DEECE66DL;
private static final long mask = (1L << 48) - 1;

// 把用户设置的种子进行运算 返回long
private static long initialScramble(long seed) {
    return (seed ^ multiplier) & mask;
}

synchronized public void setSeed(long seed) {
    this.seed.set(initialScramble(seed));
    haveNextNextGaussian = false;
}

public int nextInt(int bound) {
    // 判断 bound
    if (bound <= 0)
        throw new IllegalArgumentException(BadBound);
    // 根据旧种子生成新种子
    int r = next(31);
    // 下面这些代码都是根据新种子计算随机数
    int m = bound - 1;
    if ((bound & m) == 0) 
        r = (int)((bound * (long)r) >> 31);
    else {
        for (int u = r;
            u - (r = u % bound) + m < 0;
            u = next(31))
            ;
    }
    return r;
}

protected int next(int bits) {
    long oldseed, nextseed;
    AtomicLong seed = this.seed;
    do {
        // 获取旧种子
        oldseed = seed.get();
        // 用旧种子去生成新种子
        nextseed = (oldseed * multiplier + addend) & mask;
    // 使用CAS,多线程下只能有一个线程更新为新种子,
    // 其他线程只能通过循环重新获取更新后的种子作为当前种子去计算新的种子
    } while (!seed.compareAndSet(oldseed, nextseed));
    return (int)(nextseed >>> (48 - bits));
}

结论:Random的实例是线程安全的,内部使用了原子类和CAS确保多线程下安全,但由于原子变量的更新是CAS操作,同时只有一个线程成功,造成了大量线程进行自旋重试操作,从而降低了并发性能

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值