ThreadLocal的作用
作用是为每个线程保存线程私有数据。可以把ThreadLocal理解为一个Map,其中key为当前线程,value为要存储的数据。
下面是摘自《Java编程思想》中的一段示例代码:
public class ThreadLocalTest {
public static void main(String[] args) throws Exception{
ExecutorService executorService = Executors.newCachedThreadPool();
for(int i = 0;i < 5;i ++) {
executorService.execute(new Task(i));
}
TimeUnit.SECONDS.sleep(3);
executorService.shutdownNow();
}
}
class ThreadLocalVariableHolder {
//将ThreadLocal定义成一个全局共享变量
private static ThreadLocal<Integer> value = new ThreadLocal<Integer>(){
private Random random = new Random();
//随机给定一个初始化值
@Override
protected synchronized Integer initialValue() {
return random.nextInt(10000);
}
};
//通过set设置与当前线程绑定的数据
public static void increment(){
value.set(value.get() + 1);
}
//通过get获取与当前线程绑定的数据
public static Integer get() {
return value.get();
}
}
class Task implements Runnable {
private final int id;
public Task(int id) {
this.id = id;
}
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
//与当前线程绑定的变量值+1
ThreadLocalVariableHolder.increment();
System.out.println(this);
Thread.yield();
}
}
@Override
public String toString() {
return "#" + id + ":" + ThreadLocalVariableHolder.get();
}
}
每个线程都拥有自己的Integer变量,在操作的过程中,互不影响。
ThreadLocal的使用场景
在Web开发中,通常用ThreadLocal来存储当前登录用户的信息。
- 定义ThreadLocal容器
@Component
public class HostHolder {
private static ThreadLocal<User> usersHolder = new ThreadLocal<>();
public User getUser(){
return usersHolder.get();
}
public void setUser(User user){
usersHolder.set(user);
}
public void clear(){
usersHolder.remove();
}
}
- 定义拦截器封装用户信息
@Component
public class PassportInterceptor implements HandlerInterceptor{
private static final Logger logger = LoggerFactory.getLogger(PassportInterceptor.class);
@Autowired
private LoginTicketDao ticketDao;
@Autowired
private UserDao userDao;
@Autowired
private HostHolder userHolder;
@Override
public boolean preHandle(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse, Object o) throws Exception {
logger.info("PassportInterceptor->preHandle()");
//从Cookie中获取ticket
String ticket = null;
if(httpServletRequest.getCookies() != null){
for(Cookie cookie : httpServletRequest.getCookies()){
if(cookie.getName().equals("ticket")){
ticket = cookie.getValue();
break;
}
}
}
//如果在cookie中有通行证
if(ticket != null){
//验证ticket是否过期
LoginTicket ticketInfo = ticketDao.seletByTicket(ticket);
if(ticketInfo == null || ticketInfo.getExpired().before(new Date())
|| ticketInfo.getStatus() != 0){
return true;
}
if(ticketInfo == null){
return true;
}else{
if(ticketInfo.getStatus() == 0 && ticketInfo.getExpired().before(new Date())){
ticketDao.updateByTicket(1, ticket);
return true;
}else if(ticketInfo.getStatus() == 1){
return true;
}else{
User user = userDao.selectById(ticketInfo.getUserId());
//向ThreadLocal中保存当前登录人信息
userHolder.setUser(user);
}
}
}
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse, Object o,
ModelAndView modelAndView) throws Exception {
logger.info("PassportInterceptor->postHandle()");
//将user信息在view层共享
if(modelAndView != null && userHolder.getUser() != null){
modelAndView.addObject("user", userHolder.getUser());
}
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
logger.info("PassportInterceptor->afterCompletion()");
userHolder.clear();
}
}
- 在controller中获取用户信息
@Autowired
HostHolder hostHolder;
...
UserEntity currentUser = hostHolder.get();