什么是ThreadLocal
- ThreadLocal,即线程本地变量。其中存放的变量只属于当前线程,被其他线程所隔离。这种变量在线程的生命周期内起作用,减少了同一个线程内多个函数或者组件之间的一些公共变量的传递复杂度,同一个ThreadLocal所包含的对象,在不同的线程中有不同的副本,且其他的线程不可访问,因此不存在多线程之间共享的问题。
ThreadLocal原理
- 每一个线程都有自己的ThreadLocalMap类对象,可以将自己的对象保存到其中,每个线程可以正确的访问自己的对象。
- 当调用ThreadLocalset(T value)方法时,ThreadLocal将自身的引用,也就是this作为Key,将用户传入的值作为Value,存储在自身的ThreadLocalMap中,相当于每个线程的读写都基于自己的一个私有副本,隔离了不同线程的数据。
- 在线程执行的各处通过这个静态的ThreadLocal实例的get()方法可以取到当前线程保存的对象,避免了将这个对象作为参数传递的麻烦。
ThreadLocal的优势
- ThreadLocal采用了用空间换取时间的设计思想,在每个线程里面都有一个容器存储共享变量的副本,然后每个线程只对自己的变量副本做操作,提高了程序的执行效率。
- 基于ThreadLocal的操作不存在线程安全的问题,避免了多线程竞争加锁的开销。
ThreadLocal使用案例
- 一条代码的一条处理线,都是在同一个线程内完成的,所以我们可以在一开始就定义一个变量存入ThreadLocal中,以便在某些取不到HttpServletRequest的情况下,得以获取当前某些变量的值,eg:用户id等。
public class BaseContext {
private static ThreadLocal<String> t = new ThreadLocal<>();
public static void setUserId(String id) {
t.set(id);
}
public static String getUserId() {
return t.get();
}
}
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
@Override
public User login(User user) {
User user_db = this.getById(user.getUserId());
if(user_db!=null){
if(user_db.getPassword().equals(user.getPassword())){
BaseContext.setUserId(user_db.getUserId());
System.out.println(BaseContext.getUserId());
return user_db;
}
}
return null;
}
}