線程池任務執行器配置以及ExecutorService的invallkeAll、submit、execute方法的區別

一、任務調度器配置

task:scheduler/@pool-size:調度線程池的大小,調度線程在被調度任務完成前不會空閒
task:scheduled/@cron:cron表達式,注意,若上次任務未完成,即使到了下一次調度時間,任務也不會重複調度

<task:scheduled-tasks scheduler="scheduler">  
    <task:scheduled ref="beanID" method="methodName" cron="CronExp" />  
</task:scheduled-tasks>  
<task:scheduler id="scheduler" pool-size="1" />  

任務執行器配置
task:executor/@pool-size:可以指定執行線程池的初始大小、最大大小
task:executor/@queue-capacity:等待執行的任務隊列的容量
task:executor/@rejection-policy:當等待隊列爆了時的策略,分爲丟棄、由任務執行器直接運行等方式

<task:executor id="executor" keep-alive="3600" pool-size="100-200" queue-capacity="500" rejection-policy="CALLER_RUNS" /> 

二、線程池的類型及其應用場景

2.1,newFixedThreadPool
創建一個指定工作線程數量的線程池。每當提交一個任務就創建一個工作線程,如果工作線程數量達到線程池初始的最大數,則將提交的任務存入到池隊列中。
2.2,newCachedThreadPool
創建一個可緩存的線程池。這種類型的線程池特點是:
1).工作線程的創建數量幾乎沒有限制(其實也有限制的,數目爲Interger. MAX_VALUE), 這樣可靈活的往線程池中添加線程。
2).如果長時間沒有往線程池中提交任務,即如果工作線程空閒了指定的時間(默認爲1分鐘),則該工作線程將自動終止。終止後,如果你又提交了新的任務,則線程池重新創建一個工作線程。
2.3,newSingleThreadExecutor
創建一個單線程化的Executor,即只創建唯一的工作者線程來執行任務,如果這個線程異常結束,會有另一個取代它,保證順序執行。單工作線程最大的特點是可保證順序地執行各個任務,並且在任意給定的時間不會有多個線程是活動的 。
PS:至始至終都只有一個線程,那用線程池幹嘛呢?直接創建一個新的線程不就可以了嘛,不懂!
2.4,newScheduleThreadPool
創建一個定長的線程池,而且支持定時的以及週期性的任務執行,類似於Timer。
2.5,幾種類型的對比
FixedThreadPool
是一個典型且優秀的線程池,它具有線程池提高程序效率和節省創建線程時所耗的開銷的優點。但是,在線程池空閒時,即線程池中沒有可運行任務時,它不會釋放工作線程,還會佔用一定的系統資源。
CachedThreadPool
特點是在線程池空閒時,即線程池中沒有可運行任務時,它會釋放工作線程,從而釋放工作線程所佔用的資源。但是,但當出現新任務時,又要創建一新的工作線程,又要一定的系統開銷。並且,在使用CachedThreadPool時,一定要注意控制任務的數量,否則,由於大量線程同時運行,很有會造成系統癱瘓。

三、submit()和execute()的區別

JDK5往後,任務分兩類:一類是實現了Runnable接口的類,一類是實現了Callable接口的類。兩者都可以被ExecutorService執行,它們的區別是:
execute(Runnable x) 沒有返回值。可以執行任務,但無法判斷任務是否成功完成。——實現Runnable接口
submit(Runnable x) 返回一個future。可以用這個future來判斷任務是否成功完成。——實現Callable接口

四、線程池.invokeAll,invokeAny的區別:

invokeAll觸發執行任務列表,返回的結果順序也與任務在任務列表中的順序一致.所有線程執行完任務後才返回結果。如果設置了超時時間,未超時完成則正常返回結果,如果超時未完成則報異常。
invokeAny將第一個得到的結果作爲返回值,然後立刻終止所有的線程。如果設置了超時時間,未超時完成則正常返回結果,如果超時未完成則報超時異常。

五、總結!!

1、invallkeAll和invokeAny會直接造成主線程阻塞(需要設置超時時間)。等待所有任務執行完成後返回結果,主線程繼續執行。
2、submit不會造成主線程阻塞,在後面執行get方法的時候阻塞。超時時間在get裏面設置。
3、execute會新開啓線程直接執行任務,不會阻塞主線程。但無返回結果。

六、附測試小方法。

示例如下:

public static void main(String[] args) throws InterruptedException, ExecutionException {
    Callable<Boolean> callable1 = new Callable<Boolean>() {
      @Override
      public Boolean call() throws Exception {
        Thread.sleep(3000);
        return true;
      }
    };
    Callable<Boolean> callable2 = new Callable<Boolean>() {
      @Override
      public Boolean call() throws Exception {
        Thread.sleep(4000);
        return true;
      }
    };
    Callable<Boolean> callable3 = new Callable<Boolean>() {
      @Override
      public Boolean call() throws Exception {
        Thread.sleep(5000);
        return true;
      }
    };
    List<Callable<Boolean>> list1 = new ArrayList<>();
    List<Callable<Boolean>> list2 = new ArrayList<>();
    list1.add(callable1);
    list1.add(callable2);
    list2.add(callable3);
    ExecutorService executor = Executors.newCachedThreadPool();
    // long start = System.currentTimeMillis();
    // List<Future<Boolean>> result1 = executor.invokeAll(list1);
    // System.out.println(System.currentTimeMillis() - start);
    // List<Future<Boolean>> result2 = executor.invokeAll(list2);
    // System.out.println(System.currentTimeMillis() - start);

    // Future<Boolean> f1 = executor.submit(callable1);
    // System.out.println(System.currentTimeMillis() - start);
    // long start1 = System.currentTimeMillis();
    // f1.get();
    // System.out.println(System.currentTimeMillis() - start1);

    long start2 = System.currentTimeMillis();
    Runnable r1 = new Runnable() {

      @Override
      public void run() {
        try {
          Thread.sleep(5000);
          System.out.println("dfasdfsaf");
        } catch (InterruptedException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }
    };
    executor.execute(r1);
    System.out.println(System.currentTimeMillis() - start2);
    executor.shutdown();
    // for (Future<Boolean> ele : result) {
    // long start1 = System.currentTimeMillis();
    // ele.get();
    // System.out.println(System.currentTimeMillis() - start1);
    // }

  }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章