歡迎微信搜索並關注「小猴子的技術筆記」公衆號 私信我 領取豐富的視頻學習資料!
開發業務中有不少用到線程的場景。遇到比較耗時的場景每每會起一個線程進行執行,若是不返回結果就能夠直接new一個Thread對業務進行操做。由於runnable不會返回結果,也不會拋出異常,若是須要拿到返回值的話則須要使用Callable和Future或者Future Task進行結合。java
這裏能夠簡單理解爲「Callable」表示產生結果和拋出異常。而「Future」是一個接口,表示異步計算結果微信
「Callable」是一個泛型接口,裏面只有一個方法「call()」能夠用來計算產生結果,若是沒法執行就拋出異常。異步
@FunctionalInterface public interface Callable<V> { // 結算結果。若是沒法執行則拋出異常 V call() throws Exception; }
「Future」也是一個泛型接口用來獲取異步計算的結果,經過查看源碼能夠了解到「Future」爲咱們提供瞭如下的幾個方法:ide
public interface Future<V> { boolean cancel(boolean mayInterruptIfRunning); boolean isCancelled(); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }
「boolean cancel(boolean mayInterruptedRunning)」:嘗試取消執行此任務,若是任務已經完成,則調用返回false。若是任務已經啓動,而且「mayInterruptedRunning」設置爲true,那麼將以中斷執行此任務線程的方式來試圖中止任務,成功返回true,失敗返回false。學習
「boolean isCancelled()」:若是任務完成前被取消則返回true。測試
「boolean isDone()」:不管是任務正常結束仍是中途被中斷或者因爲其餘緣由而結束,都將返回true。this
「V get()」:獲取計算結果,若是計算尚未完成就調用了這個方法那麼線程將會阻塞等待獲取計算完成。spa
「V get(long timeout, TimeUnit unit)」:獲取計算結果,若是計算尚未完成就調用了這個方法,那麼線程將會等待設置的時間內會拋出異常。若是在獲取等待的過程當中遇到了線程的中斷、取消、線程池等異常也是會被捕獲到。線程
由於Future是一個接口,沒有辦法被實例化,所以須要使用FutureTask進行類的建立。code
public class FutureTask<V> implements RunnableFuture<V> { // 省略了一下方法 }
public interface RunnableFuture<V> extends Runnable, Future<V> { void run(); }
先看一個Callable和Future結合運行的例子:
public class MyCallable implements Callable<String> { private int sleepTime; private String msg; public MyCallable(int sleepTime, String msg) { this.sleepTime = sleepTime; this.msg = msg; } @Override public String call() throws Exception { TimeUnit.SECONDS.sleep(sleepTime); System.out.println("線程休眠了:" + sleepTime + "秒執行完畢"); return msg; } }
而後進行測試,測試代碼以下:
public class FutureTest { public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService executor = Executors.newCachedThreadPool(); System.out.println("~~~~~~~~~~~~~開始進行業務的計算~~~~~~~~~~~~~~"); Future<String> first = executor.submit(new MyCallable(3, "hello!")); Future<String> second = executor.submit(new MyCallable(2, "可愛的小猴子,要加油哦!")); // 主線程能夠繼續執行一些其餘的任務 System.out.println("~~~~~~~主線程能夠繼續執行一些其餘的任務~~~~~~~"); System.out.println("最後的結果:" + first.get() + " " + second.get()); executor.shutdown(); } }
最後的運行結果:
~~~~~~~~~~~~~開始進行業務的計算~~~~~~~~~~~~~~ ~~~~~~~主線程能夠繼續執行一些其餘的任務~~~~~~~ 線程休眠了:2秒執行完畢 線程休眠了:3秒執行完畢 最後的結果:hello!可愛的小猴子,要加油哦!
若是使用FutureTask的話,則代碼的示例以下:
public class FutureTaskTest { public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService executor = Executors.newCachedThreadPool(); System.out.println("~~~~~~~future task 開始進行業務的計算~~~~~~~~~"); FutureTask<String> first = new FutureTask<>(new MyCallable(2, "加油!")); FutureTask<String> second = new FutureTask<>(new MyCallable(5, "努力的人兒!")); executor.submit(first); executor.submit(second); executor.shutdown(); System.out.println("~~~~~~~主線程能夠繼續執行一些其餘的任務~~~~~~~"); System.out.println("最後的結果:" + first.get() + " " + second.get()); } }
運行結果:
~~~~~~~future task 開始進行業務的計算~~~~~~~~~ ~~~~~~~主線程能夠繼續執行一些其餘的任務~~~~~~~ 線程休眠了:2秒執行完畢 線程休眠了:5秒執行完畢 最後的結果:加油!努力的人兒!
歡迎微信搜索並關注「小猴子的技術筆記」公衆號 私信我 領取豐富的視頻學習資料!