Evolution of ThreadLocal -- inheritable ThreadLocal

Keywords: Java JDK github

Previously, we introduced ThreadLocal. Later, JDK made an upgrade version of InheritableThreadLocal for this purpose. Today, we will introduce it.
<!-- more -->

Why upgrade

First of all, let's think about it. Why upgrade? This is about the function of ThreadLocal.

We know that the original intention of ThreadLocal design is to have a copy for each thread in a multithreaded environment, which can solve the problem of multithreaded concurrent modification to a certain extent. However, we can make an extension on this basis, such as context. We can use ThreadLocal to have a context for each thread, which is generally written as ThreadLocal < context >, so that all the changes made on this thread can be used by everyone.

Now imagine that if we create a new sub thread, can this sub thread get the context of the parent thread? In theory, we hope to achieve such an effect. In fact? Let's look at:

public class ThreadLocalContext {

    private static ThreadLocal<Context> context = new ThreadLocal<>();

    static class Context {

        String name;

        int value;
    }

    public static void main(String[] args) {
        Context context = new Context();
        context.name = "mainName";
        context.value = 10;
        ThreadLocalContext.context.set(context);

        Thread childThread = new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        Context childContext = ThreadLocalContext.context.get();
                        System.out.println(childContext.name);
                        System.out.println(childContext.value);
                    }
                }
        );
        childThread.start();
    }
}

After running the main method, we can directly throw errors in the child thread, which is really in line with our expectation. But what should we do if we want to achieve the effect that the child thread can get the context of the parent thread?

The first thought is to pass the value in the parent thread ThreadLocal to the child thread when generating the child thread. Although this can achieve results, but the process is more complex, and the code intrusion is strong.

At this time, you can use InheritableThreadLocal.

What is InheritableThreadLocal

Look at source code

First let's look at its source code. Don't be afraid, it has few sources:

public class InheritableThreadLocal<T> extends ThreadLocal<T> {

    protected T childValue(T parentValue) {
        return parentValue;
    }

        ThreadLocalMap getMap(Thread t) {
       return t.inheritableThreadLocals;
    }

    void createMap(Thread t, T firstValue) {
        t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
    }
}

First, it inherits from ThreadLocal, so it is actually an extended version of ThreadLocal. Next, there are three methods. In fact, all three methods are available in ThreadLocal. Let's see:

    T childValue(T parentValue) {
        throw new UnsupportedOperationException();
    }

    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

Except that the childValue method throws exceptions in ThreadLocal, the other two methods are almost the same in both classes, only for different objects, but ThreadLocal and inheritablethreadlocal are ThreadLocal.ThreadLocalMap types, which was mentioned in the previous chapter, that is, a key is a weak reference Entry, which is not the point.

Let's take a look at when inheritablethreadlocations were initialized. From the source code, we can see:

    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc) {
                // Omit irrelevant code
                ...
                Thread parent = currentThread();
                ...
                // Omit irrelevant code
                ...
        if (parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
                ...
        }

When we generate a child Thread by calling the Thread's constructor from the parent Thread, its constructor will eventually call the init method. From here, we can see that inheritablethreadlocales are inheritablethreadlocales from the parent Thread, which explains why inheritablethreadlocales supports the use of variables stored in the parent Thread in the child Thread.

How to use

Let's go back to the context example mentioned above and use InheritableThreadLocal to transform it:

public class ThreadLocalContext {

    private static InheritableThreadLocal<Context> context = new InheritableThreadLocal<>();

    static class Context {

        String name;

        int value;
    }

    public static void main(String[] args) {
        Context context = new Context();
        context.name = "mainName";
        context.value = 10;
        ThreadLocalContext.context.set(context);

        Thread childThread = new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        Context childContext = ThreadLocalContext.context.get();
                        System.out.println(childContext.name);
                        System.out.println(childContext.value);
                    }
                }
        );
        childThread.start();
    }
}

After running, not only no exception is thrown, but also the value set by the parent thread is output in the child thread. everybody ' s happy!

summary

Today I shared inheritable ThreadLocal, mainly because I heard others talk about sharing in Ctrip's sharing meeting on Wednesday. The speaker talked about a more common problem. If we use thread pool to submit tasks, how can threads in the thread pool get the context of the thread submitting tasks when they are executing tasks? At this time, we need to use Alibaba's open source group TTL. I'll introduce it later.

It's been a month since joining Ctrip. Although I feel that there are many disadvantages in large companies, such as difficult communication, there are many advantages, such as technology sharing meeting. Although I'm also busy to participate in it, I have more opportunities to learn and communicate related to technology, which is also very good.

If you are interested, you can visit my blog or pay attention to my public numbers and headlines. There may be unexpected surprises.

https://death00.github.io/

Public number: the way to health

Posted by wyrd33 on Fri, 13 Dec 2019 09:03:14 -0800