java多线程基本概述(十三)——Executor
1:Executor接口
public interface Executor
执行已提交的 Runnable 任务的对象。此接口提供一种将任务提交与每个任务将如何运行的机制(包括线程使用的细节、调度等)分离开来的方法。通常使用 Executor 而不是显式地创建线程。例如,可能会使用以下方法,而不是为一组任务中的每个任务调用 new Thread(new(RunnableTask())).start(): Executor executor = anExecutor;
executor.execute(new RunnableTask1());
executor.execute(new RunnableTask2());
... 不过,Executor 接口并没有严格地要求执行是异步的。在最简单的情况下,执行程序可以在调用者的线程中立即运行已提交的任务:
class DirectExecutor implements Executor {
public void execute(Runnable r) {
r.run();
}
}
更常见的是,任务是在某个不是调用者线程的线程中执行的。以下执行程序将为每个任务生成一个新线程。
class ThreadPerTaskExecutor implements Executor {
public void execute(Runnable r) {
new Thread(r).start();
}
}
许多 Executor 实现都对调度任务的方式和时间强加了某种限制。以下执行程序使任务提交与第二个执行程序保持连续,这说明了一个复合执行程序。
class SerialExecutor implements Executor {
final Queue<Runnable> tasks = new ArrayDeque<Runnable>();
final Executor executor;
Runnable active; SerialExecutor(Executor executor) {
this.executor = executor;
} public synchronized void execute(final Runnable r) {
tasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (active == null) {
scheduleNext();
}
} protected synchronized void scheduleNext() {
if ((active = tasks.poll()) != null) {
executor.execute(active);
}
}
}
此包中提供的 Executor 实现实现了 ExecutorService,这是一个使用更广泛的接口。ThreadPoolExecutor 类提供一个可扩展的线程池实现。Executors 类为这些 Executor 提供了便捷的工厂方法。
2:ExecutorService接口
public interface ExecutorService
extends Executor
Executor 提供了管理终止的方法,以及可为跟踪一个或多个异步任务执行状况而生成 Future 的方法。
可以关闭 ExecutorService,这将导致其拒绝新任务。提供两个方法来关闭 ExecutorService。
shutdown() 方法在终止前允许执行以前提交的任务,但并不保证之前提交的任务完成。
shutdownNow() 方法阻止等待任务启动并试图停止当前正在执行的任务。
在终止时,执行程序没有任务在执行,也没有任务在等待执行,并且无法提交新任务。
应该关闭未使用的 ExecutorService 以允许回收其资源。
通过创建并返回一个可用于取消执行和/或等待完成的 Future,方法 submit 扩展了基本方法 Executor.execute(java.lang.Runnable)。
方法 invokeAny 和 invokeAll 是批量执行的最常用形式,它们执行任务 collection,然后等待至少一个,或全部任务完成(可使用 ExecutorCompletionService 类来编写这些方法的自定义变体)。
Executors 类提供了用于此包中所提供的执行程序服务的工厂方法。
用法示例
下面给出了一个网络服务的简单结构,这里线程池中的线程作为传入的请求。它使用了预先配置的 Executors.newFixedThreadPool(int) 工厂方法:
class NetworkService implements Runnable {
private final ServerSocket serverSocket;
private final ExecutorService pool; public NetworkService(int port, int poolSize)
throws IOException {
serverSocket = new ServerSocket(port);
pool = Executors.newFixedThreadPool(poolSize);
} public void run() { // run the service
try {
for (;;) {
pool.execute(new Handler(serverSocket.accept()));
}
} catch (IOException ex) {
pool.shutdown();
}
}
} class Handler implements Runnable {
private final Socket socket;
Handler(Socket socket) { this.socket = socket; }
public void run() {
// read and service request on socket
}
} 下列方法分两个阶段关闭 ExecutorService。第一阶段调用 shutdown 拒绝传入任务,然后调用 shutdownNow(如有必要)取消所有遗留的任务:
void shutdownAndAwaitTermination(ExecutorService pool) {
pool.shutdown(); // Disable new tasks from being submitted
try {
// Wait a while for existing tasks to terminate
if (!pool.awaitTermination(, TimeUnit.SECONDS)) {
pool.shutdownNow(); // Cancel currently executing tasks
// Wait a while for tasks to respond to being cancelled
if (!pool.awaitTermination(, TimeUnit.SECONDS))
System.err.println("Pool did not terminate");
}
} catch (InterruptedException ie) {
// (Re-)Cancel if current thread also interrupted
pool.shutdownNow();
// Preserve interrupt status
Thread.currentThread().interrupt();
}
}
方法api:
void shutdown()
Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted.
开始执行一次顺序关闭之前提交的任务,不会再接收新的任务
Invocation has no additional effect if already shut down.
如果已经关闭了,那么调用它不会产生额外的影响
This method does not wait for previously submitted tasks to complete execution. Use awaitTermination to do that.
该方法并不等待之前提交的任务的任务完成,请使用 awaitTermination()方法。
List<Runnable> shutdownNow()
Attempts to stop all actively executing tasks, halts the processing of waiting tasks, and returns a list of the tasks that were awaiting execution.
尝试停止所有正在执行的任务,停止处理处于等待状态的任务。并且返回一个等待执行的任务的list.
This method does not wait for actively executing tasks to terminate. Use awaitTermination to do that.
该方法并不会等待正在执行的任务被终止。请使用 awaitTermination()方法。
There are no guarantees beyond best-effort attempts to stop processing actively executing tasks. For example, typical implementations will cancel via Thread.interrupt(), so any task that fails to respond to interrupts may never terminate.
无法保证能够停止正在处理的活动执行任务,但是会尽力尝试。例如,通过 Thread.interrupt() 来取消典型的实现,所以任何任务无法响应中断都可能永远无法终止。
Returns:
list of tasks that never commenced execution
boolean isShutdown()
Returns true if this executor has been shut down.
Returns:
true if this executor has been shut down
boolean isTerminated()
Returns true if all tasks have completed following shut down. Note that isTerminated is never true unless either shutdown or shutdownNow was called first.
如果关闭后所有任务都已完成,则返回 true。注意,除非首先调用 shutdown 或 shutdownNow,否则 isTerminated 永不为 true。
Returns:
true if all tasks have completed following shut down
boolean awaitTermination(long timeout,TimeUnit unit) throws InterruptedException
Blocks until all tasks have completed execution after a shutdown request, or the timeout occurs, or the current thread is interrupted, whichever happens first.
如果所有的任务都再shutdown调用后已完成执行,或者超过超时等待时间,或者当前线程被中断,以上几个只要任意一个没有发生都会处于阻塞状态。个人理解,相当于join(long timeout,TimeUnit init).
也就是会使池中的线程执行完后再执行awaitTermination()后的代码
Parameters:
timeout - the maximum time to wait
unit - the time unit of the timeout argument
Returns:
true if this executor terminated and false if the timeout elapsed before termination
Throws:
InterruptedException - if interrupted while waiting
下面通过实例来理解上述方法:
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; class Task implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("Task "+Thread.currentThread().getName());
String base = "abcdefghijklmnopqrstuvwxyz0123456789";
Random random = new Random();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 10; i++) {
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
}
return sb.toString();
}
}
class LongTask implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("LongTask "+Thread.currentThread().getName());
TimeUnit.SECONDS.sleep(5);
return "success";
}
}
public class Test {
public static void main(String[] args) {
ExecutorService service=null;
try {
service = Executors.newCachedThreadPool();
service.submit(new Task());
service.submit(new Task());
service.submit(new LongTask());
service.submit(new Task());
System.out.println("isShutdown()="+service.isShutdown()+" isTerminated()="+service.isTerminated()+" before shutdown ");
service.shutdown();//调用shutdown()之前的都返回false.
System.out.println("isShutdown()="+service.isShutdown()+" isTerminated()="+service.isTerminated()+" after shutdown ");
//service.submit(new Task()); //line 1
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出结果:
Task pool-1-thread-2
Task pool-1-thread-1
isShutdown()=false isTerminated()=false before shutdown
LongTask pool-1-thread-3
Task pool-1-thread-4
isShutdown()=true isTerminated()=false after shutdown Process finished with exit code 0
说明的第一个问题是:isShutdown()方法仅仅只是判断ExecutorService是否已经调用或shutDown()方法,如果是就返回true,否则返回false.而isTerminated()方法只有再调用shutdown()或shutDownNow()之后才有可能返回true,否则一致返回false.如果取消1 line处的注释,那么会抛异常,因为调用shutdown()方法后不会再接收新的任务。取消注释后代码的运行结果如下:
isShutdown()=false isTerminated()=false before shutdown
java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@6d6f6e28 rejected from java.util.concurrent.ThreadPoolExecutor@135fbaa4[Shutting down, pool size = 4, active threads = 4, queued tasks = 0, completed tasks = 0]
Task pool-1-thread-1
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)
isShutdown()=true isTerminated()=false after shutdown
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)
Task pool-1-thread-2
LongTask pool-1-thread-3
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)
Task pool-1-thread-4
at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:134)
at Test.main(Test.java:41) Process finished with exit code 0
下面修改代码如下:
public class Test {
public static void main(String[] args) {
try {
ExecutorService service = Executors.newFixedThreadPool(4);
service.submit(new Task());
service.submit(new Task());
service.submit(new LongTask());
service.submit(new Task());
System.out.println("isShutdown()="+service.isShutdown()+" isTerminated()="+service.isTerminated()+" before shutdown ");
service.shutdown();
int i=1;
while (!service.awaitTermination(1, TimeUnit.SECONDS)) {//此处1秒的时间间隔内处于阻塞状态
System.out.println("isShutdown()="+service.isShutdown()+" isTerminated()="+service.isTerminated()+" inner "+(i++));
}
System.out.println("isShutdown()="+service.isShutdown()+" isTerminated()="+service.isTerminated()+" outer "+(i));
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出结果:
isShutdown()=false isTerminated()=false before shutdown
Task pool-1-thread-1
Task pool-1-thread-2
LongTask pool-1-thread-3
Task pool-1-thread-4
isShutdown()=true isTerminated()=false inner 1
isShutdown()=true isTerminated()=false inner 2
isShutdown()=true isTerminated()=false inner 3
isShutdown()=true isTerminated()=false inner 4
isShutdown()=true isTerminated()=true outer 5
service.awaitTermination(1, TimeUnit.SECONDS) 每1秒检查一次executorService是否被关闭。而LongTask正好需要执行5秒,因此会在前4秒监测时ExecutorService为未关闭状态,而在第5秒时
已经关闭,因此第5秒时输出: isShutdown()=true isTerminated()=true outer 5 。接续改代码如下:使await()的超时时间超过longTask的执行时间。
public class Test {
public static void main(String[] args) {
try {
ExecutorService service = Executors.newFixedThreadPool(4);
service.submit(new Task());
service.submit(new Task());
service.submit(new LongTask());
service.submit(new Task());
System.out.println("isShutdown()="+service.isShutdown()+" isTerminated()="+service.isTerminated()+" before shutdown ");
service.shutdown();
int i=1;
System.out.println("before awaitTermination currentTime "+System.currentTimeMillis());
while (!service.awaitTermination(11, TimeUnit.SECONDS)) {
System.out.println("isShutdown()="+service.isShutdown()+" isTerminated()="+service.isTerminated()+" inner "+(i++)); //2 line
}
System.out.println("after awaitTermination currentTime "+System.currentTimeMillis());
System.out.println("isShutdown()="+service.isShutdown()+" isTerminated()="+service.isTerminated()+" outer "+(i));
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出结果:
Task pool-1-thread-1
isShutdown()=false isTerminated()=false before shutdown
Task pool-1-thread-2
before awaitTermination currentTime 1492589643688 //调用await前的时间戳为1492589643688
Task pool-1-thread-4
LongTask pool-1-thread-3
after awaitTermination currentTime 1492589648689 //调用await后的时间戳为 1492589648689 二者之间的时间差是5秒,而2 line没有输出,说明其处于阻塞状态。因为5秒后,longTask执行完
isShutdown()=true isTerminated()=true outer 1 //就直接打印了这句话,说明再超时等待时间内完成了任务。 Process finished with exit code 0
如果代码改为下面的:
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; class Task implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("Task "+Thread.currentThread().getName());
String base = "abcdefghijklmnopqrstuvwxyz0123456789";
Random random = new Random();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 10; i++) {
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
}
return sb.toString();
}
}
class LongTask implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("LongTask "+Thread.currentThread().getName());
TimeUnit.SECONDS.sleep(Long.MAX_VALUE);
return "success";
}
}
public class Test {
public static void main(String[] args) {
try {
ExecutorService service = Executors.newFixedThreadPool(4);
service.submit(new Task());
service.submit(new Task());
service.submit(new LongTask());
service.submit(new Task());
service.shutdown();
int i=1;
System.out.println("before awaitTermination currentTime "+System.currentTimeMillis());
while (!service.awaitTermination(1, TimeUnit.MILLISECONDS)) {
/* System.out.println("isShutdown()="+service.isShutdown()+" isTerminated()="+service.isTerminated()+" inner "+(i++));
if (i==10000){
service.shutdownNow();
}*/
}
System.out.println("after awaitTermination currentTime "+System.currentTimeMillis());
System.out.println("isShutdown()="+service.isShutdown()+" isTerminated()="+service.isTerminated()+" outer "+(i));
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出结果:
isShutdown()=true isTerminated()=false inner 9993
isShutdown()=true isTerminated()=false inner 9994
isShutdown()=true isTerminated()=false inner 9995
isShutdown()=true isTerminated()=false inner 9996
isShutdown()=true isTerminated()=false inner 9997
isShutdown()=true isTerminated()=false inner 9998
isShutdown()=true isTerminated()=false inner 9999
..............
.............
..........
基本处于无限等待。而api描述说的是 “shutdown() 方法在终止前允许执行以前提交的任务,但并不保证之前提交的任务完成 “,而现在似乎一直再等待线程池中的任务完成。不知道如何验证、、、
下面更改代码,使其子线程结束
public class Test {
public static void main(String[] args) {
try {
ExecutorService service = Executors.newFixedThreadPool(4);
LongTask t = new LongTask();
service.submit(new Task());
service.submit(new Task());
service.submit(t);
service.submit(new Task());
service.shutdown();
int i=1;
System.out.println("before awaitTermination currentTime "+System.currentTimeMillis());
while (!service.awaitTermination(1, TimeUnit.MILLISECONDS)) {
System.out.println("isShutdown()="+service.isShutdown()+" isTerminated()="+service.isTerminated()+" inner "+(i++));
if (i==10000){
service.shutdownNow();
}
}
System.out.println("after awaitTermination currentTime "+System.currentTimeMillis());
System.out.println("isShutdown()="+service.isShutdown()+" isTerminated()="+service.isTerminated()+" outer "+(i));
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出结果:
.......................
.......................
.......................
.......................
isShutdown()=true isTerminated()=false inner 9993
isShutdown()=true isTerminated()=false inner 9994
isShutdown()=true isTerminated()=false inner 9995
isShutdown()=true isTerminated()=false inner 9996
isShutdown()=true isTerminated()=false inner 9997
isShutdown()=true isTerminated()=false inner 9998
isShutdown()=true isTerminated()=false inner 9999
after awaitTermination currentTime 1492591173801
isShutdown()=true isTerminated()=true outer 10000 Process finished with exit code 0
可知再i=10000的时候,调用shutdownNow()后,子线程被结束。api描述是 “该方法并不会等待正在执行的任务被终止,无法保证能够停止正在处理的活动执行任务,但是会尽力尝试。“
但现在似乎验证的场景又再次说明了调用该方法,又会停止线程池中正在执行的任务。不知道如何验证、、、
继续更改代码
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; class Task implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("Task "+Thread.currentThread().getName());
String base = "abcdefghijklmnopqrstuvwxyz0123456789";
Random random = new Random();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 10; i++) {
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
}
return sb.toString();
}
}
class LongTask implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("LongTask "+Thread.currentThread().getName());
TimeUnit.SECONDS.sleep(10);
return "success";
}
}
public class Test {
public static void main(String[] args) {
try {
ExecutorService service = Executors.newFixedThreadPool(4);
service.submit(new LongTask());
service.submit(new LongTask());
service.submit(new LongTask());
service.submit(new LongTask());
service.submit(new LongTask());
service.submit(new LongTask());
List<Runnable> runnables = service.shutdownNow();
System.out.println(runnables.size());
int i=1;
while (!service.awaitTermination(1, TimeUnit.MILLISECONDS)) {
System.out.println("isShutdown()="+service.isShutdown()+" isTerminated()="+service.isTerminated()+" inner "+(i++));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出结果:
LongTask pool-1-thread-1
LongTask pool-1-thread-2
2
LongTask pool-1-thread-3
LongTask pool-1-thread-4 Process finished with exit code 0
我们限制了线程池的长度是4,提交了6个任务,这样将有两个任务在工作队列中等待,当我们执行shutdownNow方法时,ExecutorService被立刻关闭,所以在service.awaitTermination(1, TimeUnit.MILLISECONDS)方法校验时返回的是false,因此没有输出。而在调用shutdownNow方法时,我们接受到了一个List,这里包含的是在工作队列中等待执行的任务,由于线程池长度为4,且执行的都是长任务,所以当提交了三个任务后线程池已经满了,剩下的两次提交只能在工作队列中等待,因此我们看到runnables的大小为2.
java多线程基本概述(十三)——Executor的更多相关文章
- “全栈2019”Java多线程第三十三章:await与signal/signalAll
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- Java多线程——<一>概述、定义任务
一.概述 为什么使用线程?从c开始,任何一门高级语言的默认执行顺序是“按照编写的代码的顺序执行”,日常开发过程中写的业务逻辑,但凡不涉及并发的,都是让一个任务顺序执行以确保得到想要的结果.但是,当你的 ...
- java多线程基本概述(一)——线程的基本认知
1.1.概念: 进程:进程是操作系统结构的基础,是一次程序的执行:是一个程序及其数据再处理器上顺序执行时所发生的活动:是程序再一个数据集合上运行的过程,它是系统进行系统资源分配和调度的最小单元. 线程 ...
- Java 多线程 - 总结概述
概述 菜鸟教程: Java 给多线程编程提供了内置的支持. 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务. 多线程是多任务的一种特别的形式,但多线程 ...
- java多线程基本概述(二十)——中断
线程中断我们已经直到可以使用 interrupt() 方法,但是你必须要持有 Thread 对象,但是新的并发库中似乎在避免直接对 Thread 对象的直接操作,尽量使用 Executor 来执行所有 ...
- java多线程基本概述(四)——死锁
package mytask; public class Task { public static void main(String[] args) { DeadThread thread = new ...
- java多线程基本概述(三)——同步方法
非线程安全其实是在多个线程对同一个对象实例的变量进行并发访问的时候发生,产生的后果就是脏读,也就是取到的数据是修改过的.而线程安全就是获得的实例变量的值是经过同步处理的,从而不会出现脏读现象. 1.1 ...
- java多线程基本概述(二)——Thread的一些方法
在Thread类中有很多方法值得我们关注一下.下面选取几个进行范例: 1.1.isAlive()方法 java api 描述如下: public final boolean isAlive() Tes ...
- java多线程基本概述(五)——线程通信
线程之间的通信可以通过共享内存变量的方式进行相互通信,也可以使用api提供的wait(),notify()实现线程之间的通信.wait()方法是Object类的方法,改方法用来将当前的线程置入&quo ...
随机推荐
- Android--带你一点点封装项目 MVP+BaseActivity+Retrofit+Dagger+RxJava(三)
1,这一篇博客是和大家一起来封装我们最后的Dagger2,其实之前也写过关于简单的Dagger2,这里是地址,完全没了解的同学可以先去看一下这篇,感谢很多小伙伴一直在耐心的等待这一篇 2,Dagger ...
- [POJ1028]Web Navigation(栈)
这题是01年East Central North的A题,目测是签到题 Description Standard web browsers contain features to move backwa ...
- CoreAnimation 图层几何学
CoreAnimation 图层几何学 博客园MakeDown支持不佳,如有需要请进GitHub 图层几何所讲主要是有关图层的位置,尺寸等几何类属性. 布局 在UIView中与位置,尺寸有关的属性有 ...
- Office 365开发概述及生态环境介绍(二)
本文于2017年3月19日首发于LinkedIn,原文链接在这里 在上一篇 文章,我给大家回顾了Office发展过来的一些主要的版本(XP,2003,2007,2013等),以及在Office客户端中 ...
- Java引领新生活
阅读邹欣老师的博客,谈谈你期望的师生关系是什么样的? 我觉得师生关系应当是亲密无间,课上老师讲解学生配合,课下师生交流启发思考. 你有什么技能(学习,棋类,球类,乐器,艺术,游戏,......)比大多 ...
- 一步到位分布式开发Zookeeper实现集群管理
说到分布式开发Zookeeper是必须了解和掌握的,分布式消息服务kafka .hbase 到hadoop等分布式大数据处理都会用到Zookeeper,所以在此将Zookeeper作为基础来讲解. Z ...
- Flex表格中添加图片
Flex4.5中datagrid加入图片显示image <s:DataGrid id="maingrid" x="0" y="36" ...
- 使用Topshelf组件构建简单的Windows服务
很多时候都在讨论是否需要了解一个组件或者一个语言的底层原理这个问题,其实我个人觉得,对于这个问题,每个人都有自己的看法,个人情况不同,选择的方式也就会不同了.我个人觉得无论学习什么,都应该尝试着去了解 ...
- nodejs 使用mongoose 操作mongodb
nodejs操作mongodb可以使用mongoose: Mongoose is a MongoDB object modeling tool designed to work in an async ...
- TCP的三次握手(建立连接)与 四次挥手(关闭连接)
一.TCP报文格式 TCP/IP协议的详细信息参看<TCP/IP协议详解>三卷本.下面是TCP报文格式图: TCP报文格式上图中有几个字段需要重点介绍下: (1)序号:Seq序号,占32位 ...