Java 在ExecutorService和x27之间进行选择;s提交并执行服务';执行
如果返回的值不是我所关心的,我应该如何在执行服务的之间进行选择 如果我同时测试这两个,除了返回值之外,我看不到它们之间有任何差异Java 在ExecutorService和x27之间进行选择;s提交并执行服务';执行,java,multithreading,executorservice,Java,Multithreading,Executorservice,如果返回的值不是我所关心的,我应该如何在执行服务的之间进行选择 如果我同时测试这两个,除了返回值之外,我看不到它们之间有任何差异 ExecutorService threadExecutor = Executors.newSingleThreadExecutor(); threadExecutor.execute(new Task()); 摘自Javadoc: 方法submit通过创建和 返回可用于取消执行和/或等待的{@link Future} 完成 就个人而言,我更喜欢使用execute
ExecutorService threadExecutor = Executors.newSingleThreadExecutor();
threadExecutor.execute(new Task());
摘自Javadoc: 方法
submit
通过创建和
返回可用于取消执行和/或等待的{@link Future}
完成
就个人而言,我更喜欢使用execute,因为它感觉更具声明性,尽管这实际上是个人偏好的问题
提供更多信息:对于ExecutorService
实现,调用Executors.newSingleThreadedExecutor()
返回的核心实现是ThreadPoolExecutor
submit
调用由其父级AbstractExecutorService
提供,所有调用都在内部执行。execute由线程池执行器直接重写/提供。如果不关心返回类型,请使用execute。它与提交相同,只是不返回Future。在异常/错误处理方面存在差异
使用execute()
排队并生成一些Throwable
的任务将导致调用运行该任务的线程的UncaughtExceptionHandler
。默认的UncaughtExceptionHandler
,通常将可丢弃的堆栈跟踪打印到System.err
,如果未安装自定义处理程序,将调用该处理程序
另一方面,由使用submit()
排队的任务生成的Throwable
将Throwable
绑定到调用submit()
生成的未来。在该Future
上调用get()
将抛出一个ExecutionException
,原始的Throwable
作为其原因(可通过调用ExecutionException
上的getCause()
访问)
该命令可以在新线程、池线程或调用线程中执行,具体取决于执行器实现
因此,根据执行器的实现情况,您可能会发现提交线程在任务执行时会阻塞。执行器:将其用于激发和忘记调用
submit:使用它检查方法调用的结果,并对调用返回的Future
对象采取适当的操作
从
submit(可调用任务)
提交值返回任务以执行,并返回未来值
表示任务的挂起结果
未来提交(可运行任务)
提交可运行任务以执行,并返回表示该任务的未来
任务
在将来的某个时间执行给定的命令。该命令可以在新线程、池线程或调用线程中执行,具体取决于执行器实现
使用submit()
时必须采取预防措施。它在框架本身中隐藏异常,除非您将任务代码嵌入try{}catch{}
块中
示例代码:此代码将算术异常:/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
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)
java ExecuteSubmitDemo
creating service
a and b=4:0
java.lang.ArithmeticException: / by zero
将submit()
替换为execute
(),会引发相同的代码:
替换
service.submit(new Runnable(){
与
输出:
java ExecuteSubmitDemo
creating service
a and b=4:0
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)
java ExecuteSubmitDemo
creating service
a and b=4:0
java.lang.ArithmeticException: / by zero
如何在使用submit()时处理这些类型的场景?
用try{}catch{}块代码嵌入任务代码(可运行或可调用实现)
实施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);
}
}
完整答案由两个答案组成,这两个答案在这里发布(加上一点“额外”):
- 通过提交任务(与执行任务相比),您可以获得一个未来,该未来可用于获得结果或取消操作。当执行
时,您没有这种控制(因为它的返回类型idvoid
)
execute
需要Runnable
,而submit
可以将Runnable
或Callable
作为参数(有关两者之间差异的更多信息,请参阅下文)
execute
立即弹出任何未检查的异常(它不能抛出已检查的异常!!!),而submit
将任何类型的异常绑定到作为结果返回的未来,并且只有在调用future.get()
a时,(包装的)异常才会被抛出。您将获得的Throwable是ExecutionException
的一个实例,如果调用此对象的getCause()
,它将返回原始Throwable
还有几个(相关)要点:
- 即使要提交的任务不需要返回
结果,您仍然可以使用
Callable
(而不是使用Runnable
)李>
- 可以使用该机制取消任务。下面是如何实施取消策略的示例
总之,使用submit
和Callable
(与使用Runnable
的execute
相比)是一种更好的做法。我将引用Brian Goetz的“Java并发在实践中”一文:
6.3.2结果承载任务:可调用和未来
Executor框架使用Runnable作为其基本任务表示。Runnable是一个相当不错的选择
限制抽象;run无法返回值或抛出已选中的值
异常,尽管它可能有副作用,例如写入日志
文件或将结果放置在共享数据结构中。许多任务都很复杂
有效的