Java解析線程池

什麼是線程池

線程池就是裝有線程的池子,把要執行的線程交給線程池來處理,通過維護一定數量的線程池來達到多個線程的複用。

線程池的好處

如果不用線程池,每個線程都要通過new Thread(xxRunnable).start()的方法來創建並運行一個線程。每次創建一個和銷燬一個線程都是要消耗系統資源的。當線程數達到一定數量就會耗盡系統的CPU和內存資源,也會造成GC頻繁收集和停頓。而線程複用節省了很大的一部分系統資源,當線程一段時間不再有任務時自動銷燬,不會常駐內存。

線程池核心類

public ThreadPoolExecutor(int corePoolSize,//線程池的核心大小,也是最小的線程池大小
                              int maximumPoolSize,//最大線程池大小
                              long keepAliveTime,//空餘線程存活時間,指的是超過corePoolSize大小的空餘線程多長時間後銷燬
                              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.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

線程池工作流程

  1. 如果線程池中的線程小於corePoolSize,創建新線程執行任務
  2. 如果線程池中的線程大於corePoolSize,把任務存儲到工作隊列workQueue中等待執行
  3. 如果workQueue也滿了,線程數小於maximumPoolSize就創建新線程執行任務;線程數大於等於maximumPoolSize就執行拒絕策略

線程池分類

Executors是JDK提供的創建線程池的工廠類

  • newFixedThreadPool
    固定線程池,核心線程數和最大線程固定相等,空閒存活時間爲0,工作隊列是最大爲Integer.MAX_VALUE大小的阻塞隊列。執行任務時,如果線程都很忙,就會等到工作隊列有空閒線程時再執行,隊列滿了就執行默認的拒絕策略。
public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
  • newCachedThreadPool
    帶緩衝線程池,核心線程數爲0,最大線程數爲Integer最大值大小,超過0個的空閒線程在60秒後銷燬。SynchronousQueue這是一個直接提交的隊列,每個新任務都會有線程來執行。如果線程池有可用線程則執行任務,沒有就創建一個來執行。線程池中的線程數不確定。一般建議執行速度較快較小的線程,不然這個最大線程池邊界過大容易造成內存溢出。
public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
  • newSingleThreadExecutor
    單線程線程池,核心線程數和最大線程數均爲1,空閒線程存活0毫秒。每次只執行一個線程,多餘的先存儲到工作隊列,一個一個執行,保證了線程的順序執行。
public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
  • newScheduledThreadPool
    調度線程池,即按一定的週期執行任務,即定時任務,對ThreadPoolExecutor進行了包裝。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }

拒絕策略

  • AbortPolicy
    直接拋出拒絕異常,這也是默認的拒絕策略。
public static class AbortPolicy implements RejectedExecutionHandler {
        /**
         * Creates an {@code AbortPolicy}.
         */
        public AbortPolicy() { }

        /**
         * Always throws RejectedExecutionException.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         * @throws RejectedExecutionException always
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            throw new RejectedExecutionException("Task " + r.toString() +
                                                 " rejected from " +
                                                 e.toString());
        }
    }
  • CallerRunsPolicy
    如果線程池未關閉,則會在調用者線程中直接執行新任務,導致主線程提交線程性能變慢。
public static class CallerRunsPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code CallerRunsPolicy}.
         */
        public CallerRunsPolicy() { }

        /**
         * Executes task r in the caller's thread, unless the executor
         * has been shut down, in which case the task is discarded.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                r.run();
            }
        }
    }
  • DiscardPolicy
    不處理新任務,丟棄。
public static class DiscardPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code DiscardPolicy}.
         */
        public DiscardPolicy() { }

        /**
         * Does nothing, which has the effect of discarding task r.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        }
    }
  • DiscardOldestPolicy
    拋棄最老的任務執行新任務
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code DiscardOldestPolicy} for the given executor.
         */
        public DiscardOldestPolicy() { }

        /**
         * Obtains and ignores the next task that the executor
         * would otherwise execute, if one is immediately available,
         * and then retries execution of task r, unless the executor
         * is shut down, in which case task r is instead discarded.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                e.getQueue().poll();
                e.execute(r);
            }
        }
    }

提交線程

ExecutorService es = Executors.newFixedThreadPool(3);//定義一個固定大小的線程池
es.submit(xxRunnble);//提交線程,execute沒有返回值,不知道線程結果
es.execute(xxRunnble);//提交線程,submit返回一個Future對象,並能在主線程中通過Future的get方法捕獲線程中的異常

關閉線程池

es.shutdown();//不再接受新的任務,等執行完所有任務後關閉線程池。
es.shutdownNow();//不再接受新的任務,嘗試停止所有任務後關閉線程池,返回未處理的線程list列表。

歡迎關注我的公衆號

在這裏插入圖片描述

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