任务执行(第六章)

简介:

任务执行

任务边界:当围绕“任务执行”来设计应用程序时,第一步就是要找出清晰的任务边界。

1.为每个任务创建一个线程的风险:

  1. 线程生命周期的开销非常高:线程的创建于销毁
  2. 资源消耗:活跃的线程会消耗系统资源,尤其是内存。如果可运行的线程数量多于可用处理器的数量,那么有些线程将闲置。所以,如果已经拥有足够多的线程使CPU保持忙碌状态,那么创建再多的线程反而会降低性能
  3. 稳定性:在可创建线程的数量上存在一定限制,这个闲置值将随平台的不同而不同,并且受多个因素闲置。如果破坏了这些限制,那么可能抛出OutOfMemoryError异常

    
           应该对程序中创建的线程数量进行限制。
        

2. Executor框架

    在Java中,执行任务的主要抽象不是Thread,而是Executor。
    
public interface Executor {
       void execute(Runnable command);
}

Executor框架能支持多种不同类型的任务执行策略,它提供了一种标准的方法将任务的提交过程与执行过程解耦,并用Runnable来表示任务。Executor的实现还提供了对生命周期的支持,以及统计信息收集、应用程序管理机制和性能监视等机制。
Executor基于生产者----消费者模式,提交任务的操作相当于生产者,执行任务的线程相当于消费者。

  1. Executor的生命周期

JVM只有在所有(非守护)线程都终止后才会退出,因此,如果Executor没有正确关闭,那么JVM将无法退出。
Executor执行的任务有4个证明周期阶段:创建、提交、开始和完成。已提交但尚未开始的任务可以取消,但对于已经开始执行的任务,只有当他们响应中断时才能取消。
Executor扩展了ExecutorService接口,用于管理生命周期:

//Executor的生命周期有3中运行状态:运行、关闭和已终止。
public interface ExecutorService extends Executor {
    /*shutdown执行平稳的关闭过程:不再接受新任务,同时等待已提交的任务执行完----包括那些还未开始执行的任务*/
    void shutdown();
    /*shutdownNow将执行粗暴的关闭过程:它将尝试取消所有运行中的任务,并且不再启动队列中尚未开始执行的任务*/
    List<Runnable> shutdownNow();
    boolean isShutdown();
    boolean isTerminated();
    boolean awaitTermination(long timeout,TimeUnit unit) throws InterruptedExecutor;
}

Executor的缺陷:

  1. Executor使用Runnable作为基本的任务标志形式,但Runnable中的run()不能返回值也不能抛出异常

3.执行策略

在执行策略中定义了任务执行的“What、Where、When、How”等方面。包括:

    1. 在什么(what)线程中执行
    2. 任务按照什么顺序(FIFO、LIFO、优先级)执行
    3. 有多少个(how many)任务能并发执行
    4. 在队列中有多少个(how many)任务等待执行
    5. 如果系统由于过载而需要拒绝一个任务,那么应该选择哪一个(which)任务?另外如何(how)通知应用程序有任务被拒绝
    6. 在执行一个任务之前或之后,应该进行哪些(what)动作
    

4.线程池

线程池指管理一组同构工作线程的资源池。
可以通过调用Executor中的一些静态函数创建线程池:

  1. newFixedThreadPool:创建一个固定长度的线程池,每当提交一个任务时就创建一个线程,直到创建的线程数量达到最大,此后线程的数量不会再变化。如果某个线程由于发生未预期的Exception而结束,那么线程会补充一个新的线程
  2. newCachedThreadPool:创建一个可缓存的线程池,如果线程池的规模超过了处理需求,那么将回收空闲的线程,而当需求增加时,则可以添加新的线程,线程池的规模不存在人任何限制
  3. newSingleThreadExecutor:单线程的Executor,它创建单个工作者线程来执行任务,如果这个线程异常结束,会创建一个新的线程来代替,其能确保依照任务在队列中的顺序串行序执行
  4. new ScheduledThreadPool:创建一个固定长度的线程池,而且以延时或定时的方式来执行顺序

        “在线程池中执行任务”要比“为每个任务分配一个线程”优势更多。
        

5.延迟任务与周期任务

Timer类负责管理延迟任务以及周期任务,但是Timer类存在一些缺陷,应该考虑使用ScheduledThreadPool类代替它
Timer类的缺陷

  1. Timer在执行所有定时任务时只会创建一个线程,如果某个任务的延时时间过长,那么将破坏其他TimerTask的定时精确性。
  2. 如果TimerTask抛出了一个未受检查的异常,由于Timer线程并不捕获异常,因此Timer将终止线程的执行。

        如果要构建自己的调度服务,那么可以使用DelayQueue,它实现了BlockingQueue,并为ScheduledThreadPoolExecutor提供调度功能。DelayQueue管理着一组Delayed对象,每个Delayed对象都有一个相应的延迟时间:在DelayQueue中,只有某个元素逾期后,才能从DelayQueue中执行take操作,从DelayQueue中返回的对象将根据他们的延迟时间进行排序。
        

6.Callable与Future

Callable提供了一种相比Runnable更好的抽象:call,call()有返回值(要用Callable表示无返回值的任务,使用Callable),并且允许抛出异常。
Future表示一个任务的生命周期,并提供了相应的方法来判断是否已经完成或取消,以及获取任务的结果和取消任务等。Future意味着任务的生命周期只能前进,不能后退
如果任务抛出了异常,那么get将异常封装为ExecutorException并重新抛出,并且可以通过getCause来获得被封装的初始异常,如果任务被取消,那么get将抛出 CancellationException

public interface Callable<V> {
    V call() throws Exception;
}
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;
}
    只有当大量相互独立且同构的任务可以并发处理时,才能体现出将程序的工作负载分配到多个任务中带来的性能提升。
相关文章
|
7月前
|
Java Python
解释Python中的引用计数机制是如何工作的,以及它的优劣势。
【2月更文挑战第7天】【2月更文挑战第17篇】解释Python中的引用计数机制是如何工作的,以及它的优劣势。
85 1
|
1月前
|
XML JSON 监控
Shell脚本要点和难点以及具体应用和优缺点介绍
Shell脚本在系统管理和自动化任务中扮演着重要角色。尽管存在调试困难、可读性差等问题,但其简洁高效、易于学习和强大的功能使其在许多场景中不可或缺。通过掌握Shell脚本的基本语法、常用命令和函数,并了解其优缺点,开发者可以编写出高效的脚本来完成各种任务,提高工作效率。希望本文能为您在Shell脚本编写和应用中提供有价值的参考和指导。
62 1
|
3月前
|
存储 C语言
C语言程序设计核心详解 第七章 函数和预编译命令
本章介绍C语言中的函数定义与使用,以及预编译命令。主要内容包括函数的定义格式、调用方式和示例分析。C程序结构分为`main()`单框架或多子函数框架。函数不能嵌套定义但可互相调用。变量具有类型、作用范围和存储类别三种属性,其中作用范围分为局部和全局。预编译命令包括文件包含和宏定义,宏定义分为无参和带参两种形式。此外,还介绍了变量的存储类别及其特点。通过实例详细解析了函数调用过程及宏定义的应用。
|
6月前
|
编译器 vr&ar C++
c++primer plus 6 读书笔记 第七章 函数--C++的编程模块
c++primer plus 6 读书笔记 第七章 函数--C++的编程模块
|
7月前
|
存储 算法 编译器
第七章:函数
第七章:函数
69 0
|
编译器 数据安全/隐私保护 Python
Python编程基础:实验1——程序的控制结构
Python编程基础实验1——程序的控制结构
431 0
Python编程基础:实验1——程序的控制结构
|
移动开发 关系型数据库 MySQL
第五章《函数》
第五章《函数》
第五章《函数》
|
网络协议 NoSQL 安全
【精通内核】计算机程序的执行原理深度解析
深度解析ELF文件中将内存布局地址,CPU是如何执行指令的,C语言中方法的执行过程的内核调用。
|
SQL 测试技术
软件测试面试题:解释以下函数及他们的不同之处?
软件测试面试题:解释以下函数及他们的不同之处?
78 0
|
存储 机器学习/深度学习 自然语言处理
软件测试前置基础知识(基本概念,DOS命令)
软件测试前置基础知识(基本概念,DOS命令)