線程池(重點)
一:線程池:三大方法,七大參數,四種拒絕策略
池化技術:
01:程序的運行,本質 :占用系統的資源! 優化資源的使用! =>池化技術
02:線程池、連接池、內存池、對象池///......創建、銷毀。 十分浪費資源
03:池化技術:事先准備好一些資源,有人要用,就來我這里拿,用完之后還給我。
線程池的好處:
01:降低資源的消耗
02:提高響應的速度
03:方便管理
(重點)線程復用、可以控制最大並發數、管理線程
二:三大方法:
01:Executors.newSingleThreadExecutor() //單個線程
代碼示例01
1 package pool; 2 3 import java.util.concurrent.ExecutorService; 4 import java.util.concurrent.Executors; 5 6 //Executors 工具類、3大方法 7 8 public class Demo01 { 9 public static void main(String[] args) { 10 11 ExecutorService threadpool = Executors.newSingleThreadExecutor(); //單個線程 12 13 try { 14 for (int i = 0; i < 10; i++) { 15 //使用了線程池之后,使用線程池來創建線程 16 threadpool.execute(()->{ 17 System.out.println(Thread.currentThread().getName()+" ok"); 18 }); 19 } 20 } catch (Exception e) { 21 e.printStackTrace(); 22 } finally { 23 //線程池用完,程序結束,關閉線程池 24 threadpool.shutdown(); //(為確保關閉,將關閉方法放入到finally中) 25 } 26 } 27 }
運行結果: (10個任務被同一個線程所操作)
02:newFixedThreadPool(int nThreads) //創建一個固定的線程池的大小
代碼示例02
1 package pool; 2 3 import java.util.concurrent.ExecutorService; 4 import java.util.concurrent.Executors; 5 6 //Executors 工具類、3大方法 7 8 public class Demo01 { 9 public static void main(String[] args) { 10 11 //最多5個線程同時執行,從控制台中查看結果 12 ExecutorService threadpool = Executors.newFixedThreadPool(5); //創建一個固定的線程池的大小,(5個線程) 13 14 try { 15 for (int i = 0; i < 10; i++) { 16 //使用了線程池之后,使用線程池來創建線程 17 threadpool.execute(()->{ 18 System.out.println(Thread.currentThread().getName()+" ok"); 19 }); 20 } 21 } catch (Exception e) { 22 e.printStackTrace(); 23 } finally { 24 //線程池用完,程序結束,關閉線程池 25 threadpool.shutdown(); //(為確保關閉,將關閉方法放入到finally中) 26 } 27 } 28 }
運行結果:(最高同時有5個線程在執行)
03:newCachedThreadPool() //緩存池,可伸縮的, 遇強則強,遇弱則弱
代碼示例03
1 package pool; 2 3 import java.util.concurrent.ExecutorService; 4 import java.util.concurrent.Executors; 5 6 //Executors 工具類、3大方法 7 8 public class Demo01 { 9 public static void main(String[] args) { 10 11 ExecutorService threadpool = Executors.newCachedThreadPool(); //緩存池,可伸縮的, 遇強則強,遇弱則弱 12 13 try { 14 for (int i = 0; i < 10; i++) { 15 //使用了線程池之后,使用線程池來創建線程 16 threadpool.execute(()->{ 17 System.out.println(Thread.currentThread().getName()+" ok"); 18 }); 19 } 20 } catch (Exception e) { 21 e.printStackTrace(); 22 } finally { 23 //線程池用完,程序結束,關閉線程池 24 threadpool.shutdown(); //(為確保關閉,將關閉方法放入到finally中) 25 } 26 } 27 }
運行結果:(最高同時有10個線程在執行,可伸縮的, 遇強則強,遇弱則弱)
三:七大參數
01:三大方法之源碼分析:
1 (1) newSingleThreadExecutor() //單個線程 2 3 public static ExecutorService newSingleThreadExecutor() { 4 return new FinalizableDelegatedExecutorService 5 (new ThreadPoolExecutor(1, 1, 6 0L, TimeUnit.MILLISECONDS, 7 new LinkedBlockingQueue<Runnable>())); 8 } 9 ================================================================================== 10 (2) newFixedThreadPool(int nThreads) //創建一個固定的線程池的大小 11 12 public static ExecutorService newFixedThreadPool(int nThreads) { 13 return new ThreadPoolExecutor(nThreads, nThreads, 14 0L, TimeUnit.MILLISECONDS, 15 new LinkedBlockingQueue<Runnable>()); 16 } 17 =================================================================================== 18 (3) newCachedThreadPool() //緩存池,可伸縮的, 遇強則強,遇弱則弱 19 20 public static ExecutorService newCachedThreadPool() { 21 return new ThreadPoolExecutor(0, Integer.MAX_VALUE, //Integer.Max_VALUE 約等於21億 //如果我們有這么多條線程一起跑的話,電腦會OOM(溢出),出現問題 22 60L, TimeUnit.SECONDS, 23 new SynchronousQueue<Runnable>()); 24 } 25 ==================================================================================== 26 (4) 三大方法所公共的 ThreadPoolExecutor() 方法 27 28 ******7大參數****** 29 30 public ThreadPoolExecutor(int corePoolSize, //核心線程池大小 31 int maximumPoolSize, //最大核心線程池大小 32 long keepAliveTime, //超時了沒有人調用就會釋放 33 TimeUnit unit, //超時單位 34 BlockingQueue<Runnable> workQueue, //阻塞隊列 35 ThreadFactory threadFactory, //線程工廠,創建線程的,一般不用動 36 RejectedExecutionHandler handler) { //拒絕策略 37 if (corePoolSize < 0 || 38 maximumPoolSize <= 0 || 39 maximumPoolSize < corePoolSize || 40 keepAliveTime < 0) 41 throw new IllegalArgumentException(); 42 if (workQueue == null || threadFactory == null || handler == null) 43 throw new NullPointerException(); 44 this.corePoolSize = corePoolSize; 45 this.maximumPoolSize = maximumPoolSize; 46 this.workQueue = workQueue; 47 this.keepAliveTime = unit.toNanos(keepAliveTime); 48 this.threadFactory = threadFactory; 49 this.handler = handler; 50 }
阿里巴巴開發手冊中有如下規定:
例如銀行辦理業務圖:
四:四種拒絕策略:
/**
* new ThreadPoolExecutor.AbortPolicy() //銀行滿了,還有人進來,不處理這個人的,拋出異常
* new ThreadPoolExecutor.CallerRunsPolicy() //哪來的去哪里!
* new ThreadPoolExecutor.DiscardPolicy() //隊列滿了,丟掉任務,不會拋出異常!
* new ThreadPoolExecutor.DiscardOldestPolicy() //隊列滿了,嘗試和最早的競爭,也不會拋出異常
*/
五:手動(自定義)創建一個線程池:
代碼示例01 new ThreadPoolExecutor.AbortPolicy() //銀行滿了,還有人進來,不處理這個人的,拋出異常
1 package pool; 2 3 import java.util.concurrent.Executors; 4 import java.util.concurrent.LinkedBlockingDeque; 5 import java.util.concurrent.ThreadPoolExecutor; 6 import java.util.concurrent.TimeUnit; 7 8 public class Demo02 { 9 public static void main(String[] args) { 10 //自定義線程池! 工作中只會使用 ThreadPoolExecutor 11 ThreadPoolExecutor threadPool = new ThreadPoolExecutor( 12 2, //核心線程池大小 13 5, //最大核心線程池大小 14 3, //超時了沒有人調用就會釋放 15 TimeUnit.SECONDS, //超時單位 16 new LinkedBlockingDeque<>(3), //阻塞隊列 17 Executors.defaultThreadFactory(), //線程工廠,創建線程的,一般不用動 18 new ThreadPoolExecutor.AbortPolicy()); //銀行滿了,還有人進來,不處理這個人的,拋出異常 19 20 try { 21 //最大承載數,Deque + Max (隊列線程數+最大線程數) 22 //超出 拋出 RejectedExecutionException 異常 23 for (int i = 1; i <= 9; i++) { 24 //使用了線程池之后,使用線程池來創建線程 25 threadPool.execute(()->{ 26 System.out.println(Thread.currentThread().getName()+" ok"); 27 }); 28 } 29 } catch (Exception e) { 30 e.printStackTrace(); 31 } finally { 32 //線程池用完,程序結束,關閉線程池 33 threadPool.shutdown(); //(為確保關閉,將關閉方法放入到finally中) 34 } 35 } 36 }
運行結果(對比):
代碼示例02 new ThreadPoolExecutor.CallerRunsPolicy() //哪來的去哪里
1 package pool; 2 3 import java.util.concurrent.Executors; 4 import java.util.concurrent.LinkedBlockingDeque; 5 import java.util.concurrent.ThreadPoolExecutor; 6 import java.util.concurrent.TimeUnit; 7 8 public class Demo02 { 9 public static void main(String[] args) { 10 //自定義線程池! 工作中只會使用 ThreadPoolExecutor 11 ThreadPoolExecutor threadPool = new ThreadPoolExecutor( 12 2, //核心線程池大小 13 5, //最大核心線程池大小 14 3, //超時了沒有人調用就會釋放 15 TimeUnit.SECONDS, //超時單位 16 new LinkedBlockingDeque<>(3), //阻塞隊列 17 Executors.defaultThreadFactory(), //線程工廠,創建線程的,一般不用動 18 new ThreadPoolExecutor.CallerRunsPolicy()); //哪來的去哪里! 19 20 try { 21 //最大承載數,Deque + Max (隊列線程數+最大線程數) 22 //超出 拋出 RejectedExecutionException 異常 23 for (int i = 1; i <= 9; i++) { 24 //使用了線程池之后,使用線程池來創建線程 25 threadPool.execute(()->{ 26 System.out.println(Thread.currentThread().getName()+" ok"); 27 }); 28 } 29 } catch (Exception e) { 30 e.printStackTrace(); 31 } finally { 32 //線程池用完,程序結束,關閉線程池 33 threadPool.shutdown(); //(為確保關閉,將關閉方法放入到finally中) 34 } 35 } 36 }
運行結果:
代碼示例03 new ThreadPoolExecutor.DiscardPolicy() //隊列滿了,丟掉任務,不會拋出異常!
1 package pool; 2 3 import java.util.concurrent.Executors; 4 import java.util.concurrent.LinkedBlockingDeque; 5 import java.util.concurrent.ThreadPoolExecutor; 6 import java.util.concurrent.TimeUnit; 7 8 public class Demo02 { 9 public static void main(String[] args) { 10 //自定義線程池! 工作中只會使用 ThreadPoolExecutor 11 ThreadPoolExecutor threadPool = new ThreadPoolExecutor( 12 2, //核心線程池大小 13 5, //最大核心線程池大小 14 3, //超時了沒有人調用就會釋放 15 TimeUnit.SECONDS, //超時單位 16 new LinkedBlockingDeque<>(3), //阻塞隊列 17 Executors.defaultThreadFactory(), //線程工廠,創建線程的,一般不用動 18 new ThreadPoolExecutor.DiscardPolicy()); //隊列滿了,丟掉任務,不會拋出異常! 19 20 try { 21 //最大承載數,Deque + Max (隊列線程數+最大線程數) 22 //超出 拋出 RejectedExecutionException 異常 23 for (int i = 1; i <= 9; i++) { 24 //使用了線程池之后,使用線程池來創建線程 25 threadPool.execute(()->{ 26 System.out.println(Thread.currentThread().getName()+" ok"); 27 }); 28 } 29 } catch (Exception e) { 30 e.printStackTrace(); 31 } finally { 32 //線程池用完,程序結束,關閉線程池 33 threadPool.shutdown(); //(為確保關閉,將關閉方法放入到finally中) 34 } 35 } 36 }
運行結果:
04:代碼示例 new ThreadPoolExecutor.DiscardOldestPolicy() //隊列滿了,嘗試和最早的競爭,也不會拋出異常
1 package pool; 2 3 import java.util.concurrent.Executors; 4 import java.util.concurrent.LinkedBlockingDeque; 5 import java.util.concurrent.ThreadPoolExecutor; 6 import java.util.concurrent.TimeUnit; 7 8 public class Demo02 { 9 public static void main(String[] args) { 10 //自定義線程池! 工作中只會使用 ThreadPoolExecutor 11 ThreadPoolExecutor threadPool = new ThreadPoolExecutor( 12 2, //核心線程池大小 13 5, //最大核心線程池大小 14 3, //超時了沒有人調用就會釋放 15 TimeUnit.SECONDS, //超時單位 16 new LinkedBlockingDeque<>(3), //阻塞隊列 17 Executors.defaultThreadFactory(), //線程工廠,創建線程的,一般不用動 18 new ThreadPoolExecutor.DiscardOldestPolicy()); //隊列滿了,嘗試和最早的競爭,也不會拋出異常 19 20 try { 21 //最大承載數,Deque + Max (隊列線程數+最大線程數) 22 //超出 拋出 RejectedExecutionException 異常 23 for (int i = 1; i <= 9; i++) { 24 //使用了線程池之后,使用線程池來創建線程 25 threadPool.execute(()->{ 26 System.out.println(Thread.currentThread().getName()+" ok"); 27 }); 28 } 29 } catch (Exception e) { 30 e.printStackTrace(); 31 } finally { 32 //線程池用完,程序結束,關閉線程池 33 threadPool.shutdown(); //(為確保關閉,將關閉方法放入到finally中) 34 } 35 } 36 }
運行結果: