1 结构分析 【java|Java并发编程—ThreadLocalRandom类】因为Random类在高并发情况下将造成多个线程竞争同一个原子类种子,所以为了提高高并发性能诞生了该类,即让每一个Thread都持有一个种子计算自己的随机数,ThreadLocalRandom类的类图如下:
文章图片
Thread类中和ThreadLocalRandom相关的字段
文章图片
2 主要方法分析 1 current()方法
该方法会获得ThreadLocal实例并且将会初始化线程中的Seed和Probe属性(这两个属性初始值都是0)
public static ThreadLocalRandom current() {
//利用unsafe来判断当前线程的Probe是否等于0,
//等于0则表示该线程是第一次调佣该方法,然后会接着调用localInit()方法进行初始化
if (UNSAFE.getInt(Thread.currentThread(), PROBE) == 0)
localInit();
//返回ThreadLocalRandom实例,该方法是静态方法,所有线程调用该方法返回的是同一个ThreadLocalRandom实例
return instance;
}
static final void localInit() {
//下面三行代码是用来初始化probe和seed
int p = probeGenerator.addAndGet(PROBE_INCREMENT);
int probe = (p == 0) ? 1 : p;
// skip 0
long seed = mix64(seeder.getAndAdd(SEEDER_INCREMENT));
//下面三行代码使用来设置当前线程的probe和seed,完成当前线程属性的初始化
Thread t = Thread.currentThread();
UNSAFE.putLong(t, SEED, seed);
UNSAFE.putInt(t, PROBE, probe);
}
2 nextInt(int bound)方法
该方法用来计算下一个随机数
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;
}
3 用法 在线程内部调用current()方法获得ThreadLocalRandom实例后再调用相应方法获得随机数,注意一定不要和用Random类一样在main线程创建实例后再在子线程中使用,因为仅仅在main线程中调用后只会初始化main线程的seed和probe,而子线程中由于没有进行初始化seed和probe的工作所以最后得到的随机数是一样的(原因可以看前述localInit()方法源,只初始化了当前线程的seed,没有调用current()方法的线程都是相同的默认初始值)
public static void main(String[] args) {
//创建线程1并启动
new Thread(() -> {
ThreadLocalRandom current = ThreadLocalRandom.current();
System.out.println(current.nextInt(10));
}).start();
//创建线程2并启动
new Thread(() -> {
ThreadLocalRandom current = ThreadLocalRandom.current();
System.out.println(current.nextInt(10));
}).start();
}
错误用法,两个线程不论执行多少次最后得到的随机数都是4
public static void main(String[] args) {
ThreadLocalRandom current = ThreadLocalRandom.current();
//创建线程1并启动
new Thread(() -> {
//ThreadLocalRandom current = ThreadLocalRandom.current();
System.out.println(current.nextInt(100));
//4
}).start();
//创建线程2并启动
new Thread(() -> {
//ThreadLocalRandom current = ThreadLocalRandom.current();
System.out.println(current.nextInt(100));
//4
}).start();
}
推荐阅读
- java|快速失败与安全失败
- Java知识点|Java判定相等---==和equals()和“compareTo()”
- GWAS|颜值即正义 | 只知道qqman而不知道cmplot是不专业的
- python|10 款最好的 Python IDE(十)
- flask|Flask学习_07_Cookie 与 Session
- python|Python入门
- python|10个最好用的Python开发工具(IDE)
- C++|【C++】类和对象(上篇)
- ITI 1121 体系计算