最近在看多線程方面的內容,注意到java中原來除了Runnable和Thread之外還有Callable的方式實現多線程,並且Callable還能得到子線程的返回值,這是前面兩種方式所不具有的。
Callable是一個借口,並且支持泛型,我們編寫多線程只需要實現這個接口,並且重寫call方法,要得到Callable的返回值就要使用Future對象,Callable負責計算結果,Future負責拿到結果,具體的使用請看如下兩個例子:
public class CallableAndFuture { public static void main(String[] args) { Callable<Integer> callable = new Callable<Integer>() { public Integer call() throws Exception { return new Random().nextInt(100); } }; FutureTask<Integer> future = new FutureTask<Integer>(callable); new Thread(future).start(); try { Thread.sleep(5000);// 可能做一些事情 System.out.println(future.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } }
上面例子是通過Thread來包裝FutureTask來啟動線程,FutureTask實現了兩個接口,Runnable和Future,所以它既可以作為Runnable被線程執行,又可以作為Future得到Callable的返回值,那么這個組合的使用有什么好處呢?假設有一個很耗時的返回值需要計算,並且這個返回值不是立刻需要的話,那么就可以使用這個組合,用另一個線程去計算返回值,而當前線程在使用這個返回值之前可以做其它的操作,等到需要這個返回值時,再通過Future得到,豈不美哉!
下面來看另一種方式使用Callable和Future,通過ExecutorService的submit方法執行Callable,並返回Future,代碼如下:
public class CallableAndFuture { public static void main(String[] args) { ExecutorService threadPool = Executors.newSingleThreadExecutor(); Future<Integer> future = threadPool.submit(new Callable<Integer>() { public Integer call() throws Exception { return new Random().nextInt(100); } }); try { Thread.sleep(5000);// 可能做一些事情 System.out.println(future.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } }
執行多個帶返回值的任務,並取得多個返回值,代碼如下:
public class CallableAndFuture { public static void main(String[] args) { ExecutorService threadPool = Executors.newCachedThreadPool(); CompletionService<Integer> cs = new ExecutorCompletionService<Integer>(threadPool); for(int i = 1; i < 5; i++) { final int taskID = i; cs.submit(new Callable<Integer>() { public Integer call() throws Exception { return taskID; } }); } // 可能做一些事情 for(int i = 1; i < 5; i++) { try { System.out.println(cs.take().get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } } }