ThreadLocal application ------ one of the solutions to thread insecurity, destroying shared resources

ThreadLocal application

ThreadLocal is used to save a thread shared variable: For the same static ThreadLocal, different threads can only get, set, and remove their own variables from it, without affecting the variables of other threads.

1. ThreadLocal.get: Get the value of the current thread shared variable in ThreadLocal.

2. ThreadLocal.set: Set the value of the current thread shared variable in ThreadLocal.

3. ThreadLocal.remove: Remove the value of the current thread shared variable in ThreadLocal.

4. ThreadLocal.initialValue: When ThreadLocal is not assigned a value by the current thread or the current thread calls the get method just after calling the remove method, the value of this method is returned.

The ThreadLocal method mainly destroys the conditions of public resources in the three major issues of thread insecurity (multithreading, public resources, and write operations) to ensure thread safety.

public class ThreadLocalDemo {
    private static ThreadLocal<Object> threadLocal = new ThreadLocal<Object>(){
        @Override
        protected Object initialValue() {
            System.out.println("调用此方法后进行初始化。。");
            return null;
        }
    };
    public static void main(String[] args) {
            new Thread(new addInt(),"int1").start();
            new Thread(new addString(),"string1").start();
            new Thread(new addInt(),"int2").start();
            new Thread(new addString(),"string2").start();
    }

    static class addInt implements  Runnable{
        @Override
        public void run() {
            for (int i = 0; i < 6; i++) {
                if (null == threadLocal.get()){
                    //说明没有赋初始值
                    threadLocal.set(0);
                    System.out.println("线程:"+Thread.currentThread().getName()+":0");
                }else{
                    int num = (int) threadLocal.get();
                    threadLocal.set(num+1);
                    System.out.println("线程:"+Thread.currentThread().getName()+":"+threadLocal.get());
                    if (i==3){
                        threadLocal.remove();
                    }
                }
                try {
                    Thread.sleep(1000);
                }catch (Exception e){
                    e.printStackTrace();
                }
            }

        }
    }
    static class addString implements  Runnable{

        @Override
        public void run() {
            for (int i = 0; i < 6; i++) {
                if (null == threadLocal.get()){
                    threadLocal.set("a");
                    System.out.println("线程:"+Thread.currentThread().getName()+":a");
                }else {
                    String a = (String) threadLocal.get();
                    threadLocal.set(a+"a");
                    System.out.println("线程:"+Thread.currentThread().getName()+":"+threadLocal.get());
                }
                try {
                    Thread.sleep(1000);
                }catch (Exception e){
                    e.printStackTrace();
                }
            }

        }
    }
}
运行结果:
调用此方法后进行初始化。。
线程:int1:0
调用此方法后进行初始化。。
线程:int2:0
调用此方法后进行初始化。。
线程:string2:a
调用此方法后进行初始化。。
线程:string1:a
线程:int2:1
线程:int1:1
线程:string2:aa
线程:string1:aa
线程:int1:2
线程:int2:2
线程:string2:aaa
线程:string1:aaa
线程:int2:3
线程:int1:3
线程:string2:aaaa
线程:string1:aaaa
调用此方法后进行初始化。。
调用此方法后进行初始化。。
线程:int2:0
线程:int1:0
线程:string2:aaaaa
线程:string1:aaaaa
线程:int1:1
线程:int2:1
线程:string2:aaaaaa
线程:string1:aaaaaa

The thread shared variable cache is as follows:

Thread.ThreadLocalMap<ThreadLocalObject>;

1. Thread: The current thread, which can be obtained through Thread.currentThread().

2. ThreadLocal: Our static  ThreadLocal variable.

3. Object: The current thread shared variable.

When we call the ThreadLocal.get method, we actually get ThreadLocalMap< ThreadLocalObject > from the current thread, and then get the current thread shared variable Object according to the current ThreadLocal.

ThreadLocal.set, ThreadLocal.remove are actually the same.

The benefits of this storage structure:

1. When the thread dies, the thread shared variable ThreadLocalMap is destroyed.

2. The number of ThreadLocalMap<ThreadLocal, Object> key-value pairs is the number of ThreadLocals. Generally speaking, the number of ThreadLocals is very small. Compared with using Map<Thread, Object> key-value pairs in ThreadLocal to store thread shared variables (the number of Threads is generally More than ThreadLocal), the performance is improved a lot.

 

Regarding the weak reference of ThreadLocalMap< ThreadLocalObject >:

When the thread has not ended, but the ThreadLocal has been recycled, it may cause the key-value pairs of ThreadLocalMap< nullObject > to exist in the thread, resulting in memory leaks. (ThreadLocal is recycled, and the thread shared variables associated with ThreadLocal still exist).

Although the get and set methods of ThreadLocal can clear the value whose key is null in the ThreadLocalMap, the get and set methods will not necessarily be called after a memory leak, so we have two methods to prevent such situations from happening.

1. After using the thread shared variable, call the ThreadLocalMap.remove method to clear the thread shared variable;

2. JDK recommends that ThreadLocal be defined as private static, so that the weak reference problem of ThreadLocal does not exist.

Reference: https://www.cnblogs.com/coshaho/p/5127135.html

Why does ThreadLocal cause memory leaks: https://blog.csdn.net/csujiangyu/article/details/52999573

 

おすすめ

転載: blog.csdn.net/a34651714/article/details/102895907