ThreadLocal引起的问题

我们曾经做过一个多租户的项目,每个租户用一个唯一的平台号。程序中有的地方把当前用户的平台号放在一个ThreadLocal变量中。部署到tomcat上后发现一个很奇怪的现象:有时候用户的平台号会出现错乱,即一个人的平台号会出现在另一个登录用户的身上。最后发现问题出在线程池上。


大家知道ThreadLocal中的值实际上保存在线程对象中。在有线程池的情况下,线程用完后会还到线程池中,下一次需要线程时就从线程池中获取一个。如果ThreadLocal中的值上次没清空,这个值就会保留下来继续被使用。就是这个原因导致ThreadLocal中的数据混乱的。


原因清楚了,解决方法也就很简单了。ThreadLocal使用完后把值清除即可。


为简化问题,可以写一个ThreadLocalRegistry负责记住所有需要清除的ThreadLocal,然后在ThreadLocalCleanerInterceptor中统一清除。代码如下:

public class ThreadLocalRegistry {
	private static ThreadLocal<List<ThreadLocal>> threadLocals = new ThreadLocal<List<ThreadLocal>>();
	
	public static void register(ThreadLocal threadLocal) {
		synchronized (threadLocals) {
			if (threadLocals.get() == null) {
				threadLocals.set(new ArrayList<ThreadLocal>());
			}
			threadLocals.get().add(threadLocal);
		}
	}
	
	public static void clear() {
		synchronized (threadLocals) {
			if (threadLocals.get() == null) {
				return;
			}
			
			for (ThreadLocal threadLocal : threadLocals.get()) {
				threadLocal.remove();
			}
			threadLocals.get().clear();
			threadLocals.remove();
			
			Guzz.setDBGroup(null);
			Guzz.setTableCondition(null);
		}
	}
}

public class ThreadLocalCleanerInterceptor implements Filter {
	public void destroy() {
	}

	public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
		try {
			chain.doFilter(req, res);
		} finally {
			ThreadLocalRegistry.clear();
		}
	}

	public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
		try {
			chain.doFilter(request, response);
		} finally {
			ThreadLocalRegistry.clear();
		}
	}

	@Override
	public void init(FilterConfig config) throws ServletException {
	}
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值