定時任務實現方式對比

1. 定時任務實現方式對比

1.1. Timer

  • 代碼例子以下
public static void main(String[] args) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime localDateTime = LocalDateTime.now();
        String format = localDateTime.format(formatter);
        System.out.println("1:"+format);
        Timer timer = new Timer();
        for (int i = 0; i < 2; i++) {
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("Thread name : "+ Thread.currentThread().getName());
                    LocalDateTime localDateTime = LocalDateTime.now();
                    String format = localDateTime.format(formatter);
                    System.out.println("2:"+format);
                }
            }, 3000);
        }

        localDateTime = LocalDateTime.now();
        format = localDateTime.format(formatter);
        System.out.println("3:"+format);
    }

結果git

1:2019-10-14 17:35:13
3:2019-10-14 17:35:13
Thread name : Timer-0
2:2019-10-14 17:35:19
Thread name : Timer-0
2:2019-10-14 17:35:22
  • 能夠看出同一個Timer的定時任務,後臺就一個線程管理任務分配,遇到任務阻塞,可能致使下一個任務延遲
  • 且若是任務發生異常,系統就終止了

1.2. ScheduledExecutorService

  • 爲了解決Timer的問題,ScheduledExecutorService作了改進,採用了線程池的定時任務隊列,實際使用的也是最小堆排序
  • 代碼以下
private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    public static void main(String[] args) {
//        timerTest();
        print("1:");
        ScheduledExecutorService service = new ScheduledThreadPoolExecutor(2);
        for (int i = 0; i < 2; i++) {
            service.schedule(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("Thread name : " + Thread.currentThread().getName());
                    print("2:");
                }
            }, 3, TimeUnit.SECONDS);
        }
        print("3:");
        service.shutdown();
    }

    private static void print(String s) {
        LocalDateTime localDateTime = LocalDateTime.now();
        String format = localDateTime.format(formatter);
        System.out.println(s + format);
    }

結果github

1:2019-10-15 11:53:54
3:2019-10-15 11:53:54
Thread name : pool-1-thread-1
2:2019-10-15 11:54:00
Thread name : pool-1-thread-2
2:2019-10-15 11:54:00

明白它的延遲原理和Timer同樣,能夠知道若是我把核心線程數改爲1,則效果和Timer相似數組

  • 結果以下,兩個任務延遲3秒,前一個任務會致使後一個任務延遲
1:2019-10-15 11:57:40
3:2019-10-15 11:57:40
Thread name : pool-1-thread-1
2:2019-10-15 11:57:46
Thread name : pool-1-thread-1
2:2019-10-15 11:57:49
  • 它的優點在於能夠多線程執行,必定程度上避免任務間互相影響,同時單個任務異常不影響其它任務

1.3. 時間輪(延遲消息)

1

  • 本質是環形數組,好比上述8個節點的時間輪,每一個節點存聽任務隊列,好比咱們須要新建5s延遲的任務,就放5的節點,新建10s延遲的任務就放2的節點,設延遲時間爲n,則節點位置爲n%8,同時需記下輪詢圈數n/8
  • 優點:當任務數量很是多的時候採用這樣環形數組加隊列是個效率比較高的選擇
  • 想要了解更多時間輪實現,能夠參考文章下的參考博客

1.4. 分佈式定時任務

  • github上也有些開源的分佈式定時任務的方案,能夠直接使用
  • xxl_jobelastic-job-litelight-task-scheduler,以哪一個火用哪一個的原則,那仍是xxl_job的星星最多,另外兩個已經兩年沒更新了

參考博客:
延遲消息之時間輪多線程

相關文章
相關標籤/搜索