java Runnable、Callable、FutureTask 和線程池


一:Runnable、Callable、FutureTask簡介

(1)Runnable:其中的run()方法沒有返回值。

①.Runnable對象可以直接扔給Thread創建線程實例,並且創建的線程實例與Runnable綁定,線程實例調用start()方法時,Runnable任務就開始真正在線程中執行。

②.Runnable對象也可以直接扔給線程池對象的execute方法和submit方法,讓線程池為其綁定池中的線程來執行。

③.Runnable對象也可以進一步封裝成FutureTask對象之后再扔給線程池的execute方法和submit方法。

(2)Callable:功能相比Runnable來說少很多,不能用來創建線程,也不能直接扔給線程池的execute方法,但是可以使用submit。其中的call方法有返回值,也進一步封裝成Future,再由線程執行。

(3)FutureTask:是對Runnable和Callable的進一步封裝,並且這種任務是有返回值的,它的返回值存在FutureTask類的一個名叫outcome的數據成員中。(疑惑)那么為什么可以把沒有返回值的Runnable也封裝成FutureTask呢,馬上我們會討論這個問題。相比直接把Runnable和Callable扔給線程池,FutureTask的功能更多,它可以監視任務在池子中的狀態。用Runnable和Callable創建FutureTask的方法稍有不同。

(4)Runable 轉換 Callable

  Callable<Object> callable = Executors.callable(new MyRunnable());

(5)FutureTask 的使用

FutureTask futureTask = new FutureTask(new CallableTask());
         new Thread(futureTask).start();//或者由線程池執行

FutureTask類實現了RunnableFuture接口,而RunnableFuture接口又繼承了Runnable接口和Future接口,所以FutureTask類本質上是Runnable接口的實現類,且兼具Future接口的特性,我們知道線程池的execute方法和submit方法都可以執行Runable任務,所以同樣可以執行FutureTask任務。

//FutureTask 構造函數
    public FutureTask(Callable<V> callable);
    public FutureTask(Runnable runnable, V result); 
 FutureTask類有一個done方法,該方法在任務執行完畢時自動回調,我們可以重寫該方法並在該方法中調用get()方法獲取任務執行的結果,並且因為任務已經執行完畢,此時調用get()方法可以直接得到結果,所以並不會阻塞線程。

二:線程池

(1)Executor 接口 只提供一個void execute(Runnable command),只能執行Runnable 任務,但是不能執行Callable 任務。所以提供了ExecutorService 接口。

(2)ExecutorService 接口 其繼承了Executor,提供了submit()方法重載可以執行Runnable 任務和Callable任務。ExecutorService 可以創建四種線程池
①newSingleThreadExecutor 創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行。

   ExecutorService  singleThreadExecutor = Executors.newSingleThreadExecutor(); //返回ExecutorService
   singleThreadExecutor .submit() //可以是Runable任務或者Callable任務
   

②newFixedThreadPool 創建一個定長線程池,可控制線程最大並發數,超出的線程會在隊列中等待。

   ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3); //返回ExecutorService
   fixedThreadPool .submit();//可以是Runable任務或者Callable任務

③newCachedThreadPool創建一個可緩存線程池,如果處理需求超過線程池長度,可靈活回收空閑線程,若無可回收,則新建線程,線程池無限大,舉例:要執行兩個人,如果在第二個任務執行前,第一個任務已經完成,則會復用第一個線程去執行第二個任務,不創建新的線程。

   ExecutorService cachedThreadPool = Executors.newCachedThreadPool();  //返回ExecutorService
  cachedThreadPool.submit();// 可以是Runable任務或者Callable任務

**④newScheduledThreadPool **創建一個定長線程池,支持定時及周期性任務執行。

   ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5); //返回ScheduledExecutorService  其繼承了ExecutorService
   scheduledThreadPool .scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit);
   
   /*
   ScheduledExecutorService接口 主要有以下方法,由ScheduledThreadPoolExecutor實現
    1,<V> ScheduledFuture<V>	schedule(Callable<V> callable, long delay, TimeUnit unit)  //執行Callable
    2,ScheduledFuture<?>	schedule(Runnable command, long delay, TimeUnit unit)  //執行Runable
    3,ScheduledFuture<?>	scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)  //以任務執行開始時間為起點,過多久執行一次
    4,ScheduledFuture<?>	scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) //以任務執行結束時間為起點,過多久執行一次
  */
   


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM