jdk1.7.0_79
前回の記事「ThreadPoolExecutorのスレッドプールの原理とその実行メソッド」で、スレッドプールThreadPoolExecutorの原理とその実行メソッドについて触れました。この記事では ThreadPoolExecutor#submit を分析します。
タスクの実行では、結果を返す必要がない場合もありますが、実行結果を返す必要があります。スレッドの場合、結果を返す必要がない場合は Runnable を実装でき、結果を実行する必要がある場合は Callable を実装できます。スレッド プールでは、execute は結果を返す必要のないタスクの実行も提供し、結果を返す必要があるタスクに対してその submit メソッドを呼び出すことができます。
ThreadPoolExecutorの継承関係を見直してください。
Executorインターフェースにはexecuteメソッドのみが定義されており、ExecutorServiceインターフェースにはsubmitメソッドが定義されています。
//ExecutorServicepublic interface ExecutorService extends Executor { ... <T> Future<T> submit(Callable<T> task); <T> Future<T> submit(Runnable task, T result); <T> Future<T> submit(Runnable task); ... }
そしてsubmitメソッドはそのサブクラスAbstractExecutorServiceに実装されています。
//AbstractExecutorServicepublic abstract class AbstractExecutorService implements ExecutorService { ... 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); execute(ftask); return ftask; } public Future<?> submit(Runnable task) { if (task == null) throw new NullPointerExeption(); RunnableFuture<Void> ftask = newTaskFor(task, null); execute(ftask); return ftask; } ... }
AbstractExecutorServiceに実装されているsubmitメソッドは、実際にはsubmitメソッドのアルゴリズム骨格を定義するテンプレートメソッドであり、その実行はサブクラスに渡されます。 (多くのソースコードでテンプレートメソッドのパターンが広く使われていることが分かります。テンプレートメソッドのパターンについては「テンプレートメソッドのパターン」を参照してください。)
submitメソッドはスレッド実行の戻り値を提供できますが、 Callable が実装されている場合にのみ戻り値が返され、Runnable を実装するスレッドには戻り値がありません。つまり、上記の 3 つのメソッドのうち、submit(Callable
submit メソッドの雰囲気をつかむために、以下に 3 つの例を示します。
submit(呼び出し可能な
package com.threadpoolexecutor;import java.util.concurrent.*;/** * ThreadPoolExecutor#sumit(Callable<T> task) * Created by yulinfeng on 6/17/17. */public class Sumit1 {public static void main(String[] args) throws ExecutionException, InterruptedException { Callable<String> callable = new Callable<String>() {public String call() throws Exception { System.out.println("This is ThreadPoolExetor#submit(Callable<T> task) method.");return "result"; } }; ExecutorService executor = Executors.newSingleThreadExecutor(); Future<String> future = executor.submit(callable); System.out.println(future.get()); } }
submit(実行可能なタスク、Tの結果)
package com.threadpoolexecutor;import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;/** * ThreadPoolExecutor#submit(Runnable task, T result) * Created by yulinfeng on 6/17/17. */public class Submit2 {public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService executor = Executors.newSingleThreadExecutor(); Data data = new Data(); Future<Data> future = executor.submit(new Task(data), data); System.out.println(future.get().getName()); } }class Data { String name;public String getName() {return name; }public void setName(String name) {this.name = name; } }class Task implements Runnable { Data data;public Task(Data data) {this.data = data; }public void run() { System.out.println("This is ThreadPoolExetor#submit(Runnable task, T result) method."); data.setName("kevin"); } }
submit(R不可能なタスク)
package com.threadpoolexecutor;import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;/** * ThreadPoolExecutor#sumit(Runnable runnables) * Created by yulinfeng on 6/17/17. */public class Submit {public static void main(String[] args) throws ExecutionException, InterruptedException { Runnable runnable = new Runnable() {public void run() { System.out.println("This is ThreadPoolExetor#submit(Runnable runnable) method."); } }; ExecutorService executor = Executors.newSingleThreadExecutor(); Future future = executor.submit(runnable); System.out.println(future.get()); } }
上記の例から、submit(Runnable runnable) を呼び出す場合、定義された型は必要ないことがわかります。つまり、ExecutorService で定義されたジェネリック メソッドですが、AbstractExecutorService ではジェネリック メソッドではありません。戻り値はありません。 (Object、T、?の違いについては「JavaのObject、T(ジェネリック)、?の違い」を参照してください。)
上記のソースコードを見ると、これら 3 つのメソッドがほぼ同じであることがわかります。鍵となるのは、
RunnableFuture<T> ftask = newTaskFor(task); execute(ftask);
タスクをパラメータとして newTaskFor に渡し、execute メソッドを呼び出し、最後に ftask を返す方法です。どうですか?
//AbstractExecutorService#newTaskForprotected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) { return new FutureTask<T>(callable); } protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) { return new FutureTask<T>(runnable, value); }
FutureTaskインスタンスが返されるようで、FutureTaskはFutureインターフェースとRunnableインターフェースを実装しています。 Future インターフェイスは、非同期計算に使用できる Java スレッド Future モードの実装です。Runnable インターフェイスを実装すると、スレッドとして実行できるようになります。 FutureTask はこれら 2 つのインターフェイスを実装しています。これは、非同期計算の結果を表し、実行用のスレッドとして Executor に渡すことができることを意味します。 FutureTask については、次の章で個別に分析します。したがって、この記事のスレッド プール ThreadPoolExecutor スレッド プールの submit メソッドの分析は完了していません。Java スレッドの Future モード (「14. Java の Future モード」) を理解する必要があります。
以上がThreadPoolExecutor スレッド プールの Submit メソッドの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。