java并發編程--線程池初步
服務器應用程序經常需要處理執行時間很短而數目巨大的請求, 如果為每一個請求創建一個新的線程, 會導致一些問題的出現, 如:
1. 性能瓶頸. 線程的創建和銷毀需要執行大量的后臺操作, 如果單個請求的執行時間很短, 有可能花在創建和銷毀線程上的時間大于真正執行請求的時間.
2. 可能會導致資源不足. 大量的并發請求意味著需要創建大量的線程, 過多的線程存在會吞噬大量的系統資源, 而且CPU需要在這些線程間不斷切換, 這可能引發"切換過度"的問題.
為了適應上述場合, java在JDK1.5中引入了線程池的概念. 線程池中存放著一定數量的已創建好的線程, 當一個請求到來時, 只需從線程池中取出一個線程來執行請求, 請求完成后再將線程歸還給線程池. 同時, 我們可以為線程池指定最大的線程數量, 當池中所有線程都處于活動狀態下, 新的任務會排隊等候, 直到之前的某個任務處理完成后, 新的任務才能得到處理.
創建線程池. java.util.concurrent.Executors類提供了多個靜態方法用于創建線程池.
|--public static ExecutorService newFixedThreadPool(int nThreads): 創建一個可重用的固定線程數的線程池. 如果池中所有的nThreads個線程都處于活動狀態時提交任務(任務通常是Runnable或Callable對象), 任務將在隊列中等待, 直到池中出現可用線程.
|--public static ExecutorService newCachedThreadPool(): 調用此方法創建的線程池可根據需要自動調整池中線程的數量. 執行任務時將重用存在先前創建的線程(如果池中存在可用線程的話). 如果池中沒有可用線程, 將創建一個新的線程, 并將其添加到池中. 池中的線程超過60秒未被使用就會被銷毀, 因此長時間保持空閑的CachedThreadPool不會消耗額外的資源.
|--public static ExecutorService newSingleThreadExecutor(): 創建一個單線程的Executor. 這個Executor保證按照任務提交的順序依次執行任務.
|--public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize): 創建一個可重用的固定線程數的線程池. ScheduledExecutorService是ExecutorService的子接口, 調用ScheduledExecutorService的相關方法, 可以延遲或定期執行任務.
以上靜態方法均使用默認的ThreadFactory(即Executors.defaultThreadFactory()方法的返回值)創建線程, 如果想要指定ThreadFactory, 可調用他們的重載方法.通過指定ThreadFactory, 可以定制新建線程的名稱, 線程組, 優先級, 守護線程狀態等.
如果Executors提供的創建線程池的方法無法滿足要求, 可以使用ThreadPoolExecutor類創建線程池.
提交任務. 所有的線程池都是ExecutorService及其子類的對象, 因此, 可以調用ExecutorService的相關方法提交任務.
|--void execute(Runnable command): 使用池中已存在的線程或新建一個線程執行command.
public class ExecutorsDemo {
public static void main(String[] args) throws Exception {
System.out.println("----------------FixedThreadPool---------------------");
ExecutorService fixedPool = getFixedThreadPool();
executeThread(fixedPool);
// 為了避免混淆, 需要等待executeThread(fixedPool)執行完成
Thread.sleep(3000);
System.out.println("----------------CashedThreadPool---------------------");
ExecutorService cashedPool = getCashedThreadPool();
executeThread(cashedPool);
// 為了避免混淆, 需要等待executeThread(cashedPool)執行完成
Thread.sleep(3000);
System.out.println("----------------SingleThreadExecutor---------------------");
ExecutorService singleExecutor = getSingleThreadExecutor();
executeThread(singleExecutor);
}
// 只存在一個線程的線程池
private static ExecutorService getSingleThreadExecutor() {
return Executors.newSingleThreadExecutor();
}
// 創建一個根據需要自動調整大小的線程池
private static ExecutorService getCashedThreadPool() {
return Executors.newCachedThreadPool();
}
// 創建一個可重用的固定線程數的線程池
private static ExecutorService getFixedThreadPool() {
return Executors.newFixedThreadPool(2);
}
private static void executeThread(ExecutorService pool) {
Thread t1 = new MyThread();
Thread t2 = new MyThread();
Thread t3 = new MyThread();
Thread t4 = new MyThread();
// 將Tread放入線程池中執行
// MyThread類繼承自Thread, 而Thread類實現了Runnable接口
pool.execute(t1);
pool.execute(t2);
pool.execute(t3);
pool.execute(t4);
// 關閉線程池
pool.shutdown();
}
private static final class MyThread extends Thread {
@Override
public void run() {
super.run();
System.out.println(Thread.currentThread().getName() + ": is running!");
}
}
}
程序的輸出為:
----------------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): 使用池中已存在的線程或新建一個線程執行task, 與execute()方法不同的是, 該方法會返回線程的執行結果. submit方法接受一個Callable<T>對象, Callable<T>接口是一個泛型接口, 實現Callable<T>接口需要重寫其中的call()方法, call()方法將返回一個T對象. submit方法的返回值是Future<T>對象, 調用該對象的get()可以獲得call()方法的返回值.
public class FutureDemo {
public static void main(String[] args) throws Exception {
ExecutorService pool = Executors.newFixedThreadPool(2);
Future<Integer> intFuture = pool.submit(new IntegerCallable());
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;
}
}
}
程序的輸出結果為:
返回值為2
返回值為true
|--List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks): 批量執行多個任務.
關閉線程池. 使用完線程池后需要關閉它, 否則程序可能一直處于運行狀態. ExecutorService提供了2個方法用于關閉線程池:
|--void shutdown(): 關閉線程池, 不再接受新任務. 如果存在正在執行的任務, 則等待任務執行完成.
|--List<Runnable> shutdownNow(): 關閉線程池, 不再接受新任務. 盡力嘗試停止正在執行的任務, 并返回正在等待的任務列表.
|--boolean isShutdown(): 判斷線程池是否已經關閉.
轉自:http://coolxing.iteye.com/blog/1236588