Executor框架学习笔记
关于ThreadPoolExecutor的源码解读,请参考我的最新博客《ThreadPoolExecutor源码解读》。
Java中的线程即是工作单元也是执行机制,从JDK 5后,工作单元与执行机制被分离。工作单元包括Runnable和Callable,执行机制由JDK 5中增加的java.util.concurrent包中Executor框架提供。
HotSpot VM的线程模型中将java的线程映射为本地操作系统的线程,java线程的启动意味着一个本地操作系统线程的创建,而java线程的终止也就意味着对应的系统线程的回收。
Executor框架主要包含三个部分:
任务:包括Runnable和Callable,其中Runnable表示一个可以异步执行的任务,而Callable表示一个会产生结果的任务
任务的执行:包括Executor框架的核心接口Executor以及其子接口ExecutorService。在Executor框架中有两个关键类ThreadPoolExecutor和ScheduledThreadPoolExecutor实现了ExecutorService接口。
异步计算的结果:包括接口Future和其实现类FutureTask。
下面是对Executor框架中的一些关键接口与类的简介
Executor接口(java.util.concurrent.Executor)
它是Executor的基础与核心,其定义如下:
public interface Executor {
void execute(Runnable command);
}
它包含了一个方法execute,参数为一个Runnable接口引用。
Executor接口将任务的提交与执行分离开来。
ThreadPoolExecutor类(java.util.concurrent.ThreadPoolExecutor)
它是线程池的核心实现类,用来执行被提交的任务。
它通常由工厂类Executors来创建,Executors可以创建SingleThreadExecutor,FixedThreadPool以及CachedThreadPool等不同的ThreadPoolExecutor。
SingleThreadExecutor使用单线程执行任务,Executors提供的API有如下两个
public static ExecutorService newSingleThreadExecutor();
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory);
SingleThreadExecutor保证了任务执行的顺序,不会存在多线程活动。
FixedThreadPool是使用固定线程数的线程池,Executors提供的API有如下两个
public static ExecutorService newFixedThreadPool(int nThreads);
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory);
FixedThreadPool满足了资源管理的需求,可以限制当前线程数量。适用于负载较重的服务器环境。
CachedThreadPool是无界线程池,Executors提供的API有如下两个
public static ExecutorService newCachedThreadPool();
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory);
CachedThreadPool适用于执行很多短期异步任务的小程序,适用于负载较轻的服务器。
ScheduledThreadPoolExecutor类(java.util.concurrent.ScheduledThreadPoolExecutor)
它是ThreadPoolExecutor的子类且实现了ScheduledExecutorService接口,它可以在给定的延迟时间后执行命令,或者定期执行命令,它比Timer更强大更灵活。
Executors可以创建的ScheduledThreadPoolExecutor的类型有ScheduledThreadPoolExecutor和SingleThreadScheduledExecutor等
ScheduledThreadPoolExecutor具有固定线程个数,适用于需要多个后台线程执行周期任务,并且为了满足资源管理需求而限制后台线程数量的场景,Executors中提供的API有如下两个:
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize);
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory);
SingleThreadScheduledExecutor具有单个线程,Executors提供的创建API有如下两个:
public static ScheduledExecutorService newSingleThreadScheduledExecutor();
public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory);
它适用于单个后台线程执行周期任务,并且保证顺序一致执行的场景。
上述的ThreadPoolExecutor和ScheduledThreadPoolExecutor都可以用于执行Runnable与Callable接口的实现类
Future接口(Java.concurrent.Future)
Future代表着提交的任务的计算状态与结果,可以对其进行取消,查询是否取消,查询是否完成,查询结果等操作。
首先来看一下Future接口的定义:
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
FutureTask类间接实现了Future接口,它用来表示异步计算的结果。当ThreadPoolExecutor或者ScheduledThreadPoolExecutor执行Runnable接口或者Callable接口的实现类时,它们会返回一个Future接口引用(实现类为FutureTask)。
Runnable接口或者Callable接口的实现类在被上述两者执行的区别是,前者没有返回结果,而后者可以返回结果。Runnable可以通过Executors提供的API(Executors#callable)包装为Callable。
本文参考资料:《Java并发编程的艺术》以及其他网上文档
-----------------------------------------------------------------------------------------------------------------
下面是一些简单的Demo程序
import java.util.concurrent.Executor;
import java.util.concurrent.Executors; public class ExecutorTest {
public static void main(String[] args) { Runnable hello = () -> {
for (int i = 0; i < 100; i++) {
System.out.println(i + " hello");
}
};
Runnable bye = () -> {
for (int i = 0; i < 100; i++) {
System.out.println(i + " bye");
}
}; Executor executor = Executors.newCachedThreadPool(); executor.execute(hello);
executor.execute(bye); }
}
上面程序使用了两个Runnable任务hello和bye来打印相应语句,程序将会交错打印hello和bye。如果将executor改为SingleThreadExecutor,将会先打印100个"hello",再打印100个"bye"。
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 ExecutorTest {
public static void main(String[] args) {
Random random = new Random();
List<Integer> numbers = new ArrayList<>();
for (int i = 0; i < 100000; i++) {
numbers.add(random.nextInt(100000));
}
int result = calculate(numbers, 3);
System.out.println(result);
} public static int calculate(List<Integer> numbers,int digit) {
List<Callable<Integer>> tasks = new ArrayList<>();
for (Integer x : numbers) {
tasks.add(() -> {
int count=0;
int y=x;
do {
if (y % 10 == digit) {
count++;
}
y /= 10;
} while (y > 0);
return count;
});
}
ExecutorService service = Executors.newFixedThreadPool(10);
int answer=0;
try {
List<Future<Integer>> results = service.invokeAll(tasks);
for (Future<Integer> result : results) {
try {
answer+=result.get();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return answer;
}
}
上面的程序随机生成了100000个随机数,然后统计这些数字中每个数字10进制中具有多少个数位3的数量和。使用具有10个线程的线程池进行计算,最终通过Future引用对象的结果来统计答案。
Executor框架学习笔记的更多相关文章
- phalcon(费尔康)框架学习笔记
phalcon(费尔康)框架学习笔记 http://www.qixing318.com/article/phalcon-framework-to-study-notes.html 目录结构 pha ...
- Yii框架学习笔记(二)将html前端模板整合到框架中
选择Yii 2.0版本框架的7个理由 http://blog.chedushi.com/archives/8988 刚接触Yii谈一下对Yii框架的看法和感受 http://bbs.csdn.net/ ...
- JavaSE中Collection集合框架学习笔记(2)——拒绝重复内容的Set和支持队列操作的Queue
前言:俗话说“金三银四铜五”,不知道我要在这段时间找工作会不会很艰难.不管了,工作三年之后就当给自己放个暑假. 面试当中Collection(集合)是基础重点.我在网上看了几篇讲Collection的 ...
- JavaSE中Collection集合框架学习笔记(3)——遍历对象的Iterator和收集对象后的排序
前言:暑期应该开始了,因为小区对面的小学这两天早上都没有像以往那样一到七八点钟就人声喧闹.车水马龙. 前两篇文章介绍了Collection框架的主要接口和常用类,例如List.Set.Queue,和A ...
- JavaSE中Map框架学习笔记
前言:最近几天都在生病,退烧之后身体虚弱.头疼.在床上躺了几天,什么事情都干不了.接下来这段时间,要好好加快进度才好. 前面用了三篇文章的篇幅学习了Collection框架的相关内容,而Map框架相对 ...
- JavaSE中线程与并行API框架学习笔记1——线程是什么?
前言:虽然工作了三年,但是几乎没有使用到多线程之类的内容.这其实是工作与学习的矛盾.我们在公司上班,很多时候都只是在处理业务代码,很少接触底层技术. 可是你不可能一辈子都写业务代码,而且跳槽之后新单位 ...
- JavaSE中线程与并行API框架学习笔记——线程为什么会不安全?
前言:休整一个多月之后,终于开始投简历了.这段时间休息了一阵子,又病了几天,真正用来复习准备的时间其实并不多.说实话,心里不是非常有底气. 这可能是学生时代遗留的思维惯性--总想着做好万全准备才去做事 ...
- scrapy爬虫框架学习笔记(一)
scrapy爬虫框架学习笔记(一) 1.安装scrapy pip install scrapy 2.新建工程: (1)打开命令行模式 (2)进入要新建工程的目录 (3)运行命令: scrapy sta ...
- TensorFlow机器学习框架-学习笔记-001
# TensorFlow机器学习框架-学习笔记-001 ### 测试TensorFlow环境是否安装完成-----------------------------```import tensorflo ...
随机推荐
- 解决springmvc在单纯返回一个字符串对象时所出现的乱码情况(极速版)
使用springmvc框架开发了这么长时间,之前都是直接返回jsp页面,乱码情况都是通过配置和手动编解码来解决,但是今天突然返回一段单纯的字符串时,发现中文乱码情况解决不了了,下面就给各位分享一下如何 ...
- Java面试13|算法
1.冒泡排序 for(int i=0;i<n;i++){ for(int j=0;j<n-1-i;j++){ if(temp[j]>temp[j+1]){ int t=temp[j] ...
- Struts2中的配置文件的加载
Struts2框架配置文件加载顺序(服务器启动之后, 这些配置文件会按照顺序一一加载进内存, 进行类等匹配的时候才会去内存查找): 1. default.properties 2. str ...
- struts2知识点复习
一. MVC Model 1:将所有的程序代码,都写到JSP页面中. Model 2:JSP(流程控制.数据显示) + JavaBean 改进的Model2:Servlet(流程控制) + Jsp(数 ...
- 九度OJ题目1080:进制转换(java)使用BigInteger进行进制转换
题目描述: 将M进制的数X转换为N进制的数输出. 输入: 输入的第一行包括两个整数:M和N(2<=M,N<=36). 下面的一行输入一个数X,X是M进制的数,现在要求你将M进制的数X转换成 ...
- Selenium自动化脚本开发总结
Selenium Selenium 是ThoughtWorks专门为Web应用程序编写的一个验收测试工具. Selenium测试直接运行在浏览器中,就像真正的用户在操作一样.支持的浏览器包括IE.Mo ...
- SQL函数和SQL Server2008
1.绝对值 SQL:select abs(-1) value O:select abs(-1) value from dual 2.取整(大) S:select ceiling(-1.00 ...
- [译]Selenium Python文档:五、Waits等待
大多数现代web应用都使用了AJAX技术.当浏览器加载一个页面的时候,该页面内的元素可能在不用的时间间隔内进行加载.这使得元素定位变得比较困难:如果一个元素还没有出现在DOM中,定位函数将会抛出一个E ...
- .net平台的MongoDB使用
前言 最近花了点时间玩了下MongoDB.Driver,进行封装了工具库,平常也会经常用到MongoDB,因此写一篇文章梳理知识同时把自己的成果分享给大家. 本篇会设计到Lambda表达式的解析,有兴 ...
- 读书笔记 effective c++ Item 39 明智而谨慎的使用private继承
1. private 继承介绍 Item 32表明C++把public继承当作”is-a”关系来对待.考虑一个继承体系,一个类Student public 继承自类Person,如果一个函数的成功调用 ...