[Multi-threaded programming]--ThreadLocal, InheritableThreadLocal (ITL), TransmittableThreadLocal (TTL) analysis

I. Introduction

In a recent project, a colleague defined a global variable during development. In order to prevent data confusion [different thread operations when concurrently requesting this interface will affect the variable value], he added a lock, which greatly affected performance. I silently recommended ThreadLocal, saying it could solve his problem. In the end, although he used ThreadLocal, he encountered a problem again, saying that after the code was executed, he found that the value was inexplicably blank [After reading the code, I found that in order not to affect the return result, part of the business was executed asynchronously]. . . . .
Based on the use of ThreadLocal in the project and some complex scenarios, this article will introduce the principles of the ThreadLocal series for better use.

There are common questions to consider when using ThreadLocal:
(1) How does the main thread transfer values ​​​​to sub-threads
(2) If the sub-thread modifies the variable value, will it have any impact on the main thread or other threads
(3) ThreadLocal is so easy to use , is it being used without restraint, is there anything I need to pay attention to?

Therefore, this article will introduce the principles, advantages and disadvantages of ThreadLocal, InheritableThreadLocal (ITL), and TransmittableThreadLocal (TTL).

2.ThreadLocal

ThreadLocal avoids multi-thread concurrency problems and competition. Mainly the set(), get(), and remove() methods.

2.1. Why ThreadLocal is used (ThreadLocal application scenario)

For time conversion, we often use the SimpleDateFormat class to complete. Common usage:

方法一
public static  String formatDate(Date date)throws ParseException{
   
    
    
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(date);
    }
    public static Date parse(String strDate) throws ParseException{
   
    
    
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.parse(strDate);
    }

------Make the created object private to solve the multi-threading problem, but increase the burden of creating the object.

方法二
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");   
    public static String formatDate(Date date)throws ParseException{
   
    
    
         return sdf.format(date);
    } 
    public static Date parse(String strDate) throws ParseException{
   
    
    
         return sdf.parse(date);
    }

------Although the new SimpleDateFormat object becomes a global variable, date conversion errors and date conversion confusion will occur under multi-threading.
Cause of the problem : SimpleDateFormat is thread-unsafe. The class member variables passed in the parse() method and the methods of the Calendar object under multi-threading will cause data insecurity.

The best way to consider is whether, under multi-threading, corresponding resources can be allocated to each thread to prevent competition errors. ThreadLocal solves the problem of multi-thread concurrency very well.

private static ThreadLocal<DateFormat> threadLocal = new ThreadLocal<DateFormat>(){
   
    
    
    protected DateFormat initialValue(){
   
    
    
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    }
};
public static String currentDate() {
   
    
    
   return threadLocal.get().format(now());
}

private static ThreadLocal<DateFormat> threadLocal2 = new ThreadLocal<DateFormat>();
public static DateFormat getDateFormat(){
   
    
    
    DateFormat df = threadLocal2.get();
    if(df ==null){
   
    
    
        df = new SimpleDateFormat(DT_FORMAT);
        threadLocal2.set(df);
    }
    return df;
}

public static String currentDate() {
   
    
    
    return getDateFormat().format(now());
}

2.2. ThreadLocal implementation principle

Purpose : To ensure that the current thread has its own variables and that there will be no multi-thread concurrency security issues.
Implementation principle:
Thread maintains a unique ThreadLocalMap reference for each thread. ThreadLocalMap is an internal class of ThreadLocal and uses the Entry array to store data [all ThreadLocal instances of this thread will be stored]; Entry inherits weak references
and uses the KV method to organize data. Among them, K is a different ThreadLocal object instance of the current thread, and V is the stored object value; the
main methods are set, get, and remove, which all first obtain the own thread with currentThread(), and then operate the ThreadLocalMap. Different threads have their own ThreadLocalMap, thus achieving "data isolation".

Specifically compare the relationship between Thread and ThreadLocal classes and the following diagram

 Thread{
   
    
    
   ThreadLocal.ThreadLocalMap threadLocals = null;
 
 }
 
 ThreadLocal{
   
    
    
     static class ThreadLocalMap {
   
    
    
	     
		  static class Entry extends WeakReference<ThreadLocal<?>> {
   
    
    
		       //K-V方法存储数据。K是这个Thread线程的某个ThreadLocal的实例,V是对应数值
		      Entry(ThreadLocal<?> k, Object v) {
   
    
    
                super(k);
                value = v;
              }
		  }
	 }
 }

Insert image description here

2.3、ThreadLocalMap

ThreadLocalMap is an internal class that uses E

Guess you like

Origin blog.csdn.net/xunmengyou1990/article/details/128985752