AbstractExecutorService的submit方法概要介绍
1.概述
ExecutorService是JDK提供的框架,它简化了异步模式下的任务执行。一般来说,ExecutorService会自动提供一个线程池和API,用于为其分配任务。
2.实例化ExecutorService
2.1 Executors类的工厂方法
打造ExecutorService最简单的方法是使用的的工厂方法之一Executors类。
例如,以下代码行将创建一个包含10个线程的线程池:
ExecutorService executor = Executors.newFixedThreadPool(10);
还有其他几种工厂方法可以创建满足特定用例的预定义ExecutorService。要找到满足您需求的最佳方法,请参阅Oracle官方文档。
2.2 直接创建ExecutorService
因为ExecutorService是一个接口,所以可以使用其任何实现的实例。在java.util.concurrent中有几种实现可供选择包中或者您可以创建自己的实现。
例如,ThreadPoolExecutor类有一些构造函数,可用于配置执行程序服务及其内部池。
ExecutorService executorService = new ThreadPoolExecutor(1,1, 0L,TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
您可能会注意到上面的代码与工厂方法newSingleThreadExecutor()的源代码非常相似。对于大多数情况,不需要详细的手动配置。
3.将任务分配给ExecutorService
ExecutorService可以执行Runnable和Callable任务。为了简化本文,将使用两个原始任务。请注意,此处使用lambda表达式而不是匿名内部类:
Runnable runnableTask = () -> {
try {
TimeUnit.MILLISECONDS.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
};
Callable<String> callableTask = () -> {
TimeUnit.MILLISECONDS.sleep(300);
return "Task's execution";
};
List<Callable<String>> callableTasks = new ArrayList<>();
callableTasks.add(callableTask);
callableTasks.add(callableTask);
callableTasks.add(callableTask);
可以使用多种方法将任务分配给ExecutorService,包括从Executor接口继承的execute(),以及submit(),invokeAny(),invokeAll()。
该execute()方法是void的,而且不能获得任务的执行结果或检查任务的状态(是否运行或执行)。
executorService.execute(runnableTask);
submit()将一个Callable或Runnable任务提交给ExecutorService并返回Future类型的结果。
Future<String> future = executorService.submit(callableTask);
invokeAny()将一组任务分配给ExecutorService,使每个任务执行,并返回成功执行一个任务的结果(如果成功执行)。
String result = executorService.invokeAny(callableTasks);
invokeAll()将一组任务分配给ExecutorService,使每个任务执行,并以Future类型的对象列表的形式返回所有任务执行的结果。
List<Future<String>> futures = executorService.invokeAll(callableTasks);
现在,在继续之前,还必须讨论另外两件事:关闭ExecutorService并处理Future返回类型。
4.关闭ExecutorService
一般来说,ExecutorService当没有要处理的任务时,不会自动销毁。它会活着并等待新的工作要做。
在某些情况下,这非常有用; 例如,如果应用程序需要处理不规则出现的任务,或者在编译时不知道这些任务的数量。
另一方面,应用程序可以到达它的终点,但它不会被停止,因为等待的ExecutorService将导致JVM继续运行。
要正确关闭ExecutorService,我们有shutdown()和shutdownNow() API。
该shutdown() 方法不会导致立即销毁ExecutorService。它将使ExecutorService停止接受新任务,并在所有正在运行的线程完成当前工作后关闭。
executorService.shutdown();
该shutdownNow()方法试图立即摧毁ExecutorService,但是它并不能保证所有正在运行的线程将同时停止。此方法返回等待处理的任务列表。由开发人员决定如何处理这些任务。
List<Runnable> notExecutedTasks = executorService.shutDownNow();
关闭ExecutorService(Oracle也推荐)的一个好方法是使用这两种方法结合awaitTermination()方法。使用这种方法,ExecutorService将首先停止执行新任务,等待指定的时间段完成所有任务。如果该时间到期,则立即停止执行:
executorService.shutdown();
try {
if (!executorService.awaitTermination(800, TimeUnit.MILLISECONDS)) {
executorService.shutdownNow();
}
} catch (InterruptedException e) {
executorService.shutdownNow();
}
5. *Future *接口
在submit()和的invokeAll()方法返回一个对象或类型的对象的集合*Future *,这使我们能够得到一个任务的执行结果或检查任务的状态(是否运行或执行)。
该Future 接口提供了一个特殊的阻塞方法get() ,它返回的实际结果,Callable任务的执行或无效的情况下Runnable任务。在任务仍在运行时调用get()方法将导致执行被阻塞,直到任务正确执行并且结果可用。
Future<String> future = executorService.submit(callableTask);
String result = null;
try {
result = future.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
由于get()方法导致非常长的阻塞,应用程序的性能会降低。如果结果数据不重要,可以通过使用超时来避免这样的问题:
String result = future.get(200, TimeUnit.MILLISECONDS);
如果执行周期长于指定的时间(在本例中为200毫秒),则将抛出TimeoutException。
该isDone()方法可用于检查所分配的任务已经处理或没有。
该Future 接口还提供了任务执行的取消方法cancel(),以及检查取消状态的isCancelled()方法:
boolean canceled = future.cancel(true);
boolean isCancelled = future.isCancelled();
6. ScheduledExecutorService接口
该ScheduledExecutorService的运行一些预定义的延迟和/或定期后任务。再一次,实例化ScheduledExecutorService的最佳方法是使用Executors类的工厂方法。
对于本节,将使用具有一个线程的ScheduledExecutorService:
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
要在固定延迟之后安排单个任务的执行,请使用ScheduledExecutorService的scheduled()方法。有两个scheduled()方法允许您执行Runnable或Callable任务:
Future<String> resultFuture = executorService.schedule(callableTask, 1, TimeUnit.SECONDS);
该scheduleAtFixedRate()方法允许一个固定的延迟之后定期执行的任务。上面的代码在执行callableTask之前延迟了一秒钟。
下面的代码块将在100毫秒的初始延迟后执行任务,之后,它将每450毫秒执行相同的任务。如果处理器需要更多时间来执行分配的任务而不是scheduleAtFixedRate()方法的period参数,则ScheduledExecutorService将等到当前任务完成后才开始下一个:
Future<String> resultFuture = service.scheduleAtFixedRate(runnableTask, 100, 450, TimeUnit.MILLISECONDS);
如果必须在任务的迭代之间具有固定长度的延迟,则应使用scheduleWithFixedDelay()。例如,以下代码将保证当前执行结束与另一个执行结束之间的暂停时间为150毫秒。
service.scheduleWithFixedDelay(task, 100, 150,TimeUnit.MILLISECONDS);
根据scheduleAtFixedRate()和scheduleWithFixedDelay()方法契约,任务的句点执行将在ExecutorService终止时结束,或者在任务执行期间抛出异常。
7. ExecutorService与Fork / Join
在Java 7发布之后,许多开发人员决定将ExecutorService框架替换为fork / join框架。然而,这并不总是正确的决定。尽管使用简单且与fork / join相关的频繁性能提升,但开发人员对并发执行的控制量也有所减少。
ExecutorService使开发人员能够控制生成的线程数以及应由不同线程执行的任务粒度。ExecutorService的最佳用例是处理独立任务,例如根据“一个任务的一个线程”方案的事务或请求。
相比之下,根据Oracle的文档,fork / join旨在加速工作,可以递归地分成更小的部分。
8.结论
尽管ExecutorService相对简单,但仍有一些常见的陷阱。让我们总结一下:
保持未使用的ExecutorService处于活动状态: 本文第4节中有关于如何关闭ExecutorService的详细说明;
使用固定长度线程池时错误的线程池容量:确定应用程序有效执行任务所需的线程数非常重要。一个太大的线程池只会产生不必要的开销,只是为了创建大多数将处于等待模式的线程。由于队列中任务的等待时间很长,因此太少可以使应用程序看起来没有响应;
任务取消后调用Future的get()方法: 尝试获取已取消任务的结果将触发CancellationException。
使用Future的get()方法意外地阻塞: 应该使用超时来避免意外的等待。
原文地址:https://blog.csdn.net/Growing_stu/article/details/84328723
AbstractExecutorService的submit方法概要介绍的更多相关文章
- JMeter学习-005-JMeter 主要组件概要介绍及执行顺序
本文将对 JMeter 主要组件(主要涉及 Threads(Users).Test Fragment.逻辑控制器.配置元件.定时器.前置处理器.Sampler.后置处理器.断言.监听器 十大组件)进行 ...
- 13.ThreadPoolExecutor线程池之submit方法
jdk1.7.0_79 在上一篇<ThreadPoolExecutor线程池原理及其execute方法>中提到了线程池ThreadPoolExecutor的原理以及它的execute方法 ...
- 并发编程(十二)—— Java 线程池 实现原理与源码深度解析 之 submit 方法 (二)
在上一篇<并发编程(十一)—— Java 线程池 实现原理与源码深度解析(一)>中提到了线程池ThreadPoolExecutor的原理以及它的execute方法.这篇文章是接着上一篇文章 ...
- jquery 通过submit()方法 提交表单示例
jquery 通过submit()方法 提交表单示例: 本示例:以用户注册作为例子.使用jquery中的submit()方法实现表单提交. 注:本示例仅提供了对表单的验证,本例只用选用了三个字段作为测 ...
- KEGG数据库的使用方法与介绍
KEGG数据库的使用方法与介绍 KEGG的数据 KEGG中的pathway是根据相关知识手绘的,这里的手绘的意思可能是指人工以特定的语言格式来确定通路各组件的联系:基因组信息主要是从NCBI等数据库中 ...
- Ext.Ajax.request()方法和FormPanel.getForm().submit()方法,都返回success()方法的差异
我还是不发表到博客园首页吧,要不然还是要被取消,>_< 还是言归正传吧,关于Ext.Ajax.request()方法和FormPanel.getForm().submit()方法返回suc ...
- js和jq使用submit方法无法提交表单
昨天,在做一个表单异步提交内容的时候,遇到很奇怪的问题,submit()方法无法进行提交,每次提交都是把 当前给刷新了,网络抓包发现,每次都是 get方式去获取 当前页面,完全没有post 请求,想着 ...
- 使用Memcache在PHP中调试方法的介绍及应用
使用Memcache在PHP中调试方法的介绍及应用 如果我们在网络开发中,特别是大访问量的web项目开发中,为了提高响应速度,减少数据查询运算,那么我们都会选用memcahce.首先我们必须要安装,接 ...
- InputStreamReader 和 OutputStreamWriter类使用方法简单介绍,及演示。
InputStreamReader 和 OutputStreamWriter类使用方法简单介绍. 一.InputStreamReader类 InputStreamReader 将字节流转换为字符流.是 ...
随机推荐
- 斐波那契字符串_KMP
前言:通过这道题恶补了一下字符串匹配的知识 思路:首先就是求出菲波那切字符串,这个很简单,但是要注意递归超时的问题,可以考虑加上备忘录,或者用递推法,接下来就是匹配问题了,常规的BF会超时,所以要用K ...
- 20190815-$N \Theta IP$
$NOIP$ 请选择您想测试的难度: 「困难」 「困难的地狱」 「能被神犇切掉的」 「你做不出来的」 「简单(完成前面所有后解锁)」 要难死了-- 考试过程: 首先看看三道题: 这是NOIP模拟测试? ...
- Ubuntu linux下部署golang配置环境,极客学院 无闻讲的安装配置是错的,折腾我好几遍,真是有点坑
开始按极客学院无闻讲的做,弄了几遍都不行,最后发现是错的,别人告诉我这是mac下的virtualbox是这样的,不管怎样,被坑的不浅. 虽然sudo apt install golang-go 就能安 ...
- linux 下建立桌面快捷方式
这段时间从windows转到了Linux,发现桌面上没有快捷方式很不适应,找了好久资料,找到解决方法,记录下来以后备用 1.首先建立一个新文件 ``` vi quick.desktop //后缀为de ...
- java.lang.ClassCastException: java.io.ByteArrayInputStream cannot be cast to java.io.FileInputStream
今天在做文件上传的时候遇到一个这样的问题 java.lang.ClassCastException: java.io.ByteArrayInputStream cannot be cast to ja ...
- day37 08-Hibernate的反向工程
反向工程:先创建表,创建好表之后,就是持久化类和映射文件可以不用你写,而且你的DAO它也可以帮你生成.但是它生成的DAO可能会多很多的方法.你可以不用那么多方法,但是它里面提供了这种的.用hibern ...
- Liferay 7.1发布啦
下载地址: https://cdn.lfrs.sl/releases.liferay.com/portal/7.1.0-m1/liferay-ce-portal-tomcat-7.1-m1-20180 ...
- vue使用填坑之:model和v-model的区别
v-model通常用于input的双向数据绑定 <input v-model="parentMsg">,也可以实现子组件到父组件数据的双向数据绑定:首先说说v-mode ...
- 分布式--ActiveMQ 消息中间件(一) https://www.jianshu.com/p/8b9bfe865e38
1. ActiveMQ 1). ActiveMQ ActiveMQ是Apache所提供的一个开源的消息系统,完全采用Java来实现,因此,它能很好地支持J2EE提出的JMS(Java Message ...
- 【python小随笔】Django+错误日志(配置Django报错文件指定位置)
1: 自定义日志文件.py----------几个文件需要创建日志,就需要重新定义几份 # 定义一个日志文件 创建一个操作日志对象logger file_1 = logging.FileHandle ...