日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

线程池ThreadPool,线程池底层ThreadPoolExecutor方法七大参数,拒绝策略,以及实际开发中高并发下用到哪个线程池?

發布時間:2023/12/10 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 线程池ThreadPool,线程池底层ThreadPoolExecutor方法七大参数,拒绝策略,以及实际开发中高并发下用到哪个线程池? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

為什么要用線程池

基本的三個線程池的底層就是ThreadPoolExecutor類

ExecutorService threadPool = Executors.newFixedThreadPool(int);//固定線程數的線程池,,執行長期的任務,性能好
ExecutorService threadPool = Executors.newSingleThreadExecutor(); //單線程的線程池,,一個任務一個任務執行
ExecutorService threadPool = Executors.newCachedThreadPool(); //一池N線程,,,執行很多短期異步的任務

Executors是工具類,類似Arrays、Collections

底層ThreadPoolExecutor的重要參數:7大參數(面試一般問前5個)


  • int corePoolSize, 線程池中的常駐核心線程數
  • int maximumPoolSize, 線程池能夠容納同時執行的最大線程數,此值必須大于等于1(當核心線程數滿了并且阻塞隊列的線程數也滿了,那么就會進行擴容,最大值是maximumPoolSize)
  • long keepAliveTime, 多余的空閑線程的存活時間,當前線程池數量超過corePoolSize時,
    當空閑時間達到keepAliveTime值時,多余空閑線程會被銷毀直到只剩corePoolSize個線程為止。
  • TimeUnit unit, keepAliveTime的單位
  • BlockingQueue workQueue, 任務隊列,被提交但尚未被執行的任務。(候客區)
  • ThreadFactory threadFactory, 表示生成線程池中的工作線程的線程工廠,用于創建線程一般用默認的即可
  • RejectedExecutionHandler handler 拒絕策略,表示當前隊列滿了并且工作線程大于等于線程池的最大線程數(maximumPoolSize)時如何來拒絕請求執行的runnable的策略

當空閑線程空閑的時間超過keepAliveTime,就會被銷毀,但是最少會存在corePoolsize數個線程,如下

線程池的底層工作原理(七大參數如何互動?)


文字講解

  • 在創建線程池后,等待提交過來的任務請求。
  • 當調用execute()方法添加一個請求任務時,線程池會做如下判斷:
    2.2 如果正在運行的線程數量小于corePoolSize,那么馬上創建線程運行這個任務。
    2.2 如果正在運行的線程數量大于corePoolSize,那么將這個任務加入阻塞隊列
    2.3 如果這時候阻塞隊列滿了且正在運行的線程數量小于maximumPoolSize,那么還是要創建非核心線程立刻執行這個任務。
    2.4 如果阻塞隊列滿了且正在運行的線程數大于或等于maximumPoolSize,那么線程池會啟動飽和拒絕策略(RejectedExecutionHandler)來執行。
  • 當一個線程完成任務時,他會從阻塞隊列中取出下一個任務執行。
  • 當一個線程無事可做超過keepAliveTime時,線程池會判斷:
    當運行的線程數大于corePoolSize,那么這個線程就被叫停。
    所以線程池的所有任務完成后它的線程數最終會收縮到corePoolSize的數量。
  • package JUC;import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;/*** 線程池*/ public class MyThreadPoolDemo {public static void main(String []args){//System.out.println(Runtime.getRuntime().availableProcessors());//查看cup核數//線程池的底層就是ThreadPoolExecutor類//Executors是工具類//newScheduledThreadPool帶時間的//java獲得線程的方法有4種,繼承Thread類、實現Runable(沒有返回值,不會拋異常,重新run()方法)、實現Callable(有返回值,會拋異常,重新call()方法)、線程池(ThreadPoolExecutor)//池化不用newExecutorService threadPool = Executors.newFixedThreadPool(5);//固定線程數的線程池,,執行長期的任務,性能好//ExecutorService threadPool = Executors.newSingleThreadExecutor(); //單線程的線程池,,一個任務一個任務執行//ExecutorService threadPool = Executors.newCachedThreadPool(); //一池N線程,,,執行很多短期異步的任務//模擬10用戶來辦理業務,每個用戶就是一個外部的請求線程,線程池里的線程是工作人員try{for (int i = 0; i < 10 ; i++) {threadPool.execute(()->{System.out.println(Thread.currentThread().getName()+"\t辦理業務");});//TimeUnit.MILLISECONDS.sleep(200);//在Cache線程池里,如果每次暫停0.2秒那么一個線程就可以處理過了,所以每次都是同一個線程,去掉延時就不是一個線程了}}catch (Exception e){e.printStackTrace();}finally {threadPool.shutdown();}} }

    線程池的拒絕策略RejectedExecutionHandler(四種)

  • AbortPolicy(默認):直接拋出RejectedExecutionException異常阻止系統正常運行
  • CallerRunsPolicy:“調用者運行”一種調節機制,該策略既不會拋出任務,也不會拋出異常,而是將某些任務回退到調用調用者,從而降低新的任務流量。()
  • DiscardOldestPolicy:拋出隊列中等待最久的任務,然后把當前任務加入隊列中嘗試再次提交當前任務
  • DiscardPolicy:直接丟棄任務,不予任何處理也不拋出異常。如果允許任務丟失,這是最好的一種方案。
  • 那么實際的高并發下使用哪個線程池?(面試題)

    以上三種高并發下都不會使用:(阿里java開發手冊)


    1)第一個圖片可以看到newFixedThreadPool和SingleThreadPool的阻塞隊列用的是LinkedBlockingQueue,Linked底層是鏈表,Integer.MAX_VALUE接近21億,請求可以一直加到阻塞隊列里,那么太多就會OOM。
    2)CachedThreadPool和ScheduledThreadPool的第二個參數也就是最大線程數是Integer.MAX_VALUE,可能創建大量線程,導致OOM

    接下來繼續測試下每個拒絕策略:(自定義線程池后)

    這是自定義的線程池:可以看到核心線程數為2,最大線程數為5,阻塞隊列為3,那么允許請求的最大線程數為5+3=8個

    // 自定義線程池ExecutorService threadPool = new ThreadPoolExecutor(2,5,1L,TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>(3),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());

    1.AbortPolicy():直接拋出RejectedExecutionException異常阻止系統正常運行

    public class MyThreadPoolDemo {public static void main(String []args){// 自定義線程池ExecutorService threadPool = new ThreadPoolExecutor(2,5,1L,TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>(3),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());try{for (int i = 1; i <= 10 ; i++) {threadPool.execute(()->{System.out.println(Thread.currentThread().getName()+"\t辦理業務");});//TimeUnit.MILLISECONDS.sleep(200);//在Cache線程池里,如果每次暫停0.2秒那么一個線程就可以處理過了,所以每次都是同一個線程,去掉延時就不是一個線程了}}catch (Exception e){e.printStackTrace();}finally {threadPool.shutdown();}}

    結果:可以看到會拋異常。

    2.CallerRunsPolicy():“調用者運行”一種調節機制,該策略既不會拋出任務,也不會拋出異常,而是將某些任務回退到調用調用者,從而降低新的任務流量。()

    public class MyThreadPoolDemo {public static void main(String []args){// 自定義線程池ExecutorService threadPool = new ThreadPoolExecutor(2,5,1L,TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>(3),Executors.defaultThreadFactory(),new ThreadPoolExecutor.CallerRunsPolicy());try{for (int i = 1; i <= 9 ; i++) {threadPool.execute(()->{System.out.println(Thread.currentThread().getName()+"\t辦理業務");});//TimeUnit.MILLISECONDS.sleep(200);//在Cache線程池里,如果每次暫停0.2秒那么一個線程就可以處理過了,所以每次都是同一個線程,去掉延時就不是一個線程了}}catch (Exception e){e.printStackTrace();}finally {threadPool.shutdown();}}

    結果:可以看到多出來的會回退給main線程,(這里可能出現1個main或者沒有main,因為線程執行的太快,阻塞隊列的已經被執行到了,所以可能有偏差)

    3.DiscardOldestPolicy() :拋出隊列中等待最久的任務,然后把當前任務加入隊列中嘗試再次提交當前任務

    public static void main(String []args){// 自定義線程池ExecutorService threadPool = new ThreadPoolExecutor(2,5,1L,TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>(3),Executors.defaultThreadFactory(),new ThreadPoolExecutor.DiscardOldestPolicy());try{for (int i = 1; i <= 10 ; i++) {threadPool.execute(()->{System.out.println(Thread.currentThread().getName()+"\t辦理業務");});//TimeUnit.MILLISECONDS.sleep(200);//在Cache線程池里,如果每次暫停0.2秒那么一個線程就可以處理過了,所以每次都是同一個線程,去掉延時就不是一個線程了}}catch (Exception e){e.printStackTrace();}finally {threadPool.shutdown();}}


    4.DiscardPolicy() :直接丟棄任務,不予任何處理也不拋出異常。如果允許任務丟失,這是最好的一種方案。

    public static void main(String []args){// 自定義線程池ExecutorService threadPool = new ThreadPoolExecutor(2,5,1L,TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>(3),Executors.defaultThreadFactory(),new ThreadPoolExecutor.DiscardPolicy());try{for (int i = 1; i <= 10 ; i++) {threadPool.execute(()->{System.out.println(Thread.currentThread().getName()+"\t辦理業務");});//TimeUnit.MILLISECONDS.sleep(200);//在Cache線程池里,如果每次暫停0.2秒那么一個線程就可以處理過了,所以每次都是同一個線程,去掉延時就不是一個線程了}}catch (Exception e){e.printStackTrace();}finally {threadPool.shutdown();}}

    那么實際生產中,如何配置自定義線程池的參數呢?

    1.CUP密集型:

    2.IO密集型

    2.1.
    2.2

    總結

    以上是生活随笔為你收集整理的线程池ThreadPool,线程池底层ThreadPoolExecutor方法七大参数,拒绝策略,以及实际开发中高并发下用到哪个线程池?的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。