線程封閉

咱們能夠經過把對象設計成不可變對象來躲避併發,咱們還能夠經過使用線程封閉來實現線程安全,所謂線程封閉java

就是將數據都封裝到一個線程裏,不讓其餘線程訪問。
  • Ad-hoc 線程封閉程序控制實現,比較脆弱,儘可能少用
  • 堆棧封閉:局部變量,無併發問題,在項目中使用最多,簡單說就是局部變量,方法的變量都拷貝到線程的堆棧中,只有這個線程能訪問到。儘可能少使用全局變量(變量不是常量)
  • ThreadLocal線程封閉:比較好的封閉方法
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

相關文章
相關標籤/搜索