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");
}
}
}
运行,得到的结果如下:
注意点
在代码运行过程中,有个地方十分需要注意,那就是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