Answers:
关于异常/错误处理有区别。
与排队的任务execute()
是产生一些Throwable
将导致UncaughtExceptionHandler
对Thread
正在运行的任务被调用。如果未安装任何自定义处理程序,则将调用默认值UncaughtExceptionHandler
(通常将Throwable
堆栈跟踪打印到)System.err
。
另一方面,Throwable
与排队的任务所生成的submit()
将绑定Throwable
到Future
与调用所生成的submit()
。调用get()
时,Future
将引发一个ExecutionException
带有原始Throwable
原因的(可通过调用getCause()
来访问ExecutionException
)。
Future
”。例如,请参阅Javadoc for ScheduledThreadPoolExecutor#execute。
执行:将其用于火灾并忘记通话
Submit:使用它来检查方法调用的结果并对调用Future
返回的对象采取适当的措施
来自javadocs
submit(Callable<T> task)
提交执行任务的返回值任务,并返回表示任务的未决结果的Future。
Future<?> submit(Runnable task)
提交一个Runnable任务以执行并返回一个表示该任务的Future。
void execute(Runnable command)
在将来的某个时间执行给定的命令。根据执行器的执行情况,命令可以在新线程,池线程或调用线程中执行。
使用时必须采取预防措施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
取自Javadoc:
方法通过创建并返回可用于取消执行和/或等待完成的{@link Future}来
submit
扩展基本方法{@link Executor#execute
}。
就我个人而言,我更喜欢使用execute,因为它看起来更具声明性,尽管这实际上是个人喜好问题。
提供更多信息:在实现的情况下,ExecutorService
调用返回的核心实现Executors.newSingleThreadedExecutor()
是ThreadPoolExecutor
。
该submit
呼叫通过其母公司提供的AbstractExecutorService
所有内部调用执行。ThreadPoolExecutor
直接由execute覆盖/提供。
完整答案由此处发布的两个答案组成(加上一些“额外”):
execute
(因为它的返回类型id void
)execute
希望Runnable
一会儿submit
可以使用a Runnable
或a Callable
作为参数(有关两者之间差异的更多信息-参见下文)。execute
立即冒出任何unchecked-exception(它不能引发已检查的异常!!),同时submit
将任何类型的异常绑定到作为结果返回的Future,并且仅当您调用future.get()
(包装的)异常时才会抛出。您将获得的Throwable是它的一个实例,ExecutionException
如果调用此对象getCause()
,它将返回原始的Throwable。其他(相关)要点:
综上所述,submit
与Callable
(相execute
对于Runnable
)一起使用是一种更好的做法。我将引用Brian Goetz的“实践中的Java并发性”:
6.3.2结果承担的任务:可调用的和将来的
Executor框架使用Runnable作为其基本任务表示形式。Runnable是一个相当有限的抽象。run可能会产生副作用,例如写入日志文件或将结果放置在共享数据结构中,但不会返回值或引发检查的异常。许多任务实际上是延迟计算的-执行数据库查询,通过网络获取资源或计算复杂的功能。对于这些类型的任务,Callable是更好的抽象:它希望主入口点call会返回一个值,并预期它可能会引发异常。7执行程序包括几种实用程序方法,用于包装其他类型的任务,包括Runnable和具有Callable的java.security.PrivilegedAction。
只需添加到接受的答案中,
但是,任务抛出的异常仅针对通过execute()提交的任务进入未捕获的异常处理程序。对于使用Submit()提交给执行者服务的任务,任何引发的异常都被视为任务返回状态的一部分。
Runnable
被包裹Task
,您可能无法控制。例如,如果您Executor
实际上是aScheduledExecutorService
,则您的任务将在内部包装在a中Future
,而未捕获的Throwable
s将绑定到该对象。