Java - ThreadLocal和线程池
简单说明
ThreadLocal
的目的是把数据存储在线程对象中。数据随着线程的销毁而销毁。InheriableThreadLocal
不同于ThreadLocal的地方是,后者只能是同一个线程对象,而前者可以不是同一个线程对象,但前提是这个线程对象的父线程是同一个线程对象,例如,T1存储了D1,又开辟了一个T1-1线程,那么在T1-1线程中可以拿到T1存储的数据。
线程池引发的问题
如果采用了线程池,那么一个线程会被多次使用,如果第一次使用时存储了数据,那么第二次依然可以拿到,因为线程还是同一个。这种场景很常见,我们常用的Tomcat默认就使用了线程池,且默认产生了10个线程备用。这种情况下,就需要清理掉ThreadLocal产生的线程数据。
AOP清理
如果ThreadLocal我们只允许在Service层使用,那么我们可以通过AOP切面在service方法执行完毕后,通过反射或指定变量名称来移除TheadLocal。调用ThreadLocal对象的remove方法即可。
清理器清理
我们可以编写清理器,如下:
package com.codegen.core.utils;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/** * ThreadLocal清理器 * @author Caesar Liu * @date 2019-07-20 16:27 */
public class ThreadLocalClearer {
/** * 清理对象ThreadLocal对象 * @author Caesar Liu * @date 2019-07-20 16:28 */
public static void clear(Object obj) {
Field[] fields = obj.getClass().getDeclaredFields();
try {
for (Field field: fields) {
if (field.getType().equals(ThreadLocal.class)) {
String getMethod = "get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
field.setAccessible(true);
Method method =obj.getClass().getMethod(getMethod);
Object value = method.invoke(obj);
if (value == null)
continue;
ThreadLocal threadLocal = (ThreadLocal) value;
threadLocal.remove();
field.setAccessible(false);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
在使用了ThreadLocal的类中,为ThreadLocal属性增加get方法
。在方法调用结束后调用ThreadLocalClearer.clear(this)
即可。
还没有评论,来说两句吧...