6

シングルトンのオブジェクトがあります。このオブジェクトは次を宣言します。

List<Player> players = new ArrayList<Player>();

同じオブジェクトは、この arrayList で 4 つの操作も指定します。

public List<Player> getPlayers() {
return players;
} // the result of this method can be used in another object as an iterator (or maybe by index-access)

public void removePlayer(Player player) {
players.remove(player);
}

public void addPlayer(Player player) {
players.add(player);
}

public boolean isPresent(Player player) {
if (players.constans(player)) {...
}

現在、コンストラクターで次のようにしています。

players = Collections.synchronizedList(new ArrayList<Player>());

しかし、これらのメソッドを同期する正しい方法は何ですか? 別のクラスでイテレータを使用すると、同時変更例外が発生するようです。2 つのスレッドが「remove」メソッドと「contains」メソッドを同時に呼び出すと例外が発生しますか? シングルトンにアクセスするスレッドが多いので、パフォーマンスへの影響を最小限に抑えてこれを行う方法を知りたいです。

4

2 に答える 2

15

ドキュメントはあなたの質問に答えます。

ユーザーは、返されたリストを反復処理するときに手動で同期することが不可欠です。

List list = Collections.synchronizedList(new ArrayList());
      ...
  synchronized(list) {
      Iterator i = list.iterator(); // Must be in synchronized block
      while (i.hasNext())
          foo(i.next());
  }

containsとに関してはremove、手動で同期する必要はありません。私はのソースコードを見ていますがCollections、それはあなたのためにそれを行うようです:

    public boolean contains(Object o) {
        synchronized (mutex) {return c.contains(o);}
    }
    public boolean remove(Object o) {
        synchronized (mutex) {return c.remove(o);}
    }

自分でこのようなことをしなければならない場合、同期リストにはなりません。

于 2013-07-10T18:34:29.913 に答える
6

更新する予定がない場合は、CopyOnWriteArrayListを使用することがよくあります。それ以外の場合は、@tieTYT の提案が機能します。

内の実際のリストの代わりにリストのコピーを返すことで、これを自分で管理することもできますgetPlayers。( を使用している場合Collections.synchronizedList)

public List<Player> getPlayers(){
    synchronized(list){
       Collections.unmodifiableList(new ArrayList<Player>(list));
    }
}

これには、追加/削除が行われた後にリストが古くなるという副作用があります

編集: Grzegorzの提案を盗むunmodifiableList

于 2013-07-10T18:38:30.067 に答える