如果返回的值不是我关注的话,我该如何在 ExecutorService的 submit或execute之间进行选择?
如果我同时测试两者,除了返回的值之外,我没有看到两者之间有任何差异。
ExecutorService threadExecutor = Executors.newSingleThreadExecutor();
threadExecutor.execute(new Task());
ExecutorService threadExecutor = Executors.newSingleThreadExecutor();
threadExecutor.submit(new Task());
答案 0 :(得分:194)
异常/错误处理方面存在差异。
排队execute()
的任务生成一些Throwable
将导致UncaughtExceptionHandler
运行任务的Thread
被调用。如果没有安装自定义处理程序,则将调用默认UncaughtExceptionHandler
,它通常会将Throwable
堆栈跟踪打印到System.err
。
另一方面,排队Throwable
的任务生成的submit()
会将Throwable
与Future
绑定到submit()
}}。在get()
上调用Future
会抛出ExecutionException
原始Throwable
作为其原因(可通过getCause()
上的ExecutionException
访问)。
答案 1 :(得分:57)
执行 :将其用于点火和忘记通话
提交 :使用它来检查方法调用的结果,并对调用返回的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()时处理这些类型的方案?
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
答案 2 :(得分:11)
如果您不关心返回类型,请使用execute。它与提交相同,只是没有Future的回归。
答案 3 :(得分:7)
取自Javadoc:
方法
submit
通过创建和扩展基本方法{@link Executor#execute
} 返回可用于取消执行和/或等待的{@link Future} 完成。
就个人而言,我更喜欢使用执行,因为它感觉更具声明性,尽管这确实是个人偏好的问题。
提供更多信息:对于ExecutorService
实施,调用Executors.newSingleThreadedExecutor()
时返回的核心实施是ThreadPoolExecutor
。
submit
次呼叫由其父AbstractExecutorService
提供,所有呼叫都在内部执行。执行被ThreadPoolExecutor
直接覆盖/提供。
答案 4 :(得分:2)
答案 5 :(得分:0)
完整的答案是在这里发表的两个答案的组合(加上一点&#34;额外&#34;):
execute
(因为其返回类型为void
)execute
预计Runnable
submit
可以Runnable
或Callable
作为参数(有关两者之间差异的详细信息) - 见下文)。execute
立即冒泡任何未经检查的异常(它不能抛出已检查的异常!!!),而submit
将任何类型的异常绑定到将来返回因此,只有当您调用future.get()
时,才会抛出(包装的)异常。您将获得的Throwable是ExecutionException
的一个实例,如果您将此对象称为getCause()
,它将返回原始的Throwable。更多(相关)要点:
submit
的任务不需要返回a
结果,您仍然可以使用Callable<Void>
(而不是使用Runnable
)。 总而言之,将submit
与Callable
(对execute
与Runnable
)一起使用是一种更好的做法。我将在实践中引用Java并发性&#34;作者:Brian Goetz:
6.3.2结果承载任务:可调用和未来
Executor框架使用Runnable作为其基本任务表示。 Runnable是公平的 限制抽象; run无法返回值或抛出已检查 例外,虽然它可能有副作用,如写入日志 将结果存档或放在共享数据结构中。很多任务都是 有效延迟计算 - 执行数据库查询,获取 通过网络的资源,或计算复杂的功能。对于 这些类型的任务,Callable是一个更好的抽象:它期望 主要入口点,呼叫,将返回一个值并预期 它可能会抛出异常.7执行器包括几个实用程序 包装其他类型任务的方法,包括Runnable和 java.security.PrivilegedAction,带有Callable。
答案 6 :(得分:0)
只需添加到接受的答案-
但是,任务抛出的异常会导致未捕获的异常 异常处理程序仅适用于通过execute()提交的任务;用于任务 使用submit()提交给执行者服务,抛出任何异常 被认为是任务返回状态的一部分。