1.接口的定義:
public interface Callable<V> { V call() throws Exception; }
2.Callable和Runnable的異同
先看下Runnable接口的定義
public interface Runnable { public abstract void run();}
Callable的call()方法類似于Runnable接口中run()方法,都定義任務要完成的工作,實現這兩個接口時要分別重寫這兩個方法,主要的不同之處是call()方法是有返回值的(其實還有一些區別,例如call方法可以拋出異常,run方法不可以),運行Callable任務可以拿到一個Future對象,表示異步計算的結果。它提供了檢查計算是否完成的方法,以等待計算的完成,并檢索計算的結果。通過Future對象可以了解任務執行情況,可取消任務的執行,還可獲取執行結果。
3. Callable類型的任務可以有兩種執行方式:
我們先定義一個Callable任務MyCallableTask:
class MyCallableTask 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; }}
①借助FutureTask執行
FutureTask類同時實現了兩個接口,Future和Runnable接口,所以它既可以作為Runnable被線程執行,又可以作為Future得到Callable的返回值。
借助FutureTask執行的大體流程是:
Callable<Integer> mycallabletask = new MyCallableTask(); FutureTask<Integer> futuretask= new FutureTask<Integer>(mycallabletask); new Thread(futuretask).start();
通過futuretask可以得到MyCallableTask的call()的運行結果: futuretask.get();
②借助線程池來運行
線程池中執行Callable任務的原型例如:
public interface ExecutorService extends Executor { //提交一個Callable任務,返回值為一個Future類型 <T> Future<T> submit(Callable<T> task); //other methods... }
借助線程池來運行Callable任務的一般流程為:
ExecutorService exec = Executors.newCachedThreadPool(); Future<Integer> future = exec.submit(new MyCallableTask());
通過future可以得到MyCallableTask的call()的運行結果: future.get();
在網上看到了幾個比較好的代碼例子:
a.Callable任務借助FutureTask運行:
public class CallableAndFutureTask { 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(); } }}
b.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(); } }}
c.當執行多個Callable任務,有多個返回值時,我們可以創建一個Future的集合,例如:
class MyCallableTask implements Callable<String> { private int id; public OneTask(int id){ this.id = id; } @Override public String call() throws Exception { for(int i = 0;i<5;i++){ System.out.println("Thread"+ id); Thread.sleep(1000); } return "Result of callable: "+id; } }public class Test { public static void main(String[] args) { //Callable<String> mycallabletask = new MyCallableTask(1); ExecutorService exec = Executors.newCachedThreadPool(); ArrayList<Future<String>> results = new ArrayList<Future<String>>(); for (int i = 0; i < 5; i++) { results.add(exec.submit(new MyCallableTask(i))); } for (Future<String> fs : results) { if (fs.isDone()) { try { System.out.println(fs.get()); } catch (Exception e) { e.printStackTrace(); } } else { System.out.println("MyCallableTask任務未完成!"); } } exec.shutdown(); } }
那么引入Callable接口具有哪些好處呢?
①可以獲得任務執行返回值;
②通過與Future的結合,可以實現利用Future來跟蹤異步計算的結果。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。
新聞熱點
疑難解答
圖片精選