1

Web 解析ページの EJB ステートレス メソッドを呼び出すステートフル EJB があります。

これが私のステートフルコードです:

@Override
public void parse() {
    while(true) {
        if(false == _activeMode) {
            break;
        }
        for(String url : _urls){
            if(false == _activeMode) {
                break;
            }
            for(String prioritaryUrl : _prioritaryUrls) {
                if(false == _activeMode)
                    break;
                boursoramaStateless.parseUrl(prioritaryUrl);
            }

            boursoramaStateless.parseUrl(url);
        }
    }
}

ここでは問題ありません。

_urls 変数 (リスト) に何らかの値を追加する非同期呼び出し (JMS を使用) があります。目標は、無限ループ内で新しい URL を解析することです。

JMS onMessage メソッドを介してリストに新しい URL を追加しようとすると ConcurrentModificationException を受け取りますが、この新しい URL が解析されるため、機能しているようです。

同期ブロックをラップしようとすると:

while(true){
    synchronized(_url){
        // code...
    }
}

私の新しい URL は決して解析されません。for() ループが終了した後に解析されることを期待していました...

だから私の質問は: ConcurrentModificationException を使わずに、ループ内でアクセスされたときに List を変更するにはどうすればよいですか?

同期ブロックなしで、2 つのスレッドで共有リソースを同時に変更したいだけです...

4

4 に答える 4

1

が必要な場合がありCopyOnWriteArrayListます。

于 2012-09-24T12:37:24.107 に答える
0

synchronizedまず、 JavaEEコンテナを実行するときは忘れてください。コンテナを煩わせてスレッドの使用率を最適化し、クラスター環境では機能しません。

第二に、あなたのデザインが間違っているようです。JMSを使用してBeanのプライベートフィールドを更新しないでください。このことはを引き起こしConcurrentModificationExceptionます。おそらく、Beanを変更してデータベースからコレクションを取得し、MDBを変更してURLをデータベースに格納する必要があります。

他の、あなたにとってより簡単な解決策は次のとおりです。現在存在するURLを取得し、それらを他のコレクションにコピーします。次に、このコレクションを繰り返し処理します。グローバルコレクションがJMSを介して更新される場合、更新はコピーされたコレクションに表示されないため、例外はスローされません。

while(true) {
    for (String url : copyUrls(_prioritaryUrls)) {
       // deal with url
    }
}

private List<String> copyUrls(List<Stirng> urls) {
    return new ArrayList<String>(urls); // this create copy of the source list
}


//........
public void onMessage(Message message) {
    _prioritaryUrls.add(((TextMessage)message).getText());
}
于 2012-09-24T12:43:07.737 に答える
0

For (String s : urls)内部で Iterator を使用します。イテレータは、その動作が適切に定義されるように、同時変更をチェックします。

for(int i= ...ループを使用できます。このように、例外はスローされず、要素がリストの最後にのみ追加された場合でも、一貫したスナップショット (反復中のある時点で存在するリスト) を取得できます。リスト内の要素が移動すると、エントリが欠落する可能性があります。

を使用する場合はsynchronised、両端で同期する必要がありますが、そうすると同時読み取りが失われます。

同時アクセスと一貫したスナップショットが必要な場合は、java.util.concurrentパッケージ内の任意のコレクションを使用できます。 CopyOnWriteArrayListすでに言及されています。他に興味深いのはLinkedBlockingQueueand ArrayBlockingQueue( Collections であり s ではないList) ですが、それだけです。

于 2012-09-24T12:54:20.227 に答える
0

わかりました、ありがとうございます。

そこで、いくつかの変更を加えました。

1)イテレータを追加し、同期ブロックを残しました(parse()関数内とリストに新しいURLを追加するaddUrl()関数の周り)->それは魅力のように機能し、ConcurrentModificationExceptionは起動されませんでした

2) イテレータを追加し、同期ブロックを削除 --> ConcurrentModificationException がまだ起動されている...

今のところ、私はあなたの答えについてもっと読んで、あなたの解決策をテストします.

ありがとうございました

于 2012-09-24T13:14:54.647 に答える