Java并发之ThreadLocalRandom 的一些个人理解

Random

1.首先我们知道其父类是Random,对其父类Random有所了解。

对于父类,要明白以下几点:

Random() 和 Random(long seed)的区别,详细一查一大堆。。。我就不解释了。
Random这个最大的缺点就是CAS操作那个while do那,导致多线程时候性能低。
如果你还不懂CAS的话,下面的你看了也不会很明白,先去看看CAS。

2.ThreadLocalRandom在Random的基础上增加了

seeder
// 线程共享且线程安全的seeder。
private static final AtomicLong seeder = new AtomicLong(initialSeed()); 

seeder 会在每个线程中localInit方法调用的时候起一次作用。(调用则真随机,不调用则伪随机,调用的作用就是为所在的线程生成初始的seed,如果不调用则每个线程的初始seed都是0)

instance
// 单例模式
static final ThreadLocalRandom instance = new ThreadLocalRandom(); 
// 
public static ThreadLocalRandom current() {
    if (UNSAFE.getInt(Thread.currentThread(), PROBE) ==0) 
        localInit(); // 在当前线程中首次被调用current方法会执行。
    return instance;
}

// 这个方法调用不调用,直接决定了各线程是伪随机还是真随机。
// 调用了这个方法,seeder 是线程共享且安全,那么seed这个值就会每次不一样,导致了往各自线程里放的初始
// seed值不一样。
// 这个方法如果不调用,那么每个线程的都是同样的默认值threadLocalRandomSeed=0来设定的。
// 因为localInit是通过current方法调用的,所以我们要根据自己的需求是真随机还是伪随机,
// 真随机我们需要在线程内部调用current方法。伪随机则不需要。
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);
}
// UNSAFE这个对象,并不是操作引用来改变对象属性值的,他是直接改变内存的值的。
// SEED 是 Thread 对象的 threadLocalRandomSeed 属性的偏移量。
// r = UNSAFE.getLong(t, SEED) 获取t对象的SEED偏移量位置的属性值,即threadLocalRandomSeed
// UNSAFE.putLong(t,SEED,。。。)是更新t对象SEED偏移量位置的属性值。
// 可以看出nextSeed方法得到seed值是当前线程的属性threadLocalRandomSeed
// 的值并将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;
}

3.对于UNSAFE这个东西,网上的资料还是满多的,如果对UNSAFE和偏移量这个东西不是很理解的话,说明JVM内存模型这块你还是了解不够深。
这个人写的文章真不错,不像有些人真是不要脸一顿copy。
https://copyfuture.com/blogs-details/20200409102211143qa237su8ankwcm0
虚拟机栈

引用
偏移量 https://www.jianshu.com/p/92c1fe803a22 这个入口有我认为讲的不错的。
文章中也有错误,不如jvm的对象倍数肯定不是8bit,而是8byte。不用了解太深。看了这个文章再回来看我写的东西,再看看Thread 里面的源代码最后几行的threadLocalRandomSeed。ThreadLocalRandom 这个类我看下来绕了好几个圈才明白。
比如SEED是什么 seeder又是什么。UNSAFE的putLong 和getLong又是什么。

因为喜欢,所以才有动力。
by大龄程序员,29岁转行,今年33。
附上一些测试case。https://github.com/simple321vip/g_estate/tree/master/src/main/java/com/g/estate/school
喜欢我的文章,给我点一个赞,让我知道我也帮助过其他的人。(大神也不需要看我的文章)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容