简单谈谈ThreadPoolExecutor线程池之submit方法
jdk1.7.0_79
在上一篇《threadpoolexecutor线程池原理及其execute方法》中提到了线程池threadpoolexecutor的原理以及它的execute方法。本文解析threadpoolexecutor#submit。
对于一个任务的执行有时我们不需要它返回结果,但是有我们需要它的返回执行结果。对于线程来讲,如果不需要它返回结果则实现runnable,而如果需要执行结果的话则可以实现callable。在线程池同样execute提供一个不需要返回结果的任务执行,而对于需要结果返回的则可调用其submit方法。
回顾threadpoolexecutor的继承关系。
在executor接口中只定义了execute方法,而submit方法则是在executorservice接口中定义的。
//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); ... }
而在其子类abstractexecutorservice实现了submit方法。
//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; } ... }
在abstractexecutorservice实现的submit方法实际上是一个模板方法,定义了submit方法的算法骨架,其execute交给了子类。(可以看到在很多源码中,模板方法模式被大量运用,有关模板方法模式可参考《模板方法模式》)
尽管submit方法能提供线程执行的返回值,但只有实现了callable才会有返回值,而实现runnable的线程则是没有返回值的,也就是说在上面的3个方法中,submit(callable<t> task)能获取到它的返回值,submit(runnable task, t result)能通过传入的载体result间接获得线程的返回值或者准确来说交给线程处理一下,而最后一个方法submit(runnable task)则是没有返回值的,就算获取它的返回值也是null。
下面给出3个例子,来感受下submit方法。
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()); } }
通过上面的实例可以看到在调用submit(runnable runnable)的时候是不需要其定义类型的,也就是说虽然在executorservice中对其定义的是泛型方法,而在abstractexecutorservice中则不是泛型方法,因为它没有返回值。(有关object、t、?这三者的区别,可参考《java中的object、t(泛型)、?区别》)。
从上面的源码可以看到,这三者方法几乎是一样的,关键就在于:
runnablefuture<t> ftask = newtaskfor(task); execute(ftask);
它是如何将一个任务作为参数传递给了newtaskfor,然后调用execute方法,最后进而返回ftask的呢?
//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); }
看来是返回了一个futuretask实例,futuretask实现了future和runnable接口。future接口是java线程future模式的实现,可用用来异步计算,实现runnable接口表示可以作为一个线程执行。futuretask实现了这两个接口意味着它代表异步计算的结果,同时可以作为一个线程交给executor来执行。有关futuretask放到下章来单独解析。所以本文对于线程池threadpoolexecutor线程池的submit方法解析并不完整,必须得了解java线程的future模式——《老生常谈java中的future模式》。
以上这篇简单谈谈threadpoolexecutor线程池之submit方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。
推荐阅读
-
简单谈谈ThreadPoolExecutor线程池之submit方法
-
JAVA中ThreadPoolExecutor线程池的submit方法详解
-
JAVA 之ThreadPoolExecutor线程池原理及其execute方法实例详解
-
JAVA 之ThreadPoolExecutor线程池原理及其execute方法实例详解
-
java线程池之newFixedThreadPool(包括submit() 和 execute()两种方法的详解)
-
ThreadPoolExecutor线程池之submit方法
-
ThreadPoolExecutor线程池之submit方法
-
JAVA中ThreadPoolExecutor线程池的submit方法详解