Java線程池---基本運(yùn)用到源碼解析

序言

近日后臺(tái)需要一些數(shù)據(jù)囚戚,需要從網(wǎng)上爬取酵熙,但是爬取的過(guò)程中,由于訪問(wèn)速度太頻繁驰坊,造成IP被封匾二,最終通過(guò)線程池解決;想要借此機(jī)會(huì),總結(jié)一下線程池的有關(guān)知識(shí)

線程池框架

ThreadPool_UML.png
  • 從圖中可以看出察藐,Executor提供了整個(gè)線程池的基本實(shí)現(xiàn)皮璧,而Executors則提供了各線程池方法的基本工廠方法;下面我們將從線程池的基本運(yùn)用到源碼解析逐一分析

Executor

  • 一個(gè)接口分飞,也是線程池框架的基礎(chǔ)悴务;方法只有一個(gè)execute(),可以用于自定義繼承實(shí)現(xiàn)任務(wù)的執(zhí)行方式;直接已知子類有:ExecutorService, ScheduledExecutorService
  • 去耦合譬猫,可以將任務(wù)(Runnable實(shí)現(xiàn))與執(zhí)行分離
  • 不嚴(yán)格要求異步惨寿,可以立即執(zhí)行,看自己怎么實(shí)現(xiàn)删窒;如文檔demo
  class DirectExecutor implements Executor {
    public void execute(Runnable r) {
     r.run(); //此時(shí)該任務(wù)是在調(diào)用的線程中執(zhí)行的裂垦,并非異步
   }
 }
  • 更多的還是要求異步執(zhí)行
  class ThreadPerTaskExecutor implements Executor {
     public void execute(Runnable r) {
       new Thread(r).start(); //新開辟條線程執(zhí)行任務(wù)
     }
   }

ExecutorService

  • 一個(gè)接口,繼承了Executor肌索,但是與Executor不同的是蕉拢,它還提供了終止的方法:shutdown()可以使對(duì)象拒絕再接受新的任務(wù),但是以前提交的任務(wù)還是會(huì)繼續(xù)執(zhí)行诚亚;shutdownNow()不僅可以使對(duì)象拒絕接受新的任務(wù)晕换,還嘗試阻止以前已經(jīng)提交的任務(wù)開始執(zhí)行,同時(shí)該方法還會(huì)試圖中斷當(dāng)前正在執(zhí)行的任務(wù)
  • 一個(gè)不再使用的ExecutorService應(yīng)該被關(guān)閉站宗,從而釋放它所占有的資源
  • submit()方法擴(kuò)展了原始的Executorexecute(Runnable)方法,可以返回一個(gè)Future對(duì)象闸准,該Future對(duì)象代表了該等待執(zhí)行的任務(wù),可以通過(guò)該對(duì)象來(lái)取消執(zhí)行或者判斷是否成功執(zhí)行(Futureget()方法可以判斷)

ScheduledExecutorService

  • 繼承自ExecutorService的一個(gè)接口梢灭,實(shí)現(xiàn)類為ScheduledThreadPoolExecutor

  • 可以使任務(wù)定期執(zhí)行或者延遲一段時(shí)間之后執(zhí)行

  • schedule()方法可以創(chuàng)建各種延時(shí)的任務(wù)夷家,同時(shí)返回一個(gè)代表該任務(wù)的對(duì)象()ScheduledFuture用于檢測(cè)任務(wù)執(zhí)行情況和取消執(zhí)行

  • scheduleWithFixedDelay()方法可以創(chuàng)建和執(zhí)行任務(wù),該任務(wù)具有定時(shí)性

  • 當(dāng)任務(wù)通過(guò)Executor.execute(Runnable)或者ExecutorServicesubmit()方法提交時(shí)敏释,默認(rèn)的延時(shí)是0库快;零延時(shí)和負(fù)延時(shí)都被當(dāng)做立即執(zhí)行對(duì)待

  • 所有的定時(shí)方法都支持相對(duì)延時(shí)或者時(shí)間段作為參數(shù),而不是絕對(duì)時(shí)間或者日期钥顽,示例:

    schedule(task, date.getTime() - System.currentTimeMillis(), TimeUnit.MILLISECONDS)

  • 官方示例代碼:即創(chuàng)建一個(gè)任務(wù)每10s執(zhí)行一次义屏,執(zhí)行1h后取消

    import static java.util.concurrent.TimeUnit.*;
    class BeeperControl {
        private final ScheduledExecutorService scheduler =
          Executors.newScheduledThreadPool(1);
    
        public void beepForAnHour() {
           Runnable beeper = () -> System.out.println("beep");
            ScheduledFuture<?> beeperHandle =
            scheduler.scheduleAtFixedRate(beeper, 10, 10, SECONDS);
          Runnable canceller = () -> beeperHandle.cancel(true);
          scheduler.schedule(canceller, 1, HOURS);
        }
    }
    

Future

  • 一個(gè)泛型接口,用于表示一個(gè)異步執(zhí)行的結(jié)果蜂大,可以通過(guò)該對(duì)象來(lái)判斷異步是否執(zhí)行完成(isDone())闽铐;同時(shí)也可以通過(guò)該對(duì)象來(lái)取回異步執(zhí)行的返回結(jié)果(只能通過(guò)get()方法取回,需要判斷異步是否完成奶浦,get()方法將會(huì)阻塞直到任務(wù)完成)兄墅;也可以通過(guò)cancel()方法來(lái)取消該任務(wù)的執(zhí)行

Callable<V>

  • 泛型接口,V表示最終異步執(zhí)行結(jié)果的返回類型
  • Runnable的區(qū)別是:Callable可以返回結(jié)果财喳,同時(shí)Callable還可以拋出一個(gè)可檢查的異常(當(dāng)無(wú)法正常返回結(jié)果時(shí))察迟,但是Runnable不行

Executors

  • 直接繼承自Object斩狱,擁有許多工廠方法以支持Executor, ExecutorService,ScheduledExecutorService,ThreadFactory,和Callable對(duì)象

對(duì) ExecutorService 的支持

newCachedThreadPool()

  • 使用newCachedThreadPool()的靜態(tài)方法返回一個(gè)新創(chuàng)建的線程池對(duì)象;此方法會(huì)創(chuàng)建一個(gè)線程池扎瓶,同時(shí)該線程池中的線程會(huì)被重用(如果空閑可用的話)所踊,如果沒(méi)有可用的線程,會(huì)新建一個(gè)線程并添加到該線程池中;該方法適用于需要執(zhí)行許多耗時(shí)短暫的任務(wù)集(使線程得到最大程度上的復(fù)用概荷,提高程序性能)
  • 注意該線程池中的線程如果在60s內(nèi)沒(méi)有被重用的話秕岛,將被回收,同時(shí)移除出該線程池误证;所以不用擔(dān)心因?yàn)榫€程池空閑而造成對(duì)系統(tǒng)資源的消耗
  • 實(shí)際上是返回一個(gè)ThreadPoolExecutor對(duì)象继薛,而ThreadPoolExecutor繼承于ExecutorService(源代碼見下);實(shí)際使用的構(gòu)造函數(shù)是public ThreadPoolExecutor?(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue)愈捅,表示的是創(chuàng)建一個(gè)無(wú)界線程池(即線程池中線程數(shù)量沒(méi)有固定)遏考;注意設(shè)置的60L對(duì)應(yīng)的是long keepAliveTime參數(shù),表示的是如果線程池中空閑線程數(shù)量大于corePoolSize的話蓝谨,在keepAliveTime時(shí)間內(nèi)沒(méi)有該線程沒(méi)有重用灌具,那么會(huì)自動(dòng)回收該線程,同時(shí)這里將corePoolSize設(shè)置為0譬巫,那么在任務(wù)執(zhí)行完成之后所有線程將會(huì)自動(dòng)回收咖楣;至于BlockingQueue<Runnable> workQueue)參數(shù),只是一個(gè)用于維持由execute()方法提交的任務(wù)隊(duì)列
   public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
  • 示例代碼如下芦昔;下列代碼的輸出如下诱贿;根據(jù)輸出可以看出,其實(shí)線程池中并沒(méi)有創(chuàng)建10條線程咕缎,正真的最大活躍線程數(shù)量只有7條珠十,同時(shí)也并不是按照我們預(yù)期的那樣,任務(wù)的執(zhí)行是分配到特定線程的锨阿,而是當(dāng)thread-1執(zhí)行完其本身的任務(wù)后宵睦,線程池中有空閑線程(thread-1),所以此時(shí)并沒(méi)有使用其他線程去執(zhí)行任務(wù)墅诡,而是復(fù)用了thread-1

//示例輸出
index...0--Thread info Thread[pool-1-thread-1,5,main]--Thread activeCount 4
index...2--Thread info Thread[pool-1-thread-1,5,main]--Thread activeCount 5
index...1--Thread info Thread[pool-1-thread-2,5,main]--Thread activeCount 5
index...5--Thread info Thread[pool-1-thread-1,5,main]--Thread activeCount 6
index...4--Thread info Thread[pool-1-thread-2,5,main]--Thread activeCount 6
index...8--Thread info Thread[pool-1-thread-1,5,main]--Thread activeCount 7
index...6--Thread info Thread[pool-1-thread-4,5,main]--Thread activeCount 7
index...9--Thread info Thread[pool-1-thread-5,5,main]--Thread activeCount 7
index...3--Thread info Thread[pool-1-thread-3,5,main]--Thread activeCount 7
index...7--Thread info Thread[pool-1-thread-2,5,main]--Thread activeCount 7

  //示例代碼桐智,同時(shí)注意調(diào)用`shutdownNow()`方法后
      public class demo {
          public static void main(String[] args) throws   ExecutionException,         InterruptedException {
              ExecutorService service  =Executors.newCachedThreadPool();
              for(int i=0;i<10;i++){
                  service.execute(new CallDemo(i));
              }
          }
      }

  public class CallDemo implements Runnable {
      private final int index;

      public CallDemo(int index) {
          this.index = index;
      }

      @Override
      public void run() {
          System.out.println("index..."+index+
                "--Thread info "+ Thread.currentThread()+"--Thread         activeCount "+Thread.activeCount());


      }
  }
  • (如上代碼)另外還需要注意的是末早,當(dāng)所有任務(wù)都執(zhí)行完了以后,線程池并不是馬上停止的说庭,而是此時(shí)所有的線程處于空閑狀態(tài)然磷,會(huì)如上所說(shuō)的等待60s之后再自動(dòng)回收停止(如果想要任務(wù)執(zhí)行完成之后馬上停止,可以調(diào)用shutdownNow()或者shutdown()方法)

  • 另外說(shuō)一下Thread[pool-1-thread-1,5,main]代表的意思(由Thread.currentThread()輸出刊驴,實(shí)際上currentThread()方法返回的是一個(gè)Thread對(duì)象姿搜,只不過(guò)在println()函數(shù)中會(huì)默認(rèn)調(diào)用toString()方法寡润,所以應(yīng)該看ThreadtoString()方法,如下)舅柜,對(duì)應(yīng)下面的代碼應(yīng)該可以很清楚各位置輸出代表的意思了

    public String toString() {
          ThreadGroup group = getThreadGroup();
          if (group != null) {
              return "Thread[" + getName() + "," + getPriority() + "," +
                             group.getName() + "]";
          } else {
              return "Thread[" + getName() + "," + getPriority() + "," +
                              "" + "]";
          }
      }
    
  • 至于在代碼中使用service.execute(new CallDemo(i));與使用service.submit(new CallDemo(i));的區(qū)別梭纹,需要注意的是ThreadPoolExecutor類并沒(méi)有重寫submit()方法,所以應(yīng)該在其父類AbstractExecutorService中找致份,如下:
    可見变抽,其實(shí)submit()中也是調(diào)用了execute()方法,只是還可以通過(guò)Future來(lái)取得返回值或者檢測(cè)任務(wù)執(zhí)行情況(具體見上Future說(shuō)明)

    public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
       //null這里可以看出當(dāng)沒(méi)有返回值時(shí)會(huì)默認(rèn)返回null
        RunnableFuture<Void> ftask = newTaskFor(task, null);
        execute(ftask);
        return ftask;
    }
    
    public <T> Future<T> submit(Runnable task, T result) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task, result);
        execute(ftask);
        return ftask;
    }
    
    public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }
    

newCachedThreadPool(ThreadFactory threadFactory)

  • 參數(shù)ThreadFactory對(duì)象用于創(chuàng)建新線程氮块;該方法可以根據(jù)需要?jiǎng)?chuàng)建線程绍载,所謂的根據(jù)需要是指可以通過(guò)ThreadFactory創(chuàng)建所需要的線程;至于ThreadFactory可以使程序能夠使用其他的線程子類和屬性等滔蝉,而不僅局限與new Thread()击儡,示例:

     class SimpleThreadFactory implements ThreadFactory {
      public Thread newThread(Runnable r) {
          //在這里也可以對(duì)該線程做一些共同的初始化工作
          return new Thread(r);
        }
      }
    
  • 該線程池中的線程也會(huì)被復(fù)用

  • 適用于對(duì)線程有特殊初始條件需求或者特殊屬性需求時(shí)

newFixedThreadPool?(int nThreads)

  • 會(huì)創(chuàng)建一個(gè)具有nThread條的線程池,如果待處理事件多余nThread蝠引,同時(shí)工作的線程任然只有nThread條曙痘,剩余的事件將會(huì)等待線程空閑

  • 如果線程池中的線程因?yàn)槭录惓6K止,同時(shí)還有待處理事件立肘,那么會(huì)重新創(chuàng)建一條線程(也就是說(shuō)保持線程池中的線程數(shù)量為nThread)

  • 該線程池中線程需要明確的調(diào)用shutdown()來(lái)終止

  • 還有一個(gè)newFixedThreadPool?(int nThreads, ThreadFactory threadFactory)边坤,其中ThreadFactory的使用同newCachedThreadPool

  • 這個(gè)返回的任然是一個(gè)ThreadPoolExecutor對(duì)象,調(diào)用構(gòu)造函數(shù)為ThreadPoolExecutor?(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)谅年,這里將corePoolSize設(shè)置為了傳入的線程數(shù)量茧痒,keepAliveTime參數(shù)相當(dāng)于沒(méi)有起到限定作用(需要注意的是keepAliveTime參數(shù)只有在線程池中線程數(shù)量大于corePoolSize的時(shí)候才會(huì)起限定作用,但是這里不存在線程數(shù)量超過(guò)corePoolSize的情況融蹂,所以相當(dāng)于沒(méi)有用)旺订,所以使用該方法的時(shí)候需要我們顯示的調(diào)用shutdown()shutdownNow()方法來(lái)回收系統(tǒng)資源(但是需要注意的是如果調(diào)用shutdownNow()方法的話,有可能會(huì)導(dǎo)致任務(wù)沒(méi)有執(zhí)行完超燃,因?yàn)?code>shutdownNow()會(huì)試圖終止正在執(zhí)行的線程区拳,但是shutdown()是會(huì)等待當(dāng)前任務(wù)完成的)

    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
     }
    

newSingleThreadExecutor?()

  • 線程池中只有一條線程,如果該線程因?yàn)槭录惓6K止意乓,而事件隊(duì)列中還有待處理事件樱调,那么會(huì)重新創(chuàng)建一條線程

  • 可以保證事件順序按照提交順序執(zhí)行

  • 同樣可以根據(jù)需要,使用newSingleThreadExecutor?(ThreadFactory threadFactory)來(lái)創(chuàng)建特定的線程

  • 至于其與newFixedThreadPool(1)的區(qū)別届良,參見下面代碼

    ExecutorService executors = Executors.newFixedThreadPool(1);
    System.out.println(((ThreadPoolExecutor)     executors).getCorePoolSize());//1
    ThreadPoolExecutor executor = (ThreadPoolExecutor) executors;
    executor.setCorePoolSize(4);
    System.out.println(executor.getCorePoolSize() + "..." +     ((ThreadPoolExecutor) executors).getCorePoolSize());//4...4
    executors.shutdownNow();
    

通過(guò)上面代碼笆凌,可見,newFixedThreadPool(1)線程池中線程的數(shù)量是可以調(diào)整的士葫,但是對(duì)于newSingleThreadExecutor?()線程池中線程的數(shù)量是不可調(diào)整的乞而,如下:

  ExecutorService single = Executors.newSingleThreadExecutor();
  ThreadPoolExecutor singles = (ThreadPoolExecutor) single;
  singles.setCorePoolSize(4);
  System.out.println(((ThreadPoolExecutor) single).getCorePoolSize());

這樣將會(huì)報(bào)類型轉(zhuǎn)換錯(cuò)誤:

  java.util.concurrent.Executors$FinalizableDelegatedExecutorService     cannot be cast to java.util.concurrent.ThreadPoolExecutor
  • 實(shí)際上該函數(shù)返回的是一個(gè)FinalizableDelegatedExecutorService對(duì)象,源碼見下慢显;其中FinalizableDelegatedExecutorServiceExecutors類中的一個(gè)靜態(tài)包裝類爪模,使用了默認(rèn)訪問(wèn)權(quán)限欠啤,只能同包中類才能訪問(wèn)

    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
    
  • 這里雖然使用了構(gòu)造函數(shù)ThreadPoolExecutor?(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue),但是實(shí)際上是不需要顯示調(diào)用shutdown()來(lái)顯示回收系統(tǒng)資源的屋灌,因?yàn)樵诎b類FinalizableDelegatedExecutorService中洁段,重寫了Object類的finalize()方法,在其中已經(jīng)調(diào)用了shutdown()声滥,而finalize()方法是在垃圾回收時(shí)系統(tǒng)自動(dòng)調(diào)用的眉撵。其實(shí)現(xiàn)如下(但是經(jīng)過(guò)實(shí)驗(yàn),垃圾回收這種情況是不定的(可能涉及到垃圾回收的相關(guān)知識(shí))落塑,所以筆者建議還是在不需要時(shí)顯示調(diào)用shutdown()要好一些)

    static class FinalizableDelegatedExecutorService extends     DelegatedExecutorService {
        FinalizableDelegatedExecutorService(ExecutorService executor) {
            super(executor);
        }
        protected void finalize() {
            super.shutdown(); //這里已經(jīng)自動(dòng)調(diào)用了shutdown纽疟,在垃圾回收的時(shí)        候會(huì)自動(dòng)釋放系統(tǒng)資源   
        }
    }
    

newWorkStealingPool?() 與 newWorkStealingPool(int)

  • 核心為work-stealing,意為工作竊取,意為當(dāng)一個(gè)線程完成自己的任務(wù)后憾赁,去其他的線程隊(duì)列中竊取任務(wù)執(zhí)行(即將一個(gè)大任務(wù)分解為數(shù)個(gè)小任務(wù)污朽,為了減小線程執(zhí)行任務(wù)時(shí)造成的競(jìng)爭(zhēng)(同步鎖等),將這些小任務(wù)放在不同的雙端隊(duì)列中龙考,當(dāng)一個(gè)線程執(zhí)行完任務(wù)后去其他隊(duì)列末端(這也是設(shè)計(jì)成雙端隊(duì)列的原因)取任務(wù)來(lái)執(zhí)行)蟆肆,任務(wù)結(jié)果放在另一個(gè)獨(dú)立隊(duì)列中。

  • 使用線程池作為執(zhí)行任務(wù)線程的管理者晦款,來(lái)實(shí)現(xiàn)fork/join模式的任務(wù)執(zhí)行策略炎功,所謂[圖片上傳失敗...(image-d9e8ea-1517904101171)],就是一種利用一臺(tái)計(jì)算機(jī)上的多個(gè)處理器進(jìn)行同類型問(wèn)題并行計(jì)算的模式缓溅,通過(guò)對(duì)大規(guī)模問(wèn)題逐步分解蛇损,直到可以作為獨(dú)立的小任務(wù)在單獨(dú)的線程中執(zhí)行,結(jié)合線程間的通信機(jī)制實(shí)現(xiàn)相當(dāng)于遞歸迭代的并行版本坛怪,這和現(xiàn)在流行的Map/Reduce模式有些類似淤齐,只不過(guò)Map/Reduce是在多臺(tái)計(jì)算機(jī)上執(zhí)行的。---[圖片上傳失敗...(image-52f120-1517904101172)]

  • 可通過(guò)Runtime類的availableProcessors方法得到虛擬機(jī)的可用處理器數(shù)量

    Runtime run = Runtime.getRuntime();
    System.out.println(run.availableProcessors());
    
  • 無(wú)法保證執(zhí)行順序

unconfigurableExecutorService(ExecutorService executor)

  • 主要用于包裝線程池袜匿,包裝后的線程池不能被修改(屬性等)更啄,相當(dāng)于final,實(shí)際上最終代碼里面是將傳入的executor賦值給了一個(gè)private final ExecutorService e成員變量,從而保證線程池屬性等不可變

對(duì) ThreadFactory 的支持

  • ThreadFactory顧名思義是一個(gè)用于創(chuàng)建線程的線程工廠方法居灯,可以根據(jù)需要?jiǎng)?chuàng)建線程

defaultThreadFactory()

  • 使用默認(rèn)線程工廠創(chuàng)建線程祭务,這些線程都屬于同一線程組,并且都是非守護(hù)線程

對(duì) ScheduledExecutorService 的支持

newScheduledThreadPool?(int corePoolSize)和

newScheduledThreadPool?(int corePoolSize,ThreadFactory threadFactory)

  • 創(chuàng)建指定數(shù)量線程的線程池穆壕,能夠延時(shí)或者定期執(zhí)行任務(wù)

  • 本質(zhì)上該方法返回的是一個(gè)ScheduledThreadPoolExecutor對(duì)象待牵,而ScheduledThreadPoolExecutor對(duì)象調(diào)用的又是其父類ThreadPoolExecutor的構(gòu)造方法(如下),通過(guò)其傳入的參數(shù)可知喇勋,實(shí)際上我們最終得到的是一個(gè)具有corePoolSize大小的ThreadPoolExecutor線程池

     //構(gòu)造函數(shù)
    public static ScheduledExecutorService     newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }
    
    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }
    
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit,     workQueue,
              Executors.defaultThreadFactory(), defaultHandler);
    }
    
  • 這里ScheduledThreadPoolExecutorThreadPoolExecutor的增加了定時(shí)執(zhí)行任務(wù)的功能,即核心scheduleWithFixedDelay(),scheduleAtFixedRate()方法偎行,同樣可以通過(guò)其返回的ScheduledFuture對(duì)象來(lái)對(duì)任務(wù)進(jìn)行判斷是否完成和嘗試取消任務(wù),簡(jiǎn)單使用如下(CallDemo為自定義實(shí)現(xiàn)了Runnable的類):

      ScheduledExecutorService service =     Executors.newScheduledThreadPool(5);
      service.scheduleWithFixedDelay(new       CallDemo(1),5000l,1000l,TimeUnit.MILLISECONDS);
      service.scheduleAtFixedRate(new     CallDemo(2),5000l,1000l,TimeUnit.MILLISECONDS);
    
  • 需要注意的時(shí)該任務(wù)會(huì)一直執(zhí)行下去川背,除非發(fā)生一下情況:1. 明確的通過(guò)其返回值ScheduledFuture來(lái)取消或者終止贰拿;2. 執(zhí)行的任務(wù)產(chǎn)生異常;其中對(duì)于第二種情況熄云,使用ScheduledFutureisDone()會(huì)得到true膨更,而且使用get()會(huì)跑出ExecutionException異常

  • 至于scheduleWithFixedDelay()scheduleAtFixedRate()的區(qū)別,前者的延時(shí)是對(duì)前一段任務(wù)結(jié)束開始計(jì)算缴允,后者的延時(shí)是前一段任務(wù)開始就開始計(jì)算了荚守,特別時(shí)當(dāng)任務(wù)比較耗時(shí),超過(guò)了設(shè)定的延時(shí)時(shí)练般,前者任然會(huì)保持該延時(shí)執(zhí)行矗漾,但是后者會(huì)等待前一段任務(wù)完成之后立即執(zhí)行,但是不會(huì)同時(shí)執(zhí)行

newSingleThreadScheduledExecutor?() 和

newSingleThreadScheduledExecutor?(ThreadFactory threadFactory)

  • 創(chuàng)建一個(gè)單一線程的線程池延時(shí)或者定期執(zhí)行任務(wù)
  • 同樣當(dāng)該線程因?yàn)槭录惓6K止時(shí)薄料,在shutdown()之前會(huì)再創(chuàng)建一個(gè)線程來(lái)代替
  • newScheduledThreadPool(1)的區(qū)別同樣也是通過(guò)newSingleThreadScheduledExecutor?()創(chuàng)建出來(lái)的線程池不允許增加新線程和其他屬性

unconfigurableScheduledExecutorService?(ScheduledExecutorService executor)

  • 同樣用于包裝線程池敞贡,相當(dāng)與final

對(duì) Callable 的支持

Callable<Object> callable?(Runnable task)

  • 執(zhí)行任務(wù),同時(shí)返回null

<T> Callable<T> callable?(Runnable task,T result)

  • 執(zhí)行指定返回結(jié)果result摄职,這在需要調(diào)用Callable但是結(jié)果無(wú)返回值時(shí)的會(huì)很有用

Callable<Object> callable?(PrivilegedAction<?> action)

參考博客

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末誊役,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子谷市,更是在濱河造成了極大的恐慌蛔垢,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,843評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件迫悠,死亡現(xiàn)場(chǎng)離奇詭異鹏漆,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)及皂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,538評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門甫男,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人验烧,你說(shuō)我怎么就攤上這事板驳。” “怎么了碍拆?”我有些...
    開封第一講書人閱讀 163,187評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵若治,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我感混,道長(zhǎng)端幼,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,264評(píng)論 1 292
  • 正文 為了忘掉前任弧满,我火速辦了婚禮婆跑,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘庭呜。我一直安慰自己滑进,他們只是感情好犀忱,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,289評(píng)論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著扶关,像睡著了一般阴汇。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上节槐,一...
    開封第一講書人閱讀 51,231評(píng)論 1 299
  • 那天搀庶,我揣著相機(jī)與錄音,去河邊找鬼铜异。 笑死哥倔,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的熙掺。 我是一名探鬼主播未斑,決...
    沈念sama閱讀 40,116評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼币绩!你這毒婦竟也來(lái)了蜡秽?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,945評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤缆镣,失蹤者是張志新(化名)和其女友劉穎芽突,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體董瞻,經(jīng)...
    沈念sama閱讀 45,367評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡寞蚌,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,581評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了钠糊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片挟秤。...
    茶點(diǎn)故事閱讀 39,754評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖抄伍,靈堂內(nèi)的尸體忽然破棺而出艘刚,到底是詐尸還是另有隱情,我是刑警寧澤截珍,帶...
    沈念sama閱讀 35,458評(píng)論 5 344
  • 正文 年R本政府宣布攀甚,位于F島的核電站,受9級(jí)特大地震影響岗喉,放射性物質(zhì)發(fā)生泄漏秋度。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,068評(píng)論 3 327
  • 文/蒙蒙 一钱床、第九天 我趴在偏房一處隱蔽的房頂上張望荚斯。 院中可真熱鬧,春花似錦、人聲如沸鲸拥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,692評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)刑赶。三九已至,卻和暖如春懂衩,著一層夾襖步出監(jiān)牢的瞬間撞叨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,842評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工浊洞, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留牵敷,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,797評(píng)論 2 369
  • 正文 我出身青樓法希,卻偏偏與公主長(zhǎng)得像枷餐,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子苫亦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,654評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 原文出處http://cmsblogs.com/ 『chenssy』 作為Executor框架中最核心的類毛肋,Thr...
    踩在浪花上看浪閱讀 1,227評(píng)論 0 4
  • 原文連接 在前面的文章中,我們使用線程的時(shí)候就去創(chuàng)建一個(gè)線程屋剑,這樣實(shí)現(xiàn)起來(lái)非常簡(jiǎn)便润匙,但是就會(huì)有一個(gè)問(wèn)題: 如果并發(fā)...
    zjk_00閱讀 635評(píng)論 0 1
  • 從來(lái)沒(méi)有無(wú)緣無(wú)故的愛(ài),也沒(méi)有無(wú)緣無(wú)故的恨唉匾。 我愛(ài)上你的哪一天孕讳,是源于你的漂亮的外表。你透靈的眼睛穿過(guò)鏡片巍膘,向上望去...
    別哭有我閱讀 244評(píng)論 0 1
  • 介紹 許多應(yīng)用需要處理及時(shí)收到的數(shù)據(jù)厂财,Spark Streaming是Spark為這些應(yīng)用而設(shè)計(jì)的模型。它允許用戶...
    raincoffee閱讀 286評(píng)論 0 0
  • 1峡懈,話別太多璃饱,低調(diào)往往是最高調(diào)的炫耀。 2逮诲,只有靠自己才最靠得住帜平。 3,即便就連你自己都在否定自己的時(shí)候梅鹦,也不要輕...
    泛泛的小生活閱讀 168評(píng)論 0 0