當ThreadLocal遇上Tomcat線程池

Java開發中,我們一般使用ThreadLocal來傳遞當前請求域的持久變量,比如sessiontoken、用戶信息等。

但是,當選擇Tomcat做服務容器時,可能會出現ThreadLocal傳遞的持久變量錯亂。
原因是Tomcat內部實現了線程池,存在線程複用問題。

例如:
現有abc三個空閒線程
1、request-1進來,分配了a線程去處理,存入ThreadLocal變量
2、很快request-2也來了,此時a線程尚未處理完成,只能分配bc之一去處理
3、request-3也來了,此時a線程已經處理完成,分配a線程去處理,因某些原因(參數失效等)不存入ThreadLocal變量,但是由於a線程剛剛處理完request-1,之前的變量仍有效,所以request-3進來後雖未存入變量,但仍能獲取到數據
這就導致了數據錯亂

解決辦法:

請求處理完成後,務必手動對ThreadLocal變量進行清理操作

攔截器實現:

@Component
public class LocalInterceptor implements HandlerInterceptor {

    private final UserThreadLocal local;

    public LocalInterceptor(UserThreadLocal local) {
        this.local = local;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String user = request.getParameter("user");
        // user 有效時才存入 ThreadLocal 中,否則直接略過
        if (null != user && !"".equals(user)) {
            local.set(user);
        }
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 必須 remove
        // 避免因容器線程池複用導致 ThreadLocal 錯亂問題
        local.remove();
    }
}

如此,可解!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章