java線程池 java多線程與線程池

摘自:https://www.cnblogs.com/ruanjianlaowang/p/12014490.html

java多線程與線程池

 

1. 場景描述

以前多線程也常用,這次因需再頁面上用到多線程,如下圖,總結下,有需要的朋友可以參考下。

2. 解決方案

2.1 線程池概念

線程池官方定義不說了,通俗說下:池子的概念,事先(預定義)創建後,後續的線程可以直接從池子中拿,好處:

(1)來創建線程比較消耗資源,不用重複創建;

(2)池子事先定義好,避免無節制創建線程,導致系統出現不可預測風險。

2.2 創建方式

採用jdk自帶的線程池創建方式,jdk1.5開始提供,在java.util.concurrent 的包下面。

表面上有兩種創建方式,其實一種。

(1)一種是採用new ThreadPoolExecutor進行創建;

  public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {

(2)一種是採用Executors.newFixedThreadPool(3),不過還是調用的new ThreadPoolExecutor進行的線程池創建,賦值了幾個默認參數而已。

new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());

2.3 參數含義

一共有 7 個參數:

(1)corePoolSize

核心線程數,當有任務進來的時候,如果當前線程數還未達到 corePoolSize 個數,則創建核心線程,核心線程有幾個特點:

1、當線程數未達到核心線程最大值的時候,新任務進來,即使有空閒線程,也不會複用,仍然新建核心線程;2、核心線程一般不會被銷燬,即使是空閒的狀態,但是如果通過方法 allowCoreThreadTimeOut(boolean value) 設置爲 true 時,超時也同樣會被銷燬;3、生產環境首次初始化的時候,可以調用 prestartCoreThread() 方法來預先創建所有核心線程,避免第一次調用緩慢;

(2)maximumPoolSize

除了有核心線程外,有些策略是當核心線程完全無空閒的時候,還會創建一些臨時的線程來處理任務,maximumPoolSize 就是核心線程 + 臨時線程的最大上限。臨時線程有一個超時機制,超過了設置的空閒時間沒有事兒幹,就會被銷燬。

(3)keepAliveTime

這個就是上面兩個參數裏所提到的超時時間,也就是線程的最大空閒時間,默認用於非核心線程,通過 allowCoreThreadTimeOut(boolean value) 方法設置後,也會用於核心線程。

(4)unit

這個參數配合上面的 keepAliveTime ,指定超時的時間單位,秒、分、時等。

(5)workQueue

等待執行的任務隊列,如果核心線程沒有空閒的了,新來的任務就會被放到這個等待隊列中。

(6)threadFactory

它是一個接口,用於實現生成線程的方式、定義線程名格式、是否後臺執行等等,可以用 Executors.defaultThreadFactory() 默認的實現即可,也可以用 Guava 等三方庫提供的方法實現,如果有特殊要求的話可以自己定義。它最重要的地方應該就是定義線程名稱的格式,便於排查問題了吧。

(7)handler

當沒有空閒的線程處理任務,並且等待隊列已滿(當然這隻對有界隊列有效),再有新任務進來的話,就要做一些取捨了,而這個參數就是指定取捨策略的,有下面四種策略可以選擇:

ThreadPoolExecutor.AbortPolicy:直接拋出異常,這是默認策略;
ThreadPoolExecutor.DiscardPolicy:直接丟棄任務,但是不拋出異常。
ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務,然後將新來的任務加入等待隊列
ThreadPoolExecutor.CallerRunsPolicy:由線程池所在的線程處理該任務,比如在 main 函數中創建線程池,如果執行此策略,將有 main 線程來執行該任務

2.4 測試驗證

2.4.1 測試線程
package com.yutong.laowang.test;

public class ThreadTest extends Thread{
    @Override
    public void run() {
        System.out.println("軟件老王:" +Thread.currentThread().getName());
  }
}
2.4.2 Executors創建
  private static void test4() {
        Executor mExecutor = Executors.newFixedThreadPool(3);
        for (int i = 0; i < 10; i++) {
            Thread thread = new ThreadTest();
            mExecutor.execute(thread);
        }
    }

結果:

軟件老王:pool-2-thread-2
軟件老王:pool-2-thread-3
軟件老王:pool-2-thread-1
軟件老王:pool-2-thread-3
軟件老王:pool-2-thread-2
軟件老王:pool-2-thread-1
軟件老王:pool-2-thread-3
軟件老王:pool-2-thread-2
軟件老王:pool-2-thread-3
軟件老王:pool-2-thread-1
2.4.3 ThreadPoolExecutor創建
 private static void test3() {
        int poolSize = 5;
        int queueSize = 100;
        ExecutorService executorService = new ThreadPoolExecutor(poolSize, poolSize, 0L, TimeUnit.SECONDS,
                new ArrayBlockingQueue<Runnable>(queueSize), new ThreadPoolExecutor.AbortPolicy());
                
        for (int i=0;i<10;i++) {
            executorService.submit(new ThreadTest());
        }
    }

結果:

軟件老王:pool-2-thread-1
軟件老王:pool-2-thread-3
軟件老王:pool-2-thread-4
軟件老王:pool-2-thread-2
軟件老王:pool-2-thread-5
軟件老王:pool-2-thread-5
軟件老王:pool-2-thread-1
軟件老王:pool-2-thread-2
軟件老王:pool-2-thread-2
軟件老王:pool-2-thread-1
2.4.4 線程停用
thread.interrupt();
---有時候不一定能執行成功,一般會結合判斷使用,軟件老王,例如:
在ThreadTest類中進行判斷,默認爲false,當滿足條件下爲true,停用線程。
 public volatile boolean exit = false;

I’m 「軟件老王」,如果覺得還可以的話,關注下唄,後續更新秒知!歡迎討論區、同名公衆號留言交流!

 本文版權歸作者軟件老王所有,轉載需註明作者、超鏈接,否則保留追究法律責任的權利。
 
分類: java
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章