1. 程式人生 > 其它 >面試突擊34:如何使用執行緒池執行定時任務?

面試突擊34:如何使用執行緒池執行定時任務?

在 Java 語言中,有兩個執行緒池可以執行定時任務:ScheduledThreadPool 和 SingleThreadScheduledExecutor,其中 SingleThreadScheduledExecutor 可以看做是 ScheduledThreadPool 的單執行緒版本,它的用法和 ScheduledThreadPool 是一樣的,所以本文重點來看 ScheduledThreadPool 執行緒池的使用。
ScheduledThreadPool 執行定時任務的方法有以下 3 個:

  1. 使用 schedule 方法執行定時任務,只執行一次定時任務。
  2. 使用 scheduleAtFixedRate 方法執行定時任務,執行多次定時任務。
  3. 使用 scheduleWithFixedDelay 方法執行定時任務,執行多次定時任務。

接下來我們看這 3 個方法的具體使用和區別。

1.schedule

schedule 方法只能執行一次定時任務,它需要傳遞 3 個引數:

  • 第 1 個引數:傳遞一個任務,Runnable 或 Callable 物件;
  • 第 2 個引數:新增定時任務後,再過多久開始執行定時任務;
  • 第 3 個引數:時間單位,配合引數 2 一起使用。

下面我們建立一個 3 秒以後執行的定時任務:

import java.time.LocalDateTime;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ScheduledThreadPoolExample {
    public static void main(String[] args) throws InterruptedException {
        // 建立 ScheduledThreadPool 執行緒池
        ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(10);
        System.out.println("schedule 方法新增任務:" + LocalDateTime.now());
        threadPool.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("執行 schedule 方法:" + LocalDateTime.now());
            }
        }, 3, TimeUnit.SECONDS); // 3s 之後執行

        // 以下程式碼是給業務方法一個時間對照資訊
        TimeUnit.SECONDS.sleep(10); // 休眠 10s
        System.out.println("當前時間:" + LocalDateTime.now());
    }
}

以上程式的執行結果如下圖所示:

從上述結果中可以看出,使用 schedule 方法只能執行一次定時任務。

2.scheduleAtFixedRate

scheduleAtFixedRate 方法可以執行多次定時任務,此方法需要 4 個引數:

  • 第 1 個引數:傳遞一個任務,Runnable 或 Callable 物件;
  • 第 2 個引數:新增定時任務後,再過多久開始執行定時任務;
  • 第 3 個引數:定時任務執行的時間間隔;
  • 第 4 個引數:時間單位,配合引數 2 和引數 3 一起使用。

下面我們建立一個 3 秒後執行的定時任務,每個定時任務執行的時間間隔為 2 秒,實現程式碼如下:

import java.time.LocalDateTime;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ScheduledThreadPoolExample {
    public static void main(String[] args) throws InterruptedException {
        // 建立 ScheduledThreadPool 執行緒池
        ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(10);
        System.out.println("scheduleAtFixedRate 方法新增任務:" + LocalDateTime.now());
        threadPool.scheduleAtFixedRate(new Runnable() {
                                           @Override
                                           public void run() {
                                               System.out.println("執行 scheduleAtFixedRate 方法:" + LocalDateTime.now());
                                               // 休眠 2s
                                               try {
                                                   TimeUnit.SECONDS.sleep(2);
                                               } catch (InterruptedException e) {
                                                   e.printStackTrace();
                                               }
                                           }
                                       },
                3L, // 3s 後開始執行定時任務
                2L, // 定時任務的執行間隔為 2s
                TimeUnit.SECONDS); // 描述上面兩個引數的時間單位
    }
}

以上程式的執行結果如下圖所示:

從上述結果可以看出,當任務新增成功之後,3s 後開始執行第一個定時任務,之後每隔 2s 執行一次定時任務。

3.scheduleWithFixedDelay

scheduleWithFixedDelay 方法的使用和 scheduleAtFixedRate 類似,但執行效果完全不同,這個很容易理解如果效果一樣就不用建立兩個方法了。
scheduleWithFixedDelay 方法是在方法執行完成之後,再隔 N 秒執行下一個定時任務,和 scheduleAtFixedRate 的固定時間執行不同,scheduleWithFixedDelay 方法的執行受定時任務執行的時長影響,比如以下程式碼:

import java.time.LocalDateTime;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ScheduledThreadPoolExample {
    public static void main(String[] args) throws InterruptedException {
        // 建立 ScheduledThreadPool 執行緒池
        ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(10);
        System.out.println("scheduleWithFixedDelay 方法新增任務:" + LocalDateTime.now());
        threadPool.scheduleWithFixedDelay(new Runnable() {
                                              @Override
                                              public void run() {
                                                  System.out.println("執行 scheduleWithFixedDelay 方法:" + LocalDateTime.now());
                                                  // 休眠 2s
                                                  try {
                                                      TimeUnit.SECONDS.sleep(2);
                                                  } catch (InterruptedException e) {
                                                      e.printStackTrace();
                                                  }
                                              }
                                          },
                3L, // 3s 後開始執行定時任務
                2L, // 定時任務執行完 2s 之後,再執行下一個定時任務
                TimeUnit.SECONDS); // 描述上面兩個引數的時間單位
    }
}

以上程式的執行結果如下圖所示:

從上述結果可以看出,定時任務在 3s 之後開始執行,以後每隔 4s 執行一次,這 4s 包含了,定時任務執行花費的 2s,加上每隔 2s 執行一次的時間間隔,也就是說 scheduleWithFixedDelay 是在任務執行完 N 秒之後,再執行下一次定時任務

總結

執行緒池執行定時任務的實現方法有 3 個:

  1. 使用 schedule 方法執行定時任務,只執行一次定時任務。
  2. 使用 scheduleAtFixedRate 方法執行定時任務,執行多次定時任務,它的執行時間間隔是固定的,不受定時任務執行時長影響(定時任務時間間隔 > 任務執行時間)。
  3. 使用 scheduleWithFixedDelay 方法執行定時任務,執行多次定時任務,它是在定時任務執行完之後,再隔 N 秒開始執行下一次定時任務,它的執行時間受定時任務執行時長影響。

是非審之於己,譭譽聽之於人,得失安之於數。

公眾號:Java面試真題解析

面試合集:https://gitee.com/mydb/interview