ExecutorService-线程池的关闭及Callable和Runnable区别(二)

272 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第18天,点击查看活动详情

1.6 线程池的关闭

1.6.1 方法说明

shutdown()

停止接收新任务,原来的任务继续执行

英文原意:关闭,倒闭;停工。 这里的意思是 关闭线程池与使用数据库连接池一样,每次使用完毕后,都要关闭线程池。

  1. 停止接收新的submit的任务;
  2. 已经提交的任务(包括正在跑的和队列中等待的),会继续执行完成;
  3. 等到第2步完成后,才真正停止;

shutdownNow()

停止接收新任务,原来的任务停止执行

  1. 跟 shutdown() 一样,先停止接收新submit的任务;

  2. 忽略队列里等待的任务;

  3. 尝试将正在执行的任务interrupt中断;

  4. 返回未执行的任务列表;

    说明:它试图终止线程的方法是通过调用 Thread.interrupt() 方法来实现的,这种方法的作用有限,如果线程中没有sleep 、wait、Condition、定时锁等应用, interrupt() 方法是无法中断当前的线程的。所以,shutdownNow() 并不代表线程池就一定立即就能退出,它也可能必须要等待所有正在执行的任务都执行完成了才能退出。但是大多数时候是能立即退出的。

awaitTermination(long timeOut, TimeUnit unit)

当前线程阻塞

timeout 和 TimeUnit 两个参数,用于设定超时的时间及单位

当前线程阻塞,直到:

  • 等所有已提交的任务(包括正在跑的和队列中等待的)执行完;
  • 或者 等超时时间到了(timeout 和 TimeUnit设定的时间);
  • 或者 线程被中断,抛出InterruptedException

然后会监测 ExecutorService 是否已经关闭,返回true(shutdown请求后所有任务执行完毕)或false(已超时)

1.6.2 区别

shutdown() 和 shutdownNow() 的区别

​ shutdown() 只是关闭了提交通道,用submit()是无效的;而内部该怎么跑还是怎么跑,跑完再停。​ shutdownNow() 能立即停止线程池,正在跑的和正在等待的任务都停下了。

shutdown() 和 awaitTermination() 的区别

​ shutdown() 后,不能再提交新的任务进去;但是 awaitTermination() 后,可以继续提交。 ​ awaitTermination()是阻塞的,返回结果是线程池是否已停止(true/false);shutdown() 不阻塞。

1.6.3 总结

  1. 优雅的关闭,用 shutdown()
  2. 想立马关闭,并得到未执行任务列表,用shutdownNow()
  3. 优雅的关闭,并允许关闭声明后新任务能提交,用 awaitTermination()
  4. 关闭功能 【从强到弱】 依次是:shuntdownNow() > shutdown() > awaitTermination()

1.7 Callable和Runnable

  • 实现Callable接口的线程,执行完后有返回值
  • 实现Runnable接口的线程,执行完后没有返回值

Callable和Runnable的区别

RunnableCallable
返回值重写run方法,没有返回值重写call,通过泛型定义返回值的类型
启动方式1、可以传递到==Thread中通过start启动== 2、可以通过==线程池==的==execute==或者==submit==启动只能通过==线程池的submit==方法启动
容错机制不允许抛出异常,所以无法利用全局方式(例如Spring中的异常通知)处理允许抛出异常,所以可以利用全局方式来处理异常

Callable案例

//创建一个线程池    
ExecutorService pool = Executors.newFixedThreadPool(taskSize);    
// 创建多个有返回值的任务    
List<Future> list = new ArrayList<Future>();    
for (int i = 0; i < taskSize; i++) {    
    Callable c = new MyCallable(i + " ");    
    // 执行任务并获取Future对象    
    Future f = pool.submit(c);     
    list.add(f);    
}    
// 关闭线程池   
pool.shutdown();     
// 获取所有并发任务的运行结果    
for (Future f : list) {    
    // 从Future对象上获取任务的返回值,并输出到控制台    
    System.out.println("res:" + f.get().toString());    
}