8

私の考案した例では、teamMembersのリストに関してスレッドセーフにどのような影響がありますか?

メソッドから見たリストの状態にrun()一貫性があると信頼できますか?

仮定

  1. このメソッドは、 BeansetATeamMembersを作成している春までに一度だけ呼び出されます。ATeamEpisode

  2. メソッドは、init#1の後にspring(init-method)によって呼び出されます

  3. クラスはATeamMember不変です

    • teamMembers volatileまたは同様のものを宣言する必要がありますか?

    • 私が見落としているこのアプローチに関する他の恐ろしい問題はありますか?

これが明らかな場合はお詫び、またはrtfmの明らかな失敗

ありがとう、よろしく

エド

package aTeam;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class ATeamEpisode implements Runnable{

    private List<ATeamMember> teamMembers;

    /* DI by spring */
    public void setATeamMembers(List<ATeamMember> teamMembers){
        this.teamMembers = new ArrayList<ATeamMember>(teamMembers);    
    }

    private Thread skirmishThread;

    public synchronized void init(){
        System.out.println("Starting skirmish");
        destroy();
        (skirmishThread = new Thread(this,"SkirmishThread")).start();
    }
    public synchronized void destroy(){
        if (skirmishThread != null){
            skirmishThread.interrupt();
            skirmishThread=null;
        }
    }

    private void firesWildlyIntoTheAir(ATeamMember teamMember){
        System.out.println(teamMember.getName()+" sprays the sky..");
    }

    @Override
    public void run() {
        try {
            Random rnd = new Random();
            while(! Thread.interrupted()){
                firesWildlyIntoTheAir(teamMembers.get(rnd.nextInt(teamMembers.size())));
                Thread.sleep(1000 * rnd.nextInt(5));
            }
        } catch (InterruptedException e) {
            System.out.println("End of skirmish");
            /* edit as per Adam's suggestion */
           // Thread.currentThread().interrupt();
        }
    }
}
4

2 に答える 2

5

あなたが言うように、setATeamMembers が 1 回だけ呼び出され、コードの他の部分がこのコレクションを置き換えない場合、それを揮発性にする意味はありません。揮発性は、メンバーが異なるスレッドによって書き込まれる可能性があることを示します。

コードのどの部分もこのコレクションを更新していないように見えることを考慮すると、たとえば Collections.unmodifiableList() を使用して、コレクションを明示的にunmodifiableにすることを検討することをお勧めします。これにより、このコレクションは変更されず、とにかく変更しようとすると大きな例外が発生することが、あなたや他の人に明らかになります。

Spring の遅延初期化は、AFAIR、スレッドセーフです。

于 2012-10-08T12:06:25.927 に答える
3

多分。インターフェース自体Listはスレッドセーフではなく、何をしてもコンシューマー側でスレッドセーフにすることはできません。

必要なことは、スレッド セーフ リスト (Java ランタイムにはいくつかの実装があります) を作成し、そのうちの 1 つをteamMembersBean に使用することです。

teamMembers他のスレッドは新しいインスタンスを作成せず、Bean の状態(つまり、内部のデータ)を変更するため、フィールドを介して Bean にアクセスすることは問題ではありませんteamMembers

そのため、Bean は内部構造への変更が正しく同期されていることを確認する必要があります。

あなたの場合、リストからランダムな要素を返す特別なリストの実装が必要になります。なんで?が呼び出されたときに の値teamMembers.size()が変更されている可能性があるためです。teamMembers.get()

これを実現する簡単な方法は、すべてのメソッド呼び出しをこのコードでラップすることです。

 synchronized(teamMembers) { ... }

しかし、あなたは本当にそれらすべてを捕まえたことを確信しなければなりません. これを実現する最も簡単な方法は、上で述べたように、必要なすべての特別なメソッドを提供する独自のリストを作成することです。そうすれば、必要に応じてロックまたはsynchronizedメソッド内で使用できます。

于 2012-10-08T12:08:29.390 に答える