ThreadLocal引起的问题

xiaoxiao2021-02-28  125

我们曾经做过一个多租户的项目,每个租户用一个唯一的平台号。程序中有的地方把当前用户的平台号放在一个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 { } }

转载请注明原文地址: https://www.6miu.com/read-62738.html

最新回复(0)