序言
从JDK5开始,把工作单元与执行机制分离开来,工作单元包括Runnable和Callable,而执行机制由接下来要讲的Executor框架提供。
java.util.concurrent.Executor,java.util.concurrent.ExecutorServicejava.util.concurrent.Executors这三者均是JAVA Executor框架的一部分,用来提供线程池的功能。因为创建于销毁线程消耗太多计算机资源,而且操作系统通常对线程数有限制,所以建议使用线程池来管理线程和并发执行任务,这样不用每次请求过来时就创建一个线程。从线程池免去创建销毁线程的资源(包括时间)损耗,利用这点提高了应用的响应处理速度,还可避免"java.lang.OutOfMemoryError:unable to create new native thread"之类的错误。
Executor框架简介
1.1 Executor框架的两级调度模型
根据《JAVA 并发编程的艺术》中了解到,在HotSpot VM的线程模型中,Java线程(java.lang.Thread)被一对一映射为本地操作系统线程。Java线程启动时会创建一个本地操作系统线程;当该Java线程终止时,对应操作系统线程会被回收。而CPU资源是有限的,线程数量也会被限制,由操作系统调度分配相应的CPU资源。从图中可以看出,在上层中,在任务通过Executor框架分配到线程池中的线程,而底层,操作系统内核将这些线程映射到硬件处理器上。

2.2 Executor
Executor、ExecutorService和Executors 最主要的区别是 Executor是一个抽象层的核心接口(大致代码和UML类图如下)
public interface Executor {
/**
* Executes the given command at some time in the future. The command
* may execute in a new thread, in a pooled thread, or in the calling
* thread, at the discretion of the {@code Executor} implementation.
*
* @param command the runnable task
* @throws RejectedExecutionException if this task cannot be
* accepted for execution
* @throws NullPointerException if command is null
*/
void execute(Runnable command);
}

不同于 java.lang.Thread类将任务和执行耦合在一起,Executor将任务本身和执行任务分离,可以阅读 difference between Thread and Executor 了解更多Thread和Executor的不同
2.3 ExecutorService
ExecutorService接口 对Executor接口的子接口,增加了一些常见的对线程的控制方法,如提供提交线程任务,返回Future对象,终止、关闭线程池等方法。当调用shutdown方法时,线程池会停止接受新任务,但会完成正在pending中的任务。
Future对象提供了异步执行,意味着无需等待任务执行完成,提交需要执行的任务后,它立即返回继续往下执行 ,然后在需要时检查Future是否有结果了,如果任务已执行完毕,通过Future.get()方法获取执行结果,因为Future.get()是阻塞方法,如果考虑可能会因不明原因而导致Future.get()方法阻塞下去,Future还提供了设置获取超时方法Future.get(long timeout, TimeUnit unit)方法。
通过ExecutorService.submit()方法返回的Future对象,还可以取消任务的执行。Future提供了cancel方法用于取消正在执行pending中的任务。
ExecutorService 部分代码如下
public interface ExecutorService extends Executor {
void shutdown();
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException;
}
2.4 Executors
Executors 是一个工具类,类似于Collections。 提供工厂方法来创建不同类型的线程池,例如FixedThreadPool或者CacheThreadPool
public class Executors {
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
}
下面详细看一下三者区别:
Executor 和 ExecutorService 这两个接口主要的区别是:ExecutorService 接口继承了 Executor 接口,是 Executor 的子接口
Executor 和 ExecutorService 第二个区别是:Executor 接口定义了
execute()方法用来接收一个Runnable接口的对象,而 ExecutorService 接口中的submit()方法可以接受Runnable和Callable接口的对象。Executor 和 ExecutorService 接口第三个区别是 Executor 中的
execute()方法不返回任何结果,而 ExecutorService 中的submit()方法可以通过一个 Future 对象返回运算结果。Executor 和 ExecutorService 接口第四个区别是除了允许客户端提交一个任务,ExecutorService 还提供用来控制线程池的方法。比如:调用
shutDown()方法终止线程池。可以通过 《Java Concurrency in Practice》 一书了解更多关于关闭线程池和如何处理 pending 的任务的知识。Executors 类提供工厂方法用来创建不同类型的线程池。比如:
newSingleThreadExecutor()创建一个只有一个线程的线程池,newFixedThreadPool(int numOfThreads)来创建固定线程数的线程池,newCachedThreadPool()可以根据需要创建新的线程,但如果已有线程是空闲的会重用已有线程。
2.5 Executor框架的成员
Executor框架的主要成员:ThreadPoolExecutor、ScheduledThreadPoolExecutor、Future接口、Runnable接口、Callable接口和Executors工具类。这个就不细说,下一讲,重点讲下ThreadPoolExecutor。
参考:
JAVA并发编程的艺术