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

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




猜你喜欢

转载自blog.csdn.net/yangzhaomuma/article/details/51722779