[高い同時実行性]問題を起こさないでください、ScheduledThreadPoolExecutorとTimerの違いを理解していませんか?

みなさん、こんにちは。氷河です~~

JDK 1.5は、ScheduledThreadPoolExecutorクラスの提供を開始しました。ScheduledThreadPoolExecutorクラスは、ThreadPoolExecutorクラスを継承し、スレッドプールを再利用してタスクの定期的なスケジューリング機能を実装します。JDK 1.5より前は、TimerクラスとTimerTaskクラスは、主にタスクの定期的なスケジューリングを実装するために使用されていました。この記事では、ScheduledThreadPoolExecutorクラスとTimerクラスの違い、Timerクラスと比較したScheduledThreadPoolExecutorクラスの利点、および2つがそれぞれタスクスケジューリングを実装する方法の簡単な例を簡単に紹介します。

2つの違い

ねじ山角度

  • タイマーはシングルスレッドモードです。TimerTaskタスクの実行時間が比較的長い場合、他のタスクの実行のスケジューリングに影響します。
  • ScheduledThreadPoolExecutorはマルチスレッドモードであり、スレッドプールを再利用します。ScheduledFutureTaskタスクの実行には時間がかかり、他のタスクのスケジュール実行には影響しません。

システム時間感度

  • タイマーのスケジュールは、オペレーティングシステムの絶対時間に基づいており、オペレーティングシステムの時間に影響されます。オペレーティングシステムの時間が変更されると、タイマーのスケジュールは正確ではなくなります。
  • ScheduledThreadPoolExecutorのスケジューリングは相対時間に基づいており、オペレーティングシステム時間の変更による影響を受けません。

例外をキャッチするかどうか

  • Timerは、TimerTaskによってスローされた例外をキャッチしません。さらに、Timerはシングルスレッドです。スケジュールされたタスクで例外が発生すると、スレッド全体が終了し、スケジュールが必要な他のタスクは実行されなくなります。
  • ScheduledThreadPoolExecutorは、スレッドプールに基づいてスケジューリング機能を実装します。タスクが例外をスローした後も、他の​​タスクを正常に実行できます。

タスクが優先されるかどうか

  • タイマーで実行されるTimerTaskタスクは、全体として優先順位の概念がなく、システムの絶対時間に従ってタスクを実行するだけです。
  • ScheduledThreadPoolExecutor中执行的ScheduledFutureTask类实现了java.lang.Comparable接口和java.util.concurrent.Delayed接口,这也就说明了ScheduledFutureTask类中实现了两个非常重要的方法,一个是java.lang.Comparable接口的compareTo方法,一个是java.util.concurrent.Delayed接口的getDelay方法。在ScheduledFutureTask类中compareTo方法方法实现了任务的比较,距离下次执行的时间间隔短的任务会排在前面,也就是说,距离下次执行的时间间隔短的任务的优先级比较高。而getDelay方法则能够返回距离下次任务执行的时间间隔。

是否支持对任务排序

  • Timer不支持对任务的排序。
  • ScheduledThreadPoolExecutor类中定义了一个静态内部类DelayedWorkQueue,DelayedWorkQueue类本质上是一个有序队列,为需要调度的每个任务按照距离下次执行时间间隔的大小来排序

能否获取返回的结果

  • Timer中执行的TimerTask类只是实现了java.lang.Runnable接口,无法从TimerTask中获取返回的结果。
  • ScheduledThreadPoolExecutor中执行的ScheduledFutureTask类继承了FutureTask类,能够通过Future来获取返回的结果。

通过以上对ScheduledThreadPoolExecutor类和Timer类的分析对比,相信在JDK 1.5之后,就没有使用Timer来实现定时任务调度的必要了。

二者简单的示例

这里,给出使用Timer和ScheduledThreadPoolExecutor实现定时调度的简单示例,为了简便,我这里就直接使用匿名内部类的形式来提交任务。

Timer类简单示例

源代码示例如下所示。

package io.binghe.concurrent.lab09;

import java.util.Timer;
import java.util.TimerTask;

/**
 * @author binghe
 * @version 1.0.0
 * @description 测试Timer
 */
public class TimerTest {

    public static void main(String[] args) throws InterruptedException {
        Timer timer = new Timer();
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                System.out.println("测试Timer类");
            }
        }, 1000, 1000);
        Thread.sleep(10000);
        timer.cancel();
    }
}

运行结果如下所示。

测试Timer类
测试Timer类
测试Timer类
测试Timer类
测试Timer类
测试Timer类
测试Timer类
测试Timer类
测试Timer类
测试Timer类

ScheduledThreadPoolExecutor类简单示例

源代码示例如下所示。

package io.binghe.concurrent.lab09;

import java.util.concurrent.*;

/**
 * @author binghe
 * @version 1.0.0
 * @description 测试ScheduledThreadPoolExecutor
 */
public class ScheduledThreadPoolExecutorTest {
    public static void main(String[] args) throws  InterruptedException {
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
        scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println("测试测试ScheduledThreadPoolExecutor");
            }
        }, 1, 1, TimeUnit.SECONDS);

        //主线程休眠10秒
        Thread.sleep(10000);

        System.out.println("正在关闭线程池...");
        // 关闭线程池
        scheduledExecutorService.shutdown();
        boolean isClosed;
        // 等待线程池终止
        do {
            isClosed = scheduledExecutorService.awaitTermination(1, TimeUnit.DAYS);
            System.out.println("正在等待线程池中的任务执行完成");
        } while(!isClosed);

        System.out.println("所有线程执行结束,线程池关闭");
    }
}

运行结果如下所示。

测试测试ScheduledThreadPoolExecutor
测试测试ScheduledThreadPoolExecutor
测试测试ScheduledThreadPoolExecutor
测试测试ScheduledThreadPoolExecutor
测试测试ScheduledThreadPoolExecutor
测试测试ScheduledThreadPoolExecutor
测试测试ScheduledThreadPoolExecutor
测试测试ScheduledThreadPoolExecutor
测试测试ScheduledThreadPoolExecutor
正在关闭线程池...
测试测试ScheduledThreadPoolExecutor
正在等待线程池中的任务执行完成
所有线程执行结束,线程池关闭

注意:关于Timer和ScheduledThreadPoolExecutor还有其他的使用方法,这里,我就简单列出以上两个使用示例,更多的使用方法大家可以自行实现。

好了,今天就到这儿吧,我是冰河,我们下期见~~

我正在参与掘金技术社区创作者签约计划招募活动,点击链接报名投稿

おすすめ

転載: juejin.im/post/7122305721768607775