天天看點

多線程之使用線程池建立線程

1.使用線程池的優點

1.減少資源的消耗。重複利用已經建立的線程,避免頻繁的創造和銷毀線程,減少消耗。

2.提高響應速度。當執行任務時,不需要去建立線程再來執行,隻要調動現有的線程來執行即可。

3.提高了線程的管理性。線程是稀缺資源,使用線程池可以進行統一的配置設定、調優和監控。

2.建立線程池的兩種方案

1.通過Executors建立,它提供了四種線程池:

newCachedThreadPool建立一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閑線程,若無可回收,則建立線程。

newFixedThreadPool 建立一個定長線程池,可控制線程最大并發數,超出的線程會在隊列中等待。

newScheduledThreadPool 建立一個定長線程池,支援定時及周期性任務執行。

newSingleThreadExecutor 建立一個單線程化的線程池,它隻會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行。

注意:不建議使用這種方法建立線程池。因為newFixedThreadPool 和newSingleThreadExecutor允許的最大請求隊列長度為Integer.MAX_VALUE,可能會堆積大量的請求,進而導緻OOM。newCachedThreadPoo和newScheduledThreadPool允許的建立線程的最大數量為Integer.MAX_VALUE,,進而導緻OOM。

public class Demo01 {
    public static void main(String[] args) {
        //ExecutorService threadPool = Executors.newSingleThreadExecutor(); //建立單個線程
        //ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(5);//建立一個固定大小的線程池
        //ExecutorService threadPool = Executors.newFixedThreadPool(5); //建立一個固定大小的線程池
        ExecutorService threadPool = Executors.newCachedThreadPool(); //建立大小可伸縮的線程池

        try {
            for (int i = 0; i < 30; i++) {
                //使用線程池來建立線程
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+"ok");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown(); //線程池使用完畢後需要關閉
        }

    }
}

           
2.通過ThreadPoolExecutor建立,new ThreadPoolExecutor有7個核心參數,分别如下:
ThreadPoolExecutor(int corePoolSize, //核心線程池大小,始終存在
               int maximumPoolSize, //最大線程數
                long keepAliveTime, //空閑線程等待時間,逾時則銷毀
                     TimeUnit unit, //時間機關
 BlockingQueue<Runnable> workQueue, //等待阻塞隊列
       ThreadFactory threadFactory, //線程工廠
   RejectedExecutionHandler handler) //線程拒絕政策
           
其最後一個參數拒絕政策共有四種:
//new ThreadPoolExecutor.AbortPolicy():達到最大承載量,不再處理,并且抛出異常
//new ThreadPoolExecutor.CallerRunsPolicy():達到最大承載量,從哪來的去哪裡
//new ThreadPoolExecutor.DiscardPolicy():達到最大承載量,丢掉任務,但不抛出異常
//new ThreadPoolExecutor.DiscardOldestPolicy():達到最大承載量,嘗試與最早執行的線程去競争,不抛出異常
           
public class Demo02 {
    public static void main(String[] args) {
        //new ThreadPoolExecutor.AbortPolicy():達到最大承載量,不再處理,并且抛出異常
        //new ThreadPoolExecutor.CallerRunsPolicy():達到最大承載量,從哪來的去哪裡
        //new ThreadPoolExecutor.DiscardPolicy():達到最大承載量,丢掉任務,但不抛出異常
        //new ThreadPoolExecutor.DiscardOldestPolicy():達到最大承載量,嘗試與最早執行的線程去競争,不抛出異常

        //最大線程池大小該如何定義
        //1.cpu密集型,邏輯處理器個數
        //2.io密集型 > 判斷程式十分耗IO的線程,最大線程池大小應該比這個大
        int maxPools= Runtime.getRuntime().availableProcessors();
        System.out.println(maxPools);

        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
                2,
                maxPools,
                3,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.DiscardOldestPolicy()
        );

        try {
            for (int i = 0; i < 10; i++) {
                //使用線程池來建立線程
                //最大承載:maximumPoolSize+workQueue,超過執行拒絕政策
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+" ok");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown(); //線程池使用完畢後需要關閉
        }

    }
}