一、任務調度器配置:
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);
// }
}