在此以前,咱們已經瞭解了關於線程的基本知識,今天將爲各位帶來,線程池這一技術。關注個人公衆號「Java面典」瞭解更多 Java 相關知識點。html
爲何使用線程池?線程池作的工做主要是控制運行的線程的數量。java
Java 中經常使用的線程池主要有四種:newCachedThreadPool、newFixedThreadPool、newScheduledThreadPool、newSingleThreadExecutor。緩存
做用:建立一個可緩存線程池,若是線程池長度超過處理須要,可靈活回收空閒線程(緩存中已有 60 秒鐘未被使用的線程
),若無可回收,則新建線程。多線程
特色:線程池爲無限大,當執行第二個任務時第一個任務已經完成,會複用執行第一個任務的線程,而不用每次新建線程。併發
實現:框架
ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); for (int i = 0; i < 10; i++) { final int index = i; try { Thread.sleep(index * 1000); } catch (InterruptedException e) { e.printStackTrace(); } cachedThreadPool.execute(new Runnable() { @Override public void run() { System.out.println(index); } }); }
做用:建立一個定長線程池,可控制線程最大併發數,超出的線程會在隊列中等待。ide
特色:性能
定長線程池的大小最好根據系統資源進行設置。如Runtime.getRuntime().availableProcessors()。
this
實現:線程
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3); for (int i = 0; i < 10; i++) { final int index = i; fixedThreadPool.execute(new Runnable() { @Override public void run() { try { System.out.println(index); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } }); }
做用:建立一個定長線程池,支持定時及週期性任務執行。
實現:
ScheduledExecutorService scheduledThreadPoo l= Executors.newScheduledThreadPool(3); scheduledThreadPool.schedule(newRunnable() { @Override public void run() { System.out.println("延遲三秒"); } }, 3, TimeUnit.SECONDS); scheduledThreadPool.scheduleAtFixedRate(newRunnable(){ @Override public void run() { System.out.println("延遲 1 秒後每三秒執行一次"); } }, 1, 3, TimeUnit.SECONDS);
做用:建立一個單線程化的線程池,它只會用惟一的工做線程來執行任務,保證全部任務按照指定順序(FIFO, LIFO, 優先級)執行。
特色:這個線程池能夠在線程死後(或發生異常時)從新啓動一個線程來替代原來的線程繼續執行下去。
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); for (int i = 0; i < 10; i++) { final int index = i; singleThreadExecutor.execute(new Runnable() { @Override public void run() { try { System.out.println(index); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } }); }
做用:線程複用、控制最大併發數、管理線程。線程池作的工做主要是控制運行的線程的數量,處理過程當中將任務放入隊列,而後在線程建立後啓動這些任務,若是線程數量超過了最大數量超出數量的線程排隊等候,等其它線程執行完畢,再從隊列中取出任務來執行。
每個 Thread 的類都有一個 start() 方法。 當調用 start 啓動線程時 Java 虛擬機會調用該類的 run() 方法。 那麼該類的 run() 方法中就是調用了 Runnable 對象的 run() 方法。 咱們能夠繼承重寫Thread 類,在其 start () 方法中添加不斷循環調用傳遞過來的 Runnable 對象。 這就是線程池的實現原理。循環方法中不斷獲取 Runnable 是用 Queue 實現的,在獲取下一個 Runnable 以前能夠是阻塞的。
通常的線程池主要分爲如下 4 個組成部分:
Java 中的線程池是經過 Executor 框架實現的,該框架中用到了 Executor,Executors,ExecutorService,ThreadPoolExecutor ,Callable 和 Future、FutureTask 這幾個類。ThreadPoolExecutor 的構造方法以下:
/** * @param corePoolSize 指定線程池中的線程數量 * @param maximumPoolSize 指定線程池中的最大線程數量 * @param keepAliveTime 當前線程池數量超過 corePoolSize 時,多餘的空閒線程的存活時間 * @param unit keepAliveTime 的單位 * @param workQueue 任務隊列,被提交但還沒有被執行的任務 */ public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { // threadFactory 線程工廠,用於建立線程,通常用默認的便可 // handler 拒絕策略,當任務太多來不及處理,如何拒絕任務 this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); }
做用:線程池中的線程已經用完了,沒法繼續爲新任務服務,同時,等待隊列也已經排滿了,再也塞不下新任務了。這時候咱們就須要拒絕策略機制合理的處理這個問題。
JDK 內置的拒絕策略以下:
以上內置拒絕策略均實現了 RejectedExecutionHandler 接口,若以上策略仍沒法知足實際須要,徹底能夠本身擴展 RejectedExecutionHandler 接口。
Java多線程併發03——什麼是線程上下文,線程是如何調度的