0

パーティー全体に属するArrayListからのジョブに必要なアーティファクトをチェックイン/アウトするパーティーのキャラクターをシミュレートするプログラムを作成しています。私のクリーチャーがアイテムをパーティの ArrayList にドロップし、それを反復処理して正しいアーティファクトを探した後、同時変更例外が発生します。

これが私の流れです。最初は、すべてのキャラクターがアーティファクトのランダムな組み合わせで作成されます。ジョブを実行すると、アーティファクトの量が正しいかどうかがチェックされます。もしそうなら、それは仕事をし、それが持っているすべてのアーティファクトをパーティーArrayListに解放します。そうでない場合は、パーティの ArrayList を使用する機会を待ち、機会があればすべての項目をそこにドロップして、正しい項目を反復処理します。

注:一度に 1 つのクリーチャーのみがパーティの ArrayList と対話できます

これは、すべてのスレッドが連携していることを確認するために、スレッド自体にある私のコードです。

 boolean ready = target.hasReqArtifacts( reqStones, reqPotions, reqWands, reqWeapons );
    //checks to see if creature already has correct amount of each item
    while ( !ready ) {//begin pool interaction
        synchronized ( target.poolParty ){
            while ( target.poolParty.busyPool ) {//busyPool is initialized false
                startJob.setEnabled( false );
                startJob.setText( "Waiting for Pool");
                try {
                    target.wait();
                } catch ( InterruptedException e ) {}
            }
            synchronized ( target.poolParty ) {
                target.poolParty.busyPool = true;
                target.poolParty.notifyAll();//notify all threads that they need to wait because this one will proceed
            }
        }
        target.releaseArtifacts();// adds all artifacts held by creature to an arraylist in poolParty
                                  //then clears the creatures inventory
        target.pickUpArtifacts( reqStones, reqPotions, reqWands, reqWeapons );
        //Searches through poolParty's ArrayList of artifacts for required artifacts

        ready = target.hasReqArtifacts( reqStones, reqPotions, reqWands, reqWeapons );
        if ( ready ) {
            synchronized ( target.poolParty ) {
                target.poolParty.busyPool = false;
                target.poolParty.notify();
            }
        } else {
            synchronized ( target.poolParty ) {
                target.poolParty.busyPool = false;
                target.releaseArtifacts();
                target.poolParty.notify();
            }
        }
    }//end pool interaction

「releaseArtifacts」を呼び出した後に「pickUpArtifacts」メソッドを呼び出すと、コードが壊れます。以下は私のメソッド pickUpArtifacts です。

public void pickUpArtifacts ( int stones, int potions, int wands, int weapons ){
    hasReqArtifacts( stones, potions, wands, weapons );
    String                              theType;

    if ( !poolParty.resourcePool.isEmpty() ) {//itterate through whole pool to see if it can get needed items
        for ( Artifact a : poolParty.resourcePool ) {//This is where the code breaks
            theType =                     a.getType();
            if ( theType.equals( "Stone" ) && ( curStones < stones )) {
                addArtifact( a );
                poolParty.resourcePool.remove( a );
            } else if ( theType.equals( "Potion" ) &&  ( curPotions < potions ) ) {
                addArtifact( a );
                poolParty.resourcePool.remove( a );
            } else if ( theType.equals( "Wand" ) && ( curWands < wands )) {
                addArtifact( a );
                poolParty.resourcePool.remove( a );
            } else if ( theType.equals( "Weapon" ) && ( curWeapons < weapons )) {
                addArtifact( a );
                poolParty.resourcePool.remove( a );
            }
        }
    }
    hasReqArtifacts( stones, potions, wands, weapons );
}

最初は、ロックを使用して同期を試みていました。これは同じエラーをスローすることになったので、スレッドを強制終了するために使用するものと同様のブール値フラグを使用して同期コードでアプローチしました。その後、コードが実行されていた場所を正確に微調整して、反復中に ArrayList を操作しないようにしました。

以前と同じエラーをスローし続けます。同じプロセスで壊れることさえあります。何が悪いのか理解できないようです。

4

2 に答える 2

2

反復処理中にコレクションを変更することはできません。この場合、複数のスレッドとは関係ありません。

ここでコレクションを繰り返し処理していることに注意してください

for ( Artifact a : poolParty.resourcePool )

次に、 for ブロック内で、同じコレクションから削除しようとします

poolParty.resourcePool.remove( a );

この場合、List から効果的に削除するには、Iteratorおよび Iteratorsremoveメソッドを使用します。

于 2013-07-26T19:54:55.753 に答える
-1

リストを作成するときは、おそらく次のコードを使用する必要があります。

List yourList = Collections.synchronizedList(new ArrayList())

(同期ブロック/メソッド内)

于 2013-07-26T19:46:21.180 に答える