Android多線程:這是一份全面 & 詳細的線程池(ThreadPool)講解教程


前言

  • 對於多線程,你們應該很熟悉。可是,你們瞭解線程池嗎?
  • 今天,我將帶你們所有學習關於線程池的全部知識。

目錄

示意圖


1. 簡介

示意圖


2. 工做原理

2.1 核心參數

  • 線程池中有6個核心參數,具體以下

示意圖

  • 上述6個參數的配置 決定了 線程池的功能,具體設置時機 = 建立 線程池類對象時 傳入
  1. ThreadPoolExecutor類 = 線程池的真正實現類
  2. 開發者可根據不一樣需求 配置核心參數,從而實現自定義線程池
// 建立線程池對象以下
// 經過 構造方法 配置核心參數
   Executor executor = new ThreadPoolExecutor( 
                                              CORE_POOL_SIZE,
                                              MAXIMUM_POOL_SIZE,
                                              KEEP_ALIVE,
                                              TimeUnit.SECONDS, 
                                              sPoolWorkQueue,
                                              sThreadFactory 
                                               );

// 構造函數源碼分析
    public ThreadPoolExecutor (int corePoolSize,
                               int maximumPoolSize,
                               long keepAliveTime,
                               TimeUnit unit,
                               BlockingQueue<Runnable workQueue>,
                               ThreadFactory threadFactory )
複製代碼

注:Java 裏已內置4種經常使用的線程池(即 已經配置好核心參數),下面會詳細說明數據庫

2.2 內部原理邏輯

當線程池運行時,遵循如下工做邏輯緩存

示意圖


3. 使用流程

線程池的使用流程以下bash

// 1. 建立線程池
   // 建立時,經過配置線程池的參數,從而實現本身所需的線程池
   Executor threadPool = new ThreadPoolExecutor(
                                              CORE_POOL_SIZE,
                                              MAXIMUM_POOL_SIZE,
                                              KEEP_ALIVE,
                                              TimeUnit.SECONDS,
                                              sPoolWorkQueue,
                                              sThreadFactory
                                              );
    // 注:在Java中,已內置4種常見線程池,下面會詳細說明

// 2. 向線程池提交任務:execute()
    // 說明:傳入 Runnable對象
       threadPool.execute(new Runnable() {
            @Override
            public void run() {
                ... // 線程執行任務
            }
        });

// 3. 關閉線程池shutdown() 
  threadPool.shutdown();
  
  // 關閉線程的原理
  // a. 遍歷線程池中的全部工做線程
  // b. 逐個調用線程的interrupt()中斷線程(注:沒法響應中斷的任務可能永遠沒法終止)

  // 也可調用shutdownNow()關閉線程:threadPool.shutdownNow()
  // 兩者區別:
  // shutdown:設置 線程池的狀態 爲 SHUTDOWN,而後中斷全部沒有正在執行任務的線程
  // shutdownNow:設置 線程池的狀態 爲 STOP,而後嘗試中止全部的正在執行或暫停任務的線程,並返回等待執行任務的列表
  // 使用建議:通常調用shutdown()關閉線程池;若任務不必定要執行完,則調用shutdownNow()
複製代碼

4. 常見的4類功能線程池

根據參數的不一樣配置,Java中最多見的線程池有4類:微信

  • 定長線程池(FixedThreadPool
  • 定時線程池(ScheduledThreadPool )
  • 可緩存線程池(CachedThreadPool
  • 單線程化線程池(SingleThreadExecutor

即 對於上述4類線程池,Java已根據 應用場景 配置好核心參數多線程

4.1 定長線程池(FixedThreadPool)

  • 特色:只有核心線程 & 不會被回收、線程數量固定、任務隊列無大小限制(超出的線程任務會在隊列中等待)
  • 應用場景:控制線程最大併發數
  • 具體使用:經過 Executors.newFixedThreadPool() 建立
  • 示例:
// 1. 建立定長線程池對象 & 設置線程池線程數量固定爲3
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);

// 2. 建立好Runnable類線程對象 & 需執行的任務
Runnable task =new Runnable(){
  public void run(){
    System.out.println("執行任務啦");
     }
    };
        
// 3. 向線程池提交任務:execute()
fixedThreadPool.execute(task);
        
// 4. 關閉線程池
fixedThreadPool.shutdown();
複製代碼

4.2 定時線程池(ScheduledThreadPool )

  • 特色:核心線程數量固定、非核心線程數量無限制(閒置時立刻回收)
  • 應用場景:執行定時 / 週期性 任務
  • 使用:經過*Executors.newScheduledThreadPool()*建立
  • 示例:
// 1. 建立 定時線程池對象 & 設置線程池線程數量固定爲5
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);

// 2. 建立好Runnable類線程對象 & 需執行的任務
Runnable task =new Runnable(){
       public void run(){
              System.out.println("執行任務啦");
          }
    };
// 3. 向線程池提交任務:schedule()
scheduledThreadPool.schedule(task, 1, TimeUnit.SECONDS); // 延遲1s後執行任務
scheduledThreadPool.scheduleAtFixedRate(task,10,1000,TimeUnit.MILLISECONDS);// 延遲10ms後、每隔1000ms執行任務

// 4. 關閉線程池
scheduledThreadPool.shutdown();
複製代碼

4.3 可緩存線程池(CachedThreadPool)

  • 特色:只有非核心線程、線程數量不固定(可無限大)、靈活回收空閒線程(具有超時機制,所有回收時幾乎不佔系統資源)、新建線程(無線程可用時)

任何線程任務到來都會馬上執行,不須要等待併發

  • 應用場景:執行大量、耗時少的線程任務
  • 使用:經過*Executors.newCachedThreadPool()*建立
  • 示例:
// 1. 建立可緩存線程池對象
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

// 2. 建立好Runnable類線程對象 & 需執行的任務
Runnable task =new Runnable(){
  public void run(){
        System.out.println("執行任務啦");
            }
    };

// 3. 向線程池提交任務:execute()
cachedThreadPool.execute(task);

// 4. 關閉線程池
cachedThreadPool.shutdown();

//當執行第二個任務時第一個任務已經完成
//那麼會複用執行第一個任務的線程,而不用每次新建線程。
複製代碼

4.4 單線程化線程池(SingleThreadExecutor)

  • 特色:只有一個核心線程(保證全部任務按照指定順序在一個線程中執行,不須要處理線程同步的問題)ide

  • 應用場景:不適合併發但可能引發IO阻塞性及影響UI線程響應的操做,如數據庫操做,文件操做等函數

  • 使用:經過*Executors.newSingleThreadExecutor()*建立源碼分析

  • 示例:學習

// 1. 建立單線程化線程池
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();

// 2. 建立好Runnable類線程對象 & 需執行的任務
Runnable task =new Runnable(){
  public void run(){
        System.out.println("執行任務啦");
            }
    };

// 3. 向線程池提交任務:execute()
singleThreadExecutor.execute(task);

// 4. 關閉線程池
singleThreadExecutor.shutdown();

複製代碼

4.5 常見線程池 總結 & 對比

示意圖


5. 總結

  • 閱讀本文後,相信你已經很是瞭解線程池 & 用法
  • 接下來,我會繼續講解Android開發中關於多線程的知識,具體包括Thread類、HandlerHandlerThread等等,有興趣能夠繼續關注Carson_Ho的安卓開發筆記

請點贊!由於你的鼓勵是我寫做的最大動力!


歡迎關注carson_ho的微信公衆號

示意圖

示意圖
相關文章
相關標籤/搜索