最近遇到一个比较隐蔽而又简单地问题,在使用ThreadLocal时发现出现多个线程中值串来串去,排查一番,确定问题为线程池的问题,线程池中的线程是会重复利用的,而ThreadLocal是用线程来做Key的所以在使用线程池的时候要特别注意ThreadLocal.
Servlet处理请求时也是以线程池为每次请求提供线程,所以如果有使用到ThreadLocal的话,需要注意这一点。
对于上述情况,需要我们在每次请求发起时,重新设置ThreadLocal里的值,这样才能保证每回获取到的是当前用户的信息,而非线程上次设置的值。ThreadLocal声明周期也应该为每次请求中。
新加一个ThreadLocalRequest用来记录当前请求的request的引用。如果当前代码执行的线程还属于同一次请求则不更改重置ThreadLocal中的变量。如果当前线程不属于同一次请求,则重置ThreadLocal的变量。
因为有时候一个实例在一次请求中会出现被调用多次的情况,所以需要区分线程当前处理是否同一次请求。不是同一次请求,可能ThreadLocal保存的请求信息是不同的,例如用户信息。不同用户的请求可能会共用线程池中的同一个线程去处理,这时候需要重置线程本地变量。
if(threadLocalRequest.get()!=null&&(threadLocalRequest.get()!= this.pageContext.getRequest())){
if (threadLocalVar.get() != null) {
threadLocalVar.remove();
}
}
if(threadLocalRequest.get()==null){
threadLocalRequest.set(this.pageContext.getRequest());
}