jdk1.7.0_79
In the last article ThreadPool Executor Thread Pool Principle and Excute Method The principle of ThreadPool Executor and its execute method are mentioned. This article parses ThreadPoolExecutor submit.
Sometimes we don't need it to return results for the execution of a task, but we need it to return the execution results. For threads, it implements Runnable if it does not need to return results, and Callable if it needs to execute results. Excute also provides a task execution that does not need to return a result, while its submit method can be called for returning a result.
Review the inheritance relationship of ThreadPool Executor.
In the Executor interface, only the execute method is defined, while the submit method is defined in the Executor Service interface.
//ExecutorService public 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); ... }
Subclass AbstractExecutorService implements the submit method.
//AbstractExecutorService public 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; } ... }
The submit method implemented in AbstractExecutorService is actually a template method, which defines the algorithm skeleton of the submit method, and its execute is given to subclasses. (It can be seen that template method patterns are widely used in many source codes, which can be referred to as template method patterns. Template Method Patterns)
Although the submit method can provide the return value of thread execution, only when Callable is implemented can there be a return value, while the thread implementing Runnable has no return value. That is to say, in the three methods mentioned above, submit (Callable < T > task) can get its return value, and submit(Runnable task, T result) can get the return value of thread indirectly through the incoming carrier result. Or, to be exact, it's handled by the thread, and the last method submit(Runnable task) has no return value, even if it gets its return value, it's null.
Here are three examples to feel the submit method.
submit(Callable<T> task)
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(Runnable task, T result)
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(Runnable task)
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()); } }
From the example above, we can see that submit(Runnable runnable) is not required to define its type when it is called, that is, although generic methods are defined in ExecutorService, they are not generic methods in AbstractExecutorService because it does not return a value. (For the differences between Object, T, and? Object, T (Generics),? Differences in Java).
From the source code above, we can see that the three methods are almost the same, the key lies in:
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
How does it pass a task as a parameter to newTaskFor, then call the execute method, and finally return to ftash?
//AbstractExecutorService#newTaskFor protected <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); }
It seems that a FutureTask instance is returned, and FutureTask implements the Future and Runnable interfaces. Future interface is the implementation of Java thread Future mode, which can be used for asynchronous computing. The implementation of Runnable interface representation can be executed as a thread. FutureTask implements these two interfaces, meaning that it represents the result of asynchronous computing and can be handed over to Executor as a thread for execution. FutureTask is analyzed separately in the next chapter. Therefore, the submit method for ThreadPool Executor thread pool is incomplete in this paper. It is necessary to understand the Future mode of Java thread.