Callable接口和Runnable接口相似,區別就是Callable需要實現call方法,而Runnable需要實現run方法;並且,call方法還可以返回任何對象,無論是什么對象,JVM都會當作Object來處理。但是如果使用了泛型,我們就不用每次都對Object進行轉換了。
Runnable和Callable都是接口
不同之處:
1.Callable可以返回一個類型V,而Runnable不可以
2.Callable能夠拋出checked exception,而Runnable不可以。
3.Runnable是自從java1.1就有了,而Callable是1.5之后才加上去的
4.Callable和Runnable都可以應用於executors。而Thread類只支持Runnable.
上面只是簡單的不同,其實這兩個接口在用起來差別還是很大的。Callable與executors聯合在一起,在任務完成時可立刻獲得一個更新了的Future。而Runable卻要自己處理
Future接口,一般都是取回Callable執行的狀態用的。其中的主要方法:
- cancel,取消Callable的執行,當Callable還沒有完成時
- get,獲得Callable的返回值
- isCanceled,判斷是否取消了
- isDone,判斷是否完成
用Executor來構建線程池,應該要做的事:
1).調用Executors類中的靜態方法newCachedThreadPool(必要時創建新線程,空閑線程會被保留60秒)或newFixedThreadPool(包含固定數量的線程池)等,返回的是一個實現了ExecutorService接口的ThreadPoolExecutor類或者是一個實現了ScheduledExecutorServiece接口的類對象。
2).調用submit提交Runnable或Callable對象。
3).如果想要取消一個任務,或如果提交Callable對象,那就要保存好返回的Future對象。
4).當不再提交任何任務時,調用shutdown方法。
在java5以后,一個可以調度執行的線程單元可以有三種方式定義:
Thread、Runnable、Callable,其中Runnable實現的是void run()方法,Callable實現的是 V call()方法,並且可以返回執行結果,其中Runnable可以提交給Thread來包裝下,直接啟動一個線程來執行,而Callable則一般都是提交給ExecuteService來執行。
簡單來說,Executor就是Runnable和Callable的調度容器,Future就是對於具體的調度任務的執行結果進行查看,最為關鍵的是Future可以檢查對應的任務是否已經完成,也可以阻塞在get方法上一直等待任務返回結果。Runnable和Callable的差別就是Runnable是沒有結果可以返回的,就算是通過Future也看不到任務調度的結果的。
FutureTask則是一個RunnableFuture<V>,即實現了Runnbale又實現了Futrue<V>這兩個接口,另外它還可以包裝Runnable和Callable<V>,所以一般來講是一個符合體了,它可以通過Thread包裝來直接執行,也可以提交給ExecuteService來執行,並且還可以通過v get()返回執行結果,在線程體沒有執行完成的時候,主線程一直阻塞等待,執行完則直接返回結果。
package thread.test04; import java.util.concurrent.*; public class ThreadTestA { public static void main(String[] args) { ExecutorService e=Executors.newFixedThreadPool(10); e.execute(new MyRunnableA()); e.execute(new MyRunnableB()); e.shutdown(); } } class MyRunnableA implements Runnable{ public void run(){ System.out.println("Runnable:run()...."); int i=0; while(i<20){ i++; for(int j=0;j<1000000;j++); System.out.println("i="+i); } } } class MyRunnableB implements Runnable{ public void run(){ char c='A'-1; while(c<'Z'){ c++; for(int j=0;j<1000000;j++); System.out.println("c="+c); } } }
package thread.test04; 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 ThreadTestB { public static void main(String[] args) { ExecutorService e=Executors.newFixedThreadPool(10); Future f1=e.submit(new MyCallableA()); Future f2=e.submit(new MyCallableA()); Future f3=e.submit(new MyCallableA()); System.out.println("--Future.get()...."); try { System.out.println(f1.get()); System.out.println(f2.get()); System.out.println(f3.get()); } catch (InterruptedException e1) { e1.printStackTrace(); } catch (ExecutionException e1) { e1.printStackTrace(); } e.shutdown(); } } class MyCallableA implements Callable<String>{ public String call() throws Exception { System.out.println("開始執行Callable"); String[] ss={"zhangsan","lisi"}; long[] num=new long[2]; for(int i=0;i<1000000;i++){ num[(int)(Math.random()*2)]++; } if(num[0]>num[1]){ return ss[0]; }else if(num[0]<num[1]){ throw new Exception("棄權!"); }else{ return ss[1]; } } }