ExecutorService生命周期

转自http://victorzhzh.iteye.com/blog/1010359

ExecutorService接口继承了Executor接口,定义了一些生命周期的方法

Java代码 复制代码  收藏代码
  1. public interface ExecutorService extends Executor {   
  2. void shutdown();   
  3. List<Runnable> shutdownNow();   
  4. boolean isShutdown();   
  5. boolean isTerminated();   
  6. boolean awaitTermination(long timeout, TimeUnit unit)   
  7.         throws InterruptedException;   
  8. }  
public interface ExecutorService extends Executor {
void shutdown();
List<Runnable> shutdownNow();
boolean isShutdown();
boolean isTerminated();
boolean awaitTermination(long timeout, TimeUnit unit)
        throws InterruptedException;
}

本文,我们逐一分析里面的每个方法。

 

首先,我们需要创建一个任务代码,这段任务代码主要是随机生成含有10个字符的字符串

Java代码 复制代码  收藏代码
  1. /**  
  2.  * 随机生成10个字符的字符串  
  3.  * @author dream-victor  
  4.  *  
  5.  */  
  6. public class Task1 implements Callable<String> {   
  7.   
  8.     @Override  
  9.     public String call() throws Exception {   
  10.         String base = "abcdefghijklmnopqrstuvwxyz0123456789";   
  11.         Random random = new Random();   
  12.         StringBuffer sb = new StringBuffer();   
  13.         for (int i = 0; i < 10; i++) {   
  14.             int number = random.nextInt(base.length());   
  15.             sb.append(base.charAt(number));   
  16.         }   
  17.         return sb.toString();   
  18.     }   
  19.   
  20. }  
/**
 * 随机生成10个字符的字符串
 * @author dream-victor
 *
 */
public class Task1 implements Callable<String> {

	@Override
	public String call() throws Exception {
		String base = "abcdefghijklmnopqrstuvwxyz0123456789";
		Random random = new Random();
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < 10; i++) {
			int number = random.nextInt(base.length());
			sb.append(base.charAt(number));
		}
		return sb.toString();
	}

}

 然后,我们还需要一个长任务,这里我们默认是沉睡10秒,

Java代码 复制代码  收藏代码
  1. /**  
  2.  * 长时间任务  
  3.  *   
  4.  * @author dream-victor  
  5.  *   
  6.  */  
  7. public class LongTask implements Callable<String> {   
  8.   
  9.     @Override  
  10.     public String call() throws Exception {   
  11.         TimeUnit.SECONDS.sleep(10);   
  12.         return "success";   
  13.     }   
  14.   
  15. }  
/**
 * 长时间任务
 * 
 * @author dream-victor
 * 
 */
public class LongTask implements Callable<String> {

	@Override
	public String call() throws Exception {
		TimeUnit.SECONDS.sleep(10);
		return "success";
	}

}

OK,所有前期准备完毕,下面我们就来分析一下ExecutorService接口中和生命周期有关的这些方法:

 

1、shutdown方法:这个方法会平滑地关闭ExecutorService,当我们调用这个方法时,ExecutorService停止接受任何新的任务且等待已经提交的任务执行完成(已经提交的任务会分两类:一类是已经在执行的,另一类是还没有开始执行的),当所有已经提交的任务执行完毕后将会关闭ExecutorService。这里我们先不举例在下面举例。

 

2、awaitTermination方法:这个方法有两个参数,一个是timeout即超时时间,另一个是unit即时间单位。这个方法会使线程等待timeout时长,当超过timeout时间后,会监测ExecutorService是否已经关闭,若关闭则返回true,否则返回false。一般情况下会和shutdown方法组合使用。例如:

Java代码 复制代码  收藏代码
  1. ExecutorService service = Executors.newFixedThreadPool(4);   
  2. service.submit(new Task1());   
  3. service.submit(new Task1());   
  4. service.submit(new LongTask());   
  5. service.submit(new Task1());   
  6.   
  7. service.shutdown();   
  8.   
  9. while (!service.awaitTermination(1, TimeUnit.SECONDS)) {   
  10.     System.out.println("线程池没有关闭");   
  11. }   
  12. System.out.println("线程池已经关闭");  
ExecutorService service = Executors.newFixedThreadPool(4);
service.submit(new Task1());
service.submit(new Task1());
service.submit(new LongTask());
service.submit(new Task1());

service.shutdown();

while (!service.awaitTermination(1, TimeUnit.SECONDS)) {
	System.out.println("线程池没有关闭");
}
System.out.println("线程池已经关闭");

 这段代码中,我们在第三次提交了一个长任务,这个任务将执行10秒沉睡,紧跟着执行了一次shutdown()方法,假设:这时ExecutorService被立即关闭,下面调用service.awaitTermination(1, TimeUnit.SECONDS)方法时应该返回true,程序执行结果应该只会打印出:“线程池已经关闭”。但是,真实的运行结果如下:

Java代码 复制代码  收藏代码
  1. 线程池没有关闭   
  2. 线程池没有关闭   
  3. 线程池没有关闭   
  4. 线程池没有关闭   
  5. 线程池没有关闭   
  6. 线程池没有关闭   
  7. 线程池没有关闭   
  8. 线程池没有关闭   
  9. 线程池没有关闭   
  10. 线程池已经关闭  
线程池没有关闭
线程池没有关闭
线程池没有关闭
线程池没有关闭
线程池没有关闭
线程池没有关闭
线程池没有关闭
线程池没有关闭
线程池没有关闭
线程池已经关闭

 这说明我们假设错误,service.awaitTermination(1, TimeUnit.SECONDS)每隔一秒监测一次ExecutorService的关闭情况,而长任务正好需要执行10秒,因此会在前9秒监测时ExecutorService为未关闭状态,而在第10秒时已经关闭,因此第10秒时输出:线程池已经关闭。这也验证了shutdown方法关闭ExecutorService的条件。

 

3、shutdownNow方法:这个方法会强制关闭ExecutorService,它将取消所有运行中的任务和在工作队列中等待的任务,这个方法返回一个List列表,列表中返回的是等待在工作队列中的任务。例如:

Java代码 复制代码  收藏代码
  1. ExecutorService service = Executors.newFixedThreadPool(3);   
  2. service.submit(new LongTask());   
  3. service.submit(new LongTask());   
  4. service.submit(new LongTask());   
  5. service.submit(new LongTask());   
  6. service.submit(new LongTask());   
  7.   
  8. List<Runnable> runnables = service.shutdownNow();   
  9. System.out.println(runnables.size());   
  10.   
  11. while (!service.awaitTermination(1, TimeUnit.MILLISECONDS)) {   
  12.     System.out.println("线程池没有关闭");   
  13. }   
  14. System.out.println("线程池已经关闭");  
		ExecutorService service = Executors.newFixedThreadPool(3);
		service.submit(new LongTask());
		service.submit(new LongTask());
		service.submit(new LongTask());
		service.submit(new LongTask());
		service.submit(new LongTask());
		
		List<Runnable> runnables = service.shutdownNow();
		System.out.println(runnables.size());

		while (!service.awaitTermination(1, TimeUnit.MILLISECONDS)) {
			System.out.println("线程池没有关闭");
		}
		System.out.println("线程池已经关闭");

 这段代码中,我们限制了线程池的长度是3,提交了5个任务,这样将有两个任务在工作队列中等待,当我们执行shutdownNow方法时,ExecutorService被立刻关闭,所以在service.awaitTermination(1, TimeUnit.MILLISECONDS)方法校验时返回的是false,因此没有输出:线程池没有关闭。而在调用shutdownNow方法时,我们接受到了一个List,这里包含的是在工作队列中等待执行的任务,由于线程池长度为3,且执行的都是长任务,所以当提交了三个任务后线程池已经满了,剩下的两次提交只能在工作队列中等待,因此我们看到runnables的大小为2,结果如下:

Java代码 复制代码  收藏代码
  1. 2  
  2. 线程池已经关闭  
2
线程池已经关闭
 

4、isTerminated方法:这个方法会校验ExecutorService当前的状态是否为“TERMINATED”即关闭状态,当为“TERMINATED”时返回true否则返回false。例如:

Java代码 复制代码  收藏代码
  1. ExecutorService service = Executors.newFixedThreadPool(3);   
  2. service.submit(new Task1());   
  3. service.submit(new Task1());   
  4. service.submit(new LongTask());   
  5.   
  6. service.shutdown();   
  7. System.out.println(System.currentTimeMillis());   
  8. while (!service.isTerminated()) {   
  9. }   
  10. System.out.println(System.currentTimeMillis());  
		ExecutorService service = Executors.newFixedThreadPool(3);
		service.submit(new Task1());
		service.submit(new Task1());
		service.submit(new LongTask());

		service.shutdown();
		System.out.println(System.currentTimeMillis());
		while (!service.isTerminated()) {
		}
		System.out.println(System.currentTimeMillis());

这段代码我们执行了两个正常的任务和一个长任务,然后调用了shutdown方法,我们知道调用shutdown方法并不会立即关闭ExecutorService,这时我们记录一下监测循环执行前的时间,在没有关闭前我们一直进入一个空循环中,直到 ExecutorService关闭后退出循环,这里我们知道长任务执行时间大约为10秒,我们看一下上述程序运行结果:

Java代码 复制代码  收藏代码
  1. 1303298818621  
  2. 1303298828634  
  3. 相差:10013毫秒,转换一下除以1000,得到相差大约10秒  
1303298818621
1303298828634
相差:10013毫秒,转换一下除以1000,得到相差大约10秒

这10秒正好是长任务执行的时间,因此在 ExecutorService正常关闭后isTerminated方法返回true。

 

5、isShutdown方法:这个方法在ExecutorService关闭后返回true,否则返回false。方法比较简单不再举例。

以上讨论是基于ThreadPoolExecutor的实现,不同的实现会有所不同需注意。

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值