多線程編碼方式:
class MyTask implements Runnable{
public void run(){}
}
public class Test{
public static void main(String[] args){
MyTask task = new MyTask();
Thread thread = new Thread(task);
thread.start();
}
}
傳統的編寫線程:
1:新建線程,執行任務,任務完畢,線程銷燬。線程的頻繁新建/銷燬都是由JVM管理的,非常的消耗系統性能。
2:當任務比較小時,花在創建和銷燬線程上的時間會比任務執行的時間長。尤其是如果有大量的任務時,線程的大量創建和銷燬,有內存溢出的風險。
線程池帶來的其它方面的優化和提升:
1.線程池中的線程是可以重用的,不用多次的創建和銷燬,提高了系統的性能。
2.線程池中的隊列可以管理大量的任務,任務的執行,調度,排隊,丟棄等事宜都由線程池來管理,做到任務可控。
3.線程池對線程進行一些維護和管理,比如線程定時執行,線程生命週期管理,多少個線程併發,線程執行的監控等。
線程池介紹:
接口:
1.Executor 其內僅有execute(Runnable task);方法。
2.ExecutorService 繼承Executor,對線程有更多的管理,常用的有:submit()方法、shutdown()方法等。
3.ScheduledExecutorService 繼承ExecutorService,對線程又進一步的支持了定時執行的職能。
類:
1.AbstractExecutorService 默認實現了ExecutorService接口中的部分方法。
2.ThreadPoolExecutor 我們常用的類,裏面的職能有:維護任務隊列,維護線程組,管理線程調度,執行,監控,等。
3.ScheduledThreadPoolExecutor 裏面的職能相對於父類ThreadPoolExecutor來說,多了對線程定時執行的職能。
線程池工作原理的流程圖:
/**
* 線程池的構造函數
*/
public ThreadPoolExecutor(int corePoolSize, //核心線程數 舉例說明: 有編制的正式快遞員員工個數
int maximumPoolSize, //最大線程數 雙11了,包裹量急劇增多,正式員工忙不過來,只能新招臨時工 =( 最大 - 核心 )
long keepAliveTime, //臨時工呆多久 臨時工就是臨時工(包裹量不多的時候會被辭退的),能呆幾天
TimeUnit unit, //臨時工呆多久的計量單位 臨時工呆多少小時,那麼unit就計量單位爲小時;臨時工能呆多少天,unit計量單位就是天
BlockingQueue<Runnable> workQueue, //任務隊列 需要派送的大量包裹存儲的地方
ThreadFactory threadFactory, //線程工廠
RejectedExecutionHandler handler) //異常處理
線程池工作原理描述:
1:有新任務了,儘可能的讓核心線程去執行;
2:核心線程都在忙了,再來的任務就放到隊列中去排隊等待被執行;
3:隊列中都塞滿了任務,還來新任務,就臨時招募非核心線程來執行剛到的新任務;
4:隊列滿了,核心線程/非核心線程都在忙,還來新任務,啓用安全策略;
5:安全策略來處理仍源源不斷到來的新任務,安全策略決定是丟棄新來的任務,還是其它處理。
線程池的幾條安全策略:
AbortPolicy 默認策略,不執行此任務,而且直接拋出RuntimeException。 切記execute()需要try catch,否則程序會直接退出
DiscardPolicy 直接拋棄,任務不執行,空方法
DiscardOldestPolicy 從隊列裏面拋棄head的一個任務,並再次嘗試調用execute(task);
CallerRunsPolicy 當前線程調用的execute(task)方法,當前線程阻塞在這裏,直至task執行完畢
自定義策略 (常用)自定義類實現RejectedExecutionHandler。例:可以先把任務寫入文件或者數據庫,以防止任務丟棄