Android、Java中Runnable十分常見,在開新線程時(shí),我們常用new Thread(Runnable).start() 或者線程池搭載Runnable。
日常使用,在不需要線程返回時(shí),使用的十分順手。
在需要線程返回時(shí),我們也有辦法搞定,比如外部變量控制流程、新增監(jiān)聽接口等。
有了以上理由,Callable就被冷落了。
其實(shí)Callable能讓你的實(shí)現(xiàn)以及代碼更簡(jiǎn)單。本文就是以Callable為中心來介紹的。
一、Callable與Runnable
為什么Runnable用的人多,而Callable用的少?
1、Callable還沒出現(xiàn)前,大家用的都是Runnable;(Callable是JDK5出現(xiàn)的)
2、Runnable用法更簡(jiǎn)單;
具體的區(qū)別如下:
1、結(jié)構(gòu)
Callable接口是帶有泛型的,Callable<T>。該泛型T,也是Callable返回值的類型;Callable接口需要實(shí)現(xiàn)的方法為call方法;
Runnable接口需要實(shí)現(xiàn)的方法為run方法;
2、使用
Callable一般配合線程池的submit方法以及FutureTask使用,Runnable一般是配合new Thread或者線程池使用;
3、返回
Callable有返回值,并且可以自定義返回值類型;Runnable不行;
4、控制
Callable配合FutureTask,可以通過Future來控制任務(wù)執(zhí)行、取消,查看任務(wù)是否完成等。Runnable也可以通過Future來實(shí)現(xiàn)以上功能,但方式不一樣。
二、Future以及FutureTask
Callable的價(jià)值,在Future上體現(xiàn)。
Future是一個(gè)接口,而FutureTask是Future接口的官方唯一實(shí)現(xiàn)類。
1、Future接口
Future以及其實(shí)現(xiàn)類,是用于搭載Runnable或者Callable,執(zhí)行任務(wù)、控制任務(wù)并能有效返回結(jié)果。
Future接口內(nèi)容如下(去了注釋):
- package 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;
-
- }
其中,isCancelled用于判斷是否已取消任務(wù)、isDone用于判斷是否已完成任務(wù)。
cancel用于取消任務(wù),cancel的參數(shù)表示是否可以中斷正在執(zhí)行中的任務(wù)。參數(shù)解釋如下:
任務(wù)未開始:無論設(shè)置參數(shù)為true還是false,都返回true;
任務(wù)正在執(zhí)行,并未結(jié)束:參數(shù)設(shè)置為true,則返回true(成功取消),如果設(shè)置為false,則返回false(不允許中斷正在執(zhí)行的任務(wù));
任務(wù)已結(jié)束:無論設(shè)置參數(shù)為true還是false,都返回false;
get方法用于獲取任務(wù)執(zhí)行的結(jié)果,get方法是一個(gè)阻塞方法,會(huì)等到任務(wù)執(zhí)行完畢。
get(long timeout,TimeUnit unit)方法也是一個(gè)阻塞方法,等待任務(wù)執(zhí)行的結(jié)果,但它只等到超時(shí)時(shí)間結(jié)束,如果任務(wù)還未執(zhí)行完成,則返回一個(gè)null。
2、FutureTask類
FutureTask類不止實(shí)現(xiàn)了Future接口,還實(shí)現(xiàn)了其他的接口——Runnable,如下:
- public class FutureTask<V> implements RunnableFuture<V>
- public interface RunnableFuture<V> extends Runnable, Future<V>
因此,F(xiàn)utureTask其實(shí)也可以用于new Thread(FutureTask),當(dāng)然也用于線程池。
FutureTask與Future接口相比,功能擴(kuò)張了很多。
首先看它的構(gòu)造函數(shù):
- public FutureTask(Runnable runnable, V result)
- public FutureTask(Callable<V> callable)
看到這里,我們知道通過FutureTask,你可以傳入Callable或者Runnable,而FutureTask則搭載二者。最后,F(xiàn)utureTask會(huì)將自身作為新開線程或者線程池的參數(shù)。
FutureTask有一個(gè)很重要的方法,是Done(),用于表示該FutureTask中的任務(wù)已執(zhí)行完畢。后面會(huì)在代碼中介紹。
三、實(shí)例解析
有這么一個(gè)場(chǎng)景:
你需要順序的執(zhí)行一系列任務(wù),上一個(gè)任務(wù)是下一個(gè)任務(wù)的前置。下一個(gè)任務(wù)需要根據(jù)上一個(gè)任務(wù)的結(jié)果來判斷是否執(zhí)行。如果上一個(gè)任務(wù)失敗則不再往下執(zhí)行任務(wù)。
這些任務(wù)都是耗時(shí)的,你是在Android上執(zhí)行這些任務(wù)的。
出現(xiàn)這個(gè)場(chǎng)景,在JDK5前,你用Runnable以及外部變量控制,是可以實(shí)現(xiàn)的。在JDK5以后,我們嘗試用Callable配合FutureTask來實(shí)現(xiàn)。(Runnable配合Future也是可以的,只是不常用)。
根據(jù)場(chǎng)景,設(shè)計(jì)方案:
(1)串行線程池+Callable+FutureTask
(2)串行線程池+Runnable+FutureTask
(3)外部變量控制——不再演示
(4)全局監(jiān)聽——不再演示
這里演示的是1、2兩種方案。
這里貼上為以上場(chǎng)景寫的工具類和方法:
- package com.example.androidfuturecallabledemo;
-
- import java.util.concurrent.Callable;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.FutureTask;
-
- public class FutureThreadPool {
-
- private FutureThreadPool(){}
- private volatile static FutureThreadPool futureThreadPool;
- private static ExecutorService threadExecutor;
- /**
- * 獲取線程池實(shí)例(單例模式)
- * @return
- */
- public static FutureThreadPool getInstance(){
- if(futureThreadPool==null){
- synchronized (FutureThreadPool.class) {
- futureThreadPool=new FutureThreadPool();
- threadExecutor=Executors.newSingleThreadExecutor();
- }
- }
- return futureThreadPool;
- }
-
-
- /**
- * 線程池處理Runnable(無返回值)
- * @param runnable Runnable參數(shù)
- */
- public void executeTask(Runnable runnable){
- threadExecutor.execute(runnable);
- }
-
- /**
- * 線程池處理Callable<T>,F(xiàn)utureTask<T>類型有返回值
- * @param callable Callable<T>參數(shù)
- * @return FutureTask<T>
- */
- public <T> FutureTask<T> executeTask(Callable<T> callable){
- FutureTask<T> futureTask= new FutureTask<T>(callable);
- threadExecutor.submit(futureTask);
- return futureTask;
-
- }
- /**
- * 線程池處理Runnable,F(xiàn)utureTask<T>類型有返回值(該方法不常用)
- * @param Runnable參數(shù)
- * @param T Runnable任務(wù)執(zhí)行完成后,返回的標(biāo)識(shí)(注意:在調(diào)用時(shí)傳入值,將在Runnable執(zhí)行完成后,原樣傳出)
- * @return FutureTask<T>
- */
- public <T> FutureTask<T> executeTask(Runnable runnable,T result){
- FutureTask<T> futureTask= new FutureTask<T>(runnable,result);
- threadExecutor.submit(futureTask);
- return futureTask;
- }
- /**
- * 線程池處理自定義SimpleFutureTask,任務(wù)結(jié)束時(shí)有onFinish事件返回提示
- * @param mFutureTask 自定義SimpleFutureTask
- */
- public <T> FutureTask<T> executeFutureTask(SimpleFutureTask<T> mFutureTask){
- threadExecutor.submit(mFutureTask);
- return mFutureTask;
- }
-
-
- }
- package com.example.androidfuturecallabledemo;
-
- import java.util.concurrent.Callable;
- import java.util.concurrent.FutureTask;
- /**
- * 任務(wù)結(jié)束回調(diào)onFinish的添加
- * @author zhao.yang
- *
- * @param <T>
- */
- public abstract class SimpleFutureTask<T> extends FutureTask<T>{
-
- public SimpleFutureTask(Callable<T> callable) {
- super(callable);
- }
-
- @Override
- protected void done() {
- onFinish();
- }
-
- public abstract void onFinish();
-
-
- }
以上是創(chuàng)建的工具類,結(jié)合封裝了Callable/Runnable、FutureTask以及線程池,方便調(diào)用。這里特別注意executeFutureTask方法,在該方法中,重寫了done方法以及新增
onFinish抽象方法,可以通過回調(diào)onFinish,通知調(diào)用者任務(wù)執(zhí)行結(jié)束。調(diào)用者,也可以通過FutureTask的get方法來阻塞,直到任務(wù)結(jié)束。
最后,貼上調(diào)用代碼:
運(yùn)行,得到的結(jié)果如下:

注意點(diǎn)
在代碼運(yùn)行過程中,有個(gè)地方十分需要注意,那就是FutureTask的其中一個(gè)重載方法:
- public FutureTask(Runnable runnable, V result)
在代碼的調(diào)用中,我們傳入的是一個(gè)整形i,i最初復(fù)制為0,在任務(wù)中被賦值為7,但是在參數(shù)中,我們傳入的是9。看打印出來的信息我們知道,通過get方法,我們得到的值是9,而不是其他值。
看它在源碼中的調(diào)用:
- public FutureTask(Runnable runnable, V result) {
- this.callable = Executors.callable(runnable, result);
- this.state = NEW; // ensure visibility of callable
- }
- public static <T> Callable<T> callable(Runnable task, T result) {
- if (task == null)
- throw new NullPointerException();
- return new RunnableAdapter<T>(task, result);
- }
- static final class RunnableAdapter<T> implements Callable<T> {
- final Runnable task;
- final T result;
- RunnableAdapter(Runnable task, T result) {
- this.task = task;
- this.result = result;
- }
- public T call() {
- task.run();
- return result;
- }
- }
在第三段代碼中,你就懂的,這個(gè)T result,你傳入什么,在任務(wù)結(jié)束時(shí),就傳回原值。
四、源碼
源碼地址:http://download.csdn.net/detail/yangzhaomuma/9554877
|