6.執行緒池(重點)
阿新 • • 發佈:2022-05-13
執行緒池重點: 1.三大方法 2.7大引數 3.4種拒絕策略 池化技術: 程式的執行本質是:佔用系統的資源!優化資源的使用==>池化技術 執行緒池、連線池、記憶體池、物件池等等 建立銷燬十分浪費資源 池化技術:事先準備好一些資源,有人要用,就拿來用,用完歸還 執行緒池的好處: 1.降低資源的消耗和浪費 2.提高響應的速度 3.方便管理 執行緒複用、可以控制併發數、管理執行緒 重點1:執行緒池的三大方法:Executors可以看做是執行緒池的一個工具類 1.單個執行緒 ExecutorService threadPool = Executors.newSingleThreadExecutor(); 樣例程式碼如下: public class ThreadPool { public static void main(String[] args) { 重點1:建立單個執行緒的執行緒池 ExecutorService threadPool = Executors.newSingleThreadExecutor(); try { for (int i = 0; i < 10; i++) { final int temp = i; 重點2:通過執行緒池啟動執行緒:execute(Runnable) threadPool.execute(()->{ System.out.println(Thread.currentThread().getName()+":"+temp); }); } } catch (Exception e) { e.printStackTrace(); } finally { threadPool.shutdown(); } } } 輸出:發現至此只有一個執行緒在執行方法 pool-1-thread-1:0 pool-1-thread-1:1 pool-1-thread-1:2 pool-1-thread-1:3 pool-1-thread-1:4 ... 2.建立固定大小的執行緒池Executors.newFixedThreadPool(5) ExecutorService threadPool = Executors.newFixedThreadPool(5); 輸出:發現同時最多有5個執行緒在執行 pool-1-thread-1:0 pool-1-thread-2:1 pool-1-thread-1:5 pool-1-thread-2:6 pool-1-thread-1:7 pool-1-thread-2:8 pool-1-thread-1:9 pool-1-thread-3:2 pool-1-thread-4:3 pool-1-thread-5:4 3.建立可伸縮的執行緒池:Executors.newCachedThreadPool()建立一個彈性的執行緒池,會根據cpu效能去建立對應的多個執行緒! ExecutorService threadPool = Executors.newCachedThreadPool(); 輸出:發現同時最多有10個執行緒同時執行! pool-1-thread-1:0 pool-1-thread-2:1 pool-1-thread-3:2 pool-1-thread-4:3 pool-1-thread-5:4 pool-1-thread-6:5 pool-1-thread-7:6 pool-1-thread-8:7 pool-1-thread-10:9 pool-1-thread-9:8
重點2:7大引數
研究上述三大方法的原始碼: 1.newSingleThreadExecutor:單個執行緒的執行緒池 public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); } 2.newFixedThreadPool:固定大小的執行緒池 public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); } 3.newCachedThreadPool:可伸縮的執行緒池 public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); } 發現三個方法底層都呼叫的是:ThreadPoolExecutor方法 public ThreadPoolExecutor( int corePoolSize,//核心執行緒池大小 int maximumPoolSize,//最大核心執行緒池大小 long keepAliveTime,//超時時間:超時沒人呼叫自動釋放 TimeUnit unit,//超時時間單位 BlockingQueue<Runnable> workQueue,//阻塞佇列 ThreadFactory threadFactory,//執行緒工廠,建立執行緒的,一般不用動 RejectedExecutionHandler handler//拒絕clue ) { if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0) throw new IllegalArgumentException(); if (workQueue == null || threadFactory == null || handler == null) throw new NullPointerException(); this.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; this.keepAliveTime = unit.toNanos(keepAliveTime); this.threadFactory = threadFactory; this.handler = handler; }
1.平時只有核心執行緒裡的執行緒數在工作
2.但當請求增多,阻塞佇列等待的已滿,則最大執行緒數開始工作,來應對
3.但當執行緒數最大了,並且阻塞佇列已滿,再來請求執行拒絕策略
重點3:自定義執行緒池已經幾種阻塞策略使用
執行緒池的最大併發量=最大核心執行緒數+阻塞佇列中的數量 1:第一種拒絕策略:AbortPolicy:當請求數大於最大併發數時,丟擲異常! 1.1 併發數小於最大核心執行緒數:所以此時的情況是:核心執行緒處理兩個請求,剩餘三個在阻塞區等待,最大核心執行緒未啟動! public class ThreadPool { public static void main(String[] args) { 重點1:建立自定義執行緒池 ExecutorService threadPool = new ThreadPoolExecutor( 2,//核心執行緒池數量 5,//最大執行緒池數 3,//超時時間,最大執行緒池裡的執行緒超過時間無人呼叫時,歸還執行緒資源 TimeUnit.SECONDS,//超時時間單位 new LinkedBlockingQueue<>(3),//阻塞佇列:休息區的數量 Executors.defaultThreadFactory(),//預設的執行緒工廠 new ThreadPoolExecutor.AbortPolicy()//拒絕策略 ); try { 重點2:併發數小於最大核心執行緒數:所以此時的情況是:核心執行緒處理兩個請求,剩餘三個在阻塞區等待,最大核心執行緒未啟動! for (int i = 0; i < 5; i++) { final int temp = i; threadPool.execute(()->{ System.out.println(Thread.currentThread().getName()+":"+temp); }); } } catch (Exception e) { e.printStackTrace(); } finally { threadPool.shutdown(); } } } 輸出:發現只有兩個執行緒併發處理請求 pool-1-thread-1:0 pool-1-thread-2:1 pool-1-thread-1:2 pool-1-thread-2:3 pool-1-thread-2:4 1.2 併發數>核心執行緒數+阻塞執行緒數,最大核心執行緒啟動,但是阻塞區依舊阻塞3個執行緒: 併發6個執行緒>核心執行緒數2+阻塞區執行緒數3,所以此時,最大執行緒區給出相差的1,此時有三個執行緒同時處理,剩餘的阻塞區等待 for (int i = 0; i < 6; i++) { final int temp = i; threadPool.execute(()->{ System.out.println(Thread.currentThread().getName()+":"+temp); }); } 輸出:最大3個執行緒執行 pool-1-thread-1:0 pool-1-thread-2:1 pool-1-thread-2:2 pool-1-thread-2:3 pool-1-thread-2:4 pool-1-thread-3:5 1.3 併發數>最大執行緒數+阻塞執行緒數 此時併發數9>最大執行緒數5+阻塞區3,有一個執行緒無法訪問資源,此時的拒絕策略:AbortPolicy會丟擲異常! try { for (int i = 0; i < 9; i++) { final int temp = i; threadPool.execute(()->{ System.out.println(Thread.currentThread().getName()+":"+temp); }); } } catch (Exception e) { e.printStackTrace(); } finally { threadPool.shutdown(); } 輸出: pool-1-thread-1:0 pool-1-thread-1:2 pool-1-thread-1:3 pool-1-thread-1:4 pool-1-thread-2:1 pool-1-thread-3:5 pool-1-thread-4:6 pool-1-thread-5:7 java.util.concurrent.RejectedExecutionException 2.第二種拒絕策略:CallerRunsPolicy,哪來的回哪去 ExecutorService threadPool = new ThreadPoolExecutor( 2,//核心執行緒池數量 5,//最大執行緒池數 3,//超時時間,最大執行緒池裡的執行緒超過時間無人呼叫時,歸還執行緒資源 TimeUnit.SECONDS,//超時時間單位 new LinkedBlockingQueue<>(3),//阻塞佇列:休息區的數量 Executors.defaultThreadFactory(),//預設的執行緒工廠 new ThreadPoolExecutor.CallerRunsPolicy()//拒絕策略:哪來的回哪去 ); try { for (int i = 0; i < 9; i++) { final int temp = i; threadPool.execute(()->{ System.out.println(Thread.currentThread().getName()+":"+temp); }); } } catch (Exception e) { e.printStackTrace(); } finally { threadPool.shutdown(); } 輸出:發現超出的執行緒由呼叫的main執行緒執行了! pool-1-thread-1:0 main:8 pool-1-thread-2:1 pool-1-thread-1:2 pool-1-thread-2:3 pool-1-thread-1:4 pool-1-thread-4:6 pool-1-thread-5:7 pool-1-thread-3:5 3.DiscardPolicy:丟棄任務,不會丟擲異常! ExecutorService threadPool = new ThreadPoolExecutor( 2,//核心執行緒池數量 5,//最大執行緒池數 3,//超時時間,最大執行緒池裡的執行緒超過時間無人呼叫時,歸還執行緒資源 TimeUnit.SECONDS,//超時時間單位 new LinkedBlockingQueue<>(3),//阻塞佇列:休息區的數量 Executors.defaultThreadFactory(),//預設的執行緒工廠 //DiscardPolicy的拒絕策略,丟棄任務,不會丟擲異常! new ThreadPoolExecutor.DiscardPolicy()//拒絕策略 ); try { for (int i = 0; i < 9; i++) { final int temp = i; threadPool.execute(()->{ System.out.println(Thread.currentThread().getName()+":"+temp); }); } } catch (Exception e) { e.printStackTrace(); } finally { threadPool.shutdown(); } 輸出:發現5個執行緒同時執行,多出的那個執行緒被丟棄! pool-1-thread-1:0 pool-1-thread-4:6 pool-1-thread-3:5 pool-1-thread-2:1 pool-1-thread-4:2 pool-1-thread-5:7 pool-1-thread-4:4 pool-1-thread-1:3 4.DiscardOldestPolicy:佇列滿了是,嘗試和最早的執行緒競爭,也不會丟擲異常! ExecutorService threadPool = new ThreadPoolExecutor( 2,//核心執行緒池數量 5,//最大執行緒池數 3,//超時時間,最大執行緒池裡的執行緒超過時間無人呼叫時,歸還執行緒資源 TimeUnit.SECONDS,//超時時間單位 new LinkedBlockingQueue<>(3),//阻塞佇列:休息區的數量 Executors.defaultThreadFactory(),//預設的執行緒工廠 new ThreadPoolExecutor.DiscardOldestPolicy()//拒絕策略 );
執行緒池的最大的大小如何設定呢
池的最大的大小如何設定?(調優)
1.IO密集型:判斷你程式中什麼耗資源的IO執行緒,讓後將最最大值設為其2倍
2.CPU密集型:幾何cpu就設定為幾,可以保證CPU效率最高
一般都是程式碼獲取cpu核數
Runtime.getRuntime().availableProcessors();