Executor(执行)
ExecutorService是Java中对线程池定义的⼀个接⼝,这个接⼝的实现有两个:
【1】ThreadPoolExecutor
【2】ScheduledThreadPoolExecutor
Executor的继承树是什么
ExecutorService如何创建
Java给我们提供了⼀个Executors⼯⼚类,它可以帮助我们⽅便的创建各种类型的ExecutorService
Executor可以帮助我们创建下⾯的 4 种线程池:
【1】newCachedThreadPool 创建⼀个可缓存线程池,如果线程池⻓度超过处理需要,可灵活回收空闲线程,若⽆可回收,则新建线程。
【2】newFixedThreadPool 创建⼀个定⻓线程池,可控制线程最⼤并发数,超出的线程会在队列中等待。
【3】newScheduledThreadPool 创建⼀个定⻓线程池,⽀持定时及周期性任务执⾏。
【4】newSingleThreadExecutor 创建⼀个单线程化的线程池,它只会⽤唯⼀的⼯作线程来执⾏任务,保 证所有任务按照指定顺序(FIFO, LIFO, 优先级)执⾏。
ExecutorService如何执行
- execute(Runnable)
- submit(Runnable)
- submit(Callable)
- invokeAny(...)
- invokeAll(...)
使⽤这种⽅式没有办法获取执⾏ Runnable 之后的结果,如果你希望获取运⾏之后的返回值,就必须使 ⽤ 接收 Callable 参数的 execute() ⽅法,后者将会在下⽂中提到。
5.1、execute(Runnable)
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(new Runnable() {
public void run() {
System.out.println("Asynchronous task");
}
});
executorService.shutdown();
5.2、submit(Runnable)
submit(Runnable)和execute(Runnable)区别是前者可以返回⼀个Future对象,通过返回的Future对象,我们可以检查提交的任务是否执⾏完毕,请看下⾯执⾏的例⼦:
val executorService = Executors.newSingleThreadExecutor()
val future = executorService.submit { println("Asynchronous task") }
future.get() //returns null if the task has finished correctly.
如果任务执⾏完成,future.get()⽅法会返回⼀个null。注意,future.get()⽅法会产⽣阻塞。
5.3、submit(Callable)
submit(Callable)和submit(Runnable)类似,也会返回⼀个Future对象,但是除此之外, submit(Callable)接收的是⼀个Callable的实现,Callable接⼝中的call()⽅法有⼀个返回值,可以返回 任务的执⾏结果,⽽Runnable接⼝中的run()⽅法是void的,没有返回值。
请看下⾯实例:
val executorService = Executors.newSingleThreadExecutor()
val future = executorService.submit(object : Callable<String> {
override fun call(): String {
Log.e(TAG,"call方法调用")
return "success"
}
})
LogUtil.i(TAG, future.get().toString())
如果任务执⾏完成,future.get()⽅法会返回Callable任务的执⾏结果。注意,future.get()⽅法会产⽣阻塞。
5.4、invokeAny(…)
invokeAny(...)⽅法接收的是⼀个Callable的集合,执⾏这个⽅法不会返回Future,但是会返回所有 Callable任务中其中⼀个任务的执⾏结果。这个⽅法也⽆法保证返回的是哪个任务的执⾏结果,反正是 其中的某⼀个。请看下⾯实例:
val executorService = Executors.newSingleThreadExecutor()
val callables: MutableSet<Callable<String>> = HashSet()
callables.add(Callable { "Task 1" })
callables.add(Callable { "Task 2" })
callables.add(Callable { "Task 3" })
val result = executorService.invokeAny(callables)
Log.e(TAG, "result = $result")
executorService.shutdown()
5.5、invokeAll(…)
invokeAll(...)与 invokeAny(...)类似也是接收⼀个Callable集合,但是前者执⾏之后会返回⼀个Future 的List,其中对应着每个Callable任务执⾏后的Future对象。情况下⾯这个实例:
val executorService = Executors.newSingleThreadExecutor()
val callables: ArrayList<Callable<String>> = ArrayList()
callables.add(Callable {
for (index in 1..1000) {
Log.e("cdx", "index:$index")
}
"Task 1"
})
callables.add(Callable {
for (index in 1..500) {
Log.e("cdx", "=============index:$index=============")
}
"Task 2"
})
callables.add(Callable {
for (index in 1..2000) {
Log.e("cdx", "==========================index:$index========================")
}
"Task 3"
})
val futures: List<Future<String>> = executorService.invokeAll(callables)
for (future in futures) {
Log.e(TAG, "future.get = " + future.get())
}
Log.e(TAG, "success")
executorService.shutdown()
结果:
首先打印1000 次 index: + i
然后打印500次 =========index============
然后打印 2000次 =================index ===============
然后打印 future.get = Task 1 future.get = Task 2 future.get = Task 3 success
结论:
这些任务是依次执行的。
线程池如何关闭
当我们使⽤完成ExecutorService之后应该关闭它,否则它⾥⾯的线程会⼀直处于运⾏状态。
举个例⼦,如果的应⽤程序是通过main()⽅法启动的,在这个main()退出之后,如果应⽤程序中的 ExecutorService没有关闭,这个应⽤将⼀直运⾏。之所以会出现这种情况,是因为ExecutorService中 运⾏的线程会阻⽌JVM关闭。
如果要关闭ExecutorService中执⾏的线程,我们可以调⽤ExecutorService.shutdown()⽅法。在调⽤ shutdown()⽅法之后,ExecutorService不会⽴即关闭,但是它不再接收新的任务,直到当前所有线程 执⾏完成才会关闭,所有在shutdown()执⾏之前提交的任务都会被执⾏。
如果我们想⽴即关闭ExecutorService,我们可以调⽤ExecutorService.shutdownNow()⽅法。这个动 作将跳过所有正在执⾏的任务和被提交还没有执⾏的任务。但是它并不对正在执⾏的任务做任何保证, 有可能它们都会停⽌,也有可能执⾏完成。
线程池有什么用
顺序执行线程
现在有3个线程,需要第⼀个线程执⾏完以后,执⾏第⼆个线程,第⼆个线程执⾏完以后,执⾏第三个线程。
我们可以使⽤newSingleThreadExecutor单线程化的线程池,按照优先级去执⾏,这样就完成了第⼀ 个任务执⾏完毕后执⾏第⼆个任务,第⼆个任务执⾏完第三个任务。
查看线程是否执⾏完毕
现在有3个线程,现在有⼀个需求,就是需要检测3个线程是不是执⾏完毕,执⾏完毕的时候执⾏相应 的操作 这个时候我们可以将3个线程放到线程池中,然后去执⾏invokeAll,⽤while循环去判断是不是执⾏完 毕,当执⾏完毕的执⾏相应的操作。
ThreadPoolExecutor
⽤ThreadPoolExecutor的构造函数构建线程池对象,下⾯是构造函数的参数说明。
int corePoolSize:线程池的最⼩线程个数。
int maximumPoolSize:线程池的最⼤线程个数。
long keepAliveTime:⾮核⼼线程在⽆任务时的等待时⻓。若超过该时间仍未分配任务,则该线程⾃动结束。
TimeUnit unit:时间单位,时间单位的取值说明。
BlockingQueue workQueue:设置等待队列。取值new
LinkedBlockingQueue()即可,默认表⽰等待队列⽆穷⼤,此时⼯作线程等于最⼩线程个数
当然也可在参数中指定等待队列 的⼤⼩,此时⼯作线程数等于总任务数减去等待队列⼤⼩,⼯作线程 数位于最⼩线程个数与最⼤线程个数之间。
ThreadPoolExecutor的常⽤⽅法说明
execute:向执⾏队列添加指定的任务。
remove:从执⾏队列移除指定的任务。
shutdown:关闭线程池。
isTerminated:判断线程池是否关闭。
setCorePoolSize:设置线程池的最⼩线程个数。
setMaximumPoolSize:设置线程池的最⼤线程个数。
setKeepAliveTime:设置⾮核⼼线程在⽆任务时的等待时⻓。
getPoolSize:获取当前的线程个数。
getActiveCount:获取当前的活动线程个数。