`

ExecutorService对象的shutdown()和shutdownNow()的区别

阅读更多

        从上篇文章的实例中,我们用了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()应该是在线程执行完毕后,才会去关闭

    `ExecutorService`提供了两种主要的关闭方法:`shutdown()`和`shutdownNow()`。`shutdown()`方法的设计是为了优雅地关闭线程池,它首先拒绝新的任务提交,然后等待当前正在执行的任务执行完毕。这个过程是异步的,...

    ExecutorService线程池

    3. **关闭线程池**:任务执行完毕后,应调用`shutdown()`或`shutdownNow()`方法来停止接收新任务,并等待正在执行的任务完成。`shutdown()`会等待已提交任务执行完毕,而`shutdownNow()`尝试停止所有正在执行的任务...

    2_ExecutorService源码阅读1

    ExecutorService 是 Java 中用于管理和控制线程执行的核心接口,它是 java.util.concurrent 包的一部分。ExecutorService 扩展了 Executor 接口,提供了更丰富的功能,如任务的提交、关闭服务、检查服务状态等。这个...

    Java使用ExecutorService来停止线程服务

    首先,我们需要了解 ExecutorService 的两个关闭方法:shutdown() 和 shutdownNow()。这两个方法的区别在于它们的安全性和响应性。shutdown() 方法会正常关闭线程池,等待所有任务执行完毕后关闭,而 shutdownNow() ...

    java ExecutorService使用方法详解

    而`shutdownNow()`方法会尝试停止所有正在执行的任务,并拒绝新提交的任务。 5. **移除线程** 问题提到如何从线程池中移除或使某个线程成为空闲线程。实际上,`ExecutorService`并不直接提供移除线程的方法。...

    详解Java利用ExecutorService实现同步执行大量线程

    Java中的ExecutorService是Java并发编程的重要组成部分,它提供了一种高效、灵活的方式来管理和控制线程的...同时,合理地关闭ExecutorService(通过`shutdown()`或`shutdownNow()`方法)也是防止资源泄漏的关键步骤。

    JAVA多线程框架.pdf

    需要注意的是,`shutdown()`并不会阻塞调用它的主线程,因此如果需要等待所有任务执行完毕,可以使用`ExecutorService.shutdownNow()`或`ExecutorService.awaitTermination()`。 定时任务是另一个关键特性,Java....

    关闭线程池

    这通常通过调用`ExecutorService`的`shutdown()`或`shutdownNow()`方法实现。 在给出的部分代码中,作者创建了一个名为`Listener`的类,它实现`Runnable`接口,用于监听特定端口并处理客户端请求。线程池`...

    Java ExcutorService优雅关闭方式解析

    关闭时可使用如下代码 public static void waitUntilTerminate(final ExecutorService executorService, final int timeout) { try { executorService.shutdown... executorService.shutdownNow(); } } catch (In

    java多线程断点下载

    8. **关闭线程池**:所有任务完成后,记得调用`ExecutorService.shutdown()`或`ExecutorService.shutdownNow()`来关闭线程池,释放资源。 在实际开发中,还可以考虑使用NIO(非阻塞I/O)技术,比如`java.nio....

    javamail多线程群发

    使用`executorService.shutdown()`来等待所有任务完成,或者`executorService.shutdownNow()`来立即停止所有任务。 7. **错误处理**:在多线程环境中,必须处理可能出现的异常,如网络中断、超时或邮件格式错误。...

    multithread:使用 Java8 ExecutorService 的简单多线程示例

    当所有任务执行完毕,或者 `shutdownNow()` 被调用并所有可取消的任务都被取消时,ExecutorService 进入“已终止”状态。 在 `multithread-master` 压缩包中,可能包含了演示如何使用 `ExecutorService` 创建多线程...

    线程四笔记,对于正在学习Java的朋友可以参考一下

    - 调用ExecutorService的shutdown()或shutdownNow()方法关闭线程池。 3. **ForkJoinPool**: - ForkJoinPool是Java 7引入的一种特殊类型的线程池,主要用于并行执行递归任务,特别是适合于分治算法的场景。...

    ActiveObject模板

    在Java中,可以通过调用ExecutorService的shutdown()或shutdownNow()方法来完成。 ```java public void shutdown() { if (executor != null && !executor.isShutdown()) { executor.shutdown(); } } ``` 综上所...

    shutdown-app

    - 对于多线程应用,`ExecutorService`提供`shutdown()`和`shutdownNow()`方法来停止工作线程。`shutdown()`等待所有已提交的任务执行完毕,而`shutdownNow()`尝试停止所有正在执行的任务。 7. **Docker容器中的...

    java threadpool

    `ExecutorService#shutdownNow()`则尝试停止所有正在执行的任务。 6. **线程池拒绝策略**:当工作队列满且达到最大线程数时,线程池会采取拒绝策略。Java内置了四种策略: - **AbortPolicy**:默认策略,抛出`...

    理解java多线程中ExecutorService使用

    - `shutdownNow()`:尝试停止所有正在执行的任务,并不再接受新任务。 2. **Executor接口**: 这是`ExecutorService`的基础,仅包含一个方法`execute(Runnable)`,用于启动一个任务。它是多线程编程的基本接口,...

    线程池Thread

    3. **关闭线程池**:在不再需要线程池时,应调用`ExecutorService.shutdown()`或`shutdownNow()`方法,以优雅地关闭线程池并等待任务完成。 4. **监控和调整线程池**:在生产环境中,可以使用Java的管理扩展(JMX)...

    Android线程池ExcutorService

    使用`ExecutorService`的`shutdown()`或`shutdownNow()`方法来关闭线程池。`shutdown()`方法会等待所有已提交的任务执行完毕后再停止服务,而`shutdownNow()`会尝试停止正在执行的任务,并阻止新任务的提交。 6. *...

    Java/Android线程池演示Demo

    在应用退出或不再需要线程池时,应调用`ExecutorService`的`shutdown()`或`shutdownNow()`方法来停止接收新任务并逐步终止线程池。`shutdown()`会等待所有已提交的任务执行完毕,而`shutdownNow()`则尝试取消正在...

Global site tag (gtag.js) - Google Analytics