Executor框架
适用面Executor框架代替Thread以实现更灵活的执行策略,Executor基于生产者-消费者模式,对任务提交和执行进行了解耦。
使用Executor的线程池实现web server实例:
public class TaskExecutionWebServer {
private static final int NTHREADS = 100;
private static final Executor exec
= Executors.newFixedThreadPool(NTHREADS);
public static void main(String[] args) throws IOException {
ServerSocket socket = new ServerSocket(80);
while (true) {
final Socket connection = socket.accept();
Runnable task = new Runnable() {
public void run() {
handleRequest(connection);
}
};
exec.execute(task);
}
}
private static void handleRequest(Socket connection) {
// request-handling logic here
}
}
执行策略
一个任务执行策略一个明确如下因素:
- 任务在什么线程中执行?
- 以什么顺序执行?
- 可以有多少个任务并发执行?
- 可以有多少个任务进入等待执行队列?
- 当系统过载需要放弃某个任务的执行,应该选择哪一个任务?如何通知应用程序?
- 在一个任务执行前后应该做什么处理?
Executor创建线程池的工厂方法:
newFixedThreadPool 定长线程池
newCachedThreadPool 可缓存线程池
newSingleThreadPool 单线程化的Executor
newScheduledThreadPool 定长线程池,支持周期性的任务执行
Executor的生命周期
ExecutorService接口扩展了Executor,提供管理生命周期的方法。Executor生命周期有三种状态:运行,关闭,终止。常用方法有:shutdown(平缓关闭,拒绝接受新任务,等待已提交的任务完成),ShutdownNow(强行取消所有任务),isShutdown,isTerminated,awaitTermination。
当所有任务全部完成,ExecutorService进入终止状态。
支持生命周期实现的web server:
public class LifecycleWebServer {
private final ExecutorService exec = Executors.newCachedThreadPool();
public void start() throws IOException {
ServerSocket socket = new ServerSocket(80);
while (!exec.isShutdown()) {
try {
final Socket conn = socket.accept();
exec.execute(new Runnable() {
public void run() {
handleRequest(conn);
}
});
} catch (RejectedExecutionException e) {
if (!exec.isShutdown())
log("task submission rejected", e);
}
}
}
public void stop() {
exec.shutdown();
}
private void log(String msg, Exception e) {
Logger.getAnonymousLogger().log(Level.WARNING, msg, e);
}
void handleRequest(Socket connection) {
Request req = readRequest(connection);
if (isShutdownRequest(req))
stop();
else
dispatchRequest(req);
}
interface Request {
}
private Request readRequest(Socket s) {
return null;
}
private void dispatchRequest(Request r) {
}
private boolean isShutdownRequest(Request r) {
return false;
}
}
如果想要周期性的执行或者延迟执行某个任务,应该使用ScheduledThreadPoolExecutor来代替Timer。