当前,我有一个Web项目。我在SpringMVC的Interceptor中将诸如sessionid之类的变量保存在threadlocal中,并在postHandle方法中将其删除。但是我想知道这是否安全。例如如果一个线程保存了一个sessionid,则发生了CPU上下文切换,在这种情况下,其他东西将占用此线程并设置另一个sessionid或在postHandle处将其删除。当我们切换回去时,sessionid改变了。如果可以的话,我们还有其他解决方案吗?
@Interceptor
public class BusinessInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
ThreadLocalUtil.contextThreadLocal.set(createSessionId());
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex)
throws Exception {
ThreadLocalUtil.contextThreadLocal.remove();
}
}
答案 0 :(得分:0)
您对上下文切换的含义感到困惑。仅仅从Wikipedia看,它的定义为:
在多任务处理上下文中,它是指存储 一项任务的系统状态,以便可以暂停任务和执行另一项任务 恢复。
为一项任务存储系统状态的地方是指存储线程可以访问的所有值,其中当然包括线程本地变量。因此,上下文切换与共享CPU时间有关,而不是与跨线程共享数据有关。 (嗯,是的,当操作系统从用户模式切换到内核模式时,也有上下文切换功能,但是我想这不是OP的一种功能。头脑)。
此外,线程本地变量将根据访问它的线程持有不同的值。如果我们看一下Java中ThreadLocal
的定义:
这些变量与正常变量不同之处在于,每个 (通过其
get
或set
方法访问一个线程) 独立初始化的变量副本。
因此,答案是:否,没有其他线程能够读取该线程局部变量的值,而与正在发生的上下文切换的数量无关。
在另一个注释中,我会担心您在代码中所做的假设。我的意思是,在每个请求的线程本地存储一个值使我认为您假设每个请求一个单个线程执行模型。另外,依赖于使用线程局部变量来传递值等同于使用全局变量,但所不同的是,它们与局部全局变量不同,它们通常与运行时带来有趣的惊喜。
您必须意识到,在这个时代,我们拥有异步/响应式执行模型,HTTP / 2等,由于您将有多个线程来执行给定的请求,因此您的假设将变得平坦。因此,当任何其他线程尝试访问它时,您的线程局部变量要么未初始化,要么持有完全意外的值。这会带来很多麻烦。
我建议您找到一种不同的方式来传递您的会话ID ,并且我建议您明确地将该参数作为后续功能的参数它。
答案 1 :(得分:0)
也许你可以尝试这种方式将参数从 preHandle 传递到 postHandle:
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
request.setAttribute("xxx", xxx);
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
Object obj = request.getAttribute("xxx");
request.removeAttribute("xxx");
}