线程池 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 线程池

(转)线程池 ExecutorService 详细介绍以及注意点区别的更多相关文章

  1. [转] 引用 Java自带的线程池ThreadPoolExecutor详细介绍说明和实例应用

    PS: Spring ThreadPoolTaskExecutor vs Java Executorservice cachedthreadpool 引用 [轰隆隆] 的 Java自带的线程池Thre ...

  2. PAIP.并发编程 多核编程 线程池 ExecutorService的判断线程结束

    PAIP.并发编程 多核编程 线程池 ExecutorService的判断线程结束 ExecutorService并没有提供什么 isDone()或者isComplete()之类的方法. 作者Atti ...

  3. [Java线程] Java线程池ExecutorService

    示例 import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.u ...

  4. 【Java线程】Java线程池ExecutorService

    示例 import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.u ...

  5. Java线程池ExecutorService和CountDownLatch的小例子

    import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java ...

  6. 多线程 线程池 ExecutorService

    package org.zln.thread; import java.util.Date; import java.util.concurrent.ExecutorService; import j ...

  7. Java中的线程池ExecutorService

    示例 import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.u ...

  8. 线程池(ExecutorService)初体验

    背景:查询月统计数据,因为查询日统计数据功能已经实现.月统计数据,只是参一个List(date) 参数,for循环调用日统计,然后把结果整合就OK. 问题:单线程跑  太耗时间 解决方案:使用多线程, ...

  9. 线程池ExecutorService的使用及其正确关闭方法

    创建一个容量为5的线程池 ExecutorService executorService = Executors.newFixedThreadPool(5); 向线程池提交15个任务,其实就是通过线程 ...

随机推荐

  1. 兼容火狐浏览器的select下拉框样式

    经常遇到这样的问题,在使用bootstrap框架的时候select选择框的样式在火狐浏览器上继承的是浏览器本身的样式,跟谷歌等其他的浏览器样式对比很难看,并且很难调整,但是! 好东西来了,现在能调成跟 ...

  2. NX二次开发-如何在类外面定义一个结构体

    #include <uf.h> #include <uf_obj.h> #include <uf_part.h> using namespace NXOpen; u ...

  3. [JZOJ 5861] 失意

    思路: 求交集最大老套路,排序之后用堆维护即可. #include <bits/stdc++.h> using namespace std; const int mod = 1e9+7; ...

  4. 使用Docker在服务器上部署Ubuntu,本地传文件到docker

    使用Docker在服务器上部署Ubuntu,本地传文件到docker 作者:王佳乐 目录 安装Docker 安装Docker 全部安装流程: 登录服务器 ssh username@ip 检查是否已经安 ...

  5. DXP 快捷键

    EC 复制 EY array paste TU: update

  6. 54Mbps、150Mbps、433Mbps 你知道这三个Wi-Fi速率怎么算的吗?

           802.11g能够提供54Mbps的最大速率, 802.11n和802.11ac单流分别能够提供150Mbps和433Mbps的最大速率,这些数字是怎么算的呢?(看红字,更容易理解哟) ...

  7. Mac Eclipse常用快捷键

    Option + Command + X: 运行 Command + O:显示大纲 Command + 1:快速修复 Command + D:删除当前行 Command + Option + ↓:复制 ...

  8. 从0的1学习JavaSE,Jdk的安装

    一.常用的dos命令 dir 罗列出当前目录的下所有文件名字 cd 路径 切换路径,该路径可以是相对于路径也可以是绝对路径 相对路径,只相对于当前的目录下的文件 绝对路径,是从盘符开始的路径地址 注意 ...

  9. 5.1_springboot2.x与安全(spring security)

    1.简介 常见的两个安全框架shiro|spring security,这里只介绍spring security; Spring Security是针对Spring项目的安全框架,也是Spring B ...

  10. CSS代码命名惯例语义化的方法

    CSS代码的命名惯例一直是大家热门讨论的话题.今天暴风彬彬想通过分析一个流行三栏布局中的必要元素,来为大家讲解关于使用语义化方法替代结构化方法来命名CSS类的建议和指导. 您还可以参考彬Go的相关文章 ...