0

ThreadPoolExecutorのようなものを使用して、使用可能なスレッドで一連のタスクを実行することを管理したいと思います。これらのタスクはすべて同じタイプですが、異なるアカウントを処理します。これらのアカウントの新しいタスクは定期的に追加できます。同じアカウントの古いタスクが完了するまで、新しいタスクをチェックして開始できないようにします。これを行うための最良の方法は何ですか?

  1. アカウント「234」のタスクが開始されます(ThreadPoolExecutor.execute()を介して)

  2. アカウント「238」のタスクが開始されます(ThreadPoolExecutor.execute()を介して)

  3. アカウント「234」の新しいタスクが作成されましたが、最初の「234」タスクが完了していないため、実行するために追加されていません(これを確認する最良の方法は?)

  4. アカウント「238」のタスクが完了します

  5. アカウント「238」の新しいタスクが開始されます(ThreadPoolExecutor.execute()を介して)。これは、そのアカウントで現在実行されているタスクがないためです。

これを行うための最良の方法は何ですか?「234」の最初のタスクが終了するまで、Runnableのチェック変数をwait / sleep()でチェックするだけですか?または、より良い解決策はありますか?

4

3 に答える 3

1

APIのこの部分の経験が豊富な人がより良いアイデアを持っていることは間違いありませんが、これがこのテーマに関する私の考えです...

基本的に、私は「実行中」と「待機中」のキューから始めます。「実行中」のキューは現在実行中のタスクを追跡し、「待機中」のキューは保留しているタスクを追跡します。Map<String, List<Runnable>これらのキューは、アカウント番号などの検索を容易にするために、ある種の「グループ識別子」にキー設定する必要があります。

メソッドをオーバーライドすることを検討しますexecute。ここでは、着信タスクを実行中のキューと比較して、関連するタスクが現在実行されているかどうかを判断します。ある場合は、新しいタスクを待機キューにドロップします。

次に、メソッドをオーバーライドしますbeforeExecute。ここでは、タスクを「実行中」のキューに登録します。

'afterExecute'メソッドをオーバーライドします。ここでは、完了したタスクを「実行中」のキューから削除し、待機中のタスクのキューを(完了したタスクのグループ識別子を介して)検索し、キュー内の最初のタスクをexecuteメソッドを介してエグゼキューターに追加します。

または、ルイが示唆するように行うことができます:P

于 2012-08-17T01:16:53.877 に答える
1

1つの単純な可能性。単純すぎるのかもしれません。10 個の SingleThreadedExecutor を作成します。タスクごとに

  1. accountID mod 10 を取得して accountID を「ハッシュ」し、適切な SingleThreadedExecutor を見つけます。(実際には、accountID は int ではない場合があります。たとえば、文字列の場合は、hashCode() mod 10 を取ります)。
  2. タスクをその SingleThreadedExecutor に送信します。

アカウント 238 の処理は 358 が完了するまで待機する必要があるため、これは理想的ではないかもしれませんが、少なくとも、特定のアカウント (たとえば 234) が同時に実行されることは決してないと確信できます。許容できるレイテンシーの量によって異なります。明らかに、Executor の数と、私が説明した単純な "ハッシュ" アルゴリズムで遊ぶことができます。

于 2012-08-17T02:54:54.237 に答える
1

私は同じ問題に直面しました。私の解決策は、HashSet を使用することでした。

private static HashSet<Integer> runningTasks = new HashSet();

public void run(){
  boolean isAlreadyRunning = false;
  synchronized (runningTasks) {
    if (runningTasks.contains(this.accountId)) {
      isAlreadyRunning = true;
    } else {
      runningTasks.add(this.accountId);
    }
  }
  if(isAlreadyRunning){
    //schedule this task to run later here
    //what I did was to reinsert this task to the task queue 5 seconds later
    return;
  }
  //do your stuffs here

  synchronized (runningTasks) {
    runningTasks.remove(this.accountId);
  }
}
于 2012-08-17T03:32:50.723 に答える