java并发中ExecutorService的使用
文章目录
java并发中ExecutorService的使用
ExecutorService是java中的一个异步执行的框架,通过使用ExecutorService可以方便的创建多线程执行环境。
本文将会详细的讲解ExecutorService的具体使用。
创建ExecutorService
通常来说有两种方法来创建ExecutorService。
第一种方式是使用Executors中的工厂类方法,例如:
ExecutorService executor = Executors.newFixedThreadPool(10);
除了newFixedThreadPool方法之外,Executors还包含了很多创建ExecutorService的方法。
第二种方法是直接创建一个ExecutorService, 因为ExecutorService是一个interface,我们需要实例化ExecutorService的一个实现。
这里我们使用ThreadPoolExecutor来举例:
ExecutorService executorService =
new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
为ExecutorService分配Tasks
ExecutorService可以执行Runnable和Callable的task。其中Runnable是没有返回值的,而Callable是有返回值的。我们分别看一下两种情况的使用:
Runnable runnableTask = () -> {
try {
TimeUnit.MILLISECONDS.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
};
Callable<String> callableTask = () -> {
TimeUnit.MILLISECONDS.sleep(300);
return "Task's execution";
};
将task分配给ExecutorService,可以通过调用xecute(), submit(), invokeAny(), invokeAll()这几个方法来实现。
execute() 返回值是void,他用来提交一个Runnable task。
executorService.execute(runnableTask);
submit() 返回值是Future,它可以提交Runnable task, 也可以提交Callable task。 提交Runnable的有两个方法:
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);
第一个方法在返回传入的result。第二个方法返回null。
再看一下callable的使用:
Future<String> future =
executorService.submit(callableTask);
invokeAny() 将一个task列表传递给executorService,并返回其中的一个成功返回的结果。
String result = executorService.invokeAny(callableTasks);
invokeAll() 将一个task列表传递给executorService,并返回所有成功执行的结果:
List<Future<String>> futures = executorService.invokeAll(callableTasks);
关闭ExecutorService
如果ExecutorService中的任务运行完毕之后,ExecutorService不会自动关闭。它会等待接收新的任务。如果需要关闭ExecutorService, 我们需要调用shutdown() 或者 shutdownNow() 方法。
shutdown() 会立即销毁ExecutorService,它会让ExecutorServic停止接收新的任务,并等待现有任务全部执行完毕再销毁。
executorService.shutdown();
shutdownNow()并不保证所有的任务都被执行完毕,它会返回一个未执行任务的列表:
List<Runnable> notExecutedTasks = executorService.shutdownNow();
oracle推荐的最佳关闭方法是和awaitTermination一起使用:
executorService.shutdown();
try {
if (!executorService.awaitTermination(800, TimeUnit.MILLISECONDS)) {
executorService.shutdownNow();
}
} catch (InterruptedException e) {
executorService.shutdownNow();
}
先停止接收任务,然后再等待一定的时间让所有的任务都执行完毕,如果超过了给定的时间,则立刻结束任务。
Future
submit() 和 invokeAll() 都会返回Future对象。之前的文章我们已经详细讲过了Future。 这里就只列举一下怎么使用:
Future<String> future = executorService.submit(callableTask);
String result = null;
try {
result = future.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
ScheduledExecutorService
ScheduledExecutorService为我们提供了定时执行任务的机制。
我们这样创建ScheduledExecutorService:
ScheduledExecutorService executorService
= Executors.newSingleThreadScheduledExecutor();
executorService的schedule方法,可以传入Runnable也可以传入Callable:
Future<String> future = executorService.schedule(() -> {
// ...
return "Hello world";
}, 1, TimeUnit.SECONDS);
ScheduledFuture<?> scheduledFuture = executorService.schedule(() -> {
// ...
}, 1, TimeUnit.SECONDS);
还有两个比较相近的方法:
scheduleAtFixedRate( Runnable command, long initialDelay, long period, TimeUnit unit )
scheduleWithFixedDelay( Runnable command, long initialDelay, long delay, TimeUnit unit )
两者的区别是前者的period是以任务开始时间来计算的,后者是以任务结束时间来计算。
ExecutorService和 Fork/Join
java 7 引入了Fork/Join框架。 那么两者的区别是什么呢?
ExecutorService可以由用户来自己控制生成的线程,提供了对线程更加细粒度的控制。而Fork/Join则是为了让任务更加快速的执行完毕。
本文的代码请参考https://github.com/ddean2009/learn-java-concurrency/tree/master/ExecutorService
更多教程请参考 flydean的博客
java并发中ExecutorService的使用的更多相关文章
- java并发中的Synchronized关键词
文章目录 为什么要同步 Synchronized关键词 Synchronized Instance Methods Synchronized Static Methods Synchronized B ...
- 深入浅出Java并发中的CountDownLatch
1. CountDownLatch 正如每个Java文档所描述的那样,CountDownLatch是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行.在Java并发中 ...
- java并发中CountDownLatch的使用
文章目录 主线程等待子线程全都结束之后再开始运行 等待所有线程都准备好再一起执行 停止CountdownLatch的await java并发中CountDownLatch的使用 在java并发中,控制 ...
- Java 并发工具包——ExecutorService常用线程池
1. 执行器服务 ExecutorService java.util.concurrent.ExecutorService 接口表示一个异步执行机制,使我们能够在后台执行任务.因此一个 Executo ...
- Java并发中的CopyOnWrite容器
Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改, ...
- 一起来看看java并发中volatile关键字的神奇之处
并发编程中的三个概念: 1.原子性 在Java中,对基本数据类型的变量的读取和赋值操作是原子性操作,即这些操作是不可被中断的,要么执行,要么不执行. 2.可见性 对于可见性,Java提供了volati ...
- Volatile 原理及使用,java并发中的可见性问题
1.解决并发编程中的可见性问题 volatile 代表不使用cpu缓存,修改后的数据,将直接刷到内存中,被volatile修饰的变量,读取的时候,也是从内存中读取,不从cpu缓存中读取 上代码 // ...
- java并发中的Semaphore
什么是Semaphore Semaphore可以控制某个资源可被同时访问的个数(locks和synchronized锁,在任何时刻只允许一个任务访问一个资源),通过acquire()获取一个许可,如果 ...
- java concurrent 中ExecutorService和CompletionService简单区别
举个例子,现在需要执行10个任务,这些任务都是有返回值,并且需要使用10个线程同时执行.一般的做法就是创建ExecutorService线程池,pool大小10,每个任务实现Callable接口,然后 ...
随机推荐
- GO gRPC教程-环境安装(一)
前言 gRPC 是一个高性能.开源和通用的 RPC 框架,面向移动和 HTTP/2 设计,带来诸如双向流.流控.头部压缩.单 TCP 连接上的多复用请求等特.这些特性使得其在移动设备上表现更好,更省电 ...
- STM32F103ZET6时钟
1.STM32F103ZET6时钟说明 STM32F103ZET6的时钟树图如下所示: STM32F103ZET6有很多个时钟源,分别有: HSE:高速外部时钟信号. HSI:高速内部部时钟信号. L ...
- preg_replace突然感觉好强大啊
<p><img align="absmiddle" src="https://img.alicdn.com/imgextra/i1/1696415374 ...
- mysql搭建主从复制(一主一从,双主双从)
主从复制原理 Mysql 中有一个binlog 二进制日志,这个日志会记录下所有修改了的SQL 语句,从服务器把主服务器上的binlog二进制日志在指定的位置开始复制主服务器所进行修改的语句到从服务器 ...
- Vulnhub DC-4靶机渗透
信息搜集 nmap -sP 192.168.146.0/24 #扫网段看看存活的主机,找到靶机 nmap -sS -Pn -A 192.168.146.141 可以看到开放了22和80端口,那么就可以 ...
- 打造一款 刷Java 知识的小程序(一)
一.为什么要打造 Java要学的东西太多了,所以准备把这些知识汇总到一起,而小程序是一个比较好的入口,借助微信客户端,打开方便. 二.打造成什么样 首页展示:包含了Java各大知识点模块 知识点展示: ...
- Java第二十九天,文件及目录的管理,File类
一.基础知识点 1.路径分隔符 (1)什么是路径分隔符? 这个多被应用在环境变量设置当中,例如当我设置Path环境变量时,多个环境变量的路径要用 ':'(Windows系统用封号分隔)或 ':'(Li ...
- Flask 入门(十)
flask 中的 db.relationship() 上文提到的方法,也可以找到狗的主人,但是,方便吗?,如果一个人有多只狗呢? 承接上文,修改main.py中的代码如下: #encoding:utf ...
- 五个简单的shell脚本
1.编写shell脚本 ex1.sh,提示用户输入用户名,并判断此用户名是否存在. (提示:利用read.grep和/etc/passwd) #!/bin/bash echo "请输入用户名 ...
- 28.5 Integer-- int的包装类
* 由于基本数据类型只能做一些简单的操作和运算,所以Java为我们封装了基本数据类型,为每种基本数据类型提供了包装类 * 包装类就是封装了基本数据类型的类,为我们提供了更多复杂的方法和一些变量 * * ...