【Java】线程池技术(一)Executor框架

背景

Java 底层提供了 Thread 类支持开发人员手动创建线程执行任务,但是这种操作会存在以下问题:

  • 每次都要重新创造和回收 Thread 对象,性能较差。如果并发线程数较大,且任务执行时间较短,频繁创建和回收线程对象会大大降低系统的效率
  • 线程缺乏统一管理,不同业务之间可能会无限制的创建线程,相互之间竞争资源,容易导致系统资源占用过多,从而引起 OOM 或程序奔溃
  • 功能比较单一,缺乏其他通用能力

在这样的背景下,结合池化思想,则可以通过线程池来优化设计。具体的优势在于:

  • 通过重复利用已创建的线程,避免因频繁创建和回收线程对象而对系统造成的资源开销
  • 提高任务响应速度,当任务到达后,可以立即使用已创建的线程执行任务
  • 统一管理线程的分配、调度和监控,可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞

使用线程池时场景,一般满足以下特征:

  • 单个任务的处理时间比较短
  • 需要处理的任务数量特别大

Executor 框架

Executor 是 Java 中一个经典的多线程任务管理框架,其主要提供了任务、任务执行线程池、任务执行结果三个组件,每个组件的具体定义与含义如下:

组件含义
任务Executor 框架提供了 Runnable 接口和 Callable 接口,任务需要实现这两个接口才能被线程执行
任务执行线程池Executor 框架提供了接口 Executor 和继承于 ExecutorExecutorService 接口来定义任务执行机制。Executor 框架中的线程池类 ThreadPoolExecutor 和 ScheduledThreadPoolExecutor 均实现了ExecutorService 接口
任务执行结果Executor 框架提供了 Future 接口和实现了 Future 接口的 FutureTask 类来定义任务执行结果。调用 ExecutorServicesubmit() 方法后会返回一个 Future 对象。

基本流程

  1. 主线程创建实现了 Runnable 或者 Callable 接口的任务对象;
  2. 把创建完成的 Runnable 对象或者 Callable 对象提交给 ExecutorService 执行 execute() 或者 submit() 方法;
  3. 如果执行的是 submit() 方法,则 ExecutorService 会返回一个实现了 Future 接口的对象;
  4. 最后主线程可以执行 Future 接口对象的 get() 方法来等待任务执行完成,也可以执行 cancel() 方法来取消任务的执行,通过参数 boolean mayInterruptIfRunning 来控制是否中断正在执行中的任务。

设计思想

  • 顶层接口 Executor 提供了一种思想:将任务提交和任务执行进行解耦。用户无需关注如何创建线程,如何调度线程来执行任务,用户只需提供 Runnable 对象,将任务的运行逻辑提交到执行器 Executor 中,由 Executor 框架完成线程的调配和任务的执行部分。
  • ExecutorService 接口增加了一些能力:
    • 扩充执行任务的能力,补充可以为一个或一批异步任务生成 Future 的方法;
    • 提供了管控线程池的方法,比如停止线程池的运行。
  • AbstractExecutorService 则是上层的抽象类,将执行任务的流程串联了起来,保证下层的实现只需关注一个执行任务的方法即可。
  • 最下层的实现类 ThreadPoolExecutor 实现最复杂的运行部分,一方面维护自身的生命周期,另一方面同时管理线程和任务,使两者良好的结合从而执行并行任务。
  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值