建立線程有2種方式,一種是直接繼承Thread,另一種就是實現Runnable接口。這2種方式都有一個缺陷就是:在執行完任務以後沒法獲取執行結果。若是須要獲取執行結果,就必須經過共享變量或者使用線程通訊的方式來達到效果,這樣使用起來就比較麻煩。java
而自從Java 1.5開始,就提供了Callable和Future,經過它們能夠在任務執行完畢以後獲得任務執行結果。ide
java.lang.Runnable是一個接口,在它裏面只聲明瞭一個run()方法函數
public interface Runnable { public abstract void run(); }
因爲run()方法返回值爲void類型,因此在執行完任務以後沒法返回任何結果。線程
Callable位於java.util.concurrent包下,它也是一個接口,只有一個方法call()code
public interface Callable<V> { V call() throws Exception; }
這是一個泛型接口,call()函數返回的類型就是傳遞進來的V類型。Callable通常是和ExecutorService配合來使用的,在ExecutorService接口中有個submit方法。繼承
<T> Future<T> submit(Callable<T> task); Future<?> submit(Runnable task);
Future就是對於具體的Runnable或者Callable任務的執行結果進行取消、查詢是否完成、獲取結果。必要時能夠經過get方法獲取執行結果,該方法會阻塞直到任務返回結果。接口
Future類位於java.util.concurrent包下,它是一個接口:get
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; }
在Future接口中聲明瞭5個方法:it
也就是說Future提供了三種功能:io
判斷任務是否完成; 可以中斷任務; 可以獲取任務執行結果。
FutureTask類實現了RunnableFuture接口,RunnableFuture接口繼承了Runnable接口和Future接口。因此,FutureTask既能夠做爲Runnable被線程執行,又能夠做爲Future獲得Callable的返回值。事實上,FutureTask是Future接口的一個惟一實現類。
FutureTask提供了2個構造器:
public FutureTask(Callable<V> callable) { } public FutureTask(Runnable runnable, V result) { }
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; } }
public class Test { public static void main(String[] args) { //第一種方式 ExecutorService executor = Executors.newCachedThreadPool(); Task task = new Task(); 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 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; } }