web-dev-qa-db-ja.com

ExecutorServiceの送信とExecutorServiceの実行の間で選択する

ExecutorService'ssubmit または execute の間でどのように選択する必要がありますか? ?

両方をテストした場合、戻り値以外の2つの間に違いは見られませんでした。

ExecutorService threadExecutor = Executors.newSingleThreadExecutor();
threadExecutor.execute(new Task());

ExecutorService threadExecutor = Executors.newSingleThreadExecutor();
threadExecutor.submit(new Task());
186
Cheok Yan Cheng

例外/エラー処理に関して違いがあります。

Throwableを生成するexecute()でキューに入れられたタスクは、タスクを実行しているUncaughtExceptionHandlerThreadを呼び出します。通常、UncaughtExceptionHandlerスタックトレースをSystem.errに出力するデフォルトのThrowableは、カスタムハンドラーがインストールされていない場合に呼び出されます。

一方、submit()でキューに入れられたタスクによって生成されたThrowableは、Throwablesubmit()の呼び出しから生成されたFutureにバインドします。そのFutureget()を呼び出すと、元のExecutionExceptionを原因としてThrowableがスローされます(ExecutionExceptiongetCause()を呼び出すことでアクセス可能)。

197
hochraldo

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()?を使用しながらこれらのタイプのシナリオを処理する方法

  1. Try {} catch {}ブロックコードを使用してタスクコード(Eruner RunnableまたはCallableの実装)を埋め込みます
  2. 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
59
Ravindra babu

戻り型を気にしない場合は、executeを使用してください。 Futureと同じように、submitと同じです。

11
Steven

Javadocから取得:

メソッドsubmitは、実行のキャンセルや完了の待機に使用できる{@link Future}を作成して返すことにより、ベースメソッド{@link Executor #execute}を拡張します。

個人的には、より宣言的な感じがするので、executeの使用を好みますが、これは本当に個人的な好みの問題です。

詳細情報を提供するには:ExecutorService実装の場合、Executors.newSingleThreadedExecutor()への呼び出しによって返されるコア実装はThreadPoolExecutorです。

submit呼び出しは、その親AbstractExecutorServiceによって提供され、すべての呼び出しは内部で実行されます。 executeは、ThreadPoolExecutorによって直接オーバーライド/提供されます。

7
Syntax

Javadoc から:

コマンドは、Executor実装の裁量で、新しいスレッド、プールされたスレッド、または呼び出し元のスレッドで実行できます。

そのため、Executorの実装によっては、タスクの実行中に送信スレッドがブロックすることがあります。

2
rxg

完全な回答は、ここで公開された2つの回答の構成です(さらに「余分な」):

  • タスクを送信する(実行する)と、結果を取得したりアクションをキャンセルしたりするために使用できるフューチャーを取得できます。 executeの場合、この種の制御はありません(戻り値の型ID voidのため)
  • executeRunnableを想定していますが、submitRunnableまたはCallableを引数として取ることができます(2つの違いの詳細については、以下を参照してください)。
  • executeは未チェックの例外をすぐにバブルします(チェックされた例外をスローできません!!!)、submitは結果として返される未来にany種類の例外をバインドします。 call future.get() a(ラップされた)例外がスローされます。取得するThrowableはExecutionExceptionのインスタンスであり、このオブジェクトのgetCause()を呼び出すと、元のThrowableが返されます。

いくつかの(関連する)ポイント:

  • submitにしたいタスクが結果を返す必要がない場合でも、Runnableを使用する代わりにCallable<Void>を使用できます。
  • タスクのキャンセルは interrupt メカニズムを使用して実行できます。 キャンセルポリシーの実装方法

まとめると、submitCallableを使用することをお勧めします(vs. executeRunnable)。そして、ブライアン・ゲッツによる「実践におけるJavaの並行性」から引用します。

6.3.2結果を伴うタスク:呼び出し可能および将来

Executorフレームワークは、基本的なタスク表現としてRunnableを使用します。 Runnableはかなり制限された抽象化です。 runは値を返したり、チェックされた例外をスローしたりできませんが、ログファイルへの書き込みや共有データ構造への結果の配置などの副作用がある場合があります。多くのタスクは、データベースクエリの実行、ネットワークを介したリソースのフェッチ、複雑な機能の計算など、効果的な遅延計算です。これらのタイプのタスクの場合、Callableはより優れた抽象化です。メインエントリポイントであるcallが値を返し、例外をスローする可能性があることを予期します。 Callableを使用したJava.security.PrivilegedAction。

1
alfasin