Ran into a ThreadLocal value passing problem at work. Because the corporate business has an interface that is very slow, consider using an asynchronous approach to optimization

However, because services have Redis distributed locks and lock values are stored using ThreadLocal, the value will be lost and the lock cannot be released after asynchronism

This article examines how ThreadLocal is passed in different threads

Let’s start with thread passing
The phenomenon of The solution introduce
Passing values between the same threads ThreadLocal Provide one for the threadThe local variableWhen the thread disappears, all native examples are reclaimed
Parent and child threads pass values between them InheritableThreadLocal Classes provided by the JDK, yesThreadLocalTo solve the problem of passing values between parent and child threads
Thread pool different threads pass values TransmittableThreadLocal TTL, for short, is a framework provided by The Alibaba team, which mainly solves the problem of storage thread poolsInheritableThreadLocalFailure problem
The preparatory work
  1. First introduce dependencies

    <? xml version="1.0" encoding="UTF-8"? > <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0. 0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId>  <version>2.113..RELEASE</version>
        </parent>
    
        <groupId>org.example</groupId>
        <artifactId>threadLocal-demo</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <properties>
            <maven.compiler.source>8</maven.compiler.source>
            <maven.compiler.target>8</maven.compiler.target>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
                <version>2.42.</version>
            </dependency>
        </dependencies>
    </project>
    Copy the code
  2. Create TestController

    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.annotation.Resource;
    
    / * * *@author by miao
     */
    @RestController
    public class TestController {
    
        @Resource
        private TestService testService;
    
        @RequestMapping("/test")
        public String test(a) {
            returntestService.test(); }}Copy the code
  3. Create TestService

    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    
    / * * *@author miao
     */
    @Service
    public class TestService {
    
        public String test(a) {
    
            return "ok"; }}Copy the code
  4. Create ThreadLocalUtil

    import java.util.UUID;
    
    / * * *@author miao
     */
    public class ThreadLocalUtil {
    
        private static final ThreadLocal<String> LOCK_FLAG = new ThreadLocal<>();
    
        /** * gets the value ** saved in the thread@return String
         */
        public static String getValue(a) {
            return LOCK_FLAG.get();
        }
    
        /** * Sets the value ** that the thread needs to save@return String
         */
        public static String setValue(a) {
            String uuid = UUID.randomUUID().toString();
            LOCK_FLAG.set(uuid);
            return uuid;
        }
    
        /** * removes the value */ saved in the thread
        public static void removeValue(a) { LOCK_FLAG.remove(); }}Copy the code

1. The value is transmitted in the same thread

1) TestService test()

    public String test(a) {

        System.out.println("+ + + + + + + + + + + + + + +"+ThreadLocalUtil.setValue());

        System.out.println("Business logic processing");
        System.out.println("-- -- -- -- -- -- -- -- -- -- -- -- -- -- --" + ThreadLocalUtil.getValue());
        return "ok";
    }
Copy the code
  1. Browser access:http://localhost:8080/test

The result is:

2. The parent and child threads transmit values internally

  1. In the startup class, add enable asynchronous support, add annotations@EnableAsync
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;

/ * * *@author by 15888
 * @date2021/4/21 17:34 * /
@EnableAsync
@SpringBootApplication
public class ThreadLocalApplication {
    public static void main(String[] args) { SpringApplication.run(ThreadLocalApplication.class, args); }}Copy the code
  1. createAysncService
/ * * *@author miao
 */
@Service
public class AsyncService {

    @Async
    public void getThreadLocalValue(a) {

        System.out.println("+ + + + + + + + + + + + + + +"+ ThreadLocalUtil.getValue()); }}Copy the code
  1. inTestServiceThe use ofAsyncService
    
    @Resource
    private AsyncService asyncService;

	public String test1(a) {

        System.out.println("+ + + + + + + + + + + + + + +"+ThreadLocalUtil.setValue());

        System.out.println("Business logic processing");
        asyncService.getThreadLocalValue();
        return "ok";
    }
Copy the code
  1. ThreadLocalUtilIn theLOCK_FLAGImplementation class changed toInheritableThreadLocal
private static final ThreadLocal<String> LOCK_FLAG = new InheritableThreadLocal<>();
Copy the code

5) browser visit: http://localhost:8080/test

The result is:

To resolve the problem of value passing between parent and child threads, please refer to my second article: ThreadLocal Asynchronous Thread pool passing.