0

私のアプリケーションには、「N」個の製品を見積もりに関連付けることができるという要件があります。画面レイアウトには 2 つの部分があります。上部には見積もり関連の情報を含むフォームがあり、下部には複数の製品を保持するためのものです。下部に iframe を配置することで、この機能を実装しました。商品の追加・削除はボタンクリック(javascript使用)で行います。すべての製品ウィンドウ内に表示されるコンテンツは、同じアクション (ProductLinesAction.java)、JSP (ProductLines.jsp)、およびその他の関連リソースによってレンダリングされます。ここでのポイントは、新しい製品ウィンドウが画面に読み込まれるたびに、その Action クラスの複数のインスタンスが作成されることです。表示するフォームを準備するだけなので、ウィンドウの読み込みに問題はありません。見積もりを保存する間、これらのすべての製品フォームが送信され、私が組み込んだロジックは、1 対 N-1 のアクション インスタンスがフォーム値を VO に配置し、Vector オブジェクトに追加されてセッションに保存されるというものです (他のアクション インスタンスが取得できるようにするため)。セッションから、その上に追加します)。N 番目のアクション インスタンスは、これらすべての製品値をまとめて保存するためのものです。ビジネス ルールの検証も保存の直前に実行されるため、N 番目のアクション インスタンスが使用可能になり、すべての製品ウィンドウにエラーが表示されます。N 番目のアクション インスタンスは、これらすべての製品値をまとめて保存するためのものです。ビジネス ルールの検証も保存の直前に実行されるため、N 番目のアクション インスタンスが使用可能になり、すべての製品ウィンドウにエラーが表示されます。N 番目のアクション インスタンスは、これらすべての製品値をまとめて保存するためのものです。ビジネス ルールの検証も保存の直前に実行されるため、N 番目のアクション インスタンスが使用可能になり、すべての製品ウィンドウにエラーが表示されます。

他のすべてのアクション インスタンスもそのウィンドウに対応するエラーを確実に利用できるようにするために、6 つを超える製品を保存しようとするとうまくいかない wait および notifyAll メカニズムを実装しました。コードを以下に示します。このコードは、製品数が 6 以下 (つまり、最大 6 つのアクション インスタンス) の場合に問題なく機能します。7 番目の製品をロードして保存すると、7 番目のインスタンスはデバッグ モードでまったく表示されず、追跡できません (インスタンスは、フォームの送信時に意図したメソッドに到達しません)。

この問題の原因である、ここで犯された間違いに誰かが光を当てることができますか.

public String submitProducts()
        throws Exception {

    String resultValue = "";
    /* Algorithm: */
    // 1. Read the Vector object from Session.
    // 2. Check whether the size of the Vector matches the Total Product windows count.
    // 3. If yes, call the Save operation and remove the list from session.
    // 4. If not, copy the values from current Action instance to VO.
    // 5. Add to List object and place in session.

    synchronized (productVOsInVector) {
        productVOsInVector = getProductVOVectorFromSession();
        if (productVOsInVector == null) {
            productVOsInVector = new Vector <ProductVO>();
        }
        log.info("Window Number is " + activeWindowNumber + ". List size is " + productVOsInVector.size());
        if (productVOsInVector.size() == (prodWindowCount - 1)) {
            productVOsInVector = mapActionToVO(productVOsInVector);
            resultValue = saveOperation(productVOsInVector);
            if (resultValue.equalsIgnoreCase(SUCCESS)) {
                session.put("OperationStatus", SUCCESS);
            }
            session.remove("productVOMapData");
        }
        else {
            if (quoteSaveStatus) {
                quoteSaveStatus = false;
            }
            session.put("OperationStatus", "");
            productVOsInVector = mapActionToVO(productVOsInVector);
            session.put("productVOMapData", productVOsInVector);
        }
        waitForOperationStatus();
    }
    System.out.println("Came out of sync block");
    System.out.println("Action Instance" + activeWindowNumber + " is resuming.");
    // Code to display the Error messages
    return resultValue;
}

public void waitForOperationStatus() {

    String opStatus = getOperationStatusFromSession();
    synchronized (productVOsInVector) {
        if (!opStatus.equalsIgnoreCase(SUCCESS)) {
            try {
                System.out.println("Window # " + activeWindowNumber + " Waiting");
                productVOsInVector.wait();                  
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
            opStatus = getOperationStatusFromSession();
        }
        productVOsInVector.notifyAll();
    }
}
4

1 に答える 1

5

以下は、それ自体、すでに深刻な問題です。

synchronized (productVOsInVector) {
    productVOsInVector = getProductVOVectorFromSession();
    if (productVOsInVector == null) {
        productVOsInVector = new Vector <ProductVO>();
    }
    ...
}

によって参照されるオブジェクトで同期しておりproductVOsInVector、すぐに別のオブジェクトへの参照ポイントを作成します。したがって、次のスレッドは最初のスレッドとは異なるオブジェクトで同期します。

次に、このオブジェクトを待っています。誰かがあなたに通知することを期待します。

それ以上の分析はしていませんが、設計に深刻な問題があります。そもそもサーブレットコンテナのスレッド間で同期するべきではありません。プールにスレッドが6つしかなく、7つ目のスレッドが完了するのをすべて待機している場合は、デッドロックが発生します。プールに12のスレッドがあり、2つのクライアントが同時にそれを行う場合、デッドロックも発生します。また、デッドロックがない場合でも、いくつかのスレッドを使用不可にし、後続のHTTPリクエストがそれらに通知することを期待して待機するだけです。なんらかの理由で最後のリクエストが届かない場合(たとえば、ユーザーがブラウザを強制終了した場合、6つのスレッドが永久にブロックされます。

したがって、私のアドバイスは次のとおりです。スレッドを台無しにしないでください。別の方法を見つけてください。

于 2012-09-25T12:36:28.433 に答える