This is my first article on getting started

I met a ThreadLocal

Let’s start with a piece of code to get to know ThradLocal

The main program


package com.example.threadlocal_01.com.yang;
/** * static: creates a tl of ThreadLocal objects when the class is loaded and all objects are shared * thread 1: prints a Person object with set() * thread 2: To exclude the effect of thread execution speed, thread 1 sleeps for 1s and thread 2 sleeps for 2s */
public class ThreadLocalDemo01 {
    static ThreadLocal<Person> tl = new ThreadLocal<>();
    public static void main(String[] args) {
        / / thread
        new Thread(() -> {
            SleepHelper.sleep(1);
            tl.set(new Person("Zhang"));
            System.out.println(Thread.currentThread().getName() +":"+ tl.get());
        }).start();
        / / thread 2
        new Thread(() -> {
            SleepHelper.sleep(2);
            System.out.println(Thread.currentThread().getName() +":"+ tl.get()); }).start(); }}Copy the code

Related classes

  • SleepHelper
public class SleepHelper {
    public static void sleep(int seconds) {
        try {
            Thread.sleep(1000L * seconds);
        } catch(InterruptedException e) { e.printStackTrace(); }}}Copy the code
  • Person
@Data
@AllArgsConstructor
public class Person {
    String name;
}
Copy the code

Before executing the code, we can predict the output based on past experience, and look at the results with the answers to reinforce our impression.

  • The output
Thread-0:Person(name= name) Thread-1:null
Copy the code

The result is different from what I expected. I set the value in the shared TL object, but the second thread did not get it.

conclusion

Check data, ThreadLocal can be understood as a global variable, the current thread only applies to the current thread, so the tl in the thread a set value, thread two get less than, by definition appears to explain, but the tl must be a Shared object, which in turn and runs counter to common sense, with doubt, decided to have a look at the source.

Explore the ThreadLocal source code

The set () method

public void set(T value) {
    // Get the current thread
    Thread t = Thread.currentThread();
    // Get a ThreadLocalMap object by passing in the current thread object
    ThreadLocalMap map = getMap(t);
    // If the map is not empty, use this as the key,Person as the value, and set the map. If the map is empty, create one
    if(map ! =null)
        map.set(this, value);
    else
        createMap(t, value);
}
Copy the code

This here refers to the TL object that calls the set method

getMap(t)

ThreadLocalMap getMap(Thread t) {
        // Return the current thread's threadLocals
        return t.threadLocals;
}
Copy the code

threadLocals

// Member variables of the Thread object
ThreadLocal.ThreadLocalMap threadLocals = null;
Copy the code

get()

public T get(a) {
    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;
            returnresult; }}return setInitialValue();
}
Copy the code

getMap(t)

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

We know that any Thread object that has a member variable called threadLocals of type Map exists here, so no other Thread can get the value from its threadLocals.

Note items when using ThreadLocal

Memory leak: Memory is used up and cannot be released. Memory overflow: Memory is used up and finally, memory is not enough to overflow. A memory leak may cause a memory overflow

  • ThreadLocal usage can cause memory leaks

When a thread uses a ThreadLocal, if the thread is always present, the memory occupied by the map will never be released, resulting in a memory leak. If the thread is left untreated, the map will eventually cause a serious waste of resources and eventually lead to a memory overflow. So we should manually empty the map when using ThreadLocal so that the GC can discover and reclaim the memory.

remove()

public void remove(a) {
     ThreadLocalMap m = getMap(Thread.currentThread());
     if(m ! =null)
         m.remove(this);
 }
Copy the code

ThreadLocal is used in thread pools

  • A memory leak
  • Data inconsistency

When we talk about thread deathless, we naturally think of thread pools. When we use ThreadLocal in a thread pool, if we don’t remove() it, there is a memory leak. We know that the feature of thread pool is to create multiple threads at a time, and the thread is not destroyed and reused. Then, the value set in map is not cleared when I use it last time, and the next time I use other methods, I will directly get the value of the last time, and the data will be confused.

extension

The Entry object in ThreadLocalMap

Weak references: When found by GC, they are reclaimed

Entry

static class Entry extends WeakReference<ThreadLocal<? >>{
        /** The value associated with this ThreadLocal. */Object value; Entry(ThreadLocal<? > k, Object v) {super(k); value = v; }}Copy the code

We find that the Entry here inherits from a weak reference. Here’s an interesting thing that’s hard to say. Look at the picture

Why do we use a weak reference here? If we use a strong reference, even if the TL object is null, the key in the map still points to the ThreaLocal object, so it still causes a memory leak. Even if the ThreadLocal object is reclaimed, the key becomes null and the entire Value object is no longer accessible, so there will still be a memory leak, which is not the case with weak references.

In the last words

Finally, let’s talk about the process of writing this article. When I decided to write this topic, I also read a lot of big guy’s articles. In the process of writing, I was also very uneasy, afraid of making some stupid mistakes, and misled the friends who saw this article. Therefore, when writing, it is also very careful. In the process of writing, it will be found that a simple knowledge point is very simple to understand, but it seems not a simple thing to express it and let people understand it. On the road of learning, we still need to forge ahead. If there is any mistake, please correct the big guy!