【问题标题】:New additional fields in java.lang.Thread, what is the idea?java.lang.Thread 中的新附加字段,这是什么想法?
【发布时间】:2016-04-04 09:47:36
【问题描述】:

在 Java 8 中,java.lang.Thread 类有 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 里面?

【问题讨论】:

  • 不知道这个 - 我会/实际上已经回答了你之前关于"tlr"的问题。
  • @luk2302 很好的答案,非常感谢你,但有人反对我的问题,所以我必须删除它。我真的很抱歉。
  • 不赞成票不是删除问题或答案的理由,例如,我给了你一个赞成票,将其设为 0 分。

标签: java java-8 thread-local


【解决方案1】:

这些是内部字段。解释只能来自JDK开发者自己。我能够从 2013 年 1 月的 Doug Lea 那里找到一个关于此的 post,它解释了这些字段背后的基本原理以及为什么它们在 Thread 类中。

当我们介绍ThreadLocalRandom 时,我们保守地 实现它以使用实际的ThreadLocal。然而, 随着它的应用越来越广泛,值得改进 住房ThreadLocalRandom州实施 (和相关的簿记)在课堂Thread 本身。 这将需要三个字段(总共 16 个字节)。

所以我建议在 Thread 类中添加以下内容:

// 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;

这样做的原因是:

  1. 统一更快地访问ThreadLocalRandom 状态。尽管 ThreadLocal 访问通常已经相当快了,这是 不仅速度更快,而且在用户使用的情况下也不会降级 程序创建大量ThreadLocals,其中 可能(概率地)导致任何给定的访问权限变为 慢一点。

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

  3. java.util.concurrent ForkJoinPool 进一步节省时间/空间, ConcurrentHashMapLongAdderConcurrentSkipList 等 可以使用这种形式的统一ThreadLocalRandom 的类 记账而不是自己的专用ThreadLocals 就像他们现在所做的那样。

【讨论】:

  • 非常感谢您提供论文链接,+1。但是这个解决方案看起来有点乱,你不这么认为吗?
  • 另外,我不太明白,为什么这些字段不能放在ThreadLocalRandom类里面?
  • @Andremoniy 老实说,我无法判断 JDK 开发人员自己制定的技术解决方案。将它们添加到 Thread 的原因可能归结为 Doug Lea 的评论:“但主要是:‘永久’线程本地人的空间需要放置在某个地方;为什么不选择物流问题最少的地方?请注意, java.lang.Thread 类只是系统上每个线程存储的冰山一角。因此添加 16 字节几乎是无法察觉的。”
  • @Andremoniy:如果这些字段在ThreadLocalRandom 中声明,则每个线程需要一个不同的ThreadLocalRandom 实例,这需要ThreadLocalRandom.current() 使用ThreadLocal 变量,这被认为不是足够高效。因此,ThreadLocalRandom.current() 返回一个单例实例,这很便宜,但意味着它不能托管这些每个线程必须不同的字段。因此,这些字段存储在Thread 实例中鉴于当前实现
【解决方案2】:

我也将通过添加一个小答案来恢复它,因为我刚刚在 LongAdder 中点击了这个,并且有一个很棒的视频,Shipilev 用简单的语言解释了这个(它是俄语),这里是链接:ThreadLocalRandom

对于 ForkJoinPool 的情况,它需要将任务放入队列并从队列中移除,队列的具体问题通过 PRNG 解决。

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-13
    • 2012-05-15
    • 2021-08-30
    • 1970-01-01
    • 2012-03-13
    • 1970-01-01
    • 2016-04-22
    • 1970-01-01
    相关资源
    最近更新 更多