亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

比較java中Future與FutureTask之間的關(guān)系

 更新時(shí)間:2018年10月16日 14:21:05   投稿:laozhang  
在本篇文章里我們給大家分享了java中Future與FutureTask之間的關(guān)系的內(nèi)容,有需要的朋友們可以跟著學(xué)習(xí)下。

Future與FutureTask都是用于獲取線程執(zhí)行的返回結(jié)果。下面我們就對兩者之間的關(guān)系與使用進(jìn)行一個(gè)大致的介紹與分析

一、Future與FutureTask介紹:

Future位于java.util.concurrent包下,它是一個(gè)接口

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;
}

Future接口中聲明了5個(gè)方法,下面介紹一下每個(gè)方法的作用:

cancel方法用來取消任務(wù),取消成功則返回true,取消失敗則返回false。參數(shù)mayInterruptIfRunning設(shè)置為false,表示不允許在線程運(yùn)行時(shí)中斷,設(shè)置為true則表示允許。具體可分為以下三種情況:

1、如果任務(wù)已經(jīng)完成,則無論mayInterruptIfRunning為true還是false,都返回false,這是因?yàn)槟阋∠娜蝿?wù)已經(jīng)完成,則認(rèn)為取消任務(wù)失敗;

2、如果任務(wù)正在執(zhí)行,則無論mayInterruptIfRunning為true還是false,都返回true。只不過mayInterruptIfRunning為true時(shí)線程會被中斷,false時(shí)線程不會被中斷會執(zhí)行完。

3、如果任務(wù)還沒有執(zhí)行,則無論mayInterruptIfRunning為true還是false,都返回true。

isCancelled方法用于判斷任務(wù)是否被取消成功,cancel方法成功則返回 true,反之則為false。

isDone用于判斷任務(wù)是否完成, 如果任務(wù)完成則返回true。任務(wù)完成包括正常結(jié)束、任務(wù)被取消、任務(wù)發(fā)生異常,都返回true

get()方法用來獲取執(zhí)行結(jié)果,這個(gè)方法會產(chǎn)生阻塞,會一直等到任務(wù)執(zhí)行完畢才返回;

get(long timeout, TimeUnit unit)用來獲取執(zhí)行結(jié)果,如果在指定時(shí)間內(nèi),還沒獲取到結(jié)果,拋出 java.util.concurrent.TimeoutException 異常

FutureTask 實(shí)現(xiàn)了RunnableFuture接口,而RunnableFuture則繼承了Future<V>與Runnable接口,所以 FutureTask不僅實(shí)現(xiàn)了 Future<V>接口的所有方法,還具有自己的run方法,我們可以看下它的類圖

二、Future與FutureTask使用與分析

1、使用Future時(shí),我們需要實(shí)現(xiàn)Callable接口,并通過ExecutorService接口的submit方法獲取返回的Future對象,

2、使用FutureTask時(shí),根據(jù)FutureTask的構(gòu)造函數(shù)可以看到FutureTask既可以接收Callable的實(shí)現(xiàn)類,也可以接收Runnable的實(shí)現(xiàn)類。當(dāng)你傳入的是Callable的實(shí)現(xiàn)類時(shí),可以獲取線程執(zhí)行的結(jié)果;傳入Runnable的實(shí)現(xiàn)類時(shí),由于Runnable的實(shí)現(xiàn)沒有返回值,需要傳入一個(gè)你設(shè)置的線程完成標(biāo)識,也就是result,然后當(dāng)線程結(jié)束時(shí)會把你傳入的result原值返回給你,F(xiàn)utureTask的構(gòu)造函數(shù)具體如下:

public class FutureTask<V> implements RunnableFuture<V>{
  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);//runnable轉(zhuǎn)化為callable 
  this.state = NEW;  // ensure visibility of callable
  }
}

接下來我們看下Future與FutureTask具體的使用代碼:

// 執(zhí)行任務(wù) 實(shí)現(xiàn)Runnable
 FutureTaskJobRunnable taskRun = new FutureTaskJobRunnable();
 // 執(zhí)行任務(wù) 實(shí)現(xiàn)Callable
 FutureTaskJobCallable taskCall = new FutureTaskJobCallable();
 String val = "ok";
 // 線程運(yùn)行成功后把,返回你傳入的val值
 FutureTask<String> futureTaskRun = new FutureTask<String>(taskRun, val);
 // 線程運(yùn)行,返回線程執(zhí)行的結(jié)果
 FutureTask<String> futureTaskCall = new FutureTask<String>(taskCall);
 //聲明線程池
 ExecutorService executor = Executors.newCachedThreadPool();  
 //Future
 Future<String> future = executor.submit(taskCall);
 System.out.println(future.get());
 //FutureTask
 executor.submit(futureTaskCall);
 System.out.println(futureTaskCall.get());
 //FutureTask自定義線程執(zhí)行
 new Thread(futureTaskRun).start();
 System.out.println(futureTaskRun.get());
public class FutureTaskJobCallable implements Callable<String>{
  
 public String call() throws Exception {
  System.out.println("FutureTaskJobCallable已經(jīng)執(zhí)行了哦");
  Thread.sleep(1000);
  return "返回結(jié)果";
 }
}
public class FutureTaskJobRunnable implements Runnable {
 public void run() {
  try {
   Thread.sleep(1000);
  } catch (InterruptedException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  System.out.println("FutureTaskJobRunnable已經(jīng)執(zhí)行了哦");
 }
}

根據(jù)上面的代碼我們從ExecutorService接口中submit方法入手,看下AbstractExecutorService類對submit方法的具體實(shí)現(xiàn)。

public Future<?> submit(Runnable task) {
  if (task == null) throw new NullPointerException();
  RunnableFuture<Void> ftask = newTaskFor(task, null);
  execute(ftask);
  return ftask;
 }
 public <T> Future<T> submit(Runnable task, T result) {
  if (task == null) throw new NullPointerException();
  RunnableFuture<T> ftask = newTaskFor(task, result);
  execute(ftask);
  return ftask;
 }
 public <T> Future<T> submit(Callable<T> task) {
  if (task == null) throw new NullPointerException();
  RunnableFuture<T> ftask = newTaskFor(task);
  execute(ftask);
  return ftask;
 }
 protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
  return new FutureTask<T>(runnable, value);
 }
 protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
  return new FutureTask<T>(callable);
 }

可以看到當(dāng)你使用submit方法提交任務(wù)時(shí),都會通過newTaskFor方法轉(zhuǎn)換成FutureTask對象,所以我們具體分析下上面代碼中的三種情況:

1、如果你傳入的是自己實(shí)現(xiàn)的Runaable類或者Callable類,那么sumbit方法自然會幫你自動封裝為FutureTask對象,運(yùn)行后通過Future對象獲取結(jié)果。

2、你傳入的已經(jīng)是個(gè)自己構(gòu)造的FutureTask對象,由于FutureTask其實(shí)是實(shí)現(xiàn)了Runnable接口的,它本身就是個(gè)Runaable實(shí)現(xiàn)類, sumbit方法還是會將它視為Runnable類來進(jìn)行封裝,并最終會執(zhí)行FutureTask自己的run方法,一系列實(shí)現(xiàn)都在你傳入的FutureTask對象內(nèi)完成,所以你可以直接通過自己構(gòu)建的FutureTask獲取結(jié)果;

3、自己單獨(dú)聲明線程運(yùn)行,跟第2點(diǎn)類似,F(xiàn)utureTask本身就是個(gè)Runnabel實(shí)現(xiàn)類,自然可以做為參數(shù)傳入Thread運(yùn)行;

那么我們把自定義的Runnable、Callable實(shí)現(xiàn)類做為參數(shù)構(gòu)造FutureTask后,F(xiàn)uttureTask是如何運(yùn)行的呢,我們可以看下FuttureTask中具體的代碼實(shí)現(xiàn)

//你傳入的Runnable與Callable實(shí)現(xiàn)類都會在構(gòu)造函數(shù)中轉(zhuǎn)化為Callable
private Callable<V> callable;
 public void run() {
  if (state != NEW ||
   !UNSAFE.compareAndSwapObject(this, runnerOffset,
           null, Thread.currentThread()))
   return;
  try {
   Callable<V> c = callable;//你傳入的實(shí)現(xiàn)類
   if (c != null && state == NEW) {
    V result;//返回值
    boolean ran;
    try {
     result = c.call();//運(yùn)行后返回結(jié)果
     ran = true;
    } catch (Throwable ex) {
     result = null;
     ran = false;
     setException(ex);
    }
    if (ran)
     set(result);
   }
  } finally {
   // runner must be non-null until state is settled to
   // prevent concurrent calls to run()
   runner = null;
   // state must be re-read after nulling runner to prevent
   // leaked interrupts
   int s = state;
   if (s >= INTERRUPTING)
    handlePossibleCancellationInterrupt(s);
  }
 }

可以看到FutureTask類本身的run方法,就是執(zhí)行Runnable、Callable的實(shí)現(xiàn)類并獲取返回結(jié)果的過程。

所以ExecutorService接口中submit方法歸根結(jié)底還是要把你傳入的對象封裝成FutureTask對象,并通過FutureTask類的內(nèi)部實(shí)現(xiàn)來獲取結(jié)果的,返回的Future接口對象也要依賴于FutureTask實(shí)例化的,所以無論是直接傳入自己的Runnable、Callable實(shí)現(xiàn)類還是構(gòu)建FutureTask傳入,本質(zhì)上都是通過FutureTask去實(shí)現(xiàn),沒有什么區(qū)別;

相關(guān)文章

最新評論