(八)线程池与Executor 框架

本节思维导图:

img

一 使用线程池的好处

线程池 提供一种限制和管理资源(包括执行一个任务)。每个线程池还维护一些基本统计信息,例如已完成任务的数量。

这里借用《Java并发编程的艺术》 提到的来说一下使用线程池的好处

  • 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的开销。
  • 提高响应速度。当任务可达时,任务可以不需要等到线程创建就能立即执行。
  • 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一分配,调优和监控。

二 Executor框架

2.1 简介

Executor 框架是Java5 之后引进的,在Java5 之后,通过Executor 来启动线程比使用 Thread 的start 方式更好,除了更易管理,效率更好(用线程池实现,节约开销)外,还有关键的一点:有助于避免 this 逃逸问题。

补充:this逃逸 是指在构造函数返回之前,其他线程就持有该对象的饮用。调用尚未构造完全的对象方法可能引发令人疑惑的错误。

2.2 Executor 框架结构(主要由三大部分组成)

1 任务。

执行任务需要实现的 Runnable接口Callable接口

Runable接口Callable接口实现类都可以被ThreadPoolExecutorScheduledThreadoolExecutor执行。

两者的区别:

Runnable接口不会返回结果,但是Callable接口可以返回结果。后面介绍Executor类的一些方法的时候会介绍到两者的相互转换。

2 任务的执行

如下图所示,包括认为执行机制的核心接口Executor,以及继承自Executor 接口的ExecutorService接口ScheduledThreadPoolExecutorThreadPoolExecutor这两个关键类实现了ExecutorService接口

注意:通过查看ScheduledThreadPoolExecutor源代码可以发现,ScheduledThreadPoolExecutor实际上是继承了ThreadPoolExecutor,并实现了SchduledExecutorService,而ScheduledExecutorService又实现了ExecutorService,正如下面的类图:

ThreadPoolExecutor类描述:

* @since 1.5
 * @author Doug Lea
 */
public class ThreadPoolExecutor extends AbstractExecutorService {
   

ScheduledThreadPoolExecutor类描述:

 * @since 1.5
 * @author Doug Lea
 */
public class ScheduledThreadPoolExecutor
        extends ThreadPoolExecutor
        implements ScheduledExecutorService {
   

类关系图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UNmsuiZG-1572841549196)(C:\Users\hbing\AppData\Roaming\Typora\typora-user-images\1572594208514.png)]

3 异步计算的结果

Future接口 以及 Future接口的实现类 FutureTask类

当我们把Runnable接口Callable接口的实现类提交(调用submit方法)给ThreadPoolExecutorScheduledPoolExecutor时,会返回一个FutureTask对象

我们以AbstractExecutorService接口中的一个submit方法为例子来看看源代码:

public Future<?> submit(Runnable task) {
   
        if (task == null) throw new NullPointerException();
        RunnableFuture<Void> ftask = newTaskFor(task, null);
        execute(ftask);
        return ftask;
    }

进入newTaskFor方法,看看返回值。

* @since 1.6
     */
    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
   
        return new FutureTask<T>(runnable, value);
    }

返回的是一个FutureTask对象。

2.3 Executor 框架的使用示意图

img

  1. 主线程首先要创建实现Runnable或者Callable接口的任务对象。

    工具类Executors 可以实现Runnable对象和Callable对象之间的相互转换。

    public static Callable<Object> callable(Runnable task) {
         
        
    public static <T> Callable<T> callable(Runnable task, T result) {
             
    
  2. 然后可以把创建完成的Runnable对象直接交给ExecutorService执行

    ThreadTest task = new ThreadTest();
            
    Callable callable = Executors.callable(task);
    
    ExecutorService executorService = Executors.newFixedThreadPool(5);
    executorService.execute(task);
    
    Future future1 = executorService.submit(task);
    FutureTask future2 = (FutureTask) executorService.submit(callable);
    
    boolean isDone = future1.isDone();
    

    执行execute()方法和submit()方法的区别是什么呢?

    1. execute()方法用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功与否;
    2. **submit()方法用于提交需要返回值的任务,线程池会返回一个Future类型的对象,通过这个Future对象可以判断任务是否成功执行,**并且可以通过future的get()方法获取返回值,get()方法会阻塞当前线程直到任务完成,而get(long timeout,TimeUnit unit)方法则会阻塞当前线程一段时间后立即返回,这时候有可能任务还没有完成。
  3. 如果执行ExecutorService.submit(。。。),ExecutorService将会返回一个实现Future接口对象(到目前为止的JDK中,返回的都是FutureTask对象)。由于FutureTask实现了Runnable接口,也可以创建FutureTask,然后交给ExecutorService去执行。

  4. 最后,主线程可以执行FutureTask.get()方法来等待任务执行完成。主线程也可以执行FutureTask.cancel(boolean mayInterruptIfRunning)来取消任务的执行

三 ThreadPoolExecutor详解

线程池实现类ThreadPoolExecutor是Executor 框架最核心的类,来看看比较重要的四个属性:

3.1 ThreadPoolExecutor类的四个比较重要的属性

img

3.2 ThreadPoolExecutor类中提供的四个构造方法

我们最常看到这个方法,其余三个都是在这个构造方法的基础上产生的

    /**
     * 用给定的初始参数创建一个新的ThreadPoolExecutor。

     * @param keepAliveTime 当线程池中的线程数量大于corePoolSize的时候,如果这时没有新的任务提  	    交,核心线程外的线程不会立即销毁,而是会等待,直到等待的时间超过了keepAliveTime;
     * @param unit  keepAliveTime参数的时间单位
     *
     * @param workQueue 等待队列,当任务提交时,如果线程池中的线程数量大于等于corePoolSize的时		候,把该任务封装成一个Worker对象放入等待队列ÿ
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值