多優先順序執行緒池實踐

FunTester發表於2024-05-06

在之前的 Java 執行緒池實踐當中,我遇到了任務優先順序的問題。最終採取的方案是新增一個執行緒池作為執行高優任務,然後將普通執行緒池的在執行任務執行,先去判斷高優執行緒池是否有等待任務,如果有就先執行高優執行緒池等待佇列中的任務。

雖然後期給普通非同步執行緒池增加了雙向連結串列,直接採取插隊模式執行,但是也讓非同步任務更加複雜了。所以經過一些 java.util.concurrent 包的重新學習,得到了最優的答案,就是 java.util.concurrent.PriorityBlockingQueue

PriorityBlockingQueue 簡介

java.util.concurrent.PriorityBlockingQueue 是 Java 併發包中的一個執行緒安全的優先順序阻塞佇列。它是基於優先順序的元素順序,具有以下特點:

  1. 執行緒安全: PriorityBlockingQueue 是執行緒安全的,可以在多執行緒環境下安全地進行操作,而不需要額外的同步手段。
  2. 無界佇列: PriorityBlockingQueue 是一個無界佇列,可以無限制地新增元素,因此不會因為佇列滿而阻塞生產者執行緒。
  3. 基於優先順序的元素順序: PriorityBlockingQueue 中的元素按照優先順序順序進行排序,具有較高優先順序的元素會被優先出隊。預設情況下,元素需要實現 Comparable 介面來定義它們的優先順序,也可以在建構函式中提供一個 Comparator 來自定義優先順序順序。
  4. 阻塞操作: 當佇列為空時,從 PriorityBlockingQueue 中獲取元素的操作會阻塞執行緒,直到佇列中有元素可用;當佇列滿時,向 PriorityBlockingQueue 中新增元素的操作也會阻塞執行緒,直到佇列有足夠的空間。
  5. 不支援空元素: PriorityBlockingQueue 不支援新增空元素,即元素不能為 null。

PriorityBlockingQueue 可以用於實現基於優先順序的任務排程、事件處理等場景,其中優先順序高的任務或事件會優先被處理。它提供了一種高效的方式來管理和處理具有不同優先順序的元素。

多優先順序執行緒池

下面是我自己的實現邏輯:

  1. 首先建立一個功能類,實現 java.lang.Comparablejava.lang.Runnable
  2. 制定優先順序規則,通常定義一個屬性 int 型別,代表優點等級。
  3. 封裝 execute() 方法,用來向執行緒池提交任務。

具體程式碼如下:

/**  
 * 多優先順序執行緒池  
 */  
static ThreadPoolExecutor levelPool = createPool(POOL_SIZE, POOL_SIZE, ALIVE_TIME, new PriorityBlockingQueue<PriorityTask>(), getFactory("L"), new ThreadPoolExecutor.DiscardPolicy())  


/**  
 * 執行優先順序任務  
 * @param task  
 * @return  
 */  
static def executeLevel(PriorityTask task) {  
    levelPool.execute(task)  
}  

/**  
 * 執行優先順序任務,設定優先順序  
 * @param priority  
 * @param closure  
 * @return  
 */  
static def executeLevel(int priority, Closure closure) {  
    levelPool.execute(new PriorityTask(priority) {  

        @Override  
        void run() {  
            closure()  
        }  
    })  
}  

/**  
 * 執行優先順序任務,使用預設優先順序  
 * @param closure  
 * @return  
 */  
static def executeLevel(Closure closure) {  
    levelPool.execute(new PriorityTask(PRIORITY_LEVEL_DEFAULT) {  

        @Override  
        void run() {  
            closure()  
        }  
    })  
}  

/**  
 * 優先順序任務,用於優先順序執行緒池  
 */  
static abstract class PriorityTask implements Runnable, Comparable<PriorityTask> {  

    int priority  

    PriorityTask(int priority) {  
        this.priority = priority  
    }  


    /**  
     * 比較方法,用於優先順序佇列,優先順序越高,越先執行  
     * @param o  
     * @return  
     */  
    @Override  
    int compareTo(PriorityTask o) {  
        return this.priority - o.priority  
    }  
}

測試

我們來寫一個測試用例,往執行緒池提交優先順序不斷提升的任務,列印任務執行時間。

ThreadPoolUtil.getLevelPool().setCorePoolSize(1);  
ThreadPoolUtil.getLevelPool().setMaximumPoolSize(1);  
for (int i = 0; i < 10; i++) {  
    ThreadPoolUtil.executeLevel(new ThreadPoolUtil.PriorityTask(10 - i) {  
        @Override  
        public void run() {  
            SourceCode.sleep(0.01);  
            System.out.println(this.getPriority());  
        }  
    });  
}

控制檯列印:

10
1
2
3
4
5
6
7
8
9

看起來是比較符合預期的。

  • 2021 年原創合集
  • 2022 年原創合集
  • 2023 年原創合集
  • 服務端功能測試
  • 效能測試專題
  • Java、Groovy、Go、Python
  • 單元&白盒&工具合集
  • 測試方案&BUG&爬蟲&UI 自動化
  • 測試理論雞湯
  • 社群風采&影片合集
如果覺得我的文章對您有用,請隨意打賞。您的支援將鼓勵我繼續創作!
打賞支援
暫無回覆。

相關文章