【学习笔记-并发编程实战】第6章 任务执行

在线程中执行任务

以任务执行为结构的应用程序设计的关键是找出清晰的任务边界,大多数服务器应用程序都是以独立的客户请求为界。

串行的执行任务

一种串行的web服务器,接受请求和提供服务都在同一线程中,这种串行的方式无法提供高吞吐率或快速响应。

显示地为任务创建线程

为在主循环中为每个请求的任务创建一个线程,将任务处理放在子线程进行处理。任务处理的代码必须是线程安全的,因为其有多个任务时会并发的调用。

无限制创建线程的不足

当请求量大时,使用new Thread会创建大量的线程,1线程的生命周期开销非常的高、2活跃的线程消耗内存资源,当可运行的线程数量大于cpu核心数时,大量闲置线程,占用内存、3系统对可创建的线程数有限制。

 

Executor框架

线程池接口,直接提交任务,框架安排调度线程执行。

基于Executor的web服务器

不再是每个处理任务生成一个线程,而是生成一个可执行的任务Runnable,将任务通过executor进行执行。

在调用线程中以同步方式执行所有任务的Executor,WithinThreaadExecutor,这个问题不是很明白。

执行策略

使用Executor代理Thread可以更灵活的制定任务执行的策略。

线程池

newFixedThreadPool    固定线程数量的线程池

newCachedThreadPool    缓存线程池

newSingleThreadExecutor   一个单线程,但是可以保证线程的存在性,如果异常结束后会再创建一个线程

newScheduledThreadPool    用来代替Timer

Executor的生命周期

使用shutdown或shutdownNow来结束Executor,awaitTermination判断线程池是否停止(shutdown方法被调用之后,或者参数中定义的timeout时间到达或者当前线程被打断)

延迟任务与周期任务

使用DelayQueue构建调度任务

 

找出可利用的并行性

在任务边界不是十分明显的时候,或者在一般的单线程程序中,我们仍然可以通过划分任务边界挖掘程序的并发性。

串行的页面渲染器

在同一线程中,先进行下载,再进行渲染。

携带任务的Callable与Future

Runnable是任务的基本形式,但是它不能返回一个值或者抛出一个异常,Future是任务返回的一个对象,可以通过这个对象阻塞的获取值。

使用Future实现页面渲染器

使用一个task来下载所有图像,task中迭代下载所有图像,然后通过get阻塞的获取下载的图像后,在主线程中进行迭代渲染。

在异构任务并行化中存在局限

两个异构的任务需要处理的进度不一样时,就会导致任务的执行不一致,不能完全充分的利用cpu性能,代码却变得更复杂了,所以最后将任务拆分为相互独立且同构的任务,确保这些任务适合并发处理。

CompletionService

使用Future的get方法获取计算结果,需要不停的轮询,方然虽然好,但是繁琐,于是有了CompletionService,将Executor与BlockingQueue结合,将执行完成后的结果add进BlockingQueue,然后直接获取。

使用CompletionService实现页面的渲染器

将每一幅图片作为一个任务,通过CompletionService执行,执行后先通过completionService的take获取Future,此时的Future是计算完成已经有结果的,在通过future的get方法获取最终结果,详细可见P107。

为任务设置时限

通过future的get方法设置时限,超过时限会抛出TimeoutException,捕获后需要取消任务,避免继续计算浪费算力。

旅行预订门户网站

通过invokeAll方法提交一组任务,然后返回一组future

 

你可能感兴趣的:(多线程,并发,java基础)