ThreadLocal 中保存的数据只能被当前线程私有, 不被其它线程可见
证明
声明一个全局的变量 threadLocal, 初始值为 1, 通过 3 个线程对其进行访问修改设置, 理论上 threadLocal 的最终值应该是 6, 然而我们的输出结果是 3, 说明了 threadLocal 中存放的数据是各自线程私有的
- package com.mmall.concurrency.example.threadLocal;
- public class UseThreadLocal {
- static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() {
- @Override
- protected Integer initialValue() {
- return 1;
- }
- };
- // 运行 3 个线程
- 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.out.println(Thread.currentThread().getName()+":"+threadLocal.get());
- }
- }
- public static void main(String[] args) {
- UseThreadLocal useThreadLocal = new UseThreadLocal();
- useThreadLocal.startThreadArray();
- }
- }
结果
- Thread-0:start
- Thread-2:start
- Thread-1:start
- Thread-0:1
- Thread-2:3
- Thread-1:2
小应用
ThreadLocal 结合过滤器和拦截器进行搭配使用, 通过在过滤器 HttpFilter 设置 ThreadLocal 中的值, 通过拦截器 HttpInterceptor 移除拦截器中的值
编写 `ThreadLocal 类, 包含设置, 获取, 移除操作
- 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();
- }
- }
编写过滤器 HttpFilter 类, 通过在 doFilter 方法中对 ThreadLocal 进行存数据
- 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() {
- }
- }
编写 ThreadLocalController 类, 在业务中可以获取到在过滤器 HttpFilter 中对 ThreadLocal 中存放的数据
- 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();
- }
- }
编写拦截器 HttpInterceptor 类, 在完成业务逻辑处理后, 在拦截器类 HttpInterceptor 的 afterCompletion 方法中移除我们在过滤器 HttpFilter 中对 ThreadLocal 设置的值
- 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;
- }
- }
编写 springboot 的启动类 ConcurrencyApplication, 实例化了 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("/**");
- }
- }
启动 springboot 启动类, 访问 http://localhost:8080/threadLocal/test, 控制台输出
来源: https://www.cnblogs.com/lisingshen/p/11782271.html