ExectorService
を使用してthreads
をプールし、タスクを送信することを学んでいます。私は以下の簡単なプログラムを持っています
import Java.util.concurrent.ExecutorService;
import Java.util.concurrent.Executors;
import Java.util.concurrent.TimeUnit;
class Processor implements Runnable {
private int id;
public Processor(int id) {
this.id = id;
}
public void run() {
System.out.println("Starting: " + id);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
System.out.println("sorry, being interupted, good bye!");
System.out.println("Interrupted "+Thread.currentThread().getName());
e.printStackTrace();
}
System.out.println("Completed: " + id);
}
}
public class ExecutorExample {
public static void main(String[] args) {
Boolean isCompleted=false;
ExecutorService executor = Executors.newFixedThreadPool(2);
for(int i=0; i<5; i++) {
executor.execute(new Processor(i));
}
//executor does not accept any more tasks but the submitted tasks continue
executor.shutdown();
System.out.println("All tasks submitted.");
try {
//wait for the exectutor to terminate normally, which will return true
//if timeout happens, returns false, but this does NOT interrupt the threads
isCompleted=executor.awaitTermination(100, TimeUnit.SECONDS);
//this will interrupt thread it manages. catch the interrupted exception in the threads
//If not, threads will run forever and executor will never be able to shutdown.
executor.shutdownNow();
} catch (InterruptedException e) {
}
if (isCompleted){
System.out.println("All tasks completed.");
}
else {
System.out.println("Timeout "+Thread.currentThread().getName());
}
}
}
派手なことは何もしませんが、2つのthreads
を作成し、合計5つのタスクを送信します。各thread
がタスクを完了すると、次のタスクを取ります。上記のコードでは、executor.submit
を使用します。また、executor.execute
に変更しました。しかし、出力に違いは見られません。 submit and execute
メソッドはどのように異なりますか?これはAPI
が言うこと
メソッドsubmitは、実行のキャンセルや完了の待機に使用できるFutureを作成して返すことにより、ベースメソッドExecutor.execute(Java.lang.Runnable)を拡張します。メソッドinvokeAnyおよびinvokeAllは、最も一般的に有用な形式の一括実行を実行し、タスクのコレクションを実行してから、少なくとも1つまたはすべてが完了するまで待機します。 (Class ExecutorCompletionServiceを使用して、これらのメソッドのカスタマイズされたバリアントを作成できます。)
しかし、それが正確に何を意味するのかは私には明らかではありませんか?
JavaDocからわかるように、execute(Runnable)
は何も返しません。
ただし、submit(Callable<T>)
はFuture
オブジェクトを返します。これにより、実行中のスレッドを後でプログラムでキャンセルし、T
が返されたときに返されるCallable
を取得できます。完了します。詳細については、 JavaDoc of Future を参照してください
_Future<?> future = executor.submit(longRunningJob);
...
//long running job is taking too long
future.cancel(true);
_
さらに、future.get() == null
が例外をスローしない場合、Runnableは正常に実行されました
違いは、execute
は単純にタスクを開始するだけで、submit
はタスクを管理するFuture
オブジェクトを返すことです。 Future
オブジェクトを使用して、次のことを実行できます。
cancel
メソッドを使用して、タスクを途中でキャンセルします。get
を使用して、タスクの実行が完了するまで待ちます。Future
インターフェースは、Callable
をプールに送信する場合により便利です。 call
メソッドの戻り値は、Future.get
を呼び出すと返されます。 Future
への参照を維持しない場合、違いはありません。
_execute:
_呼び出しに使用し、呼び出しを忘れる
_submit:
_これを使用して、メソッド呼び出しの結果を検査し、呼び出しによって返されたFuture
オブジェクトに対して適切なアクションを実行します
主な違い:Exception
の処理
submit()
は、フレームワーク自体で未処理のException
を非表示にします。
execute()
は未処理のException
をスローします。
submit()
を使用して例外を処理するためのソリューション
_Callable or Runnable code in try{} catch{} block
_をラップします
OR
future.get() call in try{} catch{} block
を保持
OR
独自のThreadPoolExecutor
を実装し、afterExecute
メソッドをオーバーライドします
ツアーの他のクエリについて
指定されたタスクを実行し、すべての完了またはタイムアウトが期限切れになった時点で、ステータスと結果を保持するFutureのリストを返します。
指定されたタスクが実行され、指定されたタイムアウトが経過する前に正常に完了したタスクの結果が返されます(例外がスローされない場合)。
送信されたすべてのタスクが完了するまで待機する場合は、invokeAll
を使用します。
N個の送信済みタスクから1つのタスクを正常に完了したい場合は、invokeAny
を使用します。この場合、タスクの1つが正常に完了すると、進行中のタスクはキャンセルされます。
コード例を使用した関連記事:
Submit-送信されたタスクの結果を確認するために使用できるFutureオブジェクトを返します。 isDoneなどのキャンセルまたはチェックに使用できます。
実行-何も返しません。
Submit()メソッドとexecute()メソッドの主な違いは、ExecuterService.submit()はFutureの戻り値型を持っているため、計算結果を返すことができますが、execute()メソッドは戻り値の型がvoidであるため何も返すことができないことです。 Java 1.5のExecutorフレームワークのコアインターフェイスは、execute(Runnable task)メソッドを定義するExecutorインターフェイスです。その主な目的は、タスクを実行から分離することです。
Executorに送信されたタスクは、同じスレッド、スレッドプールのワーカースレッド、または他のスレッドによって実行できます。
一方、submit()メソッドは、ExecutorのサブインターフェースであるExecutorServiceインターフェースで定義され、呼び出し可能タスクを受け入れて結果を返すsubmit()メソッドを追加するとともに、スレッドプールを終了する機能を追加します。計算の。
execute()とsubmit()の類似点:
submit()メソッドは出力を返すことができ、execute()は返せないという事実とは別に、Java 5。 =
ソースコードを確認すると、submit
がexecute
の一種のラッパーであることがわかります。
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
基本的に両方の呼び出しが実行され、将来のオブジェクトが必要な場合は、docからsubmit()メソッドをここで呼び出します
_public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
public <T> Future<T> submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}
_
ご覧のとおり、Javaは実際にrun()メソッドを呼び出す以外にスレッドを開始する方法がありません。IMO。Callable.call()
メソッドがrun()
method。したがって、オブジェクトが呼び出し可能な場合、run()
メソッドが呼び出され、次にdocからcall()
メソッドが呼び出されます。
_public void run() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
_