以下を実装する最も簡単で簡単な方法を探しています。
- メイン プログラムは、ワーカー スレッドをインスタンス化してタスクを実行します。
n
一度に実行できるのはタスクのみです。- に
n
達すると、実行中のスレッドの数が を下回るまでワーカーは開始されませんn
。
以下を実装する最も簡単で簡単な方法を探しています。
n
一度に実行できるのはタスクのみです。n
達すると、実行中のスレッドの数が を下回るまでワーカーは開始されませんn
。Executors.newFixedThreadPoolが要件に合っていると思います。結果の ExecutorService を使用するには、結果をメイン スレッドに返すかどうか、タスクが完全に自己完結型かどうか、事前に実行するタスクのコレクションがあるかどうかに応じて、さまざまな方法があります。何らかのイベントに応答してタスクがキューに入れられるかどうか。
Collection<YourTask> tasks = new ArrayList<YourTask>();
YourTask yt1 = new YourTask();
...
tasks.add(yt1);
...
ExecutorService exec = Executors.newFixedThreadPool(5);
List<Future<YourResultType>> results = exec.invokeAll(tasks);
または、何らかのイベントに応答して実行する新しい非同期タスクがある場合は、ExecutorService の単純なexecute(Runnable)
メソッドを使用したいだけでしょう。
/* Get an executor service that will run a maximum of 5 threads at a time: */
ExecutorService exec = Executors.newFixedThreadPool(5);
/* For all the 100 tasks to be done altogether... */
for (int i = 0; i < 100; i++) {
/* ...execute the task to run concurrently as a runnable: */
exec.execute(new Runnable() {
public void run() {
/* do the work to be done in its own thread */
System.out.println("Running in: " + Thread.currentThread());
}
});
}
/* Tell the executor that after these 100 steps above, we will be done: */
exec.shutdown();
try {
/* The tasks are now running concurrently. We wait until all work is done,
* with a timeout of 50 seconds: */
boolean b = exec.awaitTermination(50, TimeUnit.SECONDS);
/* If the execution timed out, false is returned: */
System.out.println("All done: " + b);
} catch (InterruptedException e) { e.printStackTrace(); }
Executors.newFixedThreadPool(int)
Executor executor = Executors.newFixedThreadPool(n);
Runnable runnable = new Runnable() {
public void run() {
// do your thing here
}
}
executor.execute(runnable);
Executor フレームワークを使用します。すなわちnewFixedThreadPool(N)
タスク キューが制限されず、タスクがより短い時間間隔で完了できる場合はExecutors.newFixedThreadPool(n)
、 ;を使用できます。専門家が示唆しているように。
このソリューションの唯一の欠点は、無制限のタスク キュー サイズです。あなたはそれを制御できません。タスク キューの大量のパイルアップは、アプリケーションのパフォーマンスを低下させ、シナリオによってはメモリ不足を引き起こす可能性があります。
アイドル状態のワーカー スレッドがタスク キュー内のタスクをスチールすることによって、ビジー状態のワーカー スレッドから作業負荷を共有するメカニズムを使用ExecutorService
および有効化する場合。work stealing
Executor Service の ForkJoinPool タイプを返します。
public static
ExecutorService newWorkStealingPool
(int 並列処理)指定された並列処理レベルをサポートするのに十分なスレッドを維持するスレッド プールを作成し、競合を減らすために複数のキューを使用する場合があります。並列処理レベルは、タスク処理にアクティブに関与している、または関与できるスレッドの最大数に対応します。スレッドの実際の数は、動的に増減する場合があります。ワークスティーリング プールは、送信されたタスクが実行される順序について保証しません。
ThreadPoolExecutor
フロー タスクの実行を制御する多くのパラメーターを制御するための API の柔軟性が気に入っています。
ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
あなたの場合、両方を設定しますcorePoolSize and maximumPoolSize as N
。ここでは、タスク キューのサイズを制御し、独自のカスタム スレッド ファクトリと拒否ハンドラー ポリシーを定義できます。
プール サイズを動的に制御するには、関連する SE の質問をご覧ください。
ここで他の人が述べているように、最善の策は、Executorsクラスでスレッドプールを作成することです。
ただし、自分でロールしたい場合は、このコードで続行する方法がわかります。基本的に、すべての新しいスレッドをスレッドグループに追加し、グループ内にN個を超えるアクティブなスレッドがないことを確認します。
Task[] tasks = getTasks(); // array of tasks to complete
ThreadGroup group = new ThreadGroup();
int i=0;
while( i<tasks.length || group.activeCount()>0 ) {
if( group.activeCount()<N && i<tasks.length ) {
new TaskThread(group, tasks[i]).start();
i++;
} else {
Thread.sleep(100);
}
}
自分でロールしたい場合:
private static final int MAX_WORKERS = n;
private List<Worker> workers = new ArrayList<Worker>(MAX_WORKERS);
private boolean roomLeft() {
synchronized (workers) {
return (workers.size() < MAX_WORKERS);
}
}
private void addWorker() {
synchronized (workers) {
workers.add(new Worker(this));
}
}
public void removeWorker(Worker worker) {
synchronized (workers) {
workers.remove(worker);
}
}
public Example() {
while (true) {
if (roomLeft()) {
addWorker();
}
}
}
Worker は Thread を拡張するクラスです。各ワーカーは、このクラスの removeWorker メソッドを呼び出し、自分自身をパラメーターとして渡します。
そうは言っても、Executor フレームワークははるかに優れているように見えます。
編集:単にダウンモッドするのではなく、なぜこれがそんなに悪いのか説明したい人はいますか?