1. 程式人生 > >Executor 線程池

Executor 線程池

sys 提高效率 class 循環 運行時 task 如果 port runnable

1、什麽是線程池: java.util.concurrent.Executors提供了一個 java.util.concurrent.Executor接口的實現用於創建線程池

多線程技術主要解決處理器單元內多個線程執行的問題,它可以顯著減少處理器單元的閑置時間,增加處理器單元的吞吐能力。
假設一個服務器完成一項任務所需時間為:T1 創建線程時間,T2 在線程中執行任務的時間,T3 銷毀線程時間。

如果:T1 + T3 遠大於 T2,則可以采用線程池,以提高服務器性能。

一個線程池包括以下四個基本組成部分:
1、線程池管理器(ThreadPool):用於創建並管理線程池,包括 創建線程池,銷毀線程池,添加新任務;
2、工作線程(PoolWorker):線程池中線程,在沒有任務時處於等待狀態,可以循環的執行任務;
3、任務接口(Task):每個任務必須實現的接口,以供工作線程調度任務的執行,它主要規定了任務的入口,任務執行完後的收尾工作,任務的執行狀態等;
4、任務隊列(taskQueue):用於存放沒有處理的任務。提供一種緩沖機制。

線程池技術正是關註如何縮短或調整T1,T3時間的技術,從而提高服務器程序性能的。它把T1,T3分別安排在服務器程序的啟動和結束的時間段或者一些空閑的時間段,這樣在服務器程序處理客戶請求時,不會有T1,T3的開銷了。
線程池不僅調整T1,T3產生的時間段,而且它還顯著減少了創建線程的數目,看一個例子:
假設一個服務器一天要處理50000個請求,並且每個請求需要一個單獨的線程完成。在線程池中,線程數一般是固定的,所以產生線程總數不會超過線程池中線程的數目,而如果服務器不利用線程池來處理這些請求則線程總數為50000。一般線程池大小是遠小於50000。所以利用線程池的服務器程序不會為了創建50000而在處理請求時浪費時間,從而提高效率。

線程池的作用:

線程池作用就是限制系統中執行線程的數量。
根據系統的環境情況,可以自動或手動設置線程數量,達到運行的最佳效果;少了浪費了系統資源,多了造成系統擁擠效率不高。用線程池控制線程數量,其他線程排隊等候。一個任務執行完畢,再從隊列的中取最前面的任務開始執行。若隊列中沒有等待進程,線程池的這一資源處於等待。當一個新任務需要運行時,如果線程池中有等待的工作線程,就可以開始運行了;否則進入等待隊列。

為什麽要用線程池:

1.減少了創建和銷毀線程的次數,每個工作線程都可以被重復利用,可執行多個任務。

2.可以根據系統的承受能力,調整線程池中工作線線程的數目,防止因為消耗過多的內存,而把服務器累趴下(每個線程需要大約1MB內存,線程開的越多,消耗的內存也就越大,最後死機)。

Java裏面線程池的頂級接口是Executor,但是嚴格意義上講Executor並不是一個線程池,而只是一個執行線程的工具。真正的線程池接口是ExecutorService

線程池介紹

package com.cmy.Executor.demo1; import java.util.concurrent.*; /** * 線程復用:線程池(為了避免系統頻繁的創建和銷毀線程,我們可以將創建的線程進行復用) * JDK對線程池的支持: * JDK提供的Executors框架,可以讓我們有效的管理和控制我們的線程,其本質上就是一個線程池 * Executor接口的繼承關系如下所示: * Executor * ↑ * ExecutorService * ↑ ↑ * AbstractExecutorService ScheduledExecutorService * ↑ ↑ * ThreadPoolExecutor ↑ * ↑ ↑ * ScheduledThreadPoolExecutor * * * Executors類常用方法如下: * * 1、newFixedThreadPool:該方法返回一個固定線程數量的線程池; * * 2、newSingleThreadExecutor:該方法返回一個只有一個現成的線程池; * * 3、newCachedThreadPool:返回一個可以根據實際情況調整線程數量的線程池; * * 4、newSingleThreadScheduledExecutor:該方法和newSingleThreadExecutor的區別是給定了時間執行某任務的功能,可以進行定時執行等; * * 5、newScheduledThreadPool:在4的基礎上可以指定線程數量。 * * * 查看Executors類的源碼如下: 例如newFixedThreadPool (同學們可自主查看) * * 以下為:newFixedThreadPool的實現: * public static ExecutorService newFixedThreadPool(int nThreads) { * return new ThreadPoolExecutor(nThreads, nThreads, * 0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()); * } * * 本質上是創建了ThreadPoolExecutor的實例而已! * * ThreadPoolExecutor構造參數如下: * public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, 核心線程池大小 long keepAliveTime, 線程最大容量 TimeUnit unit, 空閑時,線程的存活時間 ThreadFactory, 線程工廠 BlockingQueue<Runnable> workQueue, 任務隊列 RejectedExecutionHandler handler) { 線程的拒絕策略 this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), handler); } * * * */ public class ThreadPoolDemo { public static void main(String[] args){ /*在此 根據alibaba編碼規範的提示 ‘不推薦使用Executors中的方法創建線程池 而是推薦創建ThreadPoolExecutor實例的方式’ 以下為alibaba介紹: 線程池不允許使用Executors去創建,而是使用ThreadPoolExecutor的方式,這樣做可以規避很多風險 說明:各個方法的弊端 newFixedThreadPool和newSingleThreadExecutor: 主要問題是堆積的請求處理隊列可能會耗費非常大的內存 newCachedThreadPool和newScheduledThreadPool 主要問題是線程最大數Integer.MAX_VALUE 可能會創建過多的線程 導致資源浪費 */ //不推薦做法:ExecutorService service=Executors.newFixedThreadPool(4); //獲取擁有4條線程的線程池 //推薦做法 ExecutorService service=new ThreadPoolExecutor(2, 2, 0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<>(10),Executors.defaultThreadFactory()); for (int i=0;i<10;i++){ int index=i; //使用線程池中的線程重復打印index的值 service.submit(()-> System.out.println(Thread.currentThread().getName()+" i:"+index+"service")); } service.shutdown();//線程停止運行 } } 線程池的使用 package com.cmy.Executor.demo2; //使用submit函數帶來的問題 import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class ThreadPoolDemo { public static void main(String[] args){ ExecutorService service= Executors.newFixedThreadPool(4); for(int i=0;i<5;i++){ int index=i; //此處index的初值為0 但控制臺上不會輸出任何異常(原因 內部捕獲了異常) //service.submit(()-> Calc(100,index)); //1:替換為execute //service.execute(()->Calc(100,index)); //2:或者使用Future模式 自定義異常捕獲和信息 Future future=service.submit(()->Calc(100,index)); try { future.get(); } catch (Exception e) { System.out.println("我是異常信息"); } } service.shutdown(); } public static void Calc(int a,int b){ double c=a/b; System.out.println(c); } }

Executor 線程池