Java并发笔记 (16)------ Executor

Executor 框架介绍

1. 两级调度模型

在这里插入图片描述

由上面这张图片可以看出:

  • 上层:Java多线程程序通常把应用分解为若干个任务,Executor框架)将这些任务映射为固定数量的线程
  • 底层:操作系统内核将这些线程映射到硬件处理器上

2. Executor框架

Executor框架包含的主要的类与接口,如下图:

在这里插入图片描述

Executor框架的使用示意图如下:

在这里插入图片描述

过程分析

  1. 主线程首先要创建实现Runnable或者Callable接口的任务对象。Executors.callable(Runnable task)Executors.callable(Runnable task,Object resule)Runnable 封装为一个Callable的方法。

  2. 然后可以把Runnable对象直接交给ExecutorService(ExecutorService.execute(Runnable command));或者也可以把Runnable对象或Callable对象提交给ExecutorService执行。

  3. 如果执行ExecutorService.submit(...),ExecutorService将返回一个实现Future接口的对象。

    由于FutureTask实现了Runnable,程序员也可以创建FutureTask,然后直接交给ExecutorService执行。

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


3. Executor成员

  • ThreadPoolExecutor:SingleThreadExecutor、FixedThreadPool和CachedThreadPool。

  • ScheduledThreadPoolExecutor:ScheduledThreadPoolExecutor、SingleThreadScheduledExecutor

  • Future接口:Future接口和实现Future接口的FutureTask类用来表示异步计算的结果。

  • Runnable接口和Callable接口
    下面是Executors提供的,把一个Runnable包装成一个Callable的API。

    public static Callable<Object> callable(Runnable task)
    

1. FixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
    						0L, TimeUnit.MILLISECONDS,
   							new LinkedBlockingQueue<Runnable>());
}

上述代码可以看出, 这种线程池,核心线程池和最大线程池大小相同,且使用了无界阻塞队列(队列容量:Integer.MAX_VALUE),这样无法执行的线程放入阻塞队列中。

流程图如下:

在这里插入图片描述

2.SingleThreadExecutor

代码如下:

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}

SingleThreadExecutorcorePoolSizemaximumPoolSize被设置为1。其他参数与FixedThreadPool相同。

工作图如下:

在这里插入图片描述


3. CachedThreadPool

CachedThreadPool是一个会根据需要创建新线程的线程池。代码如下:

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

工作流程如下:

在这里插入图片描述

工作流程阐述:

  1. 执行SynchronousQueue.offer(Runnable task)。如果当前maximumPool中有空闲线程正在执行SynchronousQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS),那么主线程执行offer操作与空闲线程执行的poll操作配对成功,主线程把任务交给空闲线程执行,否则执行 2.
  2. maximumPool中当前没有空闲线程时,没有线程执行
    SynchronousQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS),此时CachedThreadPool会创建一个新线程执行任务。
  3. 在步骤2中新创建的线程将任务执行完后,会执行SynchronousQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS)。这个poll操作会让空闲线程最多在SynchronousQueue中等待60秒钟。如果60秒钟内主线程提交了一个新任务(执行步骤1);否则,这个空闲线程将终止。

4. ScheduledThreadPoolExecutor

ScheduledThreadPoolExecutor继承自ThreadPoolExecutor。它主要用来在给定的延迟之后运行任务,或者定期执行任务。

  • 运行机制如下图

在这里插入图片描述
DelayQueue是一个“无界”的”优先“、“阻塞”队列

  • 实现

    ScheduledThreadPoolExecutor会把待调度的任务(ScheduledFutureTask)放到一个DelayQueue中

    ScheduledFutureTask主要包含3个成员变量:

    1. long型成员变量time,表示这个任务将要被执行的具体时间。
    2. long型成员变量sequenceNumber,表示这个任务被添加到ScheduledThreadPoolExecutor中的序号。
    3. long型成员变量period,表示任务执行的间隔周期。

    DelayQueue将ScheduledFutureTask按照time从小到达进行排序,小的放在前面,如果时间相同,那么先提交的任务将被先执行。

    线程1执行某个周期任务的4个步骤如下:

    在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值