1

いくつか問題があります。

たとえば、First と Second という 2 つのアクションがあります。

executor サービスを使用して 100000 の非同期リクエストを action First と actions Second に送信する簡単なユーティリティを作成しました。

最初のアクションでは、次のことを行います。

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

2番目のアクションでは、次のことを行います。

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 アクション/Second アクションをブラウザからのみ使用し、同時要求が来ない (負荷ユーティリティによって生成された) しばらくすると、結果は実際の値に「安定」します。したがって、同時実行の問題があります。

Struts2 での同時実行性の問題を回避するために使用すべき標準的な方法はありますか?

PS HitCounter は、フィールドが 1 つしかなく、AtomicInteger であるため、スレッド セーフです。

PPS HitCounter の実現:

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

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

PPPS Thread.yield(); を削除しました。しかし、それは役に立ちませんでした。:(

4

2 に答える 2

1

Struts2アクションは、スレッドローカルストレージを使用するという点でスレッドセーフです...つまり、変数から値へのスレッドごとのマップがあります。したがって、共有された可変状態はなく、同期は必要ありません。

ただし、セッションなどのリソースはこのように扱うことができないため、同時アクセスには注意が必要です。この質問では、これらの問題について説明します。request.getSession()をロックオブジェクトとして使用しますか?

この質問によると: HttpSessionスレッドは安全ですか、属性スレッドの設定/取得は安全な操作ですか?サーブレットの仕様では、以下がスレッドセーフであると規定されています。request.getSession().setAttribute("foo", 1);

ただし、上記のリクエストはHttpSessionオブジェクトを派生させるHttpServletRequestであることに注意してください。このオブジェクトは、Struts2によって返される単なるマップではありません...つまり、struts2バージョンをラップする必要があるため、仕様に準拠していない可能性があります。そのため、HttpSessionを派生させることができるHttpServletRequestオブジェクトを提供するServletRequestAwareを実装できます。しかし、前の質問が指摘しているように、その1行はあまり役に立たないため、HttpServletRequestの実装は時間の無駄になります。Struts2が、セッションに対して返すMapを、Mapを実装していないHttpSessionとどのように調整するのか、また、マップを返すメソッドさえないのか、不思議に思います。

それでは、現在何が起こっているのかを考えてみましょう...

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

1行目:グローバルhitCounterオブジェクトをインクリメントします。

2a行目:hitCounterオブジェクトのコピーを取得します(戻り型としてint)。

2b行目:セッションでhitCounter値を設定します。

HitCounterのスレッドセーフな性質により、1行目は常に適切であることがわかっています...しかし、2行目はどうでしょうか。hitCournterコピーの取得とhitCounterの設定の間にスレッドが中断された場合、競合状態が発生するという2つの部分があることがわかります...この時点から実行される最後のスレッドが勝ちます。

1つの方法は、AtomicIntegerをそれ自体のセッションに配置することです。これにより、コピーがスリップインする問題を回避できます。

于 2012-04-25T09:41:48.180 に答える
0

2番目のアクションではHitCounterを取得していません。

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

上記の行は、単にオブジェクトを印刷します。コードに欠けているものはありますか?

于 2012-04-25T06:45:18.157 に答える