Java并发编程实战 第6章 任务执行

6.1 在线程中执行任务

在理想情况下,各个任务之间时相互独立的:任务并不依赖于其他任务的状态、结果、边界效应。
应用程序性希望支持尽可能多的用户,从而降低每个用户的服务成本,而用户则希望获得尽快的响应。

6.1.1串行的执行任务

6.1.2 显示地为任务创建线程

只要请求到达的速率不超出服务器的处理能力。

6.1.3 无限制创建线程的不足

线程生命周期的开销非常高
资源消耗
稳定性:线程数的限制值随平台不同,并受JVM启动参数、Thread构造函数中栈大小、以及地层OS对线程的限制等。会抛出OOM等异常。

6.2 Excutor框架

任务是一组逻辑工作单元,而线程则是使任务异步执行的机制。
Excutor基于生产者-消费者,提供了一种标准方法将任务的提交过程与执行过程解耦开,并用Runnable表示任务,还提供了对生命周期的支持、统计信息、性能监视等。

6.2.1 例:基于Executor的web服务器

6.2.2 执行策略

使用Executor来代替Thread

6.2.3 线程池

指管理一组同构工作线程的资源池。
可以避免线程创建和销毁过程中有巨大的开销;请求到达时工作线程已经存在,因此不会由于等待创建线程而延迟;适当调整线程池的大小,可以创建足够多的的线程以便使处理气保持忙碌状态,同时还可以防止多线程相互竞争资源而使应用程序耗尽内存或失败。

使用Executors中的静态工厂方法来创建线程池

  • newFixedThreadPool
    固定长度线程池。每次提交一个任务时就创建一个线程,直到达到最大数量。如果某个线程异常,则会补充一个新线程。
  • newCachedThreadPool
    可缓存的线程池。如果线程池的规模超过了处理需求,则回收空闲线程,而当需求增加时则可以添加新的线程,线程池的规模无限制。
  • newSingleThreadExecutor
    单个工作线程。如果异常结束,则会创建一个新线程来替代。
  • newScheduleThreadPool
    固定长度线城池。以延迟或定时的方式来执行,类似Timer。

6.2.4 Executor的生命周期

JVM只有在所有(非守护)线程全部终止后才会退出。因此如果无法正确的关闭Executor,那么JVM将无法结束。
public interface ExecutorService extends Executor
ExecutorService 的生命周期有三种状态:运行、关闭和已终止。
shutdown方法将执行平缓的关闭过程:不在接受新的任务,同时等待已提交的任务执行完成——包括还未开始执行的任务。
shutdownNow方法将粗暴执行:尝试取消所有运行中的任务,并且不再启动队列中尚未开始执行的任务。

6.2.5 延迟任务与周期任务

Timer在执行所有定时任务时只会创建一个线程。

6.3 找出可利用的并行性

6.3.2 携带结果的任务Callable与Future

Runnable不能返回一个值或抛出一个受检查的异常。
Executor执行的任务有4个生命周期阶段:创建、提交、开始和完成。
Future表示一个任务的生命周期,并提供了相应的方法来判断是否已经完成或取消,以及获取任务的结果和取消任务等。其规范隐含意义是,任务的生命周期只能前进,不能后退。

通过对异构任务进行并行化来获得重大的性能提升是很困难的,只有当大量相互独立且同构的任务可以并发进行处理时,才能体现出将程序的工作负载分配到多个任务中带来的真正性能提升。

为任务设置时限
例如web从外部广告服务器上获取广告信息,如果两秒钟内得不到响应,将显示一个默认的广告,这样即使获取不到,也不会降低站点的响应性能。类似的,一个门户网站可以从多个数据源并行的获取数据,但可能只会在指定的时间内等待数据,如果超出了等待时间,那么只显示已经获得的数据。
在使用限时任务时需要注意,当这些任务超时后应该立即停止,从而避免为继续计算一个不再使用的结果浪费资源。

学习一下使用invokeAll

你可能感兴趣的:(并发编程)