[ThreadLocal] ThreadLocal usage scenarios and examples

ThreadLocal is an important measure for thread closure, and DateTimeContextHolder and RequestContextHolder in Spring are also useful.

Usage scenarios of ThreadLocal

Scenario 1: Object isolation-the thread needs an exclusive object (such as SimpleDateFormat)

Threads exclusively share an object tool class, such as Random and DateFormat, usually for reasons of thread safety and efficiency.

For the thread-exclusive object scenario, the main method is to override the innitialValue() method.

public class RrightWaySimpleDateFormater {
    
    
    public static ExecutorService threadPool = Executors.newFixedThreadPool(10);
    /**
     * 定义ThreadLocal变量--JDK8实现形式
     */
    private static final ThreadLocal<SimpleDateFormat> dateThreadSafe = ThreadLocal.withInitial(
        () -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
   );

    public static void main(String[] args) throws InterruptedException {
    
    
        for (int i = 0; i < 1000; i++) {
    
    
            int finalI = i;
            threadPool.submit(() -> {
    
    
                System.out.println(new RrightWaySimpleDateFormater().date(finalI));
            });
        }
        threadPool.shutdown();
    }

    public String date(int seconds) {
    
    
        return dateThreadSafe.get().format(new Date(1000 * seconds));
    }
}

JDK7 and previous implementation forms

private static final ThreadLocal<SimpleDateFormat> dateThreadSafe2 = new ThreadLocal<SimpleDateFormat>() {
    
    
     @Override
     protected SimpleDateFormat initialValue() {
    
    
         return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
     }
};

It should be noted that ThreadLocal is usually not suitable for thread pools.

Ali java manual:
[Mandatory] SimpleDateFormat is a thread-unsafe class and generally should not be defined as a static variable. If it is defined as static, it must be locked, or use the DateUtils tool class. The above treatment is also recommended.
JDK8 recommends using DateTimeFormatter instead of SimpleDateFormat, Instant instead of Date, and LocalDateTime instead of Calendar.

Scenario 2: Object transfer

Threads need to save global variables so that different methods can be used directly, without the need to pass data layer by layer as parameters.

ThreadLocal can be used to save some business information, such as user authority information, user name, userId, mobile phone number, and so on. The business information is the same in the same thread, but the content in different threads is different. The emphasis is on sharing between different methods within the same request (within the same thread).

Map can also store the above-mentioned business information. When multiple threads work at the same time, thread safety needs to be guaranteed. For example, using a static ConcurrentHashMap variable, using the thread ID as the key, and storing the business data as the Value, can achieve isolation between threads, but still has a performance impact.

public class RightWayThreadLocalUse {
    
    
    public static void main(String[] args) {
    
    
        new ServiceImpl1().service(new UserInfo("lzp", "1234567890"));
    }
}

/**
 * 接收数据
 */
class ServiceImpl1 {
    
    
    public void service(UserInfo userInfo) {
    
    
        UserInfoHolder.holder.set(userInfo);
        new ServiceImpl2().service();
    }
}

/**
 * 处理数据1
 */
class ServiceImpl2 {
    
    
    public void service() {
    
    
        System.out.println("客户名:" + UserInfoHolder.holder.get().cltNam);
        new ServiceImpl3().service();
    }
}

/**
 * 处理数据2
 */
class ServiceImpl3 {
    
    
    public void service() {
    
    
        System.out.println("客户号:" + UserInfoHolder.holder.get().cltNbr);
        // 此时使用完ThreadLocal,回收该ThreadLocal
        UserInfoHolder.holder.remove();
    }
}

class UserInfoHolder {
    
    
    public static ThreadLocal<UserInfo> holder = new ThreadLocal<>();
}

class UserInfo {
    
    
    String cltNam;
    String cltNbr;

    public UserInfo(String cltNam, String cltNbr) {
    
    
        this.cltNam = cltNam;
        this.cltNbr = cltNbr;
    }
}

Advantages of ThreadLocal

(1) The ThreadLocal variable is private to the thread, so the thread is safe and does not need to be locked, so there is no blocking, and the execution efficiency is improved.
(2) Use memory efficiently and save overhead. For the scenario of using the thread pool, it is only necessary for each worker thread to have a ThreadLocal instance of the object.
(3) For the call chain scenario, avoid repeated transmission of objects, used to store business information, and achieve code decoupling.

Guess you like

Origin blog.csdn.net/LIZHONGPING00/article/details/105211631