Javaコンテナは、フェイルセーフイテレータを提供しています
質問
ここに私の問題は、次のとおりです。
このデータ構造のためにjava.util.ConcurrentModificationException
が存在しながらVector
のlisteners
が変更されるので、は、コードのこの部分は、Iterator
をスロー。
Javaの-docのは、唯一のフェイルファスト反復子このコンテナの提供と言っています。
JavaでIterator
またはVector
などの標準コンテナの上にList
を取得する可能性があることを申し出、私Iterator
、不正な取得していないこと(フェイルファストされていない)、そのIterator
時に除去要素がある場合には、「命 "?
私はC ++でstd::list
のように同じ動作をしなければなりません。そこイテレータは、現在のイテレータが削除された場合でも、常に有効です。イテレータは、リスト内の次の要素に設定されているよります。
public class ClientHandle {
private final Vector<ClientHandleListener> listeners = new Vector<ClientHandleListener>();
public synchronized void addListener(ClientHandleListener chl) {
listeners.add(chl);
}
public synchronized void removeListener(ClientHandleListener chl) {
listeners.remove(chl);
}
private void fireConnectionClosed() {
final ClientHandle c = this;
final Iterator<ClientHandleListener> it = listeners.iterator();
new Thread(){
@Override
public void run() {
while (it.hasNext()) {
it.next().connectionClosed(c); //FIXME the iterator gets modified
}
};
}.start();
}}
public class ClientHandlePool implements ClientHandleListener, TaskManagerListener {
/*...*/
public synchronized void removeClientHandle(ClientHandle ch) {
//here the listeners Vector from the ClientHandle gets modified
ch.removeListener(this);
ch.removeListener(currentListener);
clientHandles.remove(ch);
}
@Override
public void connectionClosed(ClientHandle ch) {
removeClientHandle(ch);
}
}
解決
私の知る限りでは遡及的に任意のデフォルトのCollection
の実装(実際にはIterable
)にその機能を追加する方法はありません。
しかし、実装があることを反復しながら、同時変更に明確に定義された応答を持つことにより、行動の支援そういうます。
一例は CopyOnWriteList
。
他のヒント
リスナーの場合は、あなたは、通常より多くの書き込みより読み込みの方法を持っているようjava.util.concurrent.CopyOnWriteArrayList
を使用して考えるかもしれません。
あなたはあなたが必要なすべてを見つけるでしょうjava.util.concurrentパッケージを見てます。
の高速を作成するための怠惰な方法は、フェイルセーフのイテレータ:ロックを解除しながら、アレイの上にロックされている間配列としてリストのコピーを取り、foreachの()を... <リストの任意のタイプで行うことができます/ P>
private void fireConnectionClosed() {
final ClientHandle c = this;
final ClientHandleListener[] listenersArr;
synchronized(this) {
listenersArr=listeners.toArray(new ClientHandleListener[0]);
}
new Thread(){
@Override
public void run() {
for(ClientHandleListener listener : listenersArr )
listener.connectionClosed(c);
}
};
}.start();
}