私は春のマルチスレッドに乗り込もうとしていますが、いくつか質問があります。
ThreadRatingクラスに実行可能なメソッドがあります。今、私はそれを使用する最良の方法についてはわかりません。
オプション1見つかりました:
_private void updateRating() {
ExecutorService executor = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) { // test
// thread part
Runnable worker = new ThreadRating(path, i, products.get(i), dao, fileHandler);
executor.execute(worker);
}
executor.shutdown();
try {
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
log.error("There was an error when ending threads");
System.exit(1);
}
System.out.println("Finished all threads");
}
_
これは正常に動作しているようです。 forループの後、スレッドが終了して終了するまで待機します。
私が試した2番目のオプション
_private TaskExecutor taskExecutor;
public UpdateBO(TaskExecutor taskExecutor) {
this.taskExecutor = taskExecutor;
}
private void updateRating() {
for (int i = 0; i < 10; i++) { // test
Runnable worker = new ThreadRating(path, i, products.get(i), dao, fileHandler);
taskExecutor.execute(worker);
}
// wait for threads to be finished before you go any further ??
}
_
そして私が持っているxmlファイルで
_<beans:bean id="taskExecutor"
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<beans:property name="corePoolSize" value="5" />
<beans:property name="maxPoolSize" value="10" />
<beans:property name="queueCapacity" value="25" />
<beans:property name="waitForTasksToCompleteOnShutdown" value="true" />
</beans:bean>
<beans:bean id="updateBO" class="UpdateBO">
<beans:constructor-arg ref="taskExecutor" />
</beans:bean>
_
そしてここに私の質問があります:
executor.execute(worker);
-明確にするためです。これは実際には新しいスレッドを作成していませんが、タスクをキューに追加し、キューがいっぱいの場合は、空きスペースができるまでコードのこの行で待機しますか?理解してくれてありがとう。
主な違い:オプション1)では、すべてのupdateRating()
呼び出しで新しいエグゼキューターを作成します。オプション2)では、エグゼキューターをデプロイ時に一度作成し、同じ単一のエグゼキューターに新しいジョブをフィードします。 2番目のアプローチははるかに優れています。
エグゼキューターをシャットダウンする必要があるのはなぜですか? 新しいエグゼキューターを作成し、タスクが処理されるまで待つためにそれらをシャットダウンすることはアンチパターンです。 エグゼキュータは、システムリソースを制御するために作成され、そのように扱われる必要があることに注意してください。 (たとえば、50接続のDB接続プールがある場合-DBアクセスを提供するには、50スレッドのエグゼキューターを作成します-接続制限を超えないようにします。または、サーバーに24コアがあり、可能な限り最良の方法で作業を並列化する必要があります) 。
また、コメントで述べたように、一部の環境(アプリサーバーなど)では、executorをシャットダウンする権限がない場合があります。そのような試みはSecurityException
を生成します。
ワーカーがジョブを完了するまで待機する必要がある場合は、すべてのジョブをCallable
ではなくRunnable
でラップし、メインスレッドから対応するfuture.get()
を呼び出すと、ジョブまでブロックされます終了します。タイムアウトがサポートされています。 例
絶対的に正しい。スレッドは、最適なタイミングであると考えられる場合、executor自体によって作成および破棄されます。 jvisualvmを使用してアプリを監視し、どのように発生するかを確認してください。
1.)オプション1は、executorサービスをローカルで定義し、使用するたびに閉じるため、正しく実装されていません。これは、スレッドプールを作成する目的に反します。スレッドプールはグローバルオブジェクトである必要があるため、オプション2が適しています。
2.)Webサービスを呼び出すときに、executorサービスをシャットダウンする必要はありません。 Webサービスが応答しない場合、呼び出しは最終的にタイムアウトし、スレッドは実行を完了します。 executorサービスをシャットダウンすると、次の呼び出しで使用できなくなります。
3.)スレッドが終了した後に何らかの通知が必要な場合は、代わりに Callable を Futures と組み合わせて使用する必要があります。
4.)エグゼキューターサービスには最大10個のスレッドが割り当てられており、それらを超えるスレッドは生成されません。それらのすべてがビジーの場合、これらのスレッドの1つが使用可能になるまで、タスクはアイドル状態になります。