Executor框架

從JDK1.5開始,增加了一個執行並行任務的框架——Executor框架。框架在java.util.concurrent包中。Executor是框架中的一個接口,使用Executor可以同步或異步地執行任務。

異步任務可以放在多線程中處理,但使用Executor比直接創建線程處理任務有很多好處,比如設置任務開始時間,取消任務隊列,控制任務隊列執行策略等,而且使用Executor可以很容易地創建線程池。

線程池
Executors是一個工廠類,可以方便的創建各種類型Executor或線程池:

  • newSingleThreadExecutor():創建一個Executor,順序執行一個任務隊列,每次只能執行一個任務。
  • newFixedThreadPool(nThreads):創建一個有固定數目線程的線程池,每次最多執行nThreads個任務,如果任務多於nThreads,多於的線程置於等待隊列中
  • newCachedThreadPool():創建一個線程池,線程數目會隨任務數目增加而增加,同時也會回收已經空閒的線程。
  • newScheduledThreadPool(corePoolSize):創建一個線程池,可以讓任務延遲或週期性執行。

執行單個任務

		Executor executor = Executors.newSingleThreadExecutor();

		Runnable task = new Runnable() {
			@Override
			public void run() {
				System.out.println("Executing task...");
			}
		};
		
		executor.execute(task);

創建一個線程池

		final int pool_size = 5;
		Executor executor = Executors.newFixedThreadPool(pool_size);
		//or
		//Executor executor = Executors.newCachedThreadPool();

		int nTasks = 10;
		for (int i = 0; i < nTasks; ++i){
			Runnable task = createTask();
			executor.execute(task);
		}

生命週期
Executor有個缺點,一旦任務提交,就無法獲得任務的執行情況,也無法停止,除非等待所有任務執行完畢或強制關閉JVM。

ExecutorService擴展了Executor接口,加入了生命週期管理。ExecutorService可以在運行時關閉,關閉後ExecutorService就停止接收新的任務。對已經接收到的任務有兩種處理方法:如果調用shutdown()方法,ExecutorService會等待所有接收到的任務執行完畢;如果調用shutdownNow()方法,ExecutorService會取消所有等待的任務並嘗試停止正在執行的任務。

ExecutorService.java中的例子,關閉線程池:

	void shutdownAndAwaitTermination(ExecutorService pool) {
		
		pool.shutdown(); // Disable new tasks from being submitted
		try {
			// Wait a while for existing tasks to terminate
			if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
				pool.shutdownNow(); // Cancel currently executing tasks
				// Wait a while for tasks to respond to being cancelled
				if (!pool.awaitTermination(60, TimeUnit.SECONDS))
					System.err.println("Pool did not terminate");
			}
		} catch (InterruptedException ie) {
			// (Re-)Cancel if current thread also interrupted
			pool.shutdownNow();
			// Preserve interrupt status
			Thread.currentThread().interrupt();
		}
	}

延遲、週期性執行任務
ScheduledExecutorService擴展了ExecutorService接口,可以延遲或間期執行任務。

  • schedule(command, delay, TimeUnit): 任務延遲delay時間後執行
  • scheduleAtFixedRate(command, initDelay, period, TimeUnit.SECONDS): 先延遲initDelay時間,然後每period時間執行一次任務
  • scheduleWithFixedDelay(command, initDelay, delay, TimeUnit.SECONDS): 先延遲initDelay時間,然後執行任務,每次執行完畢後延遲delay時間再執行下次任務。

注意:scheduleAtFixedRate和scheduleWithFixedDelay的區別。scheduleAtFixedRate執行任務的週期與任務消耗的時間沒有關係,如果任務消耗10秒,但設置的週期是1秒,那1秒後下次任務就會開始。而scheduleWithFixedDelay不同,一定要等本次任務完成後,間隔delay秒才執行下一個任務。

延遲、週期性執行任務:

		final int pool_size = 1;
		ScheduledExecutorService scheduleService = Executors.newScheduledThreadPool(pool_size);

		Runnable command = new Runnable() {

			@Override
			public void run() {
				System.out.println("Executing task...");
			}
		};

		scheduleService.schedule(command, 10, TimeUnit.SECONDS);
		//scheduleService.scheduleAtFixedRate(command, 10, 1, TimeUnit.SECONDS);
		//scheduleService.scheduleWithFixedDelay(command, 5, 1, TimeUnit.SECONDS);

參考"Java concurrency in practice"  6.2

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