線程池概念及實現簡單的線程池

       本文主要介紹線程池的概念,原理,以及簡單實現一個線程池,若文中有不足或錯誤之處,請指出(ps:感激涕零,不要讓我陷入錯誤的誤區。。。)

一:線程池的基本概念和原理

          在此之前,先來思考一個問題,爲啥要用線程池呢?

         線程越多,不一定就會執行的越快,受到CPU的影響,我們要控制線程的數量,線程池它的一個作用,就是用來管理線程的數量的。一般在計算機中,線程的數量是CPU數量的1到2倍。

       線程池主要有下面幾部分組成:

       1:線程池管理器。用來管理線程池的,主要可以創建線程池,銷燬線程池等。

       2:工作線程。執行任務的線程,可以循環的去執行不同的任務。

       3:任務接口。必須要去實現的接口,主要用來線程的調度,任務的收尾以及任務的狀態等。

       4:工作隊列。存放任務的隊列。

          實現一個線程池,首先需要知道線程池的基本原理,我們知道線程池有個頂級接口Excutor,初始化一個線程池,有以下幾個參數需要了解:

ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(
          5, //核心線程數
          10,  //最大線程數
          5,  //若最大線程數5s內沒有任務執行,就銷燬
          TimeUnit.SECONDS, //時間單位
          new LinkedBlockingDeque<>() //隊列
);

         1:核心線程數,線程池的核心線程,當有任務提交過來的時候就創建一個線程,執行任務。

         2:工作隊列,當核心線程數量達到我們設置的值時,就去判斷工作隊列是不是已經滿了,要是沒滿,就把任務放入工作隊列。

         3:最大線程數,當工作隊列已滿,這時候就看是否達到了最大線程數,要是沒有,就建立線程執行任務,要是達到了最大線程數,就執行拒絕策略。

二:實現一個簡單的線程池

  在實現之前,需要思考:實現線程池,需要去實現什麼?怎麼實現?需要做什麼事情?

  根據上面的介紹知道,實現一個線程池,肯定需要一個隊列去存放任務,還需要一個集合去存放線程:

    /** 需要一個任務隊列,用來存放任務 */
    private BlockingDeque<Runnable> blockingDeque;

    /** 需要一個集合,存放工作線程 */
    private static List<Thread> workerList;

  那麼接下來還需要做什麼呢?既然任務隊列和線程都有了,接下來就是從任務隊列拿任務,然後線程循環的去執行任務:

    /** 工作線程執行任務,需要可以循環的執行 */
    public class Worker extends Thread {
        private ThreadPoolDemo threadPool;
        //構造方法
        public Worker(ThreadPoolDemo pool) {
            this.threadPool = pool;
        }
        @Override
        public void run() {
            //判斷條件,線程是否關閉,任務隊列中是否還有任務
            while (isWorker == false || blockingDeque.size() > 0) {
                Runnable task = null;
                try {
                    if (isWorker) {
                        //非阻塞
                        task = blockingDeque.poll();
                    } else {
                        //阻塞
                        task = blockingDeque.take();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (task != null) {
                    task.run();
                }
            }
        }
    }

  下面就是初始化線程池的方法了,指定線程的數量,隊列的大小等:

   /** 初始化一個線程池
     * 傳入參數:線程數,工作隊列數
     */
    public ThreadPoolDemo(int threadSize, int queueSize) {
        //初始化隊列
        blockingDeque = new LinkedBlockingDeque<>(queueSize);
        //初始化工作線程集合(線程安全的)
        workerList = Collections.synchronizedList(new ArrayList<>());
        for (int i = 0; i < threadSize; i ++) {
            Worker worker = new Worker(this);
            //啓動線程
            worker.start();
            //把線程放入線程集合
            workerList.add(worker);
        }
    }

 然後,就是提供一個對外的接口,用來提交任務,下面提供一個阻塞和一個非阻塞的提交任務接口:

    /** 提交任務的接口,阻塞方式 */
    public void submit(Runnable task) {
        try {
            //關閉線程池,就不會有任務提交
            if (!this.isWorker) {
                this.blockingDeque.put(task);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /** 提交任務的接口,非阻塞方式 */
    public boolean execute(Runnable task) {
        //關閉線程池,就不會有任務提交
        if (this.isWorker) {
            return false;
        } else {
            return this.blockingDeque.offer(task);
        }
    }

最後,就是關閉線程池,關閉線程池需要滿足幾個條件:

1:當線程池關閉的時候,不會有新的任務提交過來了;

2:線程再去拿任務的時候,就不能再阻塞了;

3:已經阻塞的線程,需要打斷阻塞。

    /** 標誌位,代表線程池是否關閉 */
    public volatile boolean isWorker = false;

    /**
     * 線程池關閉時:
     * 1:不會有新的任務提交
     * 2:隊列中的任務提交時,不會再阻塞
     * 3:已經阻塞的線程,需要打斷阻塞
     * 4:需要隊列中的任務提交完畢
     */
    public void shutDown() {
        this.isWorker = true;
        for (Thread worker : workerList) {
            //線程阻塞的話,就要打斷阻塞
            if (worker.getState().equals(Thread.State.BLOCKED) || 
                worker.getState().equals(Thread.State.WAITING)) {
                worker.interrupt();
            }
        }
    }

 好了,到此基本的線程池就實現了。下面寫一個測試:

public static void main(String[] args) {
        ThreadPoolDemo pool = new ThreadPoolDemo(3, 6);
        for (int i = 0; i<6; i++) {
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("任務正在被提交");
                }
            });
            pool.submit(thread);
        }
}

最後的最後,知識有限,可能說的不夠全面和深入,見諒。

                                                                                                                                                                 --- 我自是年少,韶華傾付

 

 

 

 

 

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