我可以在很多网站上看到Struts Action类不是线程安全的。我无法理解为什么会这样。
我还读了一本书,上面写着“Struts动作类被缓存并重用于性能 优化代价是必须以线程安全的方式实现操作类“
如何缓存动作类和线程安全相关?
答案 0 :(得分:24)
如何缓存操作类并与线程安全相关?
如果您缓存并重新使用类的实例,允许多个线程同时访问同一个实例,那么该类本质上是 不 线程安全*。如果您要在类上放置可变实例或静态字段,则并发下的结果将是意外且有问题的。另一方面,如果每个线程都有自己的类实例,那么该类本质上是线程安全的。
*如果实例或静态字段是不可变的,那么多个线程可以同时访问它。
答案 1 :(得分:5)
如果任何类被缓存并重用,则存在多线程并发访问损坏的风险。在Web应用程序中,每个请求都在一个线程上处理。假设您有10个操作实例,但您的容器正在处理20个请求 - 在这种情况下,您的10个操作都被重复使用,因为您在飞行中的请求多于可用于维护它们的操作。
如果某个状态在操作中被重用,则线程安全问题只会出现问题。如果是这种情况,则为一个请求提供服务的操作可能会在共享变量中设置一个值,但随后另一个线程可能会接管,并且该操作可能会再次修改共享变量。在这种情况下,当原始线程接管时,共享状态已被修改。
处理此问题的简单方法是将堆栈配置为始终使用新操作,或确保操作中没有共享状态。
答案 2 :(得分:2)
为什么不为每个请求创建一个新的“action”对象?世界上有什么?
因为Struts太老了,他认为每个请求周期再创建一个对象就像为一杯咖啡支付一美元一样昂贵。 (也就是说,非常昂贵。因为他真的很老了。)
答案 3 :(得分:1)
查看实际的struts源代码,您将看到它只返回实例化的动作类。所以,两个请求可以命中相同的实例变量,如果它没有正确同步会产生很多问题。
protected Action processActionCreate(HttpServletRequest request,
HttpServletResponse response, ActionMapping mapping)
throws IOException {
// Acquire the Action instance we will be using (if there is one)
String className = mapping.getType();
Action instance;
synchronized (actions) {
// Return any existing Action instance of this class
instance = (Action) actions.get(className);
if (instance != null) {
return (instance);
}
.......
}
.....
}
答案 4 :(得分:0)
在为旧的Struts 1项目寻找此问题的解决方案时,该项目由于对同一动作的一些ajax调用而表现出随机性,我发现您可以通过使用scope="request"
解决此情况下的线程安全问题在您的struts-config.xml
文件中。
<action path="/blabla" type="blabla" name="bla" scope="request">
也许有帮助