咱們能夠經過把對象設計成不可變對象來躲避併發,咱們還能夠經過使用線程封閉來實現線程安全,所謂線程封閉java
就是將數據都封裝到一個線程裏,不讓其餘線程訪問。
ThreadLocal維護的是一個map 這個map是線程的名稱多爲key 咱們全部封閉的值做爲value。
咱們作使用Filter作登陸操做都作過,咱們如今來使用ThreadLoad來存儲一下用戶信息。
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(); } }
聲明一個ThreadLoad對象用來存儲ThreadLoad信息。安全
@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() { }
@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; } }
定義filter的內容,咱們在filter中將線程id加入到ThreadLoad中,而後在controller中獲取,看看能不能獲取的到。在線程執行完以後將ThreadLoad中的數據清空防止內存溢出。併發
@Controller @RequestMapping("/threadLocal") public class ThreadLocalController { @RequestMapping("/test") @ResponseBody public Long test() { return RequestHolder.getId(); } }
最後咱們用postman測試發現打印了線程id,ThreadLoad中變量值只要是一個線程中無論在哪一個類中都是共享的。app