打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Android(Java)之多线程结果返回——Future 、FutureTask、Callable、Runnable

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接口内容如下(去了注释):

  1. package java.util.concurrent;  
  2.   
  3.   
  4. public interface Future<V> {  
  5.      
  6.     boolean cancel(boolean mayInterruptIfRunning);  
  7.   
  8.     boolean isCancelled();  
  9.   
  10.     boolean isDone();  
  11.       
  12.     V get() throws InterruptedException, ExecutionException;   
  13.       
  14.     V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;  
  15.       
  16.     }  

其中,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,如下:

  1. public class FutureTask<V> implements RunnableFuture<V>  
  1. public interface RunnableFuture<V> extends Runnable, Future<V>  
因此,FutureTask其实也可以用于new Thread(FutureTask),当然也用于线程池。

FutureTask与Future接口相比,功能扩张了很多。

首先看它的构造函数:

  1. public FutureTask(Runnable runnable, V result)  
  1. 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两种方案。

这里贴上为以上场景写的工具类和方法:

  1. package com.example.androidfuturecallabledemo;  
  2.   
  3. import java.util.concurrent.Callable;  
  4. import java.util.concurrent.ExecutorService;  
  5. import java.util.concurrent.Executors;  
  6. import java.util.concurrent.FutureTask;  
  7.   
  8. public class FutureThreadPool {  
  9.   
  10.     private FutureThreadPool(){}  
  11.     private volatile static FutureThreadPool futureThreadPool;  
  12.     private static ExecutorService threadExecutor;  
  13.     /**  
  14.      * 获取线程池实例(单例模式)  
  15.      * @return  
  16.      */  
  17.     public static FutureThreadPool getInstance(){  
  18.         if(futureThreadPool==null){  
  19.             synchronized (FutureThreadPool.class) {  
  20.                 futureThreadPool=new FutureThreadPool();  
  21.                 threadExecutor=Executors.newSingleThreadExecutor();  
  22.             }  
  23.         }  
  24.         return futureThreadPool;  
  25.     }  
  26.       
  27.       
  28.     /**  
  29.      * 线程池处理Runnable(无返回值)  
  30.      * @param runnable Runnable参数  
  31.      */  
  32.     public void executeTask(Runnable runnable){  
  33.         threadExecutor.execute(runnable);  
  34.     }  
  35.       
  36.     /**  
  37.      * 线程池处理Callable<T>,FutureTask<T>类型有返回值  
  38.      * @param callable Callable<T>参数  
  39.      * @return FutureTask<T>  
  40.      */  
  41.     public <T> FutureTask<T> executeTask(Callable<T> callable){  
  42.         FutureTask<T> futureTask= new FutureTask<T>(callable);  
  43.         threadExecutor.submit(futureTask);  
  44.         return futureTask;  
  45.           
  46.     }  
  47.     /**  
  48.      * 线程池处理Runnable,FutureTask<T>类型有返回值(该方法不常用)  
  49.      * @param Runnable参数  
  50.      * @param T Runnable任务执行完成后,返回的标识(注意:在调用时传入值,将在Runnable执行完成后,原样传出)  
  51.      * @return FutureTask<T>  
  52.      */  
  53.     public <T> FutureTask<T> executeTask(Runnable runnable,T result){  
  54.         FutureTask<T> futureTask= new FutureTask<T>(runnable,result);  
  55.         threadExecutor.submit(futureTask);  
  56.         return futureTask;  
  57.     }  
  58.     /**  
  59.      * 线程池处理自定义SimpleFutureTask,任务结束时有onFinish事件返回提示  
  60.      * @param mFutureTask 自定义SimpleFutureTask  
  61.      */  
  62.     public  <T> FutureTask<T>  executeFutureTask(SimpleFutureTask<T> mFutureTask){  
  63.         threadExecutor.submit(mFutureTask);  
  64.         return mFutureTask;  
  65.     }  
  66.       
  67.       
  68. }  

  1. package com.example.androidfuturecallabledemo;  
  2.   
  3. import java.util.concurrent.Callable;  
  4. import java.util.concurrent.FutureTask;  
  5. /**  
  6.  * 任务结束回调onFinish的添加  
  7.  * @author zhao.yang  
  8.  *  
  9.  * @param <T>  
  10.  */  
  11. public abstract class SimpleFutureTask<T> extends FutureTask<T>{  
  12.   
  13.     public SimpleFutureTask(Callable<T> callable) {  
  14.         super(callable);  
  15.     }  
  16.   
  17.     @Override  
  18.     protected void done() {  
  19.         onFinish();  
  20.     }  
  21.       
  22.     public abstract void onFinish();  
  23.   
  24.       
  25. }  

以上是创建的工具类,结合封装了Callable/Runnable、FutureTask以及线程池,方便调用。这里特别注意executeFutureTask方法,在该方法中,重写了done方法以及新增

onFinish抽象方法,可以通过回调onFinish,通知调用者任务执行结束。调用者,也可以通过FutureTask的get方法来阻塞,直到任务结束


最后,贴上调用代码:

  1. package com.example.androidfuturecallabledemo;  
  2.   
  3. import java.util.concurrent.Callable;  
  4. import java.util.concurrent.ExecutionException;  
  5. import java.util.concurrent.Future;  
  6. import java.util.concurrent.FutureTask;  
  7.   
  8. import android.app.Activity;  
  9. import android.os.Bundle;  
  10. import android.view.View;  
  11. import android.view.View.OnClickListener;  
  12. import android.widget.Button;  
  13. import android.widget.TextView;  
  14.   
  15. public class MainActivity extends Activity {  
  16.   
  17.     Button btnButton;  
  18.     TextView txtTextView;  
  19.     @Override  
  20.     protected void onCreate(Bundle savedInstanceState) {  
  21.         super.onCreate(savedInstanceState);  
  22.         setContentView(R.layout.activity_main);  
  23.         btnButton=(Button)findViewById(R.id.btn);  
  24.         txtTextView=(TextView)findViewById(R.id.txt);  
  25.           
  26.         btnButton.setOnClickListener(new OnClickListener() {  
  27.               
  28.             @Override  
  29.             public void onClick(View v) {  
  30.                 try {  
  31.                     doSomeThing();  
  32.                 } catch (InterruptedException e) {  
  33.                     e.printStackTrace();  
  34.                 } catch (ExecutionException e) {  
  35.                     e.printStackTrace();  
  36.                 }  
  37.             }  
  38.         });  
  39.     }  
  40.     private int i=0;  
  41.     public void doSomeThing() throws InterruptedException, ExecutionException{  
  42.         System.out.println("1 main thread ..."+" Thread id:"+Thread.currentThread().getId());  
  43.         //Runnable  
  44.         FutureThreadPool.getInstance().executeTask(new Runnable() {  
  45.               
  46.             @Override  
  47.             public void run() {  
  48.                 try {  
  49.                     Thread.sleep(3*1000);  
  50.                     System.out.println("2 Runnable in FutureTask ..."+" Thread id:"+Thread.currentThread().getId());  
  51.                 } catch (InterruptedException e) {  
  52.                     // TODO Auto-generated catch block  
  53.                     e.printStackTrace();  
  54.                 }  
  55.                   
  56.             }  
  57.         });  
  58.       
  59.         //Callable   
  60.         Future<String> futureTask= FutureThreadPool.getInstance().executeTask(new Callable<String>() {  
  61.               
  62.             @Override  
  63.             public String call() throws Exception {  
  64.                 Thread.sleep(3*1000);  
  65.                 return "callable back return";  
  66.             }  
  67.         });  
  68.          System.out.println("3 Callable in FutureTask ... Result:"+futureTask.get()+" Thread id:"+Thread.currentThread().getId());  
  69.           
  70.        //Runnable+T result  
  71.      FutureTask<Integer> futureTask2=FutureThreadPool.getInstance().executeTask(new Runnable() {  
  72.           
  73.         @Override  
  74.         public void run() {  
  75.                  i=7;             
  76.         }  
  77.     }, 9);  
  78.        
  79.      System.out.println("4 Callable and <T> in FutureTask ... Result:"+futureTask2.get()+" Thread id:"+Thread.currentThread().getId()+" i="+i);  
  80.   
  81.           
  82.          FutureThreadPool.getInstance().executeFutureTask(new myFutrueTask(new Callable<String>() {  
  83.   
  84.             @Override  
  85.             public String call() throws Exception {  
  86.                 // TODO Auto-generated method stub  
  87.                 String resu="5 SimpleFutureTask";  
  88.                  System.out.println("5 SimpleFutureTask ... Result:"+resu+" Thread id:"+Thread.currentThread().getId());  
  89.                 return resu;  
  90.             }  
  91.         }));  
  92.     }  
  93.       
  94.     class myFutrueTask extends SimpleFutureTask<String>{  
  95.   
  96.         public myFutrueTask(Callable<String> callable) {  
  97.             super(callable);  
  98.         }  
  99.   
  100.         @Override  
  101.         public void onFinish() {  
  102.              System.out.println("6 SimpleFutureTask ...Finish");  
  103.         }  
  104.           
  105.     }  
  106.   
  107. }  

运行,得到的结果如下:



注意点


在代码运行过程中,有个地方十分需要注意,那就是FutureTask的其中一个重载方法:

  1. public FutureTask(Runnable runnable, V result)  
在代码的调用中,我们传入的是一个整形i,i最初复制为0,在任务中被赋值为7,但是在参数中,我们传入的是9。看打印出来的信息我们知道,通过get方法,我们得到的值是9,而不是其他值。

看它在源码中的调用:

  1. public FutureTask(Runnable runnable, V result) {  
  2.       this.callable = Executors.callable(runnable, result);  
  3.       this.state = NEW;       // ensure visibility of callable  
  4.   }  

  1. public static <T> Callable<T> callable(Runnable task, T result) {  
  2.        if (task == null)  
  3.            throw new NullPointerException();  
  4.        return new RunnableAdapter<T>(task, result);  
  5.    }  

  1. static final class RunnableAdapter<T> implements Callable<T> {  
  2.       final Runnable task;  
  3.       final T result;  
  4.       RunnableAdapter(Runnable task, T result) {  
  5.           this.task = task;  
  6.           this.result = result;  
  7.       }  
  8.       public T call() {  
  9.           task.run();  
  10.           return result;  
  11.       }  
  12.   }  

在第三段代码中,你就懂的,这个T result,你传入什么,在任务结束时,就传回原值。

四、源码

源码地址:http://download.csdn.net/detail/yangzhaomuma/9554877




本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
实现简单服务器学习多线程与Executor
深入理解AsyncTask的工作原理
超全的多线程面经附答案
Java多线程之基本概念
Java Thread多线程全面解析
Java多线程21:多线程下的其他组件之CyclicBarrier、Callable、Future和FutureTask
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服