• java并發編程--線程池初步

    2
    Java C/C++ Go 線程 20143 次瀏覽

    服務器應用程序經常需要處理執行時間很短而數目巨大的請求, 如果為每一個請求創建一個新的線程, 會導致一些問題的出現, 如:

    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

    相似問題

    相關經驗

    相關資訊

    相關文檔

  • sesese色