Java中存在Runnable、Callable、Future、FutureTask這幾個與線程相關的類或者接口,在Java中也是比較重要的幾個概念,我們通過下面的簡單示例來了解一下它們的作用于差別。
Runnable
其中Runnable應該是我們最熟悉的接口,它隻有一個run()函數,用于将耗時操作寫在其中,該函數沒有傳回值。然後使用某個線程去執行該runnable即可實作多線程,Thread類在調用start()函數後就是執行的是Runnable的run()函數。Runnable的聲明如下 :
[java] view plain copy
- public interface Runnable {
- public abstract void run();
- }
Callable
Callable與Runnable的功能大緻相似,Callable中有一個call()函數,但是call()函數有傳回值,而Runnable的run()函數不能将結果傳回給客戶程式。Callable的聲明如下 :
[java] view plain copy
- public interface Callable<V> {
- V call() throws Exception;
- }
可以看到,這是一個泛型接口,call()函數傳回的類型就是客戶程式傳遞進來的V類型。
Future
Executor就是Runnable和Callable的排程容器,Future就是對于具體的Runnable或者Callable任務的執行結果進行
取消、查詢是否完成、擷取結果、設定結果操作。get方法會阻塞,直到任務傳回結果(Future簡介)。Future聲明如下 :
[java] view plain copy
- 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;
- }
FutureTask
FutureTask則是一個RunnableFuture<V>,而RunnableFuture實作了Runnbale又實作了Futrue<V>這兩個接口,
[java] view plain copy
- public class FutureTask<V> implements RunnableFuture<V>
RunnableFuture
[java] view plain copy
- public interface RunnableFuture<V> extends Runnable, Future<V> {
- void run();
- }
另外它還可以包裝Runnable和Callable<V>, 由構造函數注入依賴。
[java] view plain copy
- public FutureTask(Callable<V> callable) {
- if (callable == null)
- throw new NullPointerException();
- this.callable = callable;
- this.state = NEW; // ensure visibility of callable
- }
- public FutureTask(Runnable runnable, V result) {
- this.callable = Executors.callable(runnable, result);
- this.state = NEW; // ensure visibility of callable
- }
可以看到,Runnable注入會被Executors.callable()函數轉換為Callable類型,即FutureTask最終都是執行Callable類型的任務。該适配函數的實作如下 :
[java] view plain copy
- public static <T> Callable<T> callable(Runnable task, T result) {
- if (task == null)
- throw new NullPointerException();
- return new RunnableAdapter<T>(task, result);
- }
RunnableAdapter擴充卡
[java] view plain copy
- 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;
- }
- }
由于FutureTask實作了Runnable,是以它既可以通過Thread包裝來直接執行,也可以送出給ExecuteService來執行。
并且還可以直接通過get()函數擷取執行結果,該函數會阻塞,直到結果傳回。是以FutureTask既是Future、
Runnable,又是包裝了Callable( 如果是Runnable最終也會被轉換為Callable ), 它是這兩者的合體。
簡單示例
[java] view plain copy
- package com.effective.java.concurrent.task;
- import java.util.concurrent.Callable;
- import java.util.concurrent.ExecutionException;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.Future;
- import java.util.concurrent.FutureTask;
- public class RunnableFutureTask {
- static ExecutorService mExecutor = Executors.newSingleThreadExecutor();
- public static void main(String[] args) {
- runnableDemo();
- futureDemo();
- }
- static void runnableDemo() {
- new Thread(new Runnable() {
- @Override
- public void run() {
- System.out.println("runnable demo : " + fibc(20));
- }
- }).start();
- }
- static void futureDemo() {
- try {
- Future<?> result = mExecutor.submit(new Runnable() {
- @Override
- public void run() {
- fibc(20);
- }
- });
- System.out.println("future result from runnable : " + result.get());
- Future<Integer> result2 = mExecutor.submit(new Callable<Integer>() {
- @Override
- public Integer call() throws Exception {
- return fibc(20);
- }
- });
- System.out
- .println("future result from callable : " + result2.get());
- FutureTask<Integer> futureTask = new FutureTask<Integer>(
- new Callable<Integer>() {
- @Override
- public Integer call() throws Exception {
- return fibc(20);
- }
- });
- // 送出futureTask
- mExecutor.submit(futureTask) ;
- System.out.println("future result from futureTask : "
- + futureTask.get());
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
- }
- }
- static int fibc(int num) {
- if (num == 0) {
- return 0;
- }
- if (num == 1) {
- return 1;
- }
- return fibc(num - 1) + fibc(num - 2);
- }
- }