任务执行
6.1:在线程中执行任务
1、串行执行任务:一般采用while循环执行,如果执行过程中遇到了I/O等操作阻塞,会造成服务器看似失去了相应,用户体验贼差,不推荐。
2、显示的创建线程:例如HTTP请求任务,每有一个连接请求就创建一个线程,用于处理连接请求。这种办法在一定范围内能提高服务器的响应性和吞吐率,但一旦超出了这个范围,再创建更多的线程只会降低程序的执行速度。
3、创建大量线程的弊端:
- 线程生命周期的开销非常高
- 资源消耗非常大
- 稳定性欠缺
6.2Executor框架
Executor基于生产者–消费者模式,提交任务->生产者; 执行任务->消费者
Executor可以将请求处理任务的提交和任务的实际执行解耦出来
6.2.3:线程池
1、线程池与工作队列息息相关
- 工作队列保存了所有等待执行的任务
- 工作者线程从工作队列中获取一个任务执行,然后返回线程池等待下一个任务
2、使用线程池,而不是为每个任务分配一个线程的好处
- 处理多个请求时分摊了在创建线程和销毁线程过程产生的巨大开销
- 工作线程一直存在,因此不会因为等待创建线程而延迟任务的执行,提高响应性
- 防止过多线程相互竞争资源而使应用程序耗尽内存或失败
3、六种线程池 - newFixedThreadPool:创建一个固定长度的线程池,每提交一个任务就创建一个线程,知道达到线程池的最大数量。当有线程Exception结束时,线程池会补充一个新的线程。
- newCachedThreadPool:创建一个可缓存的线程池,如果线程池当前的规模超出了处理请求时,那么会回收空闲的线程,需求增加时,添加新的线程。线程池的规模不存在限制。
- newSingleThreadPool:单线程的Executor,保证任务的顺序执行。
- newScheduledThreadPool:创建一个固定长度的线程池,以延迟或定时的任务执行任务。
- newWorkStealingPool:守护线程,每个线程都维护自己的任务队列,当自己的任务队列执行完了,会去别的线程的任务队列“偷”任务来执行。底层是ForkJoinPool
- ForkJoinPool:将大任务切分为小任务并行执行,执行完的结果进行合并。
6.2.4:Executor的生命周期
1、JVM只有在所有(非守护)线程全部终止后才会退出,因此若无法正确关闭Executor,那么JVM无法关闭
2、Executor采用异步方式来执行任务
3、为了解决执行服务的生命周期问题,Executor扩展了ExecutorService接口
public interface ExecutorService extends Executor{
void shutdown();//平稳的关闭,不再接收新的任务、同时等待已经提交的任务执行
List<Runnable> shutdownNow();//执行暴力的关闭,尝试取消所有运行的任务,并且不再启动队列中尚未启动的任务
boolean isShutDown();//如果此执行程序已关闭,则返回 true
boolean isTerminated();//查询ExecutorService是否已经终止
boolean awaitTermination(long timeout, TimeUint unit) throws InterruptedException;
//通常调用awaitTermination后会立即调用shutdown,产生同步关闭ExecutorServicce
Future<?> submit(Runnable task);
//提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。该 Future 的 get 方法在成功 完成时将会返回 null。 抛出RejectedExecutionException - 如果任务无法安排执行 ,NullPointerException - 如果该任务为 null
}
4、ExecutorService的三种生命周期状态:
- 运行:初始创建时处于运行状态。
- 关闭:shutdown方法执行平缓的关闭过程:不接受新任务,等待正在执行的任务完成。shutdownNow方法暴力关闭,直接取消所有运行中的任务。
- 终止:所有任务完成后,进入终止状态。
6.2.5:延迟任务与周期任务
1、线程池可以提供多个线程来执行延迟任务和周期任务
2、ScheduledThreadPool可以解决Timer解决不了的问题
3、构建自己调度服务时,可以使用DelayQueue
6.3找出可利用的并发性
6.3.2携带结果的任务Callable与Future
1、Runnable与Callable最大的区别:Callable有返回值
// Callable接口
public interface Callable<V> {
V call() throws Exception;//Callable有返回值
}
2、Executor执行任务的四个生命周期
- 创建
- 提交
- 开始
- 完成
3、想取消Executor提交的任务时
- 任务已提交但尚未开始:可以取消
- 任务已开始执行:只有当他们能响应中断时,才能取消
4、Future表示一个任务的生命周期
// Future接口
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException,
CancellationException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException,
CancellationException, TimeoutException;
}