ThreadLocal
源码讲解
通过Thread.currentThread()获取当前线程
通过ThreadLocal.ThreadLocalMap inheritableThreadLocals =null;绑定该线程所占用的资源。(threadLocal只是个key)
概述:ThreadLocal就是为thread维护中的一个ThreadLocalMap的工具类而已,具体资源完全和当前线程绑定
以下三个方法的实现代码辅助理解
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
return setInitialValue();
}
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
理解
线程绑定,管理单一无状态资源,存储直到当前线程销毁
常见于连接(绑定线程不会造成冲突,随着线程的销毁而随之归还)管理
如hibernate的session
private static final ThreadLocal threadSession = new ThreadLocal();
public static Session getSession() throws InfrastructureException {
Session s = (Session) threadSession.get();
try {
if (s == null) {
s = getSessionFactory().openSession();
threadSession.set(s);
}
} catch (HibernateException ex) {
throw new InfrastructureException(ex);
}
return s;
}
不解决并发访问的问题,在并发场景应用此类作为数据存储会存在问题
注:误用实例
比如说用当前类去做服务器端的用户信息存储的时候,并且有10个用户同时登陆当前系统,这个时候每一个操作人的操作过程服务器端通过threadlocal获取到的用户对象都有可能是这10个登录人中的其中一个,会引起数据混乱
误用代码实例
public class LoginUtils {
private static String key_prefix = "***_***";
private static final ThreadLocal<LoginUser> threadLocal = new ThreadLocal<LoginUser>();
private static LoginUtils cacheUtil;
@Autowired
private TairService tairService;
@PostConstruct
public void init() {
cacheUtil = this;
cacheUtil.tairService = this.tairService;
}
public static void setUser(LoginUser user) {
threadLocal.set(user);
cacheUtil.tairService.put(buildKey(user), user);
}
public static LoginUser getUser() {
return threadLocal.get();
}
public static void removeUser() {
LoginUser user = threadLocal.get();
if (user == null) {
return ;
}
threadLocal.remove();
cacheUtil.tairService.delete(buildKey(user));
}
public static String buildKey(LoginUser user) {
StringBuffer key = new StringBuffer();
key.append(key_prefix);
key.append(user.getId());
return key.toString();
}
}