- 論壇徽章:
- 0
|
java并發(fā)編程--線程池初步
[coolxing按: 轉(zhuǎn)載請注明作者和出處, 如有謬誤, 歡迎在評論中指正.]
服務器應用程序經(jīng)常需要處理執(zhí)行時間很短而數(shù)目巨大的請求, 如果為每一個請求創(chuàng)建一個新的線程, 會導致一些問題的出現(xiàn), 如:
1. 性能瓶頸. 線程的創(chuàng)建和銷毀需要執(zhí)行大量的后臺操作, 如果單個請求的執(zhí)行時間很短, 有可能花在創(chuàng)建和銷毀線程上的時間大于真正執(zhí)行請求的時間.
2. 可能會導致資源不足. 大量的并發(fā)請求意味著需要創(chuàng)建大量的線程, 過多的線程存在會吞噬大量的系統(tǒng)資源, 而且CPU需要在這些線程間不斷切換, 這可能引發(fā)"切換過度"的問題.
為了適應上述場合, java在JDK1.5中引入了線程池的概念. 線程池中存放著一定數(shù)量的已創(chuàng)建好的線程, 當一個請求到來時, 只需從線程池中取出一個線程來執(zhí)行請求, 請求完成后再將線程歸還給線程池. 同時, 我們可以為線程池指定最大的線程數(shù)量, 當池中所有線程都處于活動狀態(tài)下, 新的任務會排隊等候, 直到之前的某個任務處理完成后, 新的任務才能得到處理.
創(chuàng)建線程池. java.util.concurrent.Executors類提供了多個靜態(tài)方法用于創(chuàng)建線程池.
|--public static ExecutorService newFixedThreadPool(int nThreads): 創(chuàng)建一個可重用的固定線程數(shù)的線程池. 如果池中所有的nThreads個線程都處于活動狀態(tài)時提交任務(任務通常是Runnable或Callable對象), 任務將在隊列中等待, 直到池中出現(xiàn)可用線程.
|--public static ExecutorService newCachedThreadPool(): 調(diào)用此方法創(chuàng)建的線程池可根據(jù)需要自動調(diào)整池中線程的數(shù)量. 執(zhí)行任務時將重用存在先前創(chuàng)建的線程(如果池中存在可用線程的話). 如果池中沒有可用線程, 將創(chuàng)建一個新的線程, 并將其添加到池中. 池中的線程超過60秒未被使用就會被銷毀, 因此長時間保持空閑的CachedThreadPool不會消耗額外的資源.
|--public static ExecutorService newSingleThreadExecutor(): 創(chuàng)建一個單線程的Executor. 這個Executor保證按照任務提交的順序依次執(zhí)行任務.
|--public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize): 創(chuàng)建一個可重用的固定線程數(shù)的線程池. ScheduledExecutorService是ExecutorService的子接口, 調(diào)用ScheduledExecutorService的相關(guān)方法, 可以延遲或定期執(zhí)行任務.
以上靜態(tài)方法均使用默認的ThreadFactory(即Executors.defaultThreadFactory()方法的返回值)創(chuàng)建線程, 如果想要指定ThreadFactory, 可調(diào)用他們的重載方法.通過指定ThreadFactory, 可以定制新建線程的名稱, 線程組, 優(yōu)先級, 守護線程狀態(tài)等.
如果Executors提供的創(chuàng)建線程池的方法無法滿足要求, 可以使用ThreadPoolExecutor類創(chuàng)建線程池.
提交任務. 所有的線程池都是ExecutorService及其子類的對象, 因此, 可以調(diào)用ExecutorService的相關(guān)方法提交任務.
|--void execute(Runnable command): 使用池中已存在的線程或新建一個線程執(zhí)行command.
Java代碼程序的輸出為:
- ----------------FixedThreadPool---------------------
- pool-1-thread-1: is running!
- pool-1-thread-2: is running!
- pool-1-thread-2: is running!
- pool-1-thread-1: is running!
- ----------------CashedThreadPool---------------------
- pool-2-thread-1: is running!
- pool-2-thread-2: is running!
- pool-2-thread-4: is running!
- pool-2-thread-3: is running!
- ----------------SingleThreadExecutor---------------------
- pool-3-thread-1: is running!
- pool-3-thread-1: is running!
- pool-3-thread-1: is running!
- pool-3-thread-1: is running!
復制代碼 |--Future<T> submit(Callable<T> task): 使用池中已存在的線程或新建一個線程執(zhí)行task, 與execute()方法不同的是, 該方法會返回線程的執(zhí)行結(jié)果. submit方法接受一個Callable<T>對象, Callable<T>接口是一個泛型接口, 實現(xiàn)Callable<T>接口需要重寫其中的call()方法, call()方法將返回一個T對象. submit方法的返回值是Future<T>對象, 調(diào)用該對象的get()可以獲得call()方法的返回值.
Java代碼- 1.public class FutureDemo {
- 2. public static void main(String[] args) throws Exception {
- 3. ExecutorService pool = Executors.newFixedThreadPool(2);
- 4.
- 5. Future<Integer> intFuture = pool.submit(new IntegerCallable());
- 6. // get()方法將阻塞主線程, 直到IntegerCallable線程的call()運行結(jié)束并返回結(jié)果時為止.
- 7. Integer returnInt = intFuture.get();
- 8. System.out.println("返回值為" + returnInt);
- 9.
- 10. Future<Boolean> boolFuture = pool.submit(new BooleanCallable());
- 11. Boolean returnBool = boolFuture.get();
- 12. System.out.println("返回值為" + returnBool);
- 13.
- 14. pool.shutdown();
- 15. }
- 16.
- 17. private final static class IntegerCallable implements Callable<Integer> {
- 18. // call()方法的返回值類型由泛型決定
- 19. @Override
- 20. public Integer call() throws Exception {
- 21. return 2;
- 22. }
- 23. }
- 24.
- 25. private final static class BooleanCallable implements Callable<Boolean> {
- 26. @Override
- 27. public Boolean call() throws Exception {
- 28. return true;
- 29. }
- 30. }
- 31.}
- public class FutureDemo {
- public static void main(String[] args) throws Exception {
- ExecutorService pool = Executors.newFixedThreadPool(2);
-
- Future<Integer> intFuture = pool.submit(new IntegerCallable());
- // get()方法將阻塞主線程, 直到IntegerCallable線程的call()運行結(jié)束并返回結(jié)果時為止.
- Integer returnInt = intFuture.get();
- System.out.println("返回值為" + returnInt);
-
- Future<Boolean> boolFuture = pool.submit(new BooleanCallable());
- Boolean returnBool = boolFuture.get();
- System.out.println("返回值為" + returnBool);
-
- pool.shutdown();
- }
-
- private final static class IntegerCallable implements Callable<Integer> {
- // call()方法的返回值類型由泛型決定
- @Override
- public Integer call() throws Exception {
- return 2;
- }
- }
-
- private final static class BooleanCallable implements Callable<Boolean> {
- @Override
- public Boolean call() throws Exception {
- return true;
- }
- }
- }
復制代碼 程序的輸出結(jié)果為:
返回值為2
返回值為true
|--List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks): 批量執(zhí)行多個任務.
Future類. 如果需要獲取線程的執(zhí)行結(jié)果, 那么就會使用到Future. Future對象是一個指向異步執(zhí)行結(jié)果的引用, 由于線程的異步特性, Future對象在其創(chuàng)建之初可能并不可用, 比如線程的call()方法尚未完成時. 可以調(diào)用Future對象的isDone()方法判斷線程結(jié)果是否已經(jīng)可用, 在線程結(jié)果返回之前調(diào)用Future對象的get()方法, 將導致阻塞.
關(guān)閉線程池. 使用完線程池后需要關(guān)閉它, 否則程序可能一直處于運行狀態(tài). ExecutorService提供了2個方法用于關(guān)閉線程池:
|--void shutdown(): 關(guān)閉線程池, 不再接受新任務. 如果存在正在執(zhí)行的任務, 則等待任務執(zhí)行完成.
|--List<Runnable> shutdownNow(): 關(guān)閉線程池, 不再接受新任務. 盡力嘗試停止正在執(zhí)行的任務, 并返回正在等待的任務列表.
|--boolean isShutdown(): 判斷線程池是否已經(jīng)關(guān)閉. |
|