天天看點

多線程學習(2):ScheduledThreadPoolExecutor 與 schedule 之小結

2018年7月9日08:48:58

歡迎掃二維碼關注公衆号,擷取技術幹貨

【1】前言

    線程池與任務定時執行,一是項目随處可見的一種技術,二是自己還需打打紮實基礎;不可以僅僅局限于業務的實作,要去體會底層的思想;

【2】關于線程池ThreadPoor與Timer的使用

2.1    Java提供的Time類可以周期性地或者延期執行任務,但是有時我們需要并行執行同樣的任務,這個時候如果建立多個Time對象會給系統帶來負擔,解決辦法是将定時任務放到線程池中執行。

    Java的ScheduledThreadPoolExecutor類實作了ScheduledExecutorService接口中定義的以不同方法執行任務的方法。

2.2 ScheduleThreadPoolExecutor與Timer相比的優勢

(1)Timer是基于絕對時間的延時執行或周期執行,當系統時間改變,則任務的執行會受到的影響。而ScheduleThreadPoolExecutore中,任務時基于相對時間進行周期或延時操作。

(2)Timer也可以送出多個TimeTask任務,但隻有一個線程來執行所有的TimeTask,這樣并發性受到影響。而ScheduleThreadPoolExecutore可以設定池中線程的數量。

(3)Timer不會捕獲TimerTask的異常,隻是簡單地停止,這樣勢必會影響其他TimeTask的執行。而ScheduleThreadPoolExecutore中,如果一個線程因某些原因停止,線程池可以自動建立新的線程來維護池中線程的數量。

2.3 自jdk1.5開始,Java開始提供ScheduledThreadPoolExecutor類來支援周期性任務的排程,在這之前,這些工作需要依靠Timer/TimerTask或者其它第三方工具來完成。但Timer有着不少缺陷,如Timer是單線程模式,排程多個周期性任務時,如果某個任務耗時較久就會影響其它任務的排程;如果某個任務出現異常而沒有被catch則可能導緻唯一的線程死掉而所有任務都不會再被排程。ScheduledThreadPoolExecutor解決了很多Timer存在的缺陷。JDK1.5之前的Timer和TimerTask類已經過時了。

通過如上的介紹,可以對比一下Timer和ScheduledThreadPoolExecutor:

Timer ScheduledThreadPoolExecutor
單線程 多線程
單個任務執行時間影響其他任務排程 多線程,不會影響
基于絕對時間 基于相對時間
一旦執行任務出現異常不會捕獲,其他任務得不到執行 多線程,單個任務的執行不會影響其他線程

是以,在JDK1.5之後,應該沒什麼理由繼續使用Timer進行任務排程了。

【3】ScheduledThreadPoolExecutor 工作原理

多線程學習(2):ScheduledThreadPoolExecutor 與 schedule 之小結

【4】源碼

多線程學習(2):ScheduledThreadPoolExecutor 與 schedule 之小結

【5】實作例子

BusinessPool.java:

package test2;

import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class BusinessPool {
  
   private ScheduledThreadPoolExecutor executor;
      
      BusinessPool() {
      }
    
    public static class BusinessPoolThreadFactory implements ThreadFactory {
      final ThreadGroup group = Thread.currentThread().getThreadGroup();
          final AtomicInteger threadNumber = new AtomicInteger(1);
          final String namePrefix = "business-pool";
          
          @Override
          public Thread newThread(Runnable r) {
              Thread t = new Thread(group, r,
                                    namePrefix + threadNumber.getAndIncrement(),
                                    0);
              if (t.isDaemon())
                  t.setDaemon(false);
              if (t.getPriority() != Thread.NORM_PRIORITY)
                  t.setPriority(Thread.NORM_PRIORITY);
              return t;
          }
    }
    
      public void init() {
        this.executor = new ScheduledThreadPoolExecutor(1, new BusinessPoolThreadFactory());
      }
   
      
      public void schedule(Runnable runnable, long delay, TimeUnit unit) {
          executor.schedule(runnable, delay, unit);
      }
      
      public void execute(Runnable runnable) {
          executor.execute(runnable);
      }
      
      
}      

test.java:

package test2;

import java.util.concurrent.TimeUnit;

public class test23 {

  public static void main(String[] args) {
    BusinessPool businessPool = new BusinessPool();
    businessPool.init();
    businessPool.schedule(new Runnable() {
      @Override
      public void run() {
        System.out.println("Hello world 0_0|||");
      }
    }, 3, TimeUnit.SECONDS);
  }

}      

輸出結果(延時3s執行線程):

Hello world 0_0|||      

參考博文:https://www.jianshu.com/p/925dba9f5969