ThreadLocal question in java interview

What is ThreadLocal and what is its basic usage 

Simply put, it is a thread object that can keep variables independent in multithreading

Problems that occur when accessing the same variable without Threadlocal multithreading

package com.pxx;

/**
 * Created by Administrator on 2023/9/3.
 */
public class Demo1 {
    private String v1;

    public String getV1() {
        return v1;
    }

    public void setV1(String v1) {
        this.v1 = v1;
    }

    public static void main(String[] args) {
        //开启一个多线程去设置并且访问这个变量

        Demo1 d1 = new Demo1();
        //这里会循环五个线程
        for(int i = 0;i < 5;i++) {
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    //设置并且打印一个变量的数据
                    d1.setV1("data:" + Thread.currentThread().getName());
                    System.out.println("-------------");
                    //取出这个线程对应的名字和值
                    System.out.println(Thread.currentThread().getName() + "=>" + d1.getV1());
                }
            });

            //设置一下每一个线程的名字
            t1.setName("线程" + i);
            t1.start();//开启直接进入到运行状态,然后当前线程开始运行,然后进行下一次循环,下一个线程进来,这个时候进程可能会仙湖干扰
        }

    }
}

The following thread has been directly confused 

 Generally speaking, we can use locks to solve it, such as introducing synchronized, here we don’t need locks first, we use ThreadLocal to solve it

ThreadLocal class to solve the problem of unsynchronized threads

Its purpose is to keep variables independent of

Let's take a look at the common methods

set(): bind the variable to the current thread

get(): Get the variables bound by the current thread

Modify the code above

package com.pxx;

/**
 * Created by Administrator on 2023/9/3.
 */
public class Demo1 {
    //引入绑定变量的线程对象
    ThreadLocal<String>  tl1= new ThreadLocal();

    private String v1;

    public String getV1() {
       // return v1;
        return tl1.get();//得到通过set绑定的变量
    }

    public void setV1(String v1) {
        //this.v1 = v1;
        tl1.set(v1);//直接把这个v1绑定到对象里面
    }

    public static void main(String[] args) {

        Demo1 d1 = new Demo1();
        //这里会循环五个线程
        for(int i = 0;i < 5;i++) {
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    //设置并且打印一个变量的数据
                    d1.setV1("data:" + Thread.currentThread().getName());
                    System.out.println("-------------");
                    //取出这个线程对应的名字和值
                    System.out.println(Thread.currentThread().getName() + "=>" + d1.getV1());
                }
            });

            //设置一下每一个线程的名字
            t1.setName("线程" + i);
            t1.start();//开启直接进入到运行状态,然后当前线程开始运行,然后进行下一次循环,下一个线程进来,这个时候进程可能会仙湖干扰
        }
    }
}

operation result:

 The difference between ThreadLocal and synchronized

First turn the above code into synchronized and lock it

package com.pxx;

/**
 * Created by Administrator on 2023/9/3.
 */
public class Demo3 {
    //引入绑定变量的线程对象
    ThreadLocal<String>  tl1 = new ThreadLocal();

    private String v1;

    public String getV1() {
        return v1;
    }

    public void setV1(String v1) {
        this.v1 = v1;
    }

    public static void main(String[] args) {

        Demo3 d1 = new Demo3();
        //这里会循环五个线程
        for(int i = 0;i < 5;i++) {
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (d1) {//这个加锁了
                        //设置并且打印一个变量的数据
                        d1.setV1("data:" + Thread.currentThread().getName());
                        System.out.println("-------------");
                        //取出这个线程对应的名字和值
                        System.out.println(Thread.currentThread().getName() + "=>" + d1.getV1());
                    }
                }
            });

            //设置一下每一个线程的名字
            t1.setName("线程" + i);
            t1.start();//开启直接进入到运行状态,然后当前线程开始运行,然后进行下一次循环,下一个线程进来,这个时候进程可能会仙湖干扰
        }
    }

}

operation result:

obviously locked

Let’s talk about what they have in common: they both deal with the problem of concurrent access to variables by multiple threads.

Synchronized: Its efficiency will be lower, because it is equivalent to saying that threads are queued for access, just like there is only one toilet in a classroom, and everyone has to go in and queue up

ThreadLocal: High efficiency, which means that threads can be accessed concurrently at the same time, high efficiency, like multiple toilets in a classroom, on each other, but independent of each other

Internal structure of ThreadLocal

One of the earliest design principles

 The design principle of JDK8

Pay attention to JDK8, which regards each thread of Thread as a main thread, and then Stores a thread object such as ThreadLocal in Entry

Such a design scheme has two advantages:

1. The number of entries stored in each map is reduced, because in other words, Thread threads must be more than ThreadLocal threads.

2. Then the main thread Thread is destroyed, and the map data object inside is also destroyed

I analyze the source code

First look at the set method

Let's take a look at the ThreadLocalMap class again 

 

set is added to the map object

This does not explain a problem: it solves the problem of thread concurrent access and variable error

Quite what, go to the toilet by yourself, independent of each other without affecting each other

 May cause a memory leak problem

He sees it in two cases:

The first type: the memory is not enough, only overflow memory overflow

The second type: memory leak memory leak, the space on the heap cannot be released, which will cause waste and affect the running speed of the program. If this waste is too much, it will cause memory overflow 

Here we introduce two more concepts

The first one: what is a strong reference? When we normally refer to an object, when there is no point to it, it will be dropped by gc, that is, the garbage collector will recycle it

The second: what is a weak reference? In a word, when encountering GC, it will be recycled. As long as the garbage collection mechanism runs, the memory occupied by the object will be reclaimed regardless of whether the memory space of the jvm is sufficient or not.

The following diagram shows the reference relationship

If the key is a strong reference

Suppose the ThreadLocal is used up and the reference is withdrawn, and because the ThreadLocal in the Map is a strong reference, the ThreadLocal object cannot be recycled

If the Entry class is not manually removed and the CurrentThread is still running, the Entry class will not be waved at all, which will cause a memory leak

Assuming that the key is a weak reference, the ThreadLocal reference is gone, and there is a weak reference pointing to the ThreadLocal in the map, which means that the ThreadLocal will be recycled by the garbage collector immediately. Once it is recycled, the Key will be NULL, then we will The value can no longer be accessed, and the value cannot be recycled, which will cause a memory leak

Obviously the source code is given a weak reference

The above also shows that strong references or weak references will cause memory leaks

Then the root cause of the memory leak is:

The first point: the Entry class always exists in memory, there is no manual remove

The second point: the CurrentThread thread is still running

Well, I wish you good morning, good afternoon, and good night.

Guess you like

Origin blog.csdn.net/Pxx520Tangtian/article/details/132651957