interface Future<V> ,表示異步計算的結果,Future有個get方法而獲取結果只有在計算完成時獲取,不然會一直阻塞直到任務轉入完成狀態,而後會返回結果或者拋出異常。相對於繼承Thread來建立線程方式,使用Runnable可讓你的實現類同時實現多個接口,而相對於Callable及Future,Runnable方法並不返回任務執行結果且不能拋出異常。spring
public interface Future<V> { //取消計算,若是還沒有開始,直接取消再也不運算,若是正在進行:mayInterruptIfRunning等於true就會被中斷。注意一點:只要調用了cancle(),不管任務是否可以執行,再調用get()都會出現cancledException,這是因爲Future.state的狀態被置爲CANCELLED = 4,所致的; boolean cancel(boolean mayInterruptIfRunning) //判斷計算是否取消。 boolean isCancelled(); //判斷計算是否完成,若是計算完成返回true,不然返回false boolean isDone(); //得到異步計算的結果,若是在調用get()的時候結果尚未計算出來,調用線程將被阻塞。 V get() throws InterruptedException, ExecutionException; //得到異步計算的結果,若是在調用get()的時候結果尚未計算出來,調用線程將被阻塞。若是調用超時將會拋出TimeoutException。 V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }
補充:緩存
- FutureTask:包裝器,能夠將Callable轉換成爲Future與Runnable,它同時實現了兩者的接口。 - Callable:能夠爲異步方法返回計算結果。
public class Exercise { private SimpleApplicationService simpleApplicationService = new SimpleApplicationService(); @Test public void futureTest() throws InterruptedException, ExecutionException { long st = System.currentTimeMillis(); //這裏本是一callable接口實現,我用lambda方便一點 FutureTask result = new FutureTask<String>(() -> simpleApplicationService.query()); //記住咱們的任務都與須要開啓一個新的線程 Thread t = new Thread(result); t.start(); long end = System.currentTimeMillis(); System.out.println("耗時:" + (end - st) + " 結果:" + result.get()); } } public class SimpleApplicationService { public String query() throws InterruptedException { System.out.println("開始查詢"); Thread.sleep(2000); return "query result"; } }
Executors類有許多靜態方法可建立線程池。例如:併發
核心(簡介):異步
ThreadPoolExecutoride
public class ThreadPoolExecutor extends AbstractExecutorService { public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue); public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory); public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler); //事實上,前面三個構造器都是調用的第四個構造器進行的初始化工做。 public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler); }
參數含義:性能
workQueue:一個阻塞隊列,用來存儲等待執行的任務,這個參數的選擇也很重要,會對線程池的運行過程產生重大影響,通常來講,這裏的阻塞隊列有如下幾種選擇:學習
- ArrayBlockingQueue - LinkedBlockingQueue - SynchronousQueue;
handler:表示當拒絕處理任務時的策略,有如下四種取值:操作系統
- ThreadPoolExecutor.AbortPolicy:丟棄任務並拋出RejectedExecutionException異常。 - ThreadPoolExecutor.DiscardPolicy:也是丟棄任務,可是不拋出異常。 - ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務,而後從新嘗試執行任務(重複此過程) - ThreadPoolExecutor.CallerRunsPolicy:由調用線程處理該任務
使用鏈接池應該作的事:線程
1. 調用Executors的靜態方法建立線程池。 2. 調用submit(),提交一個Callable對象或者Runnable對象。 3. 保存好得到的Future<>對象,其中是計算結果(若是提交的是Callable)。 4. 沒有任何任務再提交的時候使用shutDown()。
public class TaskExercise { public static void main(String[] args) throws ExecutionException, InterruptedException { //future + callable ExecutorService executor = Executors.newCachedThreadPool(); CallTask callTask = new CallTask(); Future<String> taskReturn = executor.submit(callTask); System.out.println(taskReturn.get()); //futureTask FutureTask<String> futureTask = new FutureTask<String>(callTask); executor.submit(futureTask); System.out.println(futureTask.get()); //runable Runnable runTask = new RunTask(); String result = "xz"; Future<?> runTaskReturn = executor.submit(runTask,result); System.out.println(runTaskReturn.get()); executor.shutdown(); } } class CallTask implements Callable<String>{ @Override public String call() throws Exception { return "task return"; } } class RunTask implements Runnable{ @Override public void run() { System.out.println("run"); } }
有時使用執行器更有意義的場景是控制一組相關任務。設計
1. shutdownNow():取消全部任務 2. invokeAny():提交全部對象到一個Callable對象集合,並返回某個已完成的任務結果。例如:若是你願意接受任何一種解決方案的話。 3. 還有其餘一些方法等咱們真正用到時再學習好了~
spring中實現異步調用:spring爲任務調度與異步方法執行提供了註解支持。經過在方法上設置@Async註解,可以使得方法被異步調用。也就是說調用者會在調用時當即返回,而被調用方法的實際執行是交給Spring的TaskExecutor來完成。若是是有返回值的話記得:接口返回Future<>,實現返回AsyncResult<>。