Java的ThreadLocal是如何在幕后实现的? [英] How is Java's ThreadLocal implemented under the hood?

查看:137
本文介绍了Java的ThreadLocal是如何在幕后实现的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何实施ThreadLocal?它是用Java实现的(使用从ThreadID到对象的一些并发映射),还是使用一些JVM钩子来更有效地执行它?

How is ThreadLocal implemented? Is it implemented in Java (using some concurrent map from ThreadID to object), or does it use some JVM hook to do it more efficiently?

推荐答案

这里的所有答案都是正确的,但有点令人失望,因为他们在某种程度上掩盖了聪明的 ThreadLocal 的实现方式。我只是看着 ThreadLocal 的源代码,并对它的实现方式印象深刻。

All of the answers here are correct, but a little disappointing as they somewhat gloss over how clever ThreadLocal's implementation is. I was just looking at the source code for ThreadLocal and was pleasantly impressed by how it's implemented.

朴素的实施

如果我要求您实施 ThreadLocal< T> 类给定在javadoc中描述的API,你会怎么做?初始实现可能是 ConcurrentHashMap< Thread,T> 使用 Thread.currentThread()作为其键。这将相当不错,但确实有一些缺点。

If I asked you to implement a ThreadLocal<T> class given the API described in the javadoc, what would you do? An initial implementation would likely be a ConcurrentHashMap<Thread,T> using Thread.currentThread() as its key. This will would work reasonably well but does have some disadvantages.


  • 线程争用 - ConcurrentHashMap 是一个非常聪明的类,但它最终还是必须处理防止多线程以任何方式破坏它,如果不同的线程经常点击它,会有减速。

  • 永久保持指向Thread和对象的指针,即使在Thread完成后也可以GC.ed。

  • Thread contention - ConcurrentHashMap is a pretty smart class, but it ultimately still has to deal with preventing multiple threads from mucking with it in any way, and if different threads hit it regularly, there will be slowdowns.
  • Permanently keeps a pointer to both the Thread and the object, even after the Thread has finished and could be GC'ed.

GC友好的实现

好的再试一次,让我们使用弱引用。处理WeakReferences可能会令人困惑,但使用如此构建的映射应该足够了:

Ok try again, lets deal with the garbage collection issue by using weak references. Dealing with WeakReferences can be confusing, but it should be sufficient to use a map built like so:

 Collections.synchronizedMap(new WeakHashMap<Thread, T>())

或者如果我们使用番石榴(我们应该!):

Or if we're using Guava (and we should be!):

new MapMaker().weakKeys().makeMap()

这意味着一旦没有其他人持有线程(暗示它已经完成),键/值可以被垃圾收集,这是一个改进,但仍然没有解决线程争用问题,意味着到目前为止我们的 ThreadLocal 并不是一个令人惊奇的类。此外,如果某人决定在完成后持有 Thread 对象,他们将永远不会被GC,因此我们的对象也不会,即使它们是现在技术上无法到达。

This means once no one else is holding onto the Thread (implying it's finished) the key/value can be garbage collected, which is an improvement, but still doesn't address the thread contention issue, meaning so far our ThreadLocal isn't all that amazing of a class. Furthermore, if someone decided to hold onto Thread objects after they'd finished, they'd never be GC'ed, and therefore neither would our objects, even though they're technically unreachable now.

聪明的实施

我们一直在考虑 ThreadLocal 作为线程到值的映射,但实际上这可能不是考虑它的正确方法。如果我们将它视为ThreadLocal对象到每个Thread 中的值的映射,而不是将其视为从Threads到每个ThreadLocal对象中的值的映射?如果每个线程都存储了映射,并且ThreadLocal只是为该映射提供了一个很好的接口,我们可以避免以前实现的所有问题。

We've been thinking about ThreadLocal as a mapping of threads to values, but maybe that's not actually the right way to think about it. Instead of thinking of it as a mapping from Threads to values in each ThreadLocal object, what if we thought about it as a mapping of ThreadLocal objects to values in each Thread? If each thread stores the mapping, and ThreadLocal merely provides a nice interface into that mapping, we can avoid all of the issues of the previous implementations.

一个实现会看起来像什么像这样:

An implementation would look something like this:

// called for each thread, and updated by the ThreadLocal instance
new WeakHashMap<ThreadLocal,T>()

这里没有必要担心并发性,因为只有一个线程会访问这个map。

There's no need to worry about concurrency here, because only one thread will ever be accessing this map.

Java开发人员在这方面比我们有一个主要优势 - 他们可以直接开发Thread类并为其添加字段和操作,这正是他们所做的。完成。

The Java devs have a major advantage over us here - they can directly develop the Thread class and add fields and operations to it, and that's exactly what they've done.

java.lang.Thread 有以下几行:

In java.lang.Thread there's the following lines:


/* ThreadLocal values pertaining to this thread. This map is maintained
 * by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;


评论建议的确是一个包私有映射所有值都由 ThreadLocal 跟踪此线程的对象。 ThreadLocalMap 的实现不是 WeakHashMap ,但它遵循相同的基本合同,包括通过弱引用保持其键。

Which as the comment suggests is indeed a package-private mapping of all values being tracked by ThreadLocal objects for this Thread. The implementation of ThreadLocalMap is not a WeakHashMap, but it follows the same basic contract, including holding its keys by weak reference.

ThreadLocal.get()然后实现如下:


public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    return setInitialValue();
}


ThreadLocal .setInitialValue()如下:


private T setInitialValue() {
    T value = initialValue();
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
    return value;
}


基本上,使用地图在此线程中保存所有 ThreadLocal 对象。这样,我们永远不必担心其他线程中的值( ThreadLocal 字面上只能访问当前线程中的值),因此没有并发问题。此外,一旦 Thread 完成,其地图将自动进行GC,并清除所有本地对象。即使保留 Thread ThreadLocal 对象也会被弱引用保留,并且可以尽快清理因为 ThreadLocal 对象超出范围。

Essentially, use a map in this Thread to hold all our ThreadLocal objects. This way, we never need to worry about the values in other Threads (ThreadLocal literally can only access the values in the current Thread) and therefore have no concurrency issues. Furthermore, once the Thread is done, its map will automatically be GC'ed and all the local objects will be cleaned up. Even if the Thread is held onto, the ThreadLocal objects are held by weak reference, and can be cleaned up as soon as the ThreadLocal object goes out of scope.

不用比如,我对这个实现印象深刻,它非常优雅地解决了很多并发问题(诚然通过利用成为核心Java的一部分,但是因为它是如此聪明的类而可以原谅它们)并允许快速和线程 - 安全访问只需要一次一个线程访问的对象。

Needless to say, I was rather impressed by this implementation, it quite elegantly gets around a lot of concurrency issues (admittedly by taking advantage of being part of core Java, but that's forgivable them since it's such a clever class) and allows for fast and thread-safe access to objects that only need to be accessed by one thread at a time.

tl; dr ThreadLocal 的实施非常酷,比你第一眼看到的更快/更聪明。

tl;dr ThreadLocal's implementation is pretty cool, and much faster/smarter than you might think at first glance.

如果你喜欢这个答案,你可能也会欣赏我的(不太详细)讨论 ThreadLocalRandom

If you liked this answer you might also appreciate my (less detailed) discussion of ThreadLocalRandom.

线程 / ThreadLo cal Oracle / OpenJDK's获取的代码片段实施Java 8

Thread/ThreadLocal code snippets taken from Oracle/OpenJDK's implementation of Java 8.

这篇关于Java的ThreadLocal是如何在幕后实现的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆