ExecutorService'ssubmit または execute の間でどのように選択する必要がありますか? ?
両方をテストした場合、戻り値以外の2つの間に違いは見られませんでした。
ExecutorService threadExecutor = Executors.newSingleThreadExecutor();
threadExecutor.execute(new Task());
ExecutorService threadExecutor = Executors.newSingleThreadExecutor();
threadExecutor.submit(new Task());
例外/エラー処理に関して違いがあります。
Throwable
を生成するexecute()
でキューに入れられたタスクは、タスクを実行しているUncaughtExceptionHandler
のThread
を呼び出します。通常、UncaughtExceptionHandler
スタックトレースをSystem.err
に出力するデフォルトのThrowable
は、カスタムハンドラーがインストールされていない場合に呼び出されます。
一方、submit()
でキューに入れられたタスクによって生成されたThrowable
は、Throwable
をsubmit()
の呼び出しから生成されたFuture
にバインドします。そのFuture
でget()
を呼び出すと、元のExecutionException
を原因としてThrowable
がスローされます(ExecutionException
でgetCause()
を呼び出すことでアクセス可能)。
execute:呼び出しに使用し、呼び出しを忘れる
submit:メソッド呼び出しの結果を検査し、返されるFuture
に対して適切なアクションを実行するために使用します呼び出し
javadocs から
submit(Callable<T> task)
実行のために値を返すタスクを送信し、タスクの保留中の結果を表すFutureを返します。
Future<?> submit(Runnable task)
実行可能なRunnableタスクを送信し、そのタスクを表すFutureを返します。
void execute(Runnable command)
将来のある時点で指定されたコマンドを実行します。コマンドは、Executor実装の裁量で、新しいスレッド、プールされたスレッド、または呼び出し元のスレッドで実行できます。
submit()
を使用するときは、予防策を講じる必要があります。 try{} catch{}
ブロックにタスクコードを埋め込む場合を除き、フレームワーク自体に例外を隠します。
サンプルコード:このコードはArithmetic exception : / by zero
を飲み込みます。
import Java.util.concurrent.*;
import Java.util.*;
public class ExecuteSubmitDemo{
public ExecuteSubmitDemo()
{
System.out.println("creating service");
ExecutorService service = Executors.newFixedThreadPool(10);
//ExtendedExecutor service = new ExtendedExecutor();
service.submit(new Runnable(){
public void run(){
int a=4, b = 0;
System.out.println("a and b="+a+":"+b);
System.out.println("a/b:"+(a/b));
System.out.println("Thread Name in Runnable after divide by zero:"+Thread.currentThread().getName());
}
});
service.shutdown();
}
public static void main(String args[]){
ExecuteSubmitDemo demo = new ExecuteSubmitDemo();
}
}
出力:
Java ExecuteSubmitDemo
creating service
a and b=4:0
submit()
をexecute
()に置き換えることで同じコードがスローされます:
交換
service.submit(new Runnable(){
と
service.execute(new Runnable(){
出力:
Java ExecuteSubmitDemo
creating service
a and b=4:0
Exception in thread "pool-1-thread-1" Java.lang.ArithmeticException: / by zero
at ExecuteSubmitDemo$1.run(ExecuteSubmitDemo.Java:14)
at Java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.Java:1145)
at Java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.Java:615)
at Java.lang.Thread.run(Thread.Java:744)
submit()?を使用しながらこれらのタイプのシナリオを処理する方法
CustomThreadPoolExecutor
を実装する新しいソリューション:
import Java.util.concurrent.*;
import Java.util.*;
public class ExecuteSubmitDemo{
public ExecuteSubmitDemo()
{
System.out.println("creating service");
//ExecutorService service = Executors.newFixedThreadPool(10);
ExtendedExecutor service = new ExtendedExecutor();
service.submit(new Runnable(){
public void run(){
int a=4, b = 0;
System.out.println("a and b="+a+":"+b);
System.out.println("a/b:"+(a/b));
System.out.println("Thread Name in Runnable after divide by zero:"+Thread.currentThread().getName());
}
});
service.shutdown();
}
public static void main(String args[]){
ExecuteSubmitDemo demo = new ExecuteSubmitDemo();
}
}
class ExtendedExecutor extends ThreadPoolExecutor {
public ExtendedExecutor() {
super(1,1,60,TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(100));
}
// ...
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
if (t == null && r instanceof Future<?>) {
try {
Object result = ((Future<?>) r).get();
} catch (CancellationException ce) {
t = ce;
} catch (ExecutionException ee) {
t = ee.getCause();
} catch (InterruptedException ie) {
Thread.currentThread().interrupt(); // ignore/reset
}
}
if (t != null)
System.out.println(t);
}
}
出力:
Java ExecuteSubmitDemo
creating service
a and b=4:0
Java.lang.ArithmeticException: / by zero
戻り型を気にしない場合は、executeを使用してください。 Futureと同じように、submitと同じです。
Javadocから取得:
メソッド
submit
は、実行のキャンセルや完了の待機に使用できる{@link Future}を作成して返すことにより、ベースメソッド{@link Executor #execute
}を拡張します。
個人的には、より宣言的な感じがするので、executeの使用を好みますが、これは本当に個人的な好みの問題です。
詳細情報を提供するには:ExecutorService
実装の場合、Executors.newSingleThreadedExecutor()
への呼び出しによって返されるコア実装はThreadPoolExecutor
です。
submit
呼び出しは、その親AbstractExecutorService
によって提供され、すべての呼び出しは内部で実行されます。 executeは、ThreadPoolExecutor
によって直接オーバーライド/提供されます。
Javadoc から:
コマンドは、Executor実装の裁量で、新しいスレッド、プールされたスレッド、または呼び出し元のスレッドで実行できます。
そのため、Executor
の実装によっては、タスクの実行中に送信スレッドがブロックすることがあります。
完全な回答は、ここで公開された2つの回答の構成です(さらに「余分な」):
execute
の場合、この種の制御はありません(戻り値の型ID void
のため)execute
はRunnable
を想定していますが、submit
はRunnable
またはCallable
を引数として取ることができます(2つの違いの詳細については、以下を参照してください)。execute
は未チェックの例外をすぐにバブルします(チェックされた例外をスローできません!!!)、submit
は結果として返される未来にany種類の例外をバインドします。 call future.get()
a(ラップされた)例外がスローされます。取得するThrowableはExecutionException
のインスタンスであり、このオブジェクトのgetCause()
を呼び出すと、元のThrowableが返されます。いくつかの(関連する)ポイント:
submit
にしたいタスクが結果を返す必要がない場合でも、Runnable
を使用する代わりにCallable<Void>
を使用できます。まとめると、submit
でCallable
を使用することをお勧めします(vs. execute
でRunnable
)。そして、ブライアン・ゲッツによる「実践におけるJavaの並行性」から引用します。
6.3.2結果を伴うタスク:呼び出し可能および将来
Executorフレームワークは、基本的なタスク表現としてRunnableを使用します。 Runnableはかなり制限された抽象化です。 runは値を返したり、チェックされた例外をスローしたりできませんが、ログファイルへの書き込みや共有データ構造への結果の配置などの副作用がある場合があります。多くのタスクは、データベースクエリの実行、ネットワークを介したリソースのフェッチ、複雑な機能の計算など、効果的な遅延計算です。これらのタイプのタスクの場合、Callableはより優れた抽象化です。メインエントリポイントであるcallが値を返し、例外をスローする可能性があることを予期します。 Callableを使用したJava.security.PrivilegedAction。