1. 程式人生 > 其它 >6.執行緒池(重點)

6.執行緒池(重點)

執行緒池重點:
     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();