您好,我是湘王,這是我的博客園,歡迎您來,歡迎您再來~ 開完一趟車完整的過程是啟動、行駛和停車,但老司機都知道,真正費油的不是行駛,而是長時間的怠速、頻繁地踩剎車等動作。因為在速度切換的過程中,發送機要多做一些工作,當然就要多費一些油。 而一個Java線程完整的生命周期就包括: 1、T1:創建(啟動 ...
您好,我是湘王,這是我的博客園,歡迎您來,歡迎您再來~
開完一趟車完整的過程是啟動、行駛和停車,但老司機都知道,真正費油的不是行駛,而是長時間的怠速、頻繁地踩剎車等動作。因為在速度切換的過程中,發送機要多做一些工作,當然就要多費一些油。
而一個Java線程完整的生命周期就包括:
1、T1:創建(啟動)
2、T2:運行(行駛)
3、T3:銷毀(停車)
而T1 + T3的開銷(汽油或者時間)是要遠大於T2的。所以,即使是性能再好的車,或者性能再好的電腦,如果經常有T1 + T3的操作存在,那麼顯然是扛不住的。
所以,為瞭解決這種因為切換不同線程導致的效率問題,Java推出了線程池技術。通過對已創建線程的合理重用,既能解決上述問題,又能進一步提高響應速度,提升系統性能和穩定性。線程池特別適合下麵的應用場景:
1、單個任務處理時間較短
2、需要處理的任務數量大
比如硬體數據採集,像手機、車載和安防感測器的數據採集就特別符合這種情況。
這是線程池相關繼承結構圖:
很多人都分不清Executor和Executors這兩個東西:Executor是介面,是一個根據一組執行策略調用、調度、執行和控制的非同步任務框架,提供了一種將“任務提交”與“任務如何運行”分離開的機制。而Executors則是一個工具類(不用new),提供了諸多用於線程池的靜態方法。Executor和Executors的關係,和Java I/O中Collection和Collections的關係一毛一樣。所以下次再看到XXX和XXXs的時候應該就知道Java的調性了。
說起來還是有點枯燥,那麼我拿之前做的一個例子來說一下就明白了。
假設有一個工地有若幹項目經理和工人,1個經理+1個工人組成工作小隊,工地有很多個這樣的工作小隊,這些工作小隊需要加入項目組,但是只有有活乾的才能加入,沒活乾的加不了,就能要被優化裁員。
/** * 工人 * * @author 湘王 */ public class Worker { /** * 幹活 */ public void dosomething() { try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("挖坑"); } }
/** * 經理 * * @author 湘王 */ public class Manager implements Runnable { private Worker worker; public Worker getWorker() { return worker; } public void setWorker(Worker worker) { this.worker = worker; } /** * 經理動嘴,工人動手 */ @Override public void run() { worker.dosomething(); } }
/** * 項目組 * * @author 湘王 */ public class ManagerGroup { private static ExecutorService projectGroup = new ThreadPoolExecutor( 3, // 核心小隊數量 3, // 最多能容納多少個小隊 30, // 多久沒活乾就請出項目組 TimeUnit.SECONDS, // 時間單位 new ArrayBlockingQueue<Runnable>(3),// 有多少個項目經理就不再接收入組申請 new ThreadPoolExecutor.CallerRunsPolicy() // 項目組拒絕響應時怎麼處理 ); // 項目組增加工作小隊 public static void addTask(Manager manager) { projectGroup.execute(manager); } public static void main(String[] args) { Manager manager1 = new Manager(); Worker worker1 = new Worker(); manager1.setWorker(worker1); Manager manager2 = new Manager(); Worker worker2 = new Worker(); manager2.setWorker(worker2); Manager manager3 = new Manager(); Worker worker3 = new Worker(); manager3.setWorker(worker3); // 申請進入項目組有活幹才可能不被優化 ManagerGroup.addTask(manager1); ManagerGroup.addTask(manager2); ManagerGroup.addTask(manager3); } }
可以自己將核心小組數量、最多能容納的小隊數量等數字調節一下,然後運行看看效果。
和線程一樣,線程池也有自己的狀態,而且和線程的狀態差不多(想想也是,畢竟要符合線程生命周期的東西,確實應該差不多)。線程池狀態:
1、RUNNING:正常運行,能接收新任務,也能處理阻塞隊列中的任務;
2、SHUTDOWN:關閉狀態,不接收新任務,但可以繼續處理阻塞隊列中已有任務;
3、STOP:既不接收新任務,也不處理隊列中的任務,並會中斷正在處理的任務;
4、TIDYING(這個名字叫得有點奇怪):如果所有任務都已中止,且workCount有效線程數為0,則會調用terminated()方法進入TERMINATED狀態;
5、TERMINATED:terminated()方法執行完後進入該狀態,什麼也不做。
線程池運行時的流程圖:
至於線程池的構造函數什麼的就不多啰嗦了,太枯燥無聊。
感謝您的大駕光臨!咨詢技術、產品、運營和管理相關問題,請關註後留言。歡迎騷擾,不勝榮幸~