java.lang.Thread中新增的字段是什么?

java.lang.Thread中新增的字段是什么?,java,java-8,thread-local,Java,Java 8,Thread Local,在Java 8中,Java.lang.Threadclass获得了3个新字段: /** The current seed for a ThreadLocalRandom */ @sun.misc.Contended("tlr") long threadLocalRandomSeed; /** Probe hash value; nonzero if threadLocalRandomSeed initialized */ @sun.misc.Contended("tlr") int threa

在Java 8中,
Java.lang.Thread
class获得了3个新字段:

/** The current seed for a ThreadLocalRandom */
@sun.misc.Contended("tlr")
long threadLocalRandomSeed;

/** Probe hash value; nonzero if threadLocalRandomSeed initialized */
@sun.misc.Contended("tlr")
int threadLocalRandomProbe;

/** Secondary seed isolated from public ThreadLocalRandom sequence */
@sun.misc.Contended("tlr")
int threadLocalRandomSecondarySeed;
正如Javadoc中所说,它是由类
java.util.concurrent.ThreadLocalRandom
专门管理的

此外,在
ThreadLocalRandom
中,它们的使用方式非常怪异:

SEED = UNSAFE.objectFieldOffset
    (tk.getDeclaredField("threadLocalRandomSeed"));
PROBE = UNSAFE.objectFieldOffset
    (tk.getDeclaredField("threadLocalRandomProbe"));
SECONDARY = UNSAFE.objectFieldOffset
    (tk.getDeclaredField("threadLocalRandomSecondarySeed"));
(在
LockSupport
类中也可以满足相同的代码段)

然后这个偏移量在几个
java.concurrent
位置内部使用


这个主意是什么?为什么这些字段位于
java.lang.Thread
中?为什么不在
ThreadLocalRandom

内部?这些是内部字段。解释只能来自JDK开发人员自己。我从Doug Lea(日期为2013年1月)那里找到了一个关于这一点的文章,解释了这些字段背后的原理,以及它们为什么在
线程
类中

当我们引入
ThreadLocalRandom
时,我们保守地 将其实现为使用实际的
ThreadLocal
。然而, 随着它的应用越来越广泛,它值得改进 通过housing
ThreadLocalRandom
状态实现 (和相关簿记)在类
线程中
本身。 这将需要三个字段(总共16个字节)

因此,我建议在类线程中添加以下内容:

// The following three initially uninitialized fields are exclusively
// managed by class java.util.concurrent.ThreadLocalRandom.
/** The current seed for a ThreadLocalRandom */
long threadLocalRandomSeed;
/** Probe hash value; nonzero if threadLocalRandomSeed initialized */
int threadLocalRandomProbe;
/** Secondary seed isolated from public ThreadLocalRandom sequence */
int threadLocalRandomSecondarySeed;
这样做的原因是:

  • 统一更快地访问
    ThreadLocalRandom
    状态。虽然
    ThreadLocal
    访问通常已经相当快了,这是 不仅速度更快,而且在用户 程序创建大量的
    ThreadLocal
    s 可能(可能)导致任何给定的访问成为 慢一点

  • 使用
    ThreadLocalRandom
    的任何程序的总占用空间都更小。 三个字段所需的空间比装入填充字段所需的空间小
    ThreadLocal
    对象。随着
    ThreadLocalRandom
    的广泛使用 在JDK本身中,这包括几乎所有的程序

  • java.util.concurrent ForkJoinPool
    进一步节省时间/空间,
    ConcurrentHashMap
    LongAdder
    ConcurrentSkipList
    ,以及其他 可以使用这种形式的统一
    ThreadLocalRandom
    记账而不是自己的专用
    ThreadLocal
    s 就像他们现在做的那样


  • 我将通过添加一个小的答案来复活这个问题,因为我刚刚在LongAdder中找到了这个问题,有一个很棒的视频,Shipilev用简单的话解释了这一点(它是俄语的),下面是链接:

    对于ForkJoinPool的情况,它需要将任务放入队列并从队列中移除,通过良好的解决方案来解决该队列

    该prng必须非常快速且高度可扩展。好的,java有一个现成的:ThreadLocalRandom。为了将这些字段放入ThreadLocalRandom,它需要一个ThreadLocal,而ThreadLocal又在内部使用ThreadLocalMap(想想HashMap)


    ThreadLocal.get(想想HashMap#get)比直接从线程获取这些字段要慢得多。

    不知道这一点-我本来会/实际上已经对你之前关于
    “tlr”
    @luk2302的问题有了答案非常感谢你,但是有人否决了我的问题,所以我不得不删除它。对此我真的很抱歉。否决票不是删除问题或答案的理由,例如,我给了你一个向上的投票,使其为0分。非常感谢你的纸质链接,+1。但是这个解决方案看起来有点混乱,你不这么认为吗?另外,我也不太明白,为什么这些字段不能放在
    ThreadLocalRandom
    类中?@Andremoniy老实说,我无法判断JDK开发人员自己提出的技术解决方案。将它们添加到线程中的原因可能归结为Doug Lea的评论:“但主要是:用于“永久”的空间“线程局部变量需要放在某个地方;为什么不选择物流问题最少的地方呢?请注意,类java.lang.Thread只是系统上每个线程存储的冰山一角。因此,添加16个字节几乎是不可检测的。”@Andremoniy:如果这些字段是在
    ThreadLocalRandom
    中声明的,那么每个线程都需要一个不同的
    ThreadLocalRandom
    实例,这需要
    ThreadLocalRandom.current()
    使用
    ThreadLocal
    变量,该变量被认为效率不够。因此,
    ThreadLocalRandom.current()
    返回一个单例实例,这很便宜,但意味着它不能承载每个线程必须不同的字段。因此,在给定当前实现的情况下,这些字段存储在
    线程
    实例中。