Future和FutureTask實現異步計算

開發Android APP經常會使用AsyncTask框架來異步加載資源或者異步到服務器拉消息,等任務完成後再主動更新結果到UI主線程,AsyncTask框架可以非常方便的獲取線程異步執行結果。Java 5之前,Java 並沒有提供API用於查詢線程是否執行完畢以及如何獲取線程執行的結果;Java 5 之後版本提供的併發框架包java.util.concurrent對多線程提供了更多更好的支持,Future接口和FutureTask類是異步執行任務的框架的重要組成部分,爲了更清楚的理解,我們還得從Runnable、Callable、ExecutorService等接口說起。


Runnable接口:instance可以使用new Thread(Runnable r)放到一個新線程中跑,沒有返回結果;也可以使用ExecutorService.submit(Runnable r)放到線程池中跑,返回結果爲null,等於沒有返回結果,但可以通過返回的Future對象查詢執行狀態。

public abstract void run();


Callable接口:instance只能在ExecutorService的線程池中跑,但有返回結果,也可以通過返回的Future對象查詢執行狀態。表面上可以把Callable接口簡單的理解爲有返回結果的Runnalbe接口。

V call() throws Exception;


ExecutorService接口:線程池執行調度框架

<T> Future<T> submit(Callable<T> task);

<T> Future<T> submit(Runnable task, T result);

Future<?> submit(Runnable task);


Future接口:用於查詢任務執行狀態,獲取執行結果,或者取消未執行的任務。在ExecutorService框架中,由於使用線程池,所以Runnable與Callable實例都當做任務看待,而不會當做“線程”看待,所以Future纔有取消任務執行等接口。接口中的get()方法用於獲取任務執行結果,因爲任務是異步執行的,所以我們可以在需要使用結果的時候才調用get()方法,調用時如果任務還未執行完就會阻塞直到任務完成;當然我們也可以調用get的另一重載版本get(long timeout, TimeUnit unit),當阻塞時會等待指定的時間,如果時間到而任務還未完成,那麼就會拋出TimeoutException。

    boolean cancel(boolean mayInterruptIfRunning);

    boolean isCancelled();

    boolean isDone();

    V get() throws InterruptedException, ExecutionException;

    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;


FutureTask類:集Runnable、Callable、Future於一身,它首先實現了Runnable與Future接口,然後在構造函數中還要注入Callable對象(或者變形的Callable對象:Runnable + Result),所以FutureTask類既可以使用new Thread(Runnable r)放到一個新線程中跑,也可以使用ExecutorService.submit(Runnable r)放到線程池中跑,而且兩種方式都可以獲取返回結果,但實質是一樣的,即如果要有返回結果那麼構造函數一定要注入一個Callable對象,或者注入一個Runnable對象加一個預先給定的結果(個人覺得這作用不大)。

public interface RunnableFuture<V> extends Runnable, Future<V>{
...}

public class FutureTask<V> implements RunnableFuture<V> {
public FutureTask(Callable<V> callable)
public FutureTask(Runnable runnable, V result)
...
}


示例代碼:

package com.stevex.app.forkjoin;

import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;

public class FutureTaskTest {

	public static void main(String[] args) {
		Callable<String> c = new Callable<String>() {
			public String call() {
				try {
					TimeUnit.SECONDS.sleep(new Random().nextInt(5));
				} catch (InterruptedException e) {
					e.printStackTrace();
				}

				return "Callable--"+Thread.currentThread().getName();
			}
		};

		//seed a single thread
		FutureTask<String> ft1 = new FutureTask<String>(c);
		Thread t = new Thread(ft1);
		t.start();

		Runnable r = new Runnable() {
			public void run() {
				try {
					TimeUnit.SECONDS.sleep(new Random().nextInt(5));
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		};

		FutureTask<String> ft2 = new FutureTask<String>(r, "Runnable");//give return value directly
		FutureTask<String> ft3 = new FutureTask<String>(c);
		FutureTask<String> ft4 = new FutureTask<String>(c);
		FutureTask<String> ft5 = new FutureTask<String>(c);
		FutureTask<String> ft6 = new FutureTask<String>(c);
		
		ExecutorService es = Executors.newFixedThreadPool(2);//init ExecutorService
		es.submit(ft2);
		es.submit(ft3);
		es.submit(ft4);
		es.submit(ft5);
		es.submit(ft6);
		
		
		
		try {
			TimeUnit.SECONDS.sleep(1);
			
			if(ft1.isDone()){				
				ft4.cancel(false);
				
				if(ft4.isCancelled()){
					System.out.println("task4 cancelled.");
				}
			}
			
			if(ft2.isDone()){				
				ft5.cancel(false);
				
				if(ft5.isCancelled()){
					System.out.println("task5 cancelled.");
				}
			}
			
			if(ft3.isDone()){				
				ft6.cancel(false);
				
				if(ft6.isCancelled()){
					System.out.println("task5 cancelled.");
				}
			}
							
			System.out.println("task1 retult:" + ft1.get());
			System.out.println("task2 retult:" + ft2.get());
			System.out.println("task3 retult:" + ft3.get());
			
			if(! ft4.isCancelled()){
				System.out.println("task4 retult:" + ft4.get());
			}
			
			if(! ft5.isCancelled()){
				System.out.println("task5 retult:" + ft5.get());
			}
			
			if(! ft6.isCancelled()){
				System.out.println("task6 retult:" + ft6.get());
			}	
			
			es.shutdown();//shut down ExecutorService
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		}

	}
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章