2012-02-27 14 views
1

私はクライアントサーバースタイルの設計をしています。私がやったことは、RequestControllerというクラスを作成して、スレッド化されたオブジェクトとして行われたすべてのサーバー要求を制御および監視することです。同期リストから要素を削除する適切な方法

これらのリクエストスレッドは、同期MapCollections.synchronizedMap(new HashMap<Long, RequestThread>())で作成)で追跡されます。各要求スレッドは、各要求スレッドがチェックされ、まだ存続している場合は、完了したか失敗したかを、関心のあるリスナオブジェクト(要求スレッドの属性)に進捗メッセージを送信し、関心のあるリスナに通知し、同期Mapそのrun()メソッドが完了したとき。

私が各リクエストを追跡するために使用するRequestThreadオブジェクトは、すべてのリクエストを監視しているRequestControllerオブジェクトの保護された内部クラスです。したがって、それを含むマップにアクセスできます。

ここで問題が発生しています。 「デッドスレッド」がマップから削除されると、同時変更例外が発生します。地図への私のすべてのアクセスは同期されるので、私は例外をどのように得ることができるのか分かりません。

this.reqTimer = new Timer("Request Timer", true); 
TimerTask reqTask = new TimerTask() 
{ 
    @Override 
    public void run() 
    { 
     synchronized(reqList) 
     { 
      for(RequestThread rt : reqList.values()) 
       rt.updateProgress(); 
     } 
    } 
}; 
this.reqTimer.scheduleAtFixedRate(reqTask, 500L, 500L); 

そう等マップからそれ自体を除去するRequestControllerメソッドへの呼び出しがあるRequestThread.run()方法の最後に:

public void removeRequest(long id) 
    { 
     synchronized(this.reqList) 
     { 
      this.reqList.remove(id); 
     } 
    } 

それはここ

は、制御ループコードでありますTimerTask.run()メソッドがupdateProgress()メソッドを呼び出す要求のマップをループしている間にRequestThread.run()が完了すると、removeはブロックされずにマップとcを変更することができます私の例外を使用します。 2つの異なるスレッドは、同じオブジェクトに対して同時にどのようにロックを取得できますか?更新が完了するまで、別のスレッドで削除が開始されたため、削除をブロックしないでください。

+0

例外はありますか? –

+0

第1のスニペットの 'reqList'と第2の' this.reqList'は同じオブジェクトを参照しています。それを明確にするためにコードが十分に示されていません。 –

+0

Tom Hawtin - ConcurrentModificationException – BigMac66

答えて

2

私は答えに答えをつけるつもりです。

2つの異なるスレッドが同じオブジェクトに対して同時にロックを取得するにはどうすればよいですか?

これはできません。並行変更は他の場所になければなりません。私はあなたのupdateProgress()がリストから削除を行っていると思われます。これは、同時変更例外が発生している場所である可能性があります。

for (RequestThread rt : reqList.values()) { 
    // you can't make any changes to reqList inside of the loop 
    rt.updateProgress(); 
} 

リストからの要求を削除updateProgress()を持っている必要があるなら、あなたは可能性が次のいずれか

  • はそれがiterator.remove()を呼び出すことができますイテレータを使用してupdateProgress()へのイテレータを渡します。
  • List<RequestThread>updateProgress()を渡し、削除するリクエストを追加します。その後、forループの外にいれば(しかし、まだ同期ブロック内にある)、削除リスト内の項目をreqListから削除できます。
+0

これは私が実際にしたことに最も近いものでした。私は単にリストからスレッドを削除することをやめ、run()メソッドを終了させました。私はまた、提案されたIteratorに切り替え、各updateProgress()がスレッドがまだ生存していたかどうかを確認した後、Iteratorのスレッドセーフなremove()メソッドを使用しました。 – BigMac66

2

あなたのいずれかがリスト全体で繰り返し処理を後に削除を実行する必要があります -

synchronized (reqList) { 
    // Keep track of items to be removed. 
    List<RequestThread> remove = new LinkedList<RequestThread>(); 
    for (RequestThread rt : reqList.values()) { 
     rt.updateProgress(remove); 
    } 
    // Remove them. 
    reqList.removeAll(remove); 
    } 

か、Iteratorを使用し、そのremoveメソッドを使用する必要があります。

関連する問題