`
kavy
  • 浏览: 888272 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

ExecutorService之submit与execute

 
阅读更多
ExecutorService的submit与execute方法都能执行任务,但在使用过程,发现其对待run方法抛出的异常处理方式不一样。
两者执行任务最后都会通过Executor的execute方法来执行,但对于submit,会将runnable物件包装成FutureTask<Object>,其run方法会捕捉被包装的Runnable Object的run方法抛出的Throwable异常,待submit方法所返回的的Future Object调用get方法时,将执行任务时捕获的Throwable Object包装成java.util.concurrent.ExecutionException来抛出。
 
而对于execute方法,则会直接抛出异常,该异常不能被捕获,想要在出现异常时做些处理,可以实现Thread.UncaughtExceptionHandler接口:
 
class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler{
public void uncaughtException(Thread t, Throwable e) {
System.out.println("caught "+e);
}
}
 
class HandlerThreadFactory implements ThreadFactory{
public Thread newThread(Runnable r) {
Thread t=new Thread(r);
t.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
return t;
}
}
 
ExecutorService exec=Executors.newCachedThreadPool(new HandlerThreadFactory());
 
 

三个区别:

1、接收的参数不一样

2、submit有返回值,而execute没有

Method submit extends base method Executor.execute by creating and returning a Future that can be used to cancel execution and/or wait for completion. 

用到返回值的例子,比如说我有很多个做validation的task,我希望所有的task执行完,然后每个task告诉我它的执行结果,是成功还是失败,如果是失败,原因是什么。然后我就可以把所有失败的原因综合起来发给调用者。

个人觉得cancel execution这个用处不大,很少有需要去取消执行的。

而最大的用处应该是第二点。

3、submit方便Exception处理

There is a difference when looking at exception handling. If your tasks throws an exception and if it was submitted with execute this exception will go to the uncaught exception handler (when you don't have provided one explicitly, the default one will just print the stack trace to System.err). If you submitted the task with submit any thrown exception, checked or not, is then part of the task's return status. For a task that was submitted with submit and that terminates with an exception, the Future.get will rethrow this exception, wrapped in an ExecutionException.

意思就是如果你在你的task里会抛出checked或者unchecked exception,而你又希望外面的调用者能够感知这些exception并做出及时的处理,那么就需要用到submit,通过捕获Future.get抛出的异常。

 

比如说,我有很多更新各种数据的task,我希望如果其中一个task失败,其它的task就不需要执行了。那我就需要catch Future.get抛出的异常,然后终止其它task的执行,代码如下:

51cto上有一篇非常好的文章“Java5并发学习”(http://lavasoft.blog.51cto.com/62575/115112),下面的代码是基于它之上修改的。

 

[java] view plaincopy
 
  1. import java.util.ArrayList;  
  2. import java.util.List;  
  3. import java.util.Random;  
  4. import java.util.concurrent.Callable;  
  5. import java.util.concurrent.ExecutionException;  
  6. import java.util.concurrent.ExecutorService;  
  7. import java.util.concurrent.Executors;  
  8. import java.util.concurrent.Future;  
  9.   
  10. public class ExecutorServiceTest {  
  11.     public static void main(String[] args) {  
  12.         ExecutorService executorService = Executors.newCachedThreadPool();  
  13.         List<Future<String>> resultList = new ArrayList<Future<String>>();  
  14.   
  15.         // 创建10个任务并执行  
  16.         for (int i = 0; i < 10; i++) {  
  17.             // 使用ExecutorService执行Callable类型的任务,并将结果保存在future变量中  
  18.             Future<String> future = executorService.submit(new TaskWithResult(i));  
  19.             // 将任务执行结果存储到List中  
  20.             resultList.add(future);  
  21.         }  
  22.         executorService.shutdown();  
  23.   
  24.         // 遍历任务的结果  
  25.         for (Future<String> fs : resultList) {  
  26.             try {  
  27.                 System.out.println(fs.get()); // 打印各个线程(任务)执行的结果  
  28.             } catch (InterruptedException e) {  
  29.                 e.printStackTrace();  
  30.             } catch (ExecutionException e) {  
  31.                 executorService.shutdownNow();  
  32.                 e.printStackTrace();  
  33.                 return;  
  34.             }  
  35.         }  
  36.     }  
  37. }  
  38.   
  39. class TaskWithResult implements Callable<String> {  
  40.     private int id;  
  41.   
  42.     public TaskWithResult(int id) {  
  43.         this.id = id;  
  44.     }  
  45.   
  46.     /** 
  47.      * 任务的具体过程,一旦任务传给ExecutorService的submit方法,则该方法自动在一个线程上执行。 
  48.      *  
  49.      * @return 
  50.      * @throws Exception 
  51.      */  
  52.     public String call() throws Exception {  
  53.         System.out.println("call()方法被自动调用,干活!!!             " + Thread.currentThread().getName());  
  54.         if (new Random().nextBoolean())  
  55.             throw new TaskException("Meet error in task." + Thread.currentThread().getName());  
  56.         // 一个模拟耗时的操作  
  57.         for (int i = 999999999; i > 0; i--)  
  58.             ;  
  59.         return "call()方法被自动调用,任务的结果是:" + id + "    " + Thread.currentThread().getName();  
  60.     }  
  61. }  
  62.   
  63. class TaskException extends Exception {  
  64.     public TaskException(String message) {  
  65.         super(message);  
  66.     }  
  67. }  

执行的结果类似于:

 

 

[java] view plaincopy
 
  1. call()方法被自动调用,干活!!!             pool-1-thread-1  
  2. call()方法被自动调用,干活!!!             pool-1-thread-2  
  3. call()方法被自动调用,干活!!!             pool-1-thread-3  
  4. call()方法被自动调用,干活!!!             pool-1-thread-5  
  5. call()方法被自动调用,干活!!!             pool-1-thread-7  
  6. call()方法被自动调用,干活!!!             pool-1-thread-4  
  7. call()方法被自动调用,干活!!!             pool-1-thread-6  
  8. call()方法被自动调用,干活!!!             pool-1-thread-7  
  9. call()方法被自动调用,干活!!!             pool-1-thread-5  
  10. call()方法被自动调用,干活!!!             pool-1-thread-8  
  11. call()方法被自动调用,任务的结果是:0    pool-1-thread-1  
  12. call()方法被自动调用,任务的结果是:1    pool-1-thread-2  
  13. java.util.concurrent.ExecutionException: com.cicc.pts.TaskException: Meet error in task.pool-1-thread-3  
  14.     at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:222)  
  15.     at java.util.concurrent.FutureTask.get(FutureTask.java:83)  
  16.     at com.cicc.pts.ExecutorServiceTest.main(ExecutorServiceTest.java:29)  
  17. Caused by: com.cicc.pts.TaskException: Meet error in task.pool-1-thread-3  
  18.     at com.cicc.pts.TaskWithResult.call(ExecutorServiceTest.java:57)  
  19.     at com.cicc.pts.TaskWithResult.call(ExecutorServiceTest.java:1)  
  20.     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)  
  21.     at java.util.concurrent.FutureTask.run(FutureTask.java:138)  
  22.     at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)  
  23.     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)  
  24.     at java.lang.Thread.run(Thread.java:619)  
可以看见一旦某个task出错,其它的task就停止执行。
分享到:
评论

相关推荐

    ExecutorService的execute和submit方法

    `ExecutorService`通过`execute()`和`submit()`这两个方法来提交任务进行执行。理解并熟练运用这两个方法对于优化并发性能至关重要。 `execute()`方法: `execute(Runnable command)`是`ExecutorService`最基础的...

    线程池的submit和execute的区别.md

    而在实际开发中,开发者经常会遇到两种用于向线程池提交任务的方法:`execute()`与`submit()`。虽然这两种方法看似相似,但它们在功能上存在着本质区别。本文将深入探讨这两种方法的不同之处,并结合具体的使用场景...

    Java中Future、FutureTask原理以及与线程池的搭配使用

    理解`Future`和`FutureTask`的工作原理,以及如何与`ExecutorService`配合使用,是进行高效并发编程的关键。在实际应用中,它们常用于处理耗时计算、异步数据获取等场景,提高了程序的响应性和并发性。

    Executor,Executors,ExecutorService比较.docx

    Future&lt;Integer&gt; future = executorService.submit(() -&gt; { int result = computeExpensiveValue(); return result; }); executorService.shutdown(); try { Integer value = future.get(); // 等待任务执行完成...

    2_ExecutorService源码阅读1

    execute() 方法用于执行给定的 Runnable 任务,它是提交任务的基础方法,submit() 实际上也是通过 execute() 来执行任务的。 总结来说,ExecutorService 是 Java 并发编程的重要组件,它提供了一套完善的机制来管理...

    ExecutorService线程池

    2. **提交任务**:使用`execute(Runnable task)`方法提交Runnable任务,或者使用`submit(Callable&lt;T&gt; task)`提交Callable任务并获取Future结果。 3. **关闭线程池**:任务执行完毕后,应调用`shutdown()`或`shutdown...

    java并发编程:Executor、Executors、ExecutorService.docx

    - `submit(Callable)`:与submit(Runnable)类似,但Callable任务有返回值。 - `invokeAny(...)`:从Callable任务集合中选择一个任务并返回其结果,不保证是哪个任务的结果。 - `invokeAll(...)`:返回Callable任务...

    Java使用ExecutorService来停止线程服务

    executorService.execute(() -&gt; { try { command.run(); } finally { if (isShutdown() && Thread.currentThread().isInterrupted()) { taskCancelledAtShutdown.add(command); } } }); } } ``` 在上面的...

    简单谈谈ThreadPoolExecutor线程池之submit方法

    "ThreadPoolExecutor线程池之submit方法详解" 在 Java 中,ThreadPoolExecutor 是一个非常重要的线程池实现类,它提供了多种方式来执行任务,其中 submit 方法是其中一个重要的方法,本文将详细解释 ...

    Java多线程之Executor框架.docx

    例如,使用`ExecutorService.submit(Callable)`或`ExecutorService.submit(Runnable)`方法,会返回一个`Future`对象,可以用来检查任务状态、取消任务或获取结果。 总的来说,Java的Executor框架通过引入线程池和...

    Java 线程池ExecutorService详解及实例代码

    2. ExecutorService与Executor ExecutorService是Java中实现线程池功能的接口,它扩展了Executor接口。Executor接口只有一个execute()方法,用于执行Runnable任务。ExecutorService则提供了更丰富的操作,如...

    理解java多线程中ExecutorService使用

    在Java多线程编程中,`ExecutorService`是核心组件之一,它位于`java.util.concurrent`包下,为线程的管理和执行提供了便利。`ExecutorService`不仅简化了线程的创建和管理,而且通过其丰富的API使得多线程编程更加...

    Java多线程下载 实例

    为了跟踪整体进度并显示给用户,我们可以使用`Future`对象,它是`ExecutorService.submit()`方法返回的结果。`Future`提供了检查任务是否完成、获取结果或取消任务的方法。我们可以在主线程中循环遍历所有`Future`...

    Android线程池ExcutorService

    通过`ExecutorService`的`execute(Runnable task)`方法提交任务,或者使用`submit(Callable&lt;T&gt; task)`提交返回结果的任务。`Runnable`接口用于无返回值的任务,而`Callable`接口则支持带返回值的任务。 5. **关闭...

    Kotlin与java8的SAM转换对比(进阶)

    executorService.execute(() -&gt; System.out.println("hello world")); ``` 而在Kotlin中,尽管也可以使用Lambda,但其语法有所不同。首先,Kotlin的Lambda表达式有类型,如`()-&gt;Unit`表示无参无返回值的函数。因此...

    线程池核心组件源码剖析.docx

    2. **ExecutorService接口**:继承自Executor接口,增加了管理和控制线程池的功能,如`submit()`用于提交任务,`shutdown()`用于关闭线程池,`shutdownNow()`用于尝试停止所有正在执行的任务等。 3. **...

    JDK线程池和Spring线程池的使用实例解析

    JDK线程池是Java中的一个内置线程池实现,它提供了一个ExecutorService接口,该接口提供了execute、submit、shutdown等方法来管理线程池。JDK线程池可以通过ThreadPoolExecutor类来创建,ThreadPoolExecutor类提供了...

    java多线程学习-ftp上传

    3. 提交任务给线程池:使用ExecutorService的submit()或execute()方法。 4. 线程池的关闭:调用shutdown()或shutdownNow()方法,以及如何处理未完成的任务。 5. 配合Future和Callable接口获取任务结果和取消任务。 ...

    java基础知识之hadoop源码阅读必备(一).docx

    然后,通过`ExecutorService`的`submit()`方法提交这个任务,它会在新的线程中运行。这种方式不会返回结果,适用于无需等待任务完成的情况。 示例代码: ```java ExecutorService executor = Executors....

    线程池之Executor框架.docx

    - 创建`ExecutorService`的实现,如`ThreadPoolExecutor`或`ScheduledThreadPoolExecutor`,并通过`execute()`或`submit()`方法提交任务。`submit()`方法会返回一个`Future`对象,可以用来获取任务结果或取消任务。...

Global site tag (gtag.js) - Google Analytics