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 發佈!