標籤:
1.1 綜述
建立線程有兩種方式:extends Thread || inplements Runable,但是這兩種方式都有一個缺陷,就是執行完任務後不能擷取執行結果。
如果非要擷取到執行結果的話,就必須通過共用變數或者是線程通訊的方法來達到效果,使用較為麻煩,為瞭解決這種問題,java提供了Callable Future ,通過他們可以再任務執行完畢後得到任務執行結果。
1.2 Runable Callable 對比
java.lang.Runable是一個介面,聲明了run()方法:
public interface Runable { public abstract void run();} 因為run()方法傳回值void,所以執行完任務後不能返回結果。
java.util,concurrent.Callable 也是一個介面,裡面聲明了一個方法call();
public interface Callable<V> { V call() throws Exception;} call{}函數返回的類型就是這個傳遞進來的V類型,使用Callable 就需要配合ExecutorService配合使用:
<T> Future<T> submit(Callable<T> task);<T> Future<T> submit(Runnable task, T result);Future<?> submit(Runnable task);
1.3 Future 介面 方法含義
Future類位於java.util.concurrent包下,它是一個介面
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;}
cancel方法用來取消任務,如果取消任務成功則返回true,如果取消任務失敗則返回false。參數mayInterruptIfRunning表示是否允許取消正在執行卻沒有執行完畢的任務,如果設定true,則表示可以取消正在執行過程中的任務。如果任務已經完成,則無論mayInterruptIfRunning為true還是false,此方法肯定返回false,即如果取消已經完成的任務會返回false;如果任務正在執行,若mayInterruptIfRunning設定為true,則返回true,若mayInterruptIfRunning設定為false,則返回false;如果任務還沒有執行,則無論mayInterruptIfRunning為true還是false,肯定返回true。
isCancelled方法表示任務是否被取消成功,如果在任務正常完成前被取消成功,則返回 true。
isDone方法表示任務是否已經完成,若任務完成,則返回true;
get()方法用來擷取執行結果,這個方法會產生阻塞,會一直等到任務執行完畢才返回;
get(long timeout, TimeUnit unit)用來擷取執行結果,如果在指定時間內,還沒擷取到結果,就直接返回null。
1.4 Future FutureTask 相關
因為Future只是一個介面,所以是無法直接用來建立對象使用的,因此就有了下面的FutureTask。
FutureTask是Future介面的一個唯一實作類別。
public class FutureTask<V> implements RunnableFuture<V> public interface RunnableFuture<V> extends Runnable, Future<V> { void run();}
FutureTask提供了2個構造器:
public FutureTask(Callable<V> callable) {}public FutureTask(Runnable runnable, V result) {}
1.5 程式碼範例
樣本
package com.test.java.future;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;public class Test { public static void main(String[] args) { ExecutorService executor = Executors. newCachedThreadPool(); Task task = new Task(); Future<Integer> result = executor.submit(task); executor.shutdown(); try { Thread. sleep(1000); } catch (InterruptedException e1) { e1.printStackTrace(); } System. out.println("主線程在執行任務" ); try { System. out.println("task運行結果" + result.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } System. out.println("所有任務執行完畢" ); }}class Task implements Callable<Integer> { @Override public Integer call() throws Exception { System. out.println("子線程在進行計算" ); Thread. sleep(3000); int sum = 0; for (int i = 0; i < 100; i++) sum += i; return sum; }}package com.test.java.future;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.FutureTask;public class Test1 { public static void main(String[] args) { // 第一種方式 ExecutorService executor = Executors. newCachedThreadPool(); Task1 task = new Task1(); FutureTask<Integer> futureTask = new FutureTask<Integer>(task); executor.submit(futureTask); executor.shutdown(); // 第二種方式,注意這種方式和第一種方式效果是類似的,只不過一個使用的是ExecutorService,一個使用的是Thread /* * Task task = new Task(); FutureTask<Integer> futureTask = new * FutureTask<Integer>(task); Thread thread = new Thread(futureTask); * thread.start(); */ try { Thread. sleep(1000); } catch (InterruptedException e1) { e1.printStackTrace(); } System. out.println("主線程在執行任務" ); try { System. out.println("task運行結果" + futureTask.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } System. out.println("所有任務執行完畢" ); }}class Task1 implements Callable<Integer> { @Override public Integer call() throws Exception { System. out.println("子線程在進行計算" ); Thread. sleep(3000); int sum = 0; for (int i = 0; i < 100; i++) sum += i; return sum; }}
1.6 另外一個恰當的樣本說明
舉個簡單的例子:當你在網上購物時,如果付款成功了,你是否立即拿到了你買到的商品?當然不是,當你付款成功時,你得到的僅僅是一個,訂單提交成功的提示而已,其它的什麼都沒了,從這一刻開始,你是否會一直呆在家裡,什麼都不做,直到你的商品送到你手中呢?當然也不是,當你訂單提交成功後,你會去做你該做的,當你的商品送到時,你只需簽收一下即可,從訂單提交到商品送到之間,你不會因為等待商品送到而耽誤你的時間,你可以自由支配你的時間,好像什麼都沒有發生一樣。
是的,Future模式就是這個意思
當客戶提交一個請求時,這個請求有可能會花很長一段時間去處理後台資料,之後,再返回給客戶一個處理過的資料,那這段時間,客戶一直在等待服務端的響應,是不是會讓客戶覺得很厭煩呢?當然會了,所以Future模式就是為了提高回應時間而誕生的,當然這個提高其實是一個假象。當客戶提交一個請求時,我們讓客戶立即返回一個虛擬資料響應,之後,用戶端就不用為了等待響應而無事可做了,此後,用戶端可以進行別的任何操作,當真正的資料處理完返回給客戶了,客戶再去進行相應的處理,這樣就會讓客戶沒有無謂的等待了.
package com.test.java.future;import java.util.concurrent.Callable;public class MyData implements Callable<String> { private String myStr ; public MyData(String myStr) { this .myStr = myStr; } @Override public String call() throws Exception { StringBuffer sb = new StringBuffer(); for (int i=0;i<10;i++) { sb.append( myStr); try { Thread. sleep(1000); } catch (Exception e) { e.printStackTrace(); } } return sb.toString(); }}
package com.test.java.future;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.FutureTask;public class MyDataTest { public static void main(String[] args) { FutureTask<String> future = new FutureTask<String>( newMyData("alexgaoyh" )); ExecutorService exe = Executors. newFixedThreadPool(1); exe.submit(future); exe.shutdown(); System. out .println("用戶端請求結束了" ); System. out .println("任務是否已經完成:" +future.isDone()); try { /* * 這段時間,就是後台在擷取真正資料的時間 */ System. out .println("在這段時間,我可以做我自己的事情" ); System. out .println("真正的資料:" +future.get()); System. out .println("任務是否已經完成:" +future.isDone()); } catch (Exception e) { e.printStackTrace(); } } }
java Future FutureTask 並行作業