Java并发--ScheduledThreadPoolExecutor

ScheduledThreadPoolExecutor

ScheduledThreadPoolExecutor inherited from ThreadPoolExecutor . It is mainly used to run tasks after a given delay, or recurring tasks. ScheduledThreadPoolExecutor and Timer functions similar, but ScheduledThreadPoolExecutor more powerful and more flexible.

Timer corresponding to a single background thread, while background ScheduledThreadPoolExecutor can specify a plurality of threads corresponding to the constructor.

ScheduledThreadPoolExecutor operating mechanism

Performing a schematic ScheduledThreadPoolExecutor (Based JDK 6) shown below:
Here Insert Picture Description

DelayQueue is an unbounded queue , so ThreadPoolExecutor in the maximumPoolSizeScheduledThreadPoolExecutor does not make sense (to set the size of maximumPoolSize no effect).

ScheduledThreadPoolExecutor execution is divided into two parts:

  1. When you call ScheduledThreadPoolExecutor of scheduleAtFixedRate () method or scheduleWithFixedDelay () method, will be added to the DelayQueue ScheduledThreadPoolExecutor a realization of the ScheduledFutureTask RunnableScheduledFutur interface.
  2. Thread pool thread to obtain ScheduledFutureTask from DelayQueue, and then perform the task.

ScheduledThreadPoolExecutor task Flow Chart:
Here Insert Picture Description

ScheduledThreadPoolExecutor为了实现周期性的执行任务,对ThreadPoolExecutor做了如下
的修改:

  • 使用DelayQueue作为任务队列。
  • 获取任务的方式不同(后文会说明)。
  • 执行周期任务后,增加了额外的处理(后文会说明)。

ScheduledThreadPoolExecutor的实现

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

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

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

DelayQueue封装了一个PriorityQueue,这个PriorityQueue会对队列中的ScheduledFutureTask进排序。排序时,time小的排在前面(时间早的任务将被先执行)。如果两个ScheduledFutureTask的time相同,就比较sequenceNumber,sequenceNumber小的排在前面(也就是说,如果两个任务的执行时间相同,那么先提交的任务将被先执行)。

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

Here Insert Picture Description

  1. 线程1从DelayQueue中获取已到期的ScheduledFutureTask(DelayQueue.take())。到期任务是指ScheduledFutureTask的time大于等于当前时间。
  2. 线程1执行这个ScheduledFutureTask。
  3. 线程1修改ScheduledFutureTask的time变量为下次将要被执行的时间。
  4. 线程1把这个修改time之后的ScheduledFutureTask放回DelayQueue中(DelayQueue.add())。

下面是DelayQueue.take()方法的源代码实现:

Here Insert Picture Description

DelayQueue.take()的执行示意图:
Here Insert Picture Description

如图所示,获取任务分为3大步骤:

  1. 获取Lock
  2. 获取周期任务
    • 如果PriorityQueue为空,当前线程到Condition中等待;否则执行下面的2.2。
    • 如果PriorityQueue的头元素的time时间比当前时间大,到Condition中等待到time时间;否则执行下面的2.3。
    • 获取PriorityQueue的头元素(2.3.1);如果PriorityQueue不为空,则唤醒在Condition中等待的所有线程(2.3.2)。
  3. 释放Lock
    ScheduledThreadPoolExecutor在一个循环中执行步骤2,直到线程从PriorityQueue获取到一
    个元素之后(执行2.3.1之后),才会退出无限循环(结束步骤2)。

ScheduledThreadPoolExecutor中的线程执行任务的步骤4,把ScheduledFutureTask放入DelayQueue中的过程。下面是DelayQueue.add()的源代码实现。
Here Insert Picture Description

DelayQueue.add()的执行示意图:
Here Insert Picture Description如图所示,添加任务分为3大步骤。

  1. 获取Lock
  2. 添加任务
    • 向PriorityQueue添加任务。
    • 如果在上面2.1中添加的任务是PriorityQueue的头元素,唤醒在Condition中等待的所有线程。
  3. 释放Lock
Published 660 original articles · won praise 1889 · Views 240,000 +

Guess you like

Origin blog.csdn.net/cold___play/article/details/104070800