ThreadLocal小试牛刀
- 2019 年 11 月 2 日
- 筆記
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
,控制台输出
本文由博客一文多发平台 OpenWrite 发布!