Java併發編程學習(11)---線程池

目錄頁:https://blog.csdn.net/u011294519/article/details/88367808

1.類層級關係及主要方法

1.1.類層級關係

  1. Executor:頂層接口
  2. ExecutorService:繼承Executor接口,定義管理方法
  3. AbstractExecutorService:抽象類,實現ExecutorService接口作爲骨架類
  4. ThreadPoolExecutor:線程池的具體方法,繼承AbstractExecutorService類

2.主要方法

2.1.構造方法

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

    corePoolSize:線程池中的核心線程數

    maximumPoolSize:線程池中擁有的最大線程數

    unit:空閒線程的存活時間,注意,核心線程數是否減少根據另一個參數allowCoreThreadTimeOut來決定

    workQueue:阻塞隊列,當核心線程數達到最大值時仍有任務進入則放入阻塞隊列等待覈心線程空閒時來此獲取任務,主要使用的阻塞隊列有以下4種:

ArrayBlockingQueue

由數組組成的有界隊阻塞隊列

LinkedBlockingQueue

鏈表結構的有界阻塞隊列

PriorityBlockingQueue

支持優先級排列的無界阻塞隊列

LinkedTransferQueue

鏈表結構的無界阻塞隊列

    handler:表示當workQueue已滿,且池中的線程數達到maximumPoolSize時,線程池拒絕添加新任務時採取的策略。主要有以下4種

ThreadPoolExecutor.AbortPolicy()

拋出RejectedExecutionException異常

ThreadPoolExecutor.CallerRunsPolicy()

由向線程池提交任務的線程來執行該任務

ThreadPoolExecutor.DiscardOldestPolicy()

拋棄最舊的任務(最先提交而沒有得到執行的任務

ThreadPoolExecutor.DiscardPolicy()

拋棄當前的任務

下面就詳細的將下參數間的關

下面就詳細的將下參數間的關係

  1. 如果沒有空閒的線程執行新任務且當前運行的線程數少於corePoolSize,則添加新的線程執行該任務。(線程池不區分哪個線程是核心線程,只關注線程數量)
  2. 如果沒有空閒的線程且線程數等於corePoolSize設置的值,而且阻塞隊列未滿,則將任務入隊列,而不是添加新的線程。
  3. 如果沒有空閒的線程執行新任務且阻塞隊列已滿同時池中的線程數小於maximumPoolSize,則創建新的線程執行任務,所以若阻塞隊列使用的是無界隊列則線程池中執行任務的線程數永遠等於corePoolSize設置的值。
  4. 如果沒有空閒的線程執行新任務且阻塞隊列已滿同時池中的線程數等於maximumPoolSize,則根據構造函數中的handler指定的策略來拒絕新的任務。

2.2.execute與submit方法

    execute方法與submit方法都是用於提交任務到線程池,但是submit方法可以將callable線程的返回值取出。

    示例代碼如下:

package com.concurrent.coline.part13;

import com.google.common.util.concurrent.ThreadFactoryBuilder;

import java.util.concurrent.*;

public class ThreadMethodDemo {
    private static class MyWork implements Runnable {

        @Override
        public void run() {
            try {
                Thread.sleep(2000);
                System.out.println(Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private static class MyCallable implements Callable {

        @Override
        public String call() throws Exception {
            return "Callable: " + Thread.currentThread().getName();
        }
    }

    public static void main(String[] arg0) throws ExecutionException, InterruptedException {
        ThreadFactory demoThreadFactory = new ThreadFactoryBuilder()
                .setNameFormat("demo-thread-%d").build();
        ExecutorService threadPool = new ThreadPoolExecutor(2, 4
                , 10L, TimeUnit.SECONDS
                , new ArrayBlockingQueue<>(10), demoThreadFactory, new ThreadPoolExecutor.AbortPolicy());

        for (int i = 0; i < 10; i++) {
            MyWork work = new MyWork();
            threadPool.execute(work);
        }

        for (int i = 0; i < 10; i++) {
            MyCallable myCallable = new MyCallable();
            Future result = threadPool.submit(myCallable);
            System.out.println(result.get());
        }

        threadPool.shutdown();


    }

}


    代碼位置在thread-pool的ThreadMethodDemo

2.3.beforeExecute與afterExecute方法

    beforeExecute方法和afterExecute方法用於在任務執行之前和任務執行之後做一些自己的操作,類似於Spring的AOP。

示例代碼如下:

package com.concurrent.coline.part13;

import com.google.common.util.concurrent.ThreadFactoryBuilder;

import java.util.concurrent.*;


public class ThreadPoolTest {

    private static class MyWork implements Runnable {

        @Override
        public void run() {
            try {
                Thread.sleep(2000);
                System.out.println(Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private static class MyCallable implements Callable {

        @Override
        public String call() throws Exception {
            return "Callable: " + Thread.currentThread().getName();
        }
    }

    public static void main(String[] arg0) throws ExecutionException, InterruptedException {
        ThreadFactory demoThreadFactory = new ThreadFactoryBuilder()
                .setNameFormat("demo-thread-%d").build();
        ExecutorService threadPool = new ThreadPoolExecutor(2, 4
                , 10L, TimeUnit.SECONDS
                , new ArrayBlockingQueue<>(10), demoThreadFactory, new ThreadPoolExecutor.AbortPolicy()) {

            @Override
            protected void beforeExecute(Thread t, Runnable r) {
                System.out.println("before:" + Thread.currentThread().getName());
            }

            @Override
            protected void afterExecute(Runnable r, Throwable t) {
                System.out.println("after:" + Thread.currentThread().getName());
            }

            @Override
            protected void terminated() {
                System.out.println("線程結束");
            }
        };

        for (int i = 0; i < 10; i++) {
            MyWork work = new MyWork();
            threadPool.execute(work);
        }

        for (int i = 0; i < 10; i++) {
            MyCallable myCallable = new MyCallable();
            Future result = threadPool.submit(myCallable);
            System.out.println(result.get());
        }

        threadPool.shutdown();


    }
}


    
代碼位置在thread-pool模塊的ThreadPoolTest

2.4.shutdown與shutdownNow方法

    shutdown方法與shutdownNow方法都是用於關閉線程池,區別如下:

    shutdown方法首先將線程池狀態修改爲SHUTDOWN,然後調用線程interrupt()方法將空閒線程的中斷標準位設置爲中斷,使用該方式關閉線程池相對優雅。

    shutdownNow方法會將線程池中所有線程的中斷標誌位設置爲中斷,不管任務是否執行完成。

對於線程狀態有以下5種:

RUNNING

允許提交併處理任務

SHUTDOWN

不允許提交新的任務,但是會處理完已提交的任務

STOP

不允許提交新的任務,也不會處理阻塞隊列中未執行的任務,並設置正在執行的線程的中斷標誌位

TIDYING

所有任務執行完畢,池中工作的線程數爲0,等待執行terminated()方法

TERMINATED

terminated()方法執行完畢

3.思維導圖

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章