インタビューアサルト34:スレッドプールを使用して時限タスクを実行する方法は?

Java言語では、時限タスクを実行できる2つのスレッドプールがあります。ScheduledThreadPoolとSingleThreadScheduledExecutorで、SingleThreadScheduledExecutorはScheduledThreadPoolのシングルスレッドバージョンと見なすことができ、その使用法はScheduledThreadPoolと同じです。 ScheduledThreadPoolスレッドプールの使用。ScheduledThreadPoolが時限タスクを実行するための3つのメソッドがあります。

  1. スケジュールされたタスクを実行するには、scheduleメソッドを使用し、スケジュールされたタスクは1回だけ実行します。
  2. scheduleAtFixedRateメソッドを使用して、時限タスクを実行し、複数の時限タスクを実行します。
  3. scheduleWithFixedDelayメソッドを使用して、時限タスクを実行し、複数の時限タスクを実行します。

次に、これら3つの方法の具体的な使用法と違いを見ていきます。

1.スケジュール

スケジュールメソッドは、スケジュールされたタスクを1回だけ実行でき、次の3つのパラメーターを渡す必要があります。

  • 最初のパラメーター:タスク、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());
    }
}
复制代码

上記のプログラムの実行結果を次の図に示します。image.png上記の結果から、スケジュールされたタスクは、scheduleメソッドを使用して1回しか実行できないことがわかります。

2.scheduleAtFixedRate

scheduleAtFixedRateメソッドは、複数のスケジュールされたタスクを実行できます。このメソッドには、次の4つのパラメーターが必要です。

  • 最初のパラメーター:タスク、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); // 描述上面两个参数的时间单位
    }
}
复制代码

以上程序的执行结果如下图所示: image.png 从上述结果可以看出,当任务添加成功之后,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); // 描述上面两个参数的时间单位
    }
}
复制代码

以上程序的执行结果如下图所示: image.png 从上述结果可以看出,定时任务在 3s 之后开始执行,以后每隔 4s 执行一次,这 4s 包含了,定时任务执行花费的 2s,加上每隔 2s 执行一次的时间间隔,也就是说 scheduleWithFixedDelay 是在任务执行完 N 秒之后,再执行下一次定时任务

总结

线程池执行定时任务的实现方法有 3 个:

  1. 使用 schedule 方法执行定时任务,只执行一次定时任务。
  2. 使用 scheduleAtFixedRate 方法执行定时任务,执行多次定时任务,它的执行时间间隔是固定的,不受定时任务执行时长影响(定时任务时间间隔 > 任务执行时间)。
  3. 使用 scheduleWithFixedDelay 方法执行定时任务,执行多次定时任务,它是在定时任务执行完之后,再隔 N 秒开始执行下一次定时任务,它的执行时间受定时任务执行时长影响。

是非审之于己,毁誉听之于人,得失安之于数。

公众号:Java面试真题解析

面试合集:gitee.com/mydb/interv…

おすすめ

転載: juejin.im/post/7079976022199762957