Struts2会话并发问题

时间:2012-04-24 22:06:26

标签: java concurrency struts2

我有些麻烦。

例如,我有两个动作:第一个和第二个。

我编写了一个简单的实用程序,它使用执行程序服务向行动发送100000个异步请求,然后向行动发送第二个。

在我做的第一个动作中:

HitCounter.increment();
ActionContext.getContext().getSession().put("counter", HitCounter.getAtomicCounter());
return Action.SUCCESS;

我做的第二个动作:

System.out.println("From session: "+ActionContext.getContext().getSession().get("counter"));
System.out.println("Actual:"+ HitCounter.getAtomicCounter());
return Action.SUCCESS;

我看到的输出(这真让我发疯):

From session: 2 
Actual: 69352

经过一段时间后,我只在我的浏览器中使用此Fitst操作/第二个操作,并且没有并发请求(由我的加载实用程序生成),结果“稳定”到实际值。因此,我有并发问题。

我是否应该使用标准方法来避免Struts2中的并发问题?

P.S。 HitCounter是线程安全的,因为它只包含一个字段,而且它是AtomicInteger。

P.P.S。 HitCounter实现:

public class HitCounter {
    private static AtomicInteger counter = new AtomicInteger(0);

    public static void increment() {
        counter.incrementAndGet();
    }
    public static int getAtomicCounter() {
        return counter.get();
    }
}

P.P.P.S。我删除了Thread.yield();但它没有帮助。 :(

2 个答案:

答案 0 :(得分:1)

Struts2操作是线程安全的,因为它们使用线程本地存储...即存在从变量到值的每线程映射。因此,没有共享的可变性 状态,不需要同步。

但是,会话等资源不能以这种方式处理,因此必须注意并发访问。此问题讨论了这些问题:Using request.getSession() as a locking object?

根据这个问题: Is HttpSession thread safe, are set/get Attribute thread safe operations? servlet规范声明以下是线程安全的:request.getSession().setAttribute("foo", 1);

但请注意,上面的请求是一个HttpServletRequest,它反过来派生一个HttpSession对象,这个对象不仅仅是Struts2返回的一个map ...这意味着struts2版本必须被包装,因此可能不会遵守规范。因此,我们可以实现ServletRequestAware,它为我们提供了一个HttpServletRequest对象,我们可以从中派生出一个HttpSession。但是,正如先前的问题所指出的那样,这一行不会对我们有太多帮助,因此实施HttpServletRequest将浪费时间。看起来所做的就是让我想知道Struts2如何协调它为会话返回的Map和一个没有实现Map的HttpSession,它甚至没有一个返回地图的方法......

那么让我们考虑一下目前可能发生的事情......

line1: hitCounter.increment();
line2: ActionContext.getContext().getSession().put("counter", hitCounter.getAtomicCounter());

第1行:我们增加一些全局的hitCounter对象。

第2a行:我们得到了hitCounter对象的副本(int作为返回类型)。

第2b行:我们在Session中设置了hitCounter值。

由于HitCounter的线程安全性,我们知道第1行总是很好......但是对于line2呢?我们可以看到有两个部分,如果线程在获取hitCournter副本和设置hitCounter之间被暂停,那么将会出现竞争条件......从这一点开始执行的最后一个线程将获胜。

一种方法是将AtomicInteger放入自己的会话中,这可以避免副本滑入的问题。

答案 1 :(得分:0)

您没有在第二个操作中检索HitCounter。

System.out.println("From session: "+ActionContext.getContext().getSession().get("counter"));

上面的行只是打印对象。您的代码中是否缺少某些内容?