這套機制分離了任務的建立和執行。經過使用執行器,僅僅須要實現Runnable接口的對象,而後將這些對象發送給執行器便可。執行器經過建立所需線程,來負責這些Runnable對象的建立,實例化以及運行。可是執行器的功能不限於此,他使用了線程池來提升應用程序的性能。當發送一個任務給執行器時,執行器會嘗試使用線程池中的線程來執行這個任務,避免了不斷地建立和銷燬線程而致使的性能降低。java
建立線程執行器web
使用執行器框架(Executor Framework)第一步是建立ThreadPoolExecutor對象。能夠ThreadPoolExecutor類提供的四個構造器或者使用Executors的工廠類來建立ThreadPoolExecutor對象。
緩存
package com.packtpub.java7.concurrency.chapter4.recipe1.task; import java.util.Date; import java.util.concurrent.TimeUnit; /** * This class implements a concurrent task * */ public class Task implements Runnable { /** * The start date of the task */ private Date initDate; /** * The name of the task */ private String name; /** * Constructor of the class. Initializes the name of the task * @param name name asigned to the task */ public Task(String name){ initDate=new Date(); this.name=name; } /** * This method implements the execution of the task. Waits a random period of time and finish */ @Override public void run() { System.out.printf("%s: Task %s: Created on: %s\n",Thread.currentThread().getName(),name,initDate); System.out.printf("%s: Task %s: Started on: %s\n",Thread.currentThread().getName(),name,new Date()); try { Long duration=(long)(Math.random()*10); System.out.printf("%s: Task %s: Doing a task during %d seconds\n",Thread.currentThread().getName(),name,duration); TimeUnit.SECONDS.sleep(duration); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("%s: Task %s: Finished on: %s\n",Thread.currentThread().getName(),name,new Date()); } }
package com.packtpub.java7.concurrency.chapter4.recipe1.task; import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor; /** * This class simulates a server, for example, a web server, that receives * requests and uses a ThreadPoolExecutor to execute those requests * */ public class Server { /** * ThreadPoolExecutors to manage the execution of the request */ private ThreadPoolExecutor executor; /** * Constructor of the class. Creates the executor object */ public Server(){ executor=(ThreadPoolExecutor)Executors.newCachedThreadPool(); } /** * This method is called when a request to the server is made. The * server uses the executor to execute the request that it receives * @param task The request made to the server */ public void executeTask(Task task){ System.out.printf("Server: A new task has arrived\n"); executor.execute(task); System.out.printf("Server: Pool Size: %d\n",executor.getPoolSize()); System.out.printf("Server: Active Count: %d\n",executor.getActiveCount()); System.out.printf("Server: Completed Tasks: %d\n",executor.getCompletedTaskCount()); } /** * This method shuts down the executor */ public void endServer() { executor.shutdown(); } }
package com.packtpub.java7.concurrency.chapter4.recipe1.core; import com.packtpub.java7.concurrency.chapter4.recipe1.task.Server; import com.packtpub.java7.concurrency.chapter4.recipe1.task.Task; /** * Main class of the example. Creates a server and 100 request of the Task class * that sends to the server * */ public class Main { /** * Main method of the example * @param args */ public static void main(String[] args) { // Create the server Server server=new Server(); // Send 100 request to the server and finish for (int i=0; i<100; i++){ Task task=new Task("Task "+i); server.executeTask(task); } server.endServer(); } }
若是須要執行新的任務,緩存線程池就會建立新線程;若是線程所運行的任務執行完成後而且這個線程可用,那麼緩存線程池將會重用這些線程。線程的重用的優勢是減小了建立新線程所花費的時間。然而,新任務固定會依賴線程來執行,所以緩存線程池也有缺點,若是發送過多的任務給執行器,系統的負荷將會過載。框架
PS:僅當線程的數量是合理的或者線程只會運行很短的時間,合適採用Executors工廠類的newCachedThreadPool()方法來建立執行器。dom
ThreadPoolExecutor類的重要特性是,一般須要顯示地去結束他。
ide