从上篇文章的实例中,我们用了ExecutorService的shutdown方法,但我们不难发现它还有shutdownNow方法,它们到底有什么区别呢?
这两个方法都可以关闭 ExecutorService,这将导致其拒绝新任务。shutdown() 方法在终止前允许执行以前提交的任务,而 shutdownNow() 方法阻止等待任务启动并试图停止当前正在执行的任务。在终止时,执行程序没有任务在执行,也没有任务在等待执行,并且无法提交新任务。应该关闭未使用的 ExecutorService 以允许回收其资源。
下列方法分两个阶段关闭 ExecutorService。第一阶段调用 shutdown 拒绝传入任务,然后调用 shutdownNow(如有必要)取消所有遗留的任务:
private static void shutdownAndAwaitTermination(ExecutorService pool) { pool.shutdown(); // Disable new tasks from being submitted try { // Wait a while for existing tasks to terminate if (!pool.awaitTermination(60, TimeUnit.SECONDS)) { pool.shutdownNow(); // Cancel currently executing tasks // Wait a while for tasks to respond to being cancelled if (!pool.awaitTermination(60, TimeUnit.SECONDS)) System.err.println("Pool did not terminate"); } } catch (InterruptedException ie) { // (Re-)Cancel if current thread also interrupted pool.shutdownNow(); // Preserve interrupt status Thread.currentThread().interrupt(); } }
下面我们以上篇文章的实例来做测试验证:
1.在submit(task2)后shutdown()
package com.bijian.study; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; /** * Callable 和 Future接口 * Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其它线程执行的任务。 * Callable和Runnable有几点不同: * (1)Callable规定的方法是call(),而Runnable规定的方法是run(). * (2)Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。 * (3)call()方法可抛出异常,而run()方法是不能抛出异常的。 * (4)运行Callable任务可拿到一个Future对象,Future 表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。通过Future对象可了解任务执行情况,可取消任务的执行,还可获取任务执行的结果。 */ public class CallableAndFuture { public static class MyCallable implements Callable { private int flag = 0; public MyCallable(int flag) { this.flag = flag; } public String call() throws Exception { if (this.flag == 0) { return "flag = 0"; } if (this.flag == 1) { try { while (true) { System.out.println("looping."); Thread.sleep(2000); } } catch (InterruptedException e) { System.out.println("Interrupted"); } return "false"; } else { throw new Exception("Bad flag value!"); } } } public static void main(String[] args) { // 定义3个Callable类型的任务 MyCallable task1 = new MyCallable(0); MyCallable task2 = new MyCallable(1); MyCallable task3 = new MyCallable(2); // 创建一个执行任务的服务 ExecutorService es = Executors.newFixedThreadPool(3); try { // 提交并执行任务,任务启动时返回了一个Future对象, // 如果想得到任务执行的结果或者是异常可对这个Future对象进行操作 Future future1 = es.submit(task1); // 获得第一个任务的结果,如果调用get方法,当前线程会等待任务执行完毕后才往下执行 System.out.println("task1: " + future1.get()); Future future2 = es.submit(task2); es.shutdown(); // 等待5秒后,再停止第二个任务。因为第二个任务进行的是无限循环 Thread.sleep(5000); System.out.println("task2 cancel: " + future2.cancel(true)); // 获取第三个任务的输出,因为执行第三个任务会引起异常 // 所以下面的语句将引起异常的抛出 Future future3 = es.submit(task3); System.out.println("task3: " + future3.get()); } catch (Exception e) { System.out.println(e.toString()); } // 停止任务执行服务 //es.shutdown(); } }
运行结果:
task1: flag = 0 looping. looping. looping. task2 cancel: true java.util.concurrent.RejectedExecutionException Interrupted
2.在submit(task2)后shutdownNow()
package com.bijian.study; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; /** * Callable 和 Future接口 * Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其它线程执行的任务。 * Callable和Runnable有几点不同: * (1)Callable规定的方法是call(),而Runnable规定的方法是run(). * (2)Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。 * (3)call()方法可抛出异常,而run()方法是不能抛出异常的。 * (4)运行Callable任务可拿到一个Future对象,Future 表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。通过Future对象可了解任务执行情况,可取消任务的执行,还可获取任务执行的结果。 */ public class CallableAndFuture { public static class MyCallable implements Callable { private int flag = 0; public MyCallable(int flag) { this.flag = flag; } public String call() throws Exception { if (this.flag == 0) { return "flag = 0"; } if (this.flag == 1) { try { while (true) { System.out.println("looping."); Thread.sleep(2000); } } catch (InterruptedException e) { System.out.println("Interrupted"); } return "false"; } else { throw new Exception("Bad flag value!"); } } } public static void main(String[] args) { // 定义3个Callable类型的任务 MyCallable task1 = new MyCallable(0); MyCallable task2 = new MyCallable(1); MyCallable task3 = new MyCallable(2); // 创建一个执行任务的服务 ExecutorService es = Executors.newFixedThreadPool(3); try { // 提交并执行任务,任务启动时返回了一个Future对象, // 如果想得到任务执行的结果或者是异常可对这个Future对象进行操作 Future future1 = es.submit(task1); // 获得第一个任务的结果,如果调用get方法,当前线程会等待任务执行完毕后才往下执行 System.out.println("task1: " + future1.get()); Future future2 = es.submit(task2); es.shutdownNow(); // 等待5秒后,再停止第二个任务。因为第二个任务进行的是无限循环 Thread.sleep(5000); System.out.println("task2 cancel: " + future2.cancel(true)); // 获取第三个任务的输出,因为执行第三个任务会引起异常 // 所以下面的语句将引起异常的抛出 Future future3 = es.submit(task3); System.out.println("task3: " + future3.get()); } catch (Exception e) { System.out.println(e.toString()); } // 停止任务执行服务 //es.shutdown(); } }
运行结果:
task1: flag = 0 looping. Interrupted task2 cancel: false java.util.concurrent.RejectedExecutionException
当然,我们也可以分两个阶段关闭 ExecutorService。第一阶段调用 shutdown 拒绝传入任务,然后调用 shutdownNow(如有必要)取消所有遗留的任务。修改此实例如下:
package com.bijian.study; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; /** * Callable 和 Future接口 * Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其它线程执行的任务。 * Callable和Runnable有几点不同: * (1)Callable规定的方法是call(),而Runnable规定的方法是run(). * (2)Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。 * (3)call()方法可抛出异常,而run()方法是不能抛出异常的。 * (4)运行Callable任务可拿到一个Future对象,Future 表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。通过Future对象可了解任务执行情况,可取消任务的执行,还可获取任务执行的结果。 */ public class CallableAndFuture { public static class MyCallable implements Callable { private int flag = 0; public MyCallable(int flag) { this.flag = flag; } public String call() throws Exception { if (this.flag == 0) { return "flag = 0"; } if (this.flag == 1) { try { while (true) { System.out.println("looping."); Thread.sleep(2000); } } catch (InterruptedException e) { System.out.println("Interrupted"); } return "false"; } else { throw new Exception("Bad flag value!"); } } } public static void main(String[] args) { // 定义3个Callable类型的任务 MyCallable task1 = new MyCallable(0); MyCallable task2 = new MyCallable(1); MyCallable task3 = new MyCallable(2); // 创建一个执行任务的服务 ExecutorService es = Executors.newFixedThreadPool(3); try { // 提交并执行任务,任务启动时返回了一个Future对象, // 如果想得到任务执行的结果或者是异常可对这个Future对象进行操作 Future future1 = es.submit(task1); // 获得第一个任务的结果,如果调用get方法,当前线程会等待任务执行完毕后才往下执行 System.out.println("task1: " + future1.get()); Future future2 = es.submit(task2); shutdownAndAwaitTermination(es); // 等待5秒后,再停止第二个任务。因为第二个任务进行的是无限循环 Thread.sleep(5000); System.out.println("task2 cancel: " + future2.cancel(true)); // 获取第三个任务的输出,因为执行第三个任务会引起异常 // 所以下面的语句将引起异常的抛出 Future future3 = es.submit(task3); System.out.println("task3: " + future3.get()); } catch (Exception e) { System.out.println(e.toString()); } // 停止任务执行服务 //es.shutdown(); } private static void shutdownAndAwaitTermination(ExecutorService pool) { pool.shutdown(); // Disable new tasks from being submitted try { // Wait a while for existing tasks to terminate if (!pool.awaitTermination(10, TimeUnit.SECONDS)) { pool.shutdownNow(); // Cancel currently executing tasks // Wait a while for tasks to respond to being cancelled if (!pool.awaitTermination(10, TimeUnit.SECONDS)) System.err.println("Pool did not terminate"); } } catch (InterruptedException ie) { // (Re-)Cancel if current thread also interrupted pool.shutdownNow(); // Preserve interrupt status Thread.currentThread().interrupt(); } } }
运行结果:
task1: flag = 0 looping. looping. looping. looping. looping. looping. Interrupted task2 cancel: false java.util.concurrent.RejectedExecutionException
相关推荐
`ExecutorService`提供了两种主要的关闭方法:`shutdown()`和`shutdownNow()`。`shutdown()`方法的设计是为了优雅地关闭线程池,它首先拒绝新的任务提交,然后等待当前正在执行的任务执行完毕。这个过程是异步的,...
- **shutdownNow()**:尝试停止所有正在执行的任务,不再接受新任务,但可能无法立即停止所有任务。 使用`ExecutorService`示例: ```java ExecutorService executorService = Executors.newFixedThreadPool(5); ...
3. **关闭线程池**:任务执行完毕后,应调用`shutdown()`或`shutdownNow()`方法来停止接收新任务,并等待正在执行的任务完成。`shutdown()`会等待已提交任务执行完毕,而`shutdownNow()`尝试停止所有正在执行的任务...
ExecutorService 是 Java 中用于管理和控制线程执行的核心接口,它是 java.util.concurrent 包的一部分。ExecutorService 扩展了 Executor 接口,提供了更丰富的功能,如任务的提交、关闭服务、检查服务状态等。这个...
首先,我们需要了解 ExecutorService 的两个关闭方法:shutdown() 和 shutdownNow()。这两个方法的区别在于它们的安全性和响应性。shutdown() 方法会正常关闭线程池,等待所有任务执行完毕后关闭,而 shutdownNow() ...
Java中的ExecutorService是Java并发编程的重要组成部分,它提供了一种高效、灵活的方式来管理和控制线程的...同时,合理地关闭ExecutorService(通过`shutdown()`或`shutdownNow()`方法)也是防止资源泄漏的关键步骤。
List<Runnable> notRunTasks = executorService.shutdownNow(); ``` #### 五、综合实例解析 下面是一个简单的示例代码,展示了如何使用固定大小的线程池来执行任务: ```java public class ...
而`shutdownNow()`方法会尝试停止所有正在执行的任务,并拒绝新提交的任务。 5. **移除线程** 问题提到如何从线程池中移除或使某个线程成为空闲线程。实际上,`ExecutorService`并不直接提供移除线程的方法。...
- **关闭线程池**:在所有任务执行完毕后,调用 `executorService.shutdown()` 或 `executorService.shutdownNow()` 来优雅地关闭线程池。 6. **示例代码**: - `MyThread` 类实现了`Runnable`接口,`run`方法...
需要注意的是,`shutdown()`并不会阻塞调用它的主线程,因此如果需要等待所有任务执行完毕,可以使用`ExecutorService.shutdownNow()`或`ExecutorService.awaitTermination()`。 定时任务是另一个关键特性,Java....
这通常通过调用`ExecutorService`的`shutdown()`或`shutdownNow()`方法实现。 在给出的部分代码中,作者创建了一个名为`Listener`的类,它实现`Runnable`接口,用于监听特定端口并处理客户端请求。线程池`...
ExecutorService则提供了更丰富的操作,如shutdown()用于停止接收新任务并等待已提交任务完成,shutdownNow()尝试停止所有正在执行的任务,以及submit()方法用于提交Callable任务并返回Future结果。 3. Executors...
8. **关闭线程池**:所有任务完成后,记得调用`ExecutorService.shutdown()`或`ExecutorService.shutdownNow()`来关闭线程池,释放资源。 在实际开发中,还可以考虑使用NIO(非阻塞I/O)技术,比如`java.nio....
在上述代码中,我们看到一个典型的应用场景:如果`awaitTermination`在超时后返回false,这意味着不是所有的任务都在规定时间内完成,这时我们调用`executorService.shutdownNow()`。这个方法尝试停止所有正在执行的...
使用`executorService.shutdown()`来等待所有任务完成,或者`executorService.shutdownNow()`来立即停止所有任务。 7. **错误处理**:在多线程环境中,必须处理可能出现的异常,如网络中断、超时或邮件格式错误。...
当所有任务执行完毕,或者 `shutdownNow()` 被调用并所有可取消的任务都被取消时,ExecutorService 进入“已终止”状态。 在 `multithread-master` 压缩包中,可能包含了演示如何使用 `ExecutorService` 创建多线程...
- 调用ExecutorService的shutdown()或shutdownNow()方法关闭线程池。 3. **ForkJoinPool**: - ForkJoinPool是Java 7引入的一种特殊类型的线程池,主要用于并行执行递归任务,特别是适合于分治算法的场景。...
在Java中,可以通过调用ExecutorService的shutdown()或shutdownNow()方法来完成。 ```java public void shutdown() { if (executor != null && !executor.isShutdown()) { executor.shutdown(); } } ``` 综上所...
- 对于多线程应用,`ExecutorService`提供`shutdown()`和`shutdownNow()`方法来停止工作线程。`shutdown()`等待所有已提交的任务执行完毕,而`shutdownNow()`尝试停止所有正在执行的任务。 7. **Docker容器中的...
executor.shutdownNow(); // 关闭线程池 } ``` 在上述代码中,`future.get(5, TimeUnit.SECONDS)`会阻塞当前线程,直到任务完成或超过指定的超时时限。如果任务在规定时间内完成,`get`方法会返回结果;否则,它将...