学习Executor的过程中,遇到很多新的接口和类,先列举一下;
Executor , Executors ,ExecutorService ,ScheduledExecutorService
Runnable ,Callable,Future .
Executor 接口,只有一个方法void execute(Runnable command) 执行给定的命令
Executors 类,java.uti.concurrent.Executors ,该类提供static的创建线程池的方法,截一下部分API
聊聊看到这些方法有一个共同点就是都是返回 ExecutorService 接口或其子接口。所以ExecutorService是用来服务 Executors的。
这里在说一下这里比较常用的两个方法 newFixThreadPool()和 newCachedThreadPool() ,
FixThreadPool:是一种线程数量固定的线程池,只有核心线程,没有超时机制,任务队列没有大小限制.
核心线程数 = 最大线程数
行给定的任务,当所有任务完成时,返回保持任务状态和结果的 Future 列表。 当所有的线程都处于活动状态时,新任务都会处于等待状态,直到有线程空闲出来.
当线程处于空闲状态时,它们并不会被回收,除非线程池被关闭了.这意味着它能够更加快速的响应外界的请求.
//构造方法
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
CacheThreadPool:
CachedThreadPool线程数量不定,只有非核心线程,并且其最大线程数为Integer.MAX_VALUE(相当于无限大) 当线程池中的线程都处于活动状态时,线程池会创建新的线程来处理新任务,否则就会利用空闲的线程来处理新任务.
空闲线程都有超时时机,这个超时时长为60秒,限制超60秒就会被回收.
和FixedThreadPoolExecutor不同的是,CachedThreadPool的任务队列其实相当一个空集合,这将导致任何任务都会 被立即执行,因为此时SynchronousQueue是无法插入任务的.
CachedThreadPool线程池比较适合执行大量+耗时较少的任务.当整个线程池都处于闲置状态时,会因超时而被停止, 此时没有线程的线程池几乎不占用任何系统资源.
//构造方法
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
注意观察创建线程池的参数
接着谈谈ExecutorService ,接口,ScheduledExecutorService为其子接口
全部api截图
ExecutorService有个shutdown()函数,如果线程没有设置成守护线程,程序结束线程池需要用shutdown手动关闭,如果设置了守护线程则不需要。
ExecutorService能给线程池提交任务(一个或多个)。通过其得到返回值
关于submit()和 executor():
1. 接收的参数不一样;
2. submit()有返回值,而execute()没有;
例如,有个validation的task,希望该task执行完后告诉我它的执行结果,是成功还是失败,然后继续下面的操作。
3. submit()可以进行Exception处理;
例如,如果task里会抛出checked或者unchecked exception,而你又希望外面的调用者能够感知这些exception并做出及时的处理,那么就需要用到submit,通过对Future.get()进行抛出异常的捕获,然后对其进行处理。
关于invokeAll() 和 invokeAny():两者从API上很难看出差别
invokeAny():
1. 一旦有1个任务正常完成(执行过程中没有抛异常),线程池会终止其他未完成的任务。
2.如果提交的任务列表中,没有1个正常完成的任务,那么调用invokeAny会抛异常,究竟抛的是哪儿个任务的异常,无关紧要。
3.先提交3个异常任务,再提交1个正常的耗时任务,不会抛出任何异常,打印出t2任务的返回结果。也就是说:invokeAny()和任务的提交顺序无关,只是返回最早正常执行完成的任务。
invokeAll():

这个方法相对来说比较好理解,就是执行任务列表中的所有任务,并返回与每个任务对应的Futue。也就是说,任务彼此之间不会相互影响,可以通过future跟踪每一个任务的执行情况,比如是否被取消,是正常完成,还是异常完成,这主要使用Future类提供的API。
最后谈一下Future类:先截API
用Future类来获取 ExecutorService.submit() 执行的结果;很简单
强调一下:get()方法可以当任务结束后返回一个结果,如果调用时,工作还没有结束,则会阻塞线程,直到任务执行完。
下个内容要学一下 RunnableFuture