Android線程管理之ExecutorService線程池


前言:

     上篇學習了線程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定義自己的線程池,后面再做學習總結。


免責聲明!

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



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