Android、Java中Runnable十分常見,在開新線程時,我們常用new Thread(Runnable).start() 或者線程池搭載Runnable。
日常使用,在不需要線程傳回時,使用的十分順手。
在需要線程傳回時,我們也有辦法搞定,比如外部變量控制流程、新增監聽接口等。
有了以上理由,Callable就被冷落了。
其實Callable能讓你的實作以及代碼更簡單。本文就是以Callable為中心來介紹的。
一、Callable與Runnable
為什麼Runnable用的人多,而Callable用的少?
1、Callable還沒出現前,大家用的都是Runnable;(Callable是JDK5出現的)
2、Runnable用法更簡單;
具體的差別如下:
1、結構
Callable接口是帶有泛型的,Callable<T>。該泛型T,也是Callable傳回值的類型;Callable接口需要實作的方法為call方法;
Runnable接口需要實作的方法為run方法;
2、使用
Callable一般配合線程池的submit方法以及FutureTask使用,Runnable一般是配合new Thread或者線程池使用;
3、傳回
Callable有傳回值,并且可以自定義傳回值類型;Runnable不行;
4、控制
Callable配合FutureTask,可以通過Future來控制任務執行、取消,檢視任務是否完成等。Runnable也可以通過Future來實作以上功能,但方式不一樣。
二、Future以及FutureTask
Callable的價值,在Future上展現。
Future是一個接口,而FutureTask是Future接口的官方唯一實作類。
1、Future接口
Future以及其實作類,是用于搭載Runnable或者Callable,執行任務、控制任務并能有效傳回結果。
Future接口内容如下(去了注釋):
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用于判斷是否已取消任務、isDone用于判斷是否已完成任務。
cancel用于取消任務,cancel的參數表示是否可以中斷正在執行中的任務。參數解釋如下:
任務未開始:無論設定參數為true還是false,都傳回true;
任務正在執行,并未結束:參數設定為true,則傳回true(成功取消),如果設定為false,則傳回false(不允許中斷正在執行的任務);
任務已結束:無論設定參數為true還是false,都傳回false;
get方法用于擷取任務執行的結果,get方法是一個阻塞方法,會等到任務執行完畢。
get(long timeout,TimeUnit unit)方法也是一個阻塞方法,等待任務執行的結果,但它隻等到逾時時間結束,如果任務還未執行完成,則傳回一個null。
2、FutureTask類
FutureTask類不止實作了Future接口,還實作了其他的接口——Runnable,如下:
public class FutureTask<V> implements RunnableFuture<V>
public interface RunnableFuture<V> extends Runnable, Future<V>
是以,FutureTask其實也可以用于new Thread(FutureTask),當然也用于線程池。
FutureTask與Future接口相比,功能擴張了很多。
首先看它的構造函數:
public FutureTask(Runnable runnable, V result)
public FutureTask(Callable<V> callable)
看到這裡,我們知道通過FutureTask,你可以傳入Callable或者Runnable,而FutureTask則搭載二者。最後,FutureTask會将自身作為新開線程或者線程池的參數。
FutureTask有一個很重要的方法,是Done(),用于表示該FutureTask中的任務已執行完畢。後面會在代碼中介紹。
三、執行個體解析
有這麼一個場景:
你需要順序的執行一系列任務,上一個任務是下一個任務的前置。下一個任務需要根據上一個任務的結果來判斷是否執行。如果上一個任務失敗則不再往下執行任務。
這些任務都是耗時的,你是在Android上執行這些任務的。
出現這個場景,在JDK5前,你用Runnable以及外部變量控制,是可以實作的。在JDK5以後,我們嘗試用Callable配合FutureTask來實作。(Runnable配合Future也是可以的,隻是不常用)。
根據場景,設計方案:
(1)串行線程池+Callable+FutureTask
(2)串行線程池+Runnable+FutureTask
(3)外部變量控制——不再示範
(4)全局監聽——不再示範
這裡示範的是1、2兩種方案。
這裡貼上為以上場景寫的工具類和方法:
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;
/**
* 擷取線程池執行個體(單例模式)
* @return
*/
public static FutureThreadPool getInstance(){
if(futureThreadPool==null){
synchronized (FutureThreadPool.class) {
futureThreadPool=new FutureThreadPool();
threadExecutor=Executors.newSingleThreadExecutor();
}
}
return futureThreadPool;
}
/**
* 線程池處理Runnable(無傳回值)
* @param runnable Runnable參數
*/
public void executeTask(Runnable runnable){
threadExecutor.execute(runnable);
}
/**
* 線程池處理Callable<T>,FutureTask<T>類型有傳回值
* @param callable Callable<T>參數
* @return FutureTask<T>
*/
public <T> FutureTask<T> executeTask(Callable<T> callable){
FutureTask<T> futureTask= new FutureTask<T>(callable);
threadExecutor.submit(futureTask);
return futureTask;
}
/**
* 線程池處理Runnable,FutureTask<T>類型有傳回值(該方法不常用)
* @param Runnable參數
* @param T Runnable任務執行完成後,傳回的辨別(注意:在調用時傳入值,将在Runnable執行完成後,原樣傳出)
* @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,任務結束時有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;
/**
* 任務結束回調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();
}
以上是建立的工具類,結合封裝了Callable/Runnable、FutureTask以及線程池,友善調用。 這裡特别注意executeFutureTask方法,在該方法中,重寫了done方法以及新增
onFinish抽象方法,可以通過回調onFinish,通知調用者任務執行結束。調用者,也可以通過FutureTask的get方法來阻塞,直到任務結束。
最後,貼上調用代碼:
package com.example.androidfuturecallabledemo;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
Button btnButton;
TextView txtTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnButton=(Button)findViewById(R.id.btn);
txtTextView=(TextView)findViewById(R.id.txt);
btnButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
try {
doSomeThing();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
});
}
private int i=0;
public void doSomeThing() throws InterruptedException, ExecutionException{
System.out.println("1 main thread ..."+" Thread id:"+Thread.currentThread().getId());
//Runnable
FutureThreadPool.getInstance().executeTask(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3*1000);
System.out.println("2 Runnable in FutureTask ..."+" Thread id:"+Thread.currentThread().getId());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
//Callable
Future<String> futureTask= FutureThreadPool.getInstance().executeTask(new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(3*1000);
return "callable back return";
}
});
System.out.println("3 Callable in FutureTask ... Result:"+futureTask.get()+" Thread id:"+Thread.currentThread().getId());
//Runnable+T result
FutureTask<Integer> futureTask2=FutureThreadPool.getInstance().executeTask(new Runnable() {
@Override
public void run() {
i=7;
}
}, 9);
System.out.println("4 Callable and <T> in FutureTask ... Result:"+futureTask2.get()+" Thread id:"+Thread.currentThread().getId()+" i="+i);
FutureThreadPool.getInstance().executeFutureTask(new myFutrueTask(new Callable<String>() {
@Override
public String call() throws Exception {
// TODO Auto-generated method stub
String resu="5 SimpleFutureTask";
System.out.println("5 SimpleFutureTask ... Result:"+resu+" Thread id:"+Thread.currentThread().getId());
return resu;
}
}));
}
class myFutrueTask extends SimpleFutureTask<String>{
public myFutrueTask(Callable<String> callable) {
super(callable);
}
@Override
public void onFinish() {
System.out.println("6 SimpleFutureTask ...Finish");
}
}
}
運作,得到的結果如下:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICNwQTNzYDMwIDMyYDM2EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
注意點
在代碼運作過程中,有個地方十分需要注意,那就是FutureTask的其中一個重載方法:
public FutureTask(Runnable runnable, V result)
在代碼的調用中,我們傳入的是一個整形i,i最初複制為0,在任務中被指派為7,但是在參數中,我們傳入的是9。看列印出來的資訊我們知道,通過get方法,我們得到的值是9,而不是其他值。
看它在源碼中的調用:
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;
}
}
在第三段代碼中,你就懂的,這個T result,你傳入什麼,在任務結束時,就傳回原值。
四、源碼
源碼位址:http://download.csdn.net/detail/yangzhaomuma/9554877