說到java開發,免不了跟多線程打交道。Executor框架即是Java 5中引入的,其內部使用了線程池機制,它在java.util.cocurrent 包下,經過該框架來控制線程的啓動、執行和關閉,能夠簡化併發編程的操做。所以,在Java 5以後,經過Executor來啓動線程比使用Thread的start方法更好,除了更易管理,效率更好(用線程池實現,節約開銷)外,還有關鍵的一點:有助於避免this逃逸問題——若是咱們在構造器中啓動一個線程,由於另外一個任務可能會在構造器結束以前開始執行,此時可能會訪問到初始化了一半的對象用Executor在構造器中。java
ExecutorService,是一個接口,繼承了Executor;編程
Executor,只有一個方法:緩存
public interface Executor { void execute(Runnable command); }
Executors提供了4中建立線程池:多線程
public static ExecutorService newCachedThreadPool(); 建立一個可緩存線程池,若是線程池長度超過處理須要,可靈活回收空閒線程,若無可回收,則新建線程。 併發
public static ExecutorService newFixedThreadPool(int nThreads); 建立一個定長線程池,可控制線程最大併發數,超出的線程會在隊列中等待。 框架
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) 建立一個定長線程池,支持定時及週期性任務執行。 ide
public static ExecutorService newSingleThreadExecutor(); 建立一個單線程化的線程池,它只會用惟一的工做線程來執行任務,保證全部任務按照指定順序(FIFO, LIFO, 優先級)執行。this
經過Executors的以上四個靜態工廠方法得到 ExecutorService實例,然後調用該實例的execute(Runnable command)方法便可。一旦Runnable任務傳遞到execute()方法,該方法便會自動在一個線程上執行。spa
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ExecutorTest { public static void main(String[] args){ ExecutorService executorService = Executors.newCachedThreadPool(); //ExecutorService executorService = Executors.newFixedThreadPool(3); // ExecutorService executorService = Executors.newSingleThreadExecutor(); for (int i = 0; i < 3; i++){ RunnableTest method = new RunnableTest(); executorService.execute(method); System.out.println("########" + i + "########"); } executorService.shutdown(); } }
public class RunnableTest implements Runnable{ public void run(){ System.out.println(Thread.currentThread().getName() + "線程執行"); } }
輸出結果:線程
########0######## ########1######## ########2######## pool-1-thread-2線程執行 pool-1-thread-3線程執行 pool-1-thread-1線程執行
任務分兩類:一類是實現了Runnable接口的類,一類是實現了Callable接口的類。二者均可以被ExecutorService執行,可是Runnable任務沒有返回值,而Callable任務有返回值。而且Callable的call()方法只能經過ExecutorService的submit(Callable<T> task) 方法來執行,而且返回一個 <T>Future<T>,是表示任務等待完成的 Future。
下面給出一個Executor執行Callable任務的示例代碼
public class ExecutorTest { public static void main(String[] args){ ExecutorService executorService = Executors.newCachedThreadPool(); //ExecutorService executorService = Executors.newFixedThreadPool(3); // ExecutorService executorService = Executors.newSingleThreadExecutor(); List<Future<String>> resultList = new ArrayList<Future<String>>(); for (int i = 0; i < 6; i++){ CallableTest method = new CallableTest(i); Future<String> future = executorService.submit(method); System.out.println("########" + i + "########"); resultList.add(future); } //遍歷任務的結果 for (Future<String> fs : resultList){ try{ //Future返回若是沒有完成,則一直循環等待,直到Future返回完成 while(!fs.isDone()); //打印各個線程(任務)執行的結果 System.out.println(fs.get()); }catch(InterruptedException e){ e.printStackTrace(); }catch(ExecutionException e){ e.printStackTrace(); }finally{ //啓動一次順序關閉,執行之前提交的任務,但不接受新任務 executorService.shutdown(); } } } }
import java.util.concurrent.Callable; public class CallableTest implements Callable<String>{ private int id; public CallableTest(int id){ this.id = id; } @Override public String call() throws Exception { System.out.println(Thread.currentThread().getName() + "線程執行"); return Thread.currentThread().getName() + "線程執行" + "返回id=" + id; } }
輸出結果:
pool-1-thread-1線程執行返回id=0 pool-1-thread-2線程執行返回id=1 pool-1-thread-3線程執行返回id=2 pool-1-thread-4線程執行返回id=3 pool-1-thread-2線程執行返回id=4 pool-1-thread-4線程執行返回id=5
從結果中能夠一樣能夠看出,submit也是首先選擇空閒線程來執行任務,若是沒有,纔會建立新的線程來執行任務。另外,須要注意:若是Future的返回還沒有完成,則get()方法會阻塞等待,直到Future完成返回,能夠經過調用isDone()方法判斷Future是否完成了返回。