Data stored in ThreadLocal is private to the current thread and not visible to other threads

prove

Declare a global threadLocal variable with an initial value of 1, which is accessed by three threads. The final value of threadLocal should be 6, but the output is 3, indicating that the data stored in a threadLocal is private to each thread

package com.mmall.concurrency.example.threadLocal; public class UseThreadLocal { static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() { @Override protected  Integer initialValue() { return 1; }}; Public void startThreadArray() {Thread[] Thread = new Thread[3]; for (int i = 0; i < thread.length; i++) { thread[i] = new Thread(new MyThread(i)); } for (int i = 0; i < thread.length; i++) { thread[i].start(); } } private class MyThread implements Runnable { int id; public MyThread(int i) { id = i; } @Override public void run() { System.out.println(Thread.currentThread().getName()+":start"); Integer v = threadLocal.get(); v=v+id; threadLocal.set(v); System. The out. Println (Thread. CurrentThread (). The getName () + ":" + threadLocal. The get ()); } } public static void main(String[] args) { UseThreadLocal useThreadLocal = new UseThreadLocal(); useThreadLocal.startThreadArray(); }}Copy the code

The results of

Thread-0:start thread-2 :start thread-1 :start thread-0:1 thread-2:3 Thread-1:2Copy the code

Small application

ThreadLocal is used in conjunction with filters and interceptors by setting values in ThreadLocal in the HttpFilter and removing values in the interceptor through the HttpInterceptor

Write a ‘ThreadLocal’ class that contains set, get, and remove operations

package com.mmall.concurrency.example.threadLocal; public class RequestHolder { private final static ThreadLocal<Long> requestHolder = new ThreadLocal<>(); public static void add(Long id) { requestHolder.set(id); } public static Long getId() { return requestHolder.get(); } public static void remove() { requestHolder.remove(); }}Copy the code

Write a filter HttpFilter class that stores data in ThreadLocal in the doFilter method

package com.mmall.concurrency;

import com.mmall.concurrency.example.threadLocal.RequestHolder;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

@Slf4j
public class HttpFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        log.info("do filter, {}, {}", Thread.currentThread().getId(), request.getServletPath());
        RequestHolder.add(Thread.currentThread().getId());
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {

    }
}
Copy the code

Write ThreadLocalController class to get data stored in ThreadLocal in the HttpFilter

package com.mmall.concurrency.example.threadLocal; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller @RequestMapping("/threadLocal") public class ThreadLocalController { @RequestMapping("/test") @ResponseBody public Long test() { return RequestHolder.getId(); }}Copy the code

Write the HttpInterceptor class and, after completing the business logic, remove the value we set to ThreadLocal in the HttpFilter in the afterCompletion method of the HttpInterceptor class

package com.mmall.concurrency; import com.mmall.concurrency.example.threadLocal.RequestHolder; import lombok.extern.slf4j.Slf4j; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Slf4j public class HttpInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { log.info("preHandle"); return true; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { RequestHolder.remove(); log.info("afterCompletion"); return; }}Copy the code

Write the SpringBoot boot boot class ConcurrencyApplication that instantiates the FilterRegistrationBean

package com.mmall.concurrency; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; @SpringBootApplication public class ConcurrencyApplication extends WebMvcConfigurerAdapter{ public static void main(String[] args) { SpringApplication.run(ConcurrencyApplication.class, args); } @Bean public FilterRegistrationBean httpFilter() { FilterRegistrationBean registrationBean = new FilterRegistrationBean(); registrationBean.setFilter(new HttpFilter()); registrationBean.addUrlPatterns("/threadLocal/*"); return registrationBean; } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new HttpInterceptor()).addPathPatterns("/**"); }}Copy the code

Start springboot start class, go to http://localhost:8080/threadLocal/test, the console output

This article is published by OpenWrite!