Android執行緒管理之ExecutorService執行緒池

總李寫程式碼發表於2016-06-23

前言:

     上篇學習了執行緒Thread的使用,今天來學習一下執行緒池ExecutorService。

     執行緒管理相關文章地址:

為什麼要引入執行緒池?

     1.)new Thread()的缺點
  • 每次new Thread()耗費效能
  • 呼叫new Thread()建立的執行緒缺乏管理,被稱為野執行緒,而且可以無限制建立,之間相互競爭,會導致過多佔用系統資源導致系統癱瘓。
  • 不利於擴充套件,比如如定時執行、定期執行、執行緒中斷
    2.)採用執行緒池的優點
  • 重用存在的執行緒,減少物件建立、消亡的開銷,效能佳
  • 可有效控制最大併發執行緒數,提高系統資源的使用率,同時避免過多資源競爭,避免堵塞
  • 提供定時執行、定期執行、單執行緒、併發數控制等功能

ExecutorService介紹

  ExecutorService是一個介面,ExecutorService介面繼承了Executor介面,定義了一些生命週期的方法,

public interface ExecutorService extends Executor {

   
    void shutdown();//順次地關閉ExecutorService,停止接收新的任務,等待所有已經提交的任務執行完畢之後,關閉ExecutorService


    List<Runnable> shutdownNow();//阻止等待任務啟動並試圖停止當前正在執行的任務,停止接收新的任務,返回處於等待的任務列表


    boolean isShutdown();//判斷執行緒池是否已經關閉

    boolean isTerminated();//如果關閉後所有任務都已完成,則返回 true。注意,除非首先呼叫 shutdown 或 shutdownNow,否則 isTerminated 永不為 true。

    
    boolean awaitTermination(long timeout, TimeUnit unit)//等待(阻塞)直到關閉或最長等待時間或發生中斷,timeout - 最長等待時間 ,unit - timeout 引數的時間單位  如果此執行程式終止,則返回 true;如果終止前超時期滿,則返回 false 

 
    <T> Future<T> submit(Callable<T> task);//提交一個返回值的任務用於執行,返回一個表示任務的未決結果的 Future。該 Future 的 get 方法在成功完成時將會返回該任務的結果。


    <T> Future<T> submit(Runnable task, T result);//提交一個 Runnable 任務用於執行,並返回一個表示該任務的 Future。該 Future 的 get 方法在成功完成時將會返回給定的結果。

 
    Future<?> submit(Runnable task);//提交一個 Runnable 任務用於執行,並返回一個表示該任務的 Future。該 Future 的 get 方法在成功 完成時將會返回 null


    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)//執行給定的任務,當所有任務完成時,返回保持任務狀態和結果的 Future 列表。返回列表的所有元素的 Future.isDone() 為 true。
        throws InterruptedException;


    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                  long timeout, TimeUnit unit)//執行給定的任務,當所有任務完成時,返回保持任務狀態和結果的 Future 列表。返回列表的所有元素的 Future.isDone() 為 true。
        throws InterruptedException;


    <T> T invokeAny(Collection<? extends Callable<T>> tasks)//執行給定的任務,如果在給定的超時期滿前某個任務已成功完成(也就是未丟擲異常),則返回其結果。一旦正常或異常返回後,則取消尚未完成的任務。
        throws InterruptedException, ExecutionException;


    <T> T invokeAny(Collection<? extends Callable<T>> tasks,
                    long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}
Executor 介面
public interface Executor {

    void execute(Runnable command);//執行已提交的 Runnable 任務物件。此介面提供一種將任務提交與每個任務將如何執行的機制(包括執行緒使用的細節、排程等)分離開來的方法
}

Executors工廠類

  通過Executors提供四種執行緒池,newFixedThreadPool、newCachedThreadPool、newSingleThreadExecutor、newScheduledThreadPool。

  1.)newFixedThreadPool建立一個可重用固定執行緒數的執行緒池,以共享的無界佇列方式來執行這些執行緒。
示例
 ExecutorService executorService = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 20; i++) {
            Runnable syncRunnable = new Runnable() {
                @Override
                public void run() {
                    Log.e(TAG, Thread.currentThread().getName());
                }
            };
            executorService.execute(syncRunnable);
        }

執行結果:總共只會建立5個執行緒, 開始執行五個執行緒,當五個執行緒都處於活動狀態,再次提交的任務都會加入佇列等到其他執行緒執行結束,當執行緒處於空閒狀態時會被下一個任務複用

 

2.)newCachedThreadPool建立一個可快取執行緒池,如果執行緒池長度超過處理需要,可靈活回收空閒執行緒

示例:

        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 100; i++) {
            Runnable syncRunnable = new Runnable() {
                @Override
                public void run() {
                    Log.e(TAG, Thread.currentThread().getName());
                }
            };
            executorService.execute(syncRunnable);
        }

執行結果:可以看出快取執行緒池大小是不定值,可以需要建立不同數量的執行緒,在使用快取型池時,先檢視池中有沒有以前建立的執行緒,如果有,就複用.如果沒有,就新建新的執行緒加入池中,快取型池子通常用於執行一些生存期很短的非同步型任務


3.)newScheduledThreadPool建立一個定長執行緒池,支援定時及週期性任務執行

   schedule(Runnable command,long delay, TimeUnit unit)建立並執行在給定延遲後啟用的一次性操作

示例:表示從提交任務開始計時,5000毫秒後執行
    ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5);
        for (int i = 0; i < 20; i++) {
            Runnable syncRunnable = new Runnable() {
                @Override
                public void run() {
                    Log.e(TAG, Thread.currentThread().getName());
                }
            };
            executorService.schedule(syncRunnable, 5000, TimeUnit.MILLISECONDS);
        }

執行結果和newFixedThreadPool類似,不同的是newScheduledThreadPool是延時一定時間之後才執行

 scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnitunit)  建立並執行一個在給定初始延遲後首次啟用的定期操作,後續操作具有給定的週期;也就是將在 initialDelay 後開始執行,然後在initialDelay+period 後執行,接著在 initialDelay + 2 * period 後執行,依此類推 

 ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5);
        Runnable syncRunnable = new Runnable() {
            @Override
            public void run() {
                Log.e(TAG, Thread.currentThread().getName());
            }
        };
        executorService.scheduleAtFixedRate(syncRunnable, 5000, 3000, TimeUnit.MILLISECONDS);

 

scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) 建立並執行一個在給定初始延遲後首次啟用的定期操作,隨後,在每一次執行終止和下一次執行開始之間都存在給定的延遲

 ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5);
        Runnable syncRunnable = new Runnable() {
            @Override
            public void run() {
                Log.e(TAG, Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        executorService.scheduleWithFixedDelay(syncRunnable, 5000, 3000, TimeUnit.MILLISECONDS);
3.)newSingleThreadExecutor建立一個單執行緒化的執行緒池,它只會用唯一的工作執行緒來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先順序)執行

 示例

  ExecutorService executorService = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 20; i++) {
            Runnable syncRunnable = new Runnable() {
                @Override
                public void run() {
                    Log.e(TAG, Thread.currentThread().getName());
                }
            };
            executorService.execute(syncRunnable);
        }

執行結果:只會建立一個執行緒,當上一個執行完之後才會執行第二個

通過ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();實現延時的單執行緒執行緒池

 

小結:

  通過本文介紹了簡單的執行緒池使用,也可以通過ThreadPoolExecutor定義自己的執行緒池,後面再做學習總結。

相關文章