线程池 ExecutorService 相信java开发都用到,这里做个简单笔记

一 Java通过Executors提供四种线程池,分别为: 
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。 
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。 
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。 
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

二、 ExecutorService 的submit() 与execute()区别 
1、接收的参数不一样 submit()可以接受runnable无返回值和callable有返回值 
execute()接受runnable 无返回值

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告诉我它的执行结果,是成功还是失败,如果是失败,原因是什么。

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抛出的异常。

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future; public class ExecutorServiceTest {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
List<Future<String>> resultList = new ArrayList<Future<String>>(); // 创建10个任务并执行
for (int i = 0; i < 10; i++) {
// 使用ExecutorService执行Callable类型的任务,并将结果保存在future变量中
Future<String> future = executorService.submit(new TaskWithResult(i));
// 将任务执行结果存储到List中
resultList.add(future);
}
executorService.shutdown(); // 遍历任务的结果
for (Future<String> fs : resultList) {
try {
System.out.println(fs.get()); // 打印各个线程(任务)执行的结果
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
executorService.shutdownNow();
e.printStackTrace();
return;
}
}
}
} class TaskWithResult implements Callable<String> {
private int id; public TaskWithResult(int id) {
this.id = id;
} /**
* 任务的具体过程,一旦任务传给ExecutorService的submit方法,则该方法自动在一个线程上执行。
*
* @return
* @throws Exception
*/
public String call() throws Exception {
System.out.println("call()方法被自动调用,干活!!! " + Thread.currentThread().getName());
if (new Random().nextBoolean())
throw new TaskException("Meet error in task." + Thread.currentThread().getName());
// 一个模拟耗时的操作
for (int i = 999999999; i > 0; i--)
;
return "call()方法被自动调用,任务的结果是:" + id + " " + Thread.currentThread().getName();
}
} class TaskException extends Exception {
public TaskException(String message) {
super(message);
}
}
  • 1
  • 2
  • 3

执行的结果类似于:

call()方法被自动调用,干活!!!             pool-1-thread-1
call()方法被自动调用,干活!!! pool-1-thread-2
call()方法被自动调用,干活!!! pool-1-thread-3
call()方法被自动调用,干活!!! pool-1-thread-5
call()方法被自动调用,干活!!! pool-1-thread-7
call()方法被自动调用,干活!!! pool-1-thread-4
call()方法被自动调用,干活!!! pool-1-thread-6
call()方法被自动调用,干活!!! pool-1-thread-7
call()方法被自动调用,干活!!! pool-1-thread-5
call()方法被自动调用,干活!!! pool-1-thread-8
call()方法被自动调用,任务的结果是:0 pool-1-thread-1
call()方法被自动调用,任务的结果是:1 pool-1-thread-2
java.util.concurrent.ExecutionException: com.cicc.pts.TaskException: Meet error in task.pool-1-thread-3
at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:222)
at java.util.concurrent.FutureTask.get(FutureTask.java:83)
at com.cicc.pts.ExecutorServiceTest.main(ExecutorServiceTest.java:29)
Caused by: com.cicc.pts.TaskException: Meet error in task.pool-1-thread-3
at com.cicc.pts.TaskWithResult.call(ExecutorServiceTest.java:57)
at com.cicc.pts.TaskWithResult.call(ExecutorServiceTest.java:1)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)
  • 1
  • 2
  • 3

可以看见一旦某个task出错,其它的task就停止执行。

三、shotdown() showdownNow()区别

可以关闭 ExecutorService,这将导致其拒绝新任务。提供两个方法来关闭 ExecutorService。 
shutdown() 方法在终止前允许执行以前提交的任务, 
shutdownNow() 方法阻止等待任务启动并试图停止当前正在执行的任务。在终止时执行程序没有任务在执行,也没有任务在等待执行,并且无法提交新任务。关闭未使用的 ExecutorService 以允许回收其资源。 
一般分两个阶段关闭 ExecutorService。第一阶段调用 shutdown 拒绝传入任务,然后调用 shutdownNow(如有必要)取消所有遗留的任务

// 启动一次顺序关闭,执行以前提交的任务,但不接受新任务。
threadPool.shutdown();
  • 1
  • 2

四、Runnable()与Callable()区别

如果是一个多线程协作程序,比如菲波拉切数列,1,1,2,3,5,8…使用多线程来计算。 
但后者需要前者的结果,就需要用callable接口了。 
callable用法和runnable一样,只不过调用的是call方法,该方法有一个泛型返回值类型,你可以任意指定。

runnable接口实现的没有返回值的并发编程。 
 
callable实现的存在返回值的并发编程。(call的返回值String受泛型的影响) 使用Future获取返回值。 

ExecutorService 线程池

最新文章

  1. 在Python中调用glutInit遇到OpenGL.error.NullFunctionError的解决方法
  2. Linux开机流程
  3. POJ1125 Stockbroker Grapevine
  4. 【开源项目10】安卓图表引擎AChartEngine
  5. (ACM)C++ STL 训练(第一天)
  6. php-PHP试题
  7. POJ1942——Paths on a Grid(组合数学)
  8. java中的Package语句和import语句
  9. DevExpress之进度条
  10. leetcode第一刷_Merge Sorted Array
  11. 彻底领悟javascript中的this
  12. js函数柯里化,实现bind
  13. 优化算法系列-遗传算法(3)——NSGAII学习网址
  14. 【Python3学习】Python环境搭建
  15. Apollo 7 — ConfigService 消息扫描设计实现
  16. Android-TextView 控件常用属性以及基本用法
  17. 关于移动端及flex
  18. 面向对象特征:封装、多态 以及 @propetry装饰器
  19. 【托业】【新托业TOEIC新题型真题】学习笔记7-题库二-&gt;P1~4
  20. git revert 撤销merge的动作

热门文章

  1. 后缀自动机求字典序第k小的串——p3975
  2. iptables开通某些端口
  3. NX二次开发-C++ CopyFile函数的用法
  4. [JZOJ 5810] 简单的玄学
  5. jquery判断对象是undifined,判断对象是null
  6. 剑指offer——19删除链表的节点
  7. jquery操作html元素之( 获取并设置 CSS 类)
  8. Vue——组件上使用v-model
  9. netty 文件传输
  10. 纯css制作小三角