1. 程式人生 > >Java線程池(ExecutorService)使用

Java線程池(ExecutorService)使用

nan ive keepalive bsp 處理 mit shu led cat

一、前提

/**
 * 線程運行demo,運行時打出線程id以及傳入線程中參數
 */
public class ThreadRunner implements Runnable {

    private final SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss.SSS");

    /**
     * 線程私有屬性,創建線程時創建
     */
    private Integer num;

    public ThreadRunner(Integer num) {
        this
.num = num; } @Override public void run() { System.out.println("thread:" + Thread.currentThread().getName() + ",time:" + format.format(new Date()) + ",num:" + num); try {//使線程睡眠,模擬線程阻塞情況 TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } }

二、分類

1、FixedThreadPool-有一個固定大小的線程池

public class FixedThreadPoolDemo {

    public static void main(String[] args) {
        ExecutorService pool = Executors.newFixedThreadPool(4);
        for(int i = 0 ; i < 50 ; i++){
            pool.submit(new ThreadRunner((i + 1)));
        }
        pool.shutdown();
    }
}
thread:pool
-1-thread-2,time:16:14:45.677,num:2 thread:pool-1-thread-4,time:16:14:45.678,num:4 thread:pool-1-thread-3,time:16:14:45.680,num:3 thread:pool-1-thread-1,time:16:14:45.684,num:1 thread:pool-1-thread-4,time:16:14:46.680,num:5 thread:pool-1-thread-2,time:16:14:46.680,num:6 thread:pool-1-thread-3,time:16:14:46.680,num:7 thread:pool-1-thread-1,time:16:14:46.684,num:8 thread:pool-1-thread-4,time:16:14:47.680,num:9 thread:pool-1-thread-2,time:16:14:47.680,num:10 thread:pool-1-thread-3,time:16:14:47.681,num:11 thread:pool-1-thread-1,time:16:14:47.684,num:12 thread:pool-1-thread-4,time:16:14:48.681,num:13 thread:pool-1-thread-2,time:16:14:48.681,num:14 thread:pool-1-thread-3,time:16:14:48.681,num:15 thread:pool-1-thread-1,time:16:14:48.684,num:16 thread:pool-1-thread-4,time:16:14:49.681,num:17 thread:pool-1-thread-2,time:16:14:49.682,num:18 thread:pool-1-thread-3,time:16:14:49.682,num:19 thread:pool-1-thread-1,time:16:14:49.684,num:20 thread:pool-1-thread-4,time:16:14:50.681,num:21 thread:pool-1-thread-2,time:16:14:50.682,num:22 thread:pool-1-thread-3,time:16:14:50.682,num:23 thread:pool-1-thread-1,time:16:14:50.684,num:24 thread:pool-1-thread-4,time:16:14:51.681,num:25 thread:pool-1-thread-2,time:16:14:51.682,num:26 thread:pool-1-thread-3,time:16:14:51.682,num:27 thread:pool-1-thread-1,time:16:14:51.684,num:28 thread:pool-1-thread-4,time:16:14:52.681,num:29 thread:pool-1-thread-2,time:16:14:52.682,num:30 thread:pool-1-thread-3,time:16:14:52.682,num:31 thread:pool-1-thread-1,time:16:14:52.684,num:32 thread:pool-1-thread-4,time:16:14:53.681,num:33 thread:pool-1-thread-2,time:16:14:53.682,num:34 thread:pool-1-thread-3,time:16:14:53.683,num:35 thread:pool-1-thread-1,time:16:14:53.685,num:36 thread:pool-1-thread-2,time:16:14:54.682,num:38 thread:pool-1-thread-4,time:16:14:54.682,num:37 thread:pool-1-thread-3,time:16:14:54.683,num:39 thread:pool-1-thread-1,time:16:14:54.686,num:40 thread:pool-1-thread-2,time:16:14:55.682,num:41 thread:pool-1-thread-4,time:16:14:55.682,num:42 thread:pool-1-thread-3,time:16:14:55.683,num:43 thread:pool-1-thread-1,time:16:14:55.686,num:44 thread:pool-1-thread-2,time:16:14:56.682,num:45 thread:pool-1-thread-4,time:16:14:56.683,num:46 thread:pool-1-thread-3,time:16:14:56.684,num:47 thread:pool-1-thread-1,time:16:14:56.686,num:48 thread:pool-1-thread-2,time:16:14:57.683,num:49 thread:pool-1-thread-4,time:16:14:57.683,num:50

總結:
- 池中線程數量固定,不會發生變化
- 使用無界的LinkedBlockingQueue,要綜合考慮生成與消費能力,生成過剩,可能導致堆內存溢出。
- 適用一些很穩定很固定的正規並發線程,多用於服務器

2、CachedThreadPool

public class CachedThreadPoolDemo {

    public static void main(String[] args) {
        ExecutorService pool = Executors.newCachedThreadPool();
        for(int i = 0 ; i < 50 ; i++){
            pool.submit(new ThreadRunner((i + 1)));
        }
        pool.shutdown();
    }
}
thread:pool-1-thread-2,time:16:17:21.289,num:2
thread:pool-1-thread-3,time:16:17:21.290,num:3
thread:pool-1-thread-4,time:16:17:21.290,num:4
thread:pool-1-thread-6,time:16:17:21.291,num:6
thread:pool-1-thread-7,time:16:17:21.291,num:7
thread:pool-1-thread-8,time:16:17:21.291,num:8
thread:pool-1-thread-1,time:16:17:21.292,num:1
thread:pool-1-thread-10,time:16:17:21.293,num:10
thread:pool-1-thread-5,time:16:17:21.294,num:5
thread:pool-1-thread-11,time:16:17:21.294,num:11
thread:pool-1-thread-15,time:16:17:21.294,num:15
thread:pool-1-thread-9,time:16:17:21.294,num:9
thread:pool-1-thread-16,time:16:17:21.295,num:16
thread:pool-1-thread-20,time:16:17:21.295,num:20
thread:pool-1-thread-14,time:16:17:21.296,num:14
thread:pool-1-thread-12,time:16:17:21.296,num:12
thread:pool-1-thread-19,time:16:17:21.297,num:19
thread:pool-1-thread-13,time:16:17:21.299,num:13
thread:pool-1-thread-17,time:16:17:21.300,num:17
thread:pool-1-thread-18,time:16:17:21.302,num:18
thread:pool-1-thread-22,time:16:17:21.304,num:22
thread:pool-1-thread-23,time:16:17:21.304,num:23
thread:pool-1-thread-24,time:16:17:21.305,num:24
thread:pool-1-thread-21,time:16:17:21.305,num:21
thread:pool-1-thread-26,time:16:17:21.305,num:26
thread:pool-1-thread-25,time:16:17:21.306,num:25
thread:pool-1-thread-29,time:16:17:21.307,num:29
thread:pool-1-thread-28,time:16:17:21.308,num:28
thread:pool-1-thread-30,time:16:17:21.308,num:30
thread:pool-1-thread-34,time:16:17:21.308,num:34
thread:pool-1-thread-35,time:16:17:21.308,num:35
thread:pool-1-thread-33,time:16:17:21.308,num:33
thread:pool-1-thread-27,time:16:17:21.309,num:27
thread:pool-1-thread-32,time:16:17:21.308,num:32
thread:pool-1-thread-31,time:16:17:21.309,num:31
thread:pool-1-thread-36,time:16:17:21.310,num:36
thread:pool-1-thread-37,time:16:17:21.310,num:37
thread:pool-1-thread-38,time:16:17:21.310,num:38
thread:pool-1-thread-42,time:16:17:21.310,num:42
thread:pool-1-thread-40,time:16:17:21.310,num:40
thread:pool-1-thread-41,time:16:17:21.311,num:41
thread:pool-1-thread-47,time:16:17:21.762,num:47
thread:pool-1-thread-43,time:16:17:21.762,num:43
thread:pool-1-thread-39,time:16:17:21.762,num:39
thread:pool-1-thread-45,time:16:17:21.762,num:45
thread:pool-1-thread-44,time:16:17:21.763,num:44
thread:pool-1-thread-46,time:16:17:21.761,num:46
thread:pool-1-thread-48,time:16:17:21.761,num:48
thread:pool-1-thread-49,time:16:17:21.765,num:49
thread:pool-1-thread-50,time:16:17:21.765,num:50

總結
- 池中線程時隨著處理數據增加而增加
- 線程數並不是一直增加,如果有新任務需要執行時,首先查詢池中是否有空閑線程並且還為到空閑截止時間,如果有,則使用空閑線程,如果沒有,則創建新線程並放入池中。
- 用於執行一些生存期很短的異步型任務。不適用於IO等長延時操作,因為這可能會創建大量線程,導致系統崩潰。
- 使用SynchronousQueue作為阻塞隊列,如果有新任務進入隊列,必須隊列中數據被其他線程處理,否則會等待。

3、SingleThreadExecutor

public class SingleThreadPoolDemo {

    public static void main(String[] args) {
        ExecutorService pool = Executors.newSingleThreadExecutor();
        for(int i = 0 ; i < 50 ; i++){
            pool.submit(new ThreadRunner((i + 1)));
        }
        pool.shutdown();
    }
}
thread:pool-1-thread-1,time:16:20:10.194,num:1
thread:pool-1-thread-1,time:16:20:11.197,num:2
thread:pool-1-thread-1,time:16:20:12.197,num:3
thread:pool-1-thread-1,time:16:20:13.197,num:4
thread:pool-1-thread-1,time:16:20:14.197,num:5
thread:pool-1-thread-1,time:16:20:15.198,num:6
thread:pool-1-thread-1,time:16:20:16.198,num:7
thread:pool-1-thread-1,time:16:20:17.198,num:8
thread:pool-1-thread-1,time:16:20:18.198,num:9
thread:pool-1-thread-1,time:16:20:19.198,num:10
thread:pool-1-thread-1,time:16:20:20.198,num:11
thread:pool-1-thread-1,time:16:20:21.199,num:12
thread:pool-1-thread-1,time:16:20:22.200,num:13
thread:pool-1-thread-1,time:16:20:23.200,num:14
thread:pool-1-thread-1,time:16:20:24.200,num:15
thread:pool-1-thread-1,time:16:20:25.200,num:16
thread:pool-1-thread-1,time:16:20:26.201,num:17
thread:pool-1-thread-1,time:16:20:27.201,num:18
thread:pool-1-thread-1,time:16:20:28.201,num:19
thread:pool-1-thread-1,time:16:20:29.201,num:20
thread:pool-1-thread-1,time:16:20:30.202,num:21
thread:pool-1-thread-1,time:16:20:31.202,num:22
thread:pool-1-thread-1,time:16:20:32.203,num:23
thread:pool-1-thread-1,time:16:20:33.203,num:24
thread:pool-1-thread-1,time:16:20:34.203,num:25
thread:pool-1-thread-1,time:16:20:35.203,num:26
thread:pool-1-thread-1,time:16:20:36.203,num:27
thread:pool-1-thread-1,time:16:20:37.203,num:28
thread:pool-1-thread-1,time:16:20:38.203,num:29
thread:pool-1-thread-1,time:16:20:39.203,num:30
thread:pool-1-thread-1,time:16:20:40.203,num:31
thread:pool-1-thread-1,time:16:20:41.203,num:32
thread:pool-1-thread-1,time:16:20:42.203,num:33
thread:pool-1-thread-1,time:16:20:43.204,num:34
thread:pool-1-thread-1,time:16:20:44.204,num:35
thread:pool-1-thread-1,time:16:20:45.204,num:36
thread:pool-1-thread-1,time:16:20:46.204,num:37
thread:pool-1-thread-1,time:16:20:47.205,num:38
thread:pool-1-thread-1,time:16:20:48.205,num:39
thread:pool-1-thread-1,time:16:20:49.205,num:40
thread:pool-1-thread-1,time:16:20:50.206,num:41
thread:pool-1-thread-1,time:16:20:51.206,num:42
thread:pool-1-thread-1,time:16:20:52.207,num:43
thread:pool-1-thread-1,time:16:20:53.207,num:44
thread:pool-1-thread-1,time:16:20:54.207,num:45
thread:pool-1-thread-1,time:16:20:55.207,num:46
thread:pool-1-thread-1,time:16:20:56.207,num:47
thread:pool-1-thread-1,time:16:20:57.208,num:48
thread:pool-1-thread-1,time:16:20:58.208,num:49
thread:pool-1-thread-1,time:16:20:59.209,num:50

總結:
- 線程中只有一個線程在執行
- 適用於有明確執行順序但是不影響主線程的任務,壓入池中的任務會按照隊列順序執行。
- 使用無界的LinkedBlockingQueue,要綜合考慮生成與消費能力,生成過剩,可能導致堆內存溢出。

三、源碼

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
 public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

ThreadPoolExecutor 構造方法*

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         Executors.defaultThreadFactory(), defaultHandler);
}


 public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {
    if (corePoolSize < 0 ||
        maximumPoolSize <= 0 ||
        maximumPoolSize < corePoolSize ||
        keepAliveTime < 0)
        throw new IllegalArgumentException();
    if (workQueue == null || threadFactory == null || handler == null)
        throw new NullPointerException();
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}
    • corePoolSize:線程池核心線程數量
      1. 如果池中線程數量少於核心線程池數量,則直接新建線程處理當前任務。
      2. 核心線程池空閑不會被回收。
      3. 當池中無空閑線程時,新任務將被添加到阻塞隊列
    • maximumPoolSize:線程池最大線程數量
      1. 當阻塞隊列已滿,並且有新任務還在入隊時,創建新的線程處理,直到線程數大於maximumPoolSize。
      2. 超出corePoolSize部分的線程超過空閑時間後會被回收
      3. 當線程已經超出corePoolSize,並且隊列容量已滿,則拒絕入隊。
    • keepAliveTime unit:線程存活時間
      1. 當線程超出corePoolSize時生效
      2. 線程空余keepAliveTime後,將被回收
    • workQueue:線程使用阻塞隊列
    • threadFactory:創建線程池工廠
      1. 用於控制創建線程或者銷毀線程時加入其它邏輯
    • handler:線程池拒絕策略
      1. 直接丟棄(DiscardPolicy)
      2. 丟棄隊列中最老的任務(DiscardOldestPolicy)。
      3. 拋異常(AbortPolicy)
      4. 將任務分給調用線程來執行(CallerRunsPolicy)

Java線程池(ExecutorService)使用