源碼翻譯師1 Android-Lite-Go(Part2)

(2)Java Executor框架
參考:
Java Executor框架

Executor框架是指java5中引入的一系列并發(fā)庫(kù)中與executor相關(guān)的功能類,包括Executor、Executors、ExecutorService、CompletionService、Future、Callable等。通過學(xué)習(xí)Executor框架能夠更加清楚明晰作者的寫作思路和來源。


Class Executor

開始的開始 Executor

public interface Executor {
    void execute(Runnable command); 
}

Executor接口是Executor框架中最基礎(chǔ)的部分,定義了一個(gè)用于執(zhí)行Runnable的execute方法。它沒有直接的實(shí)現(xiàn)類,有一個(gè)重要的子接口ExecutorService。

ExecutorService
ExecutorService接口繼承自Executor接口,定義了終止、提交任務(wù)、跟蹤任務(wù)返回結(jié)果等方法。

Runnable、Callable、Future

// 實(shí)現(xiàn)Runnable接口的類將被Thread執(zhí)行,表示一個(gè)基本的任務(wù)
public interface Runnable {
    // run方法就是它所有的內(nèi)容,就是實(shí)際執(zhí)行的任務(wù)
    public abstract void run();
}

// Callable同樣是任務(wù),與Runnable接口的區(qū)別在于它接收泛型,同時(shí)它執(zhí)行任務(wù)后帶有返回內(nèi)容
public interface Callable<V> {
    // 相對(duì)于run方法的帶有返回值的call方法
    V call() throws Exception;
}

// Future代表異步任務(wù)的執(zhí)行結(jié)果
public interface Future<V> {

    /**
     * 嘗試取消一個(gè)任務(wù),如果這個(gè)任務(wù)不能被取消(通常是因?yàn)橐呀?jīng)執(zhí)行完了),返回false,否則返回true。
     */
    boolean cancel(boolean mayInterruptIfRunning);

    /**
     * 返回代表的任務(wù)是否在完成之前被取消了
     */
    boolean isCancelled();

    /**
     * 如果任務(wù)已經(jīng)完成,返回true
     */
    boolean isDone();

    /**
     * 獲取異步任務(wù)的執(zhí)行結(jié)果(如果任務(wù)沒執(zhí)行完將等待)
     */
    V get() throws InterruptedException, ExecutionException;

    /**
     * 獲取異步任務(wù)的執(zhí)行結(jié)果(有最常等待時(shí)間的限制)
     *
     *  timeout表示等待的時(shí)間,unit是它時(shí)間單位
     */
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

ScheduledFuture繼承自Future和Delayed接口,自身沒有添加方法。Delayed接口定義了一個(gè)獲取剩余延遲的方法。

ExecutorService有一個(gè)子接口ScheduledExecutorService和一個(gè)抽象實(shí)現(xiàn)類AbstractExecutorService。

ScheduledExecutorService
可以安排指定時(shí)間或周期性的執(zhí)行任務(wù)的ExecutorService

// 可以安排指定時(shí)間或周期性的執(zhí)行任務(wù)的ExecutorService
public interface ScheduledExecutorService extends ExecutorService {
    /**
     * 在指定延遲后執(zhí)行一個(gè)任務(wù),只執(zhí)行一次
     */
    public ScheduledFuture<?> schedule(Runnable command,
                       long delay, TimeUnit unit);
    /**
     * 與上面的方法相同,只是接受的是Callable任務(wù)
     */
    public <V> ScheduledFuture<V> schedule(Callable<V> callable,
                       long delay, TimeUnit unit);
    /**
     * 創(chuàng)建并執(zhí)行一個(gè)周期性的任務(wù),在initialDelay延遲后每間隔period個(gè)單位執(zhí)行一次,時(shí)間單位都是unit
     * 每次執(zhí)行任務(wù)的時(shí)間點(diǎn)是initialDelay, initialDelay+period, initialDelay + 2 * period...
     */
    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                          long initialDelay,
                          long period,
                          TimeUnit unit);
    /**
     * 創(chuàng)建并執(zhí)行一個(gè)周期性的任務(wù),在initialDelay延遲后開始執(zhí)行,在執(zhí)行結(jié)束后再延遲delay個(gè)單位開始執(zhí)行下一次任務(wù),時(shí)間單位都是unit
     * 每次執(zhí)行任務(wù)的時(shí)間點(diǎn)是initialDelay, initialDelay+(任務(wù)運(yùn)行時(shí)間+delay), initialDelay + 2 * (任務(wù)運(yùn)行時(shí)間+delay)...
     */
    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                             long initialDelay,
                             long delay,
                             TimeUnit unit);
}

AbstractExecutorService
看到AbstractExecutorService的時(shí)候,基本就能找到一點(diǎn)痕跡了,LiteGo的核心代碼有一些都參照了它的寫法。
我們先來了解下下面三個(gè)概念:

  • RunnableFuture繼承自Future和Runnable,只有一個(gè)run()方法。RunnableFuture接口看上去就像是Future和Runnable兩個(gè)接口的組合。
public interface RunnableFuture<V> extends Runnable, Future<V> {    
        void run();
}
  • FutureTask類實(shí)現(xiàn)了RunnableFuture接口,除了實(shí)現(xiàn)了Future和Runnable中的方法外,它還有自己的方法。
  • ExecutorCompletionService實(shí)現(xiàn)了CompletionService接口,將結(jié)果從復(fù)雜的一部分物種解耦出來。

ThreadPoolExecutor
ThreadPoolExecutor繼承自AbstractExecutorService。

ScheduledThreadPoolExecutor
它繼承自ThreadPoolExecutor并實(shí)現(xiàn)了ScheduledExecutorService接口。

Executors
Executors中所定義的 Executor、ExecutorService、ScheduledExecutorService、ThreadFactory
和 Callable
類的工廠和實(shí)用方法。

  • newFixedThreadPool
    創(chuàng)建一個(gè)定長(zhǎng)的線程池。達(dá)到最大線程數(shù)后,線程數(shù)不再增長(zhǎng)。
    如果一個(gè)線程由于非預(yù)期Exception而結(jié)束,線程池會(huì)補(bǔ)充一個(gè)新的線程。
  • newCachedThreadPool
    創(chuàng)建一個(gè)可緩存的線程池。當(dāng)池長(zhǎng)度超過處理需求時(shí),可以回收空閑的線程。
  • newSingleThreadPool
    創(chuàng)建一個(gè)單線程executor。
  • newScheduledThreadPool
    創(chuàng)建一個(gè)定長(zhǎng)的線程池,而且支持定時(shí)的以及周期性的任務(wù)執(zhí)行。
    類似于Timer。但是,Timer是基于絕對(duì)時(shí)間,對(duì)系統(tǒng)時(shí)鐘的改變是敏感的,而ScheduledThreadPoolExecutor只支持相對(duì)時(shí)間。

與Timer比較

  1. Timer是創(chuàng)建唯一的線程來執(zhí)行所有的timer任務(wù)。如果一個(gè)任務(wù)超時(shí)了,會(huì)導(dǎo)致其他的TimerTask時(shí)間準(zhǔn)確性出問題。
  2. 如果TimerTask拋出uncheck 異常,Timer將會(huì)產(chǎn)生無法預(yù)料的行為。因此,ScheduledThreadPoolExecutor可以完全代替Timer。

(3)LinkedList 和 ArrayList
參考鏈接
因?yàn)槠綍r(shí)我們大多使用的是動(dòng)態(tài)數(shù)組ArrayList,對(duì)LinkedList并不是那么的熟悉,這里探究一下它們的區(qū)別和源碼中為什么要使用LinkedList。

LinkedList和ArrayList都實(shí)現(xiàn)了List接口,但是它們的工作原理卻不一樣。它們之間最主要的區(qū)別在于ArrayList是可改變大小的數(shù)組,而LinkedList是雙向鏈接串列(doubly LinkedList)。

  • 因?yàn)锳rray是基于索引(index)的數(shù)據(jù)結(jié)構(gòu),它使用索引在數(shù)組中搜索和讀取數(shù)據(jù)是很快的。Array獲取數(shù)據(jù)的時(shí)間復(fù)雜度是O(1),但是要?jiǎng)h除數(shù)據(jù)卻是開銷很大的,因?yàn)檫@需要重排數(shù)組中的所有數(shù)據(jù)。
  • 相對(duì)于ArrayList,LinkedList插入是更快的。因?yàn)長(zhǎng)inkedList不像ArrayList一樣,不需要改變數(shù)組的大小,也不需要在數(shù)組裝滿的時(shí)候要將所有的數(shù)據(jù)重新裝入一個(gè)新的數(shù)組,這是ArrayList最壞的一種情況,時(shí)間復(fù)雜度是O(n),而LinkedList中插入或刪除的時(shí)間復(fù)雜度僅為O(1)。ArrayList在插入數(shù)據(jù)時(shí)還需要更新索引(除了插入數(shù)組的尾部)。
  • 類似于插入數(shù)據(jù),刪除數(shù)據(jù)時(shí),LinkedList也優(yōu)于ArrayList。
  • LinkedList需要更多的內(nèi)存,因?yàn)锳rrayList的每個(gè)索引的位置是實(shí)際的數(shù)據(jù),而LinkedList中的每個(gè)節(jié)點(diǎn)中存儲(chǔ)的是實(shí)際的數(shù)據(jù)和前后節(jié)點(diǎn)的位置。
    在LinkedList中有一個(gè)私有的內(nèi)部類,定義如下:
private static class Entry { 
         Object element; 
         Entry next; 
         Entry previous; 
     } 

這也就是LinkedList耗費(fèi)內(nèi)存更多的地方。

什么場(chǎng)景下更適宜使用LinkedList,而不用ArrayList

  • 你的應(yīng)用不會(huì)隨機(jī)訪問數(shù)據(jù)。因?yàn)槿绻阈枰狶inkedList中的第n個(gè)元素的時(shí)候,你需要從第一個(gè)元素順序數(shù)到第n個(gè)數(shù)據(jù),然后讀取數(shù)據(jù)。
  • 你的應(yīng)用更多的插入和刪除元素,更少的讀取數(shù)據(jù)。因?yàn)椴迦牒蛣h除元素不涉及重排數(shù)據(jù),所以它要比ArrayList要快。

以上就是關(guān)于ArrayList和LinkedList的差別。你需要一個(gè)不同步的基于索引的數(shù)據(jù)訪問時(shí),請(qǐng)盡量使用ArrayList。ArrayList很快,也很容易使用。但是要記得要給定一個(gè)合適的初始大小,盡可能的減少更改數(shù)組的大小。

由此可見,LiteGo的使用場(chǎng)景中可能會(huì)出現(xiàn)大量的任務(wù)插入和刪除(插入和刪除有可能發(fā)生在列表的前面),但并不會(huì)涉及到查詢,所以這里使用LinkedList是有道理的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 個(gè)人筆記,方便自己查閱使用 Contents Java LangAssignment, ReferenceData...
    freenik閱讀 1,529評(píng)論 0 6
  • 一.線程安全性 線程安全是建立在對(duì)于對(duì)象狀態(tài)訪問操作進(jìn)行管理,特別是對(duì)共享的與可變的狀態(tài)的訪問 解釋下上面的話: ...
    黃大大吃不胖閱讀 971評(píng)論 0 3
  • 每天一有空閑時(shí)間,我就會(huì)閱讀微信公眾號(hào)的推文,查看當(dāng)天的熱點(diǎn)新聞,還會(huì)在晚上下班后,把手機(jī)調(diào)成靜音,在家里靜靜地看...
    柳樹之閱讀 12,075評(píng)論 5 64
  • 1996年,隨著一聲清脆的哭聲,這個(gè)小女孩終于來到美好的世界,她瞪著大大的眼睛,看著這陌生的地方,真的好想知道她當(dāng)...
    二萌小兔閱讀 468評(píng)論 0 1

友情鏈接更多精彩內(nèi)容