Java併發 ---- 線程池

newThread的弊端

  (1)每次new Thread新建對象,性能較差
  (2)線程缺乏統一管理,可能無限制的新建線程,相互競爭,有可能佔用過多的系統資源導致死機或者OOM
  (3)缺少更多得功能,如更多執行,定期執行,線程中斷

線程池的好處

  (1)重用存在的線程,減少對象的創建,消亡的開銷,性能好
  (2)可以有效控制最大併發線程數,提高系統資源利用率,同時可以避免過多資源競爭,避免阻塞
  (3)提供定時執行,定期執行,單線程,併發數控制等功能

線程池 - ThreadPoolExecutor

一些重要參數,以及處理時的情況:
  1.corePoolSize : 核心線程數量。
  2.maximumPoolSize : 線程最大線程數。
  3.workQueue : 阻塞隊列,儲存等待執行的任務,很重要,會對線程池運行過程產生重大影響。

1.運行的線程數小於corePoolSize的時候,直接創建新線程來執行任務,即使其他線程池的其它線程是空閒的。
2.運行的線程數大於等於corePoolSize且小於maximumPoolSize時只有當workQueue滿的時候才創建新的線程來執行任務。
3.如果設置的corePoolSize等於maximumPoolSize,則創建的線程池大小是固定的。
4.如果運行的線程數等於maximumPoolSize,且workQueue還沒有滿,則新任務會添加到workQueue中。
5.如果運行線程數等於maximumPoolSize,且workQueue已經滿了,則通過拒絕策略的參數來處理這個任務。

keepAliveTime : 線程沒有任務執行,最多保持多長時間終止
unit : keepAliveTime的時間單位
threadFactory : 線程工廠,用來創建線程
rejectHandler : 當拒絕處理任務時的策略(1.拋出異常默認策略2.用調用者所在的線程執行任務3.丟棄隊列中最靠前的任務來執行當前任務4.丟棄任務)
  可以根據自己的使用場景,來設置審覈自己的參數。

execute()方法:提交任務,交給線程池執行

submit()方法:提交任務,能夠返回執行結果

shutdown()方法:關閉線程池,等待任務都執行完成

shutdownNow()方法:關閉線程池,不等待任務完成
getTaskCount()方法:線程池已經執行和未執行的任務總數

getCompletedTaskCount()方法:已經完成的任務數量

getPoolSize()方法:線程池當前的線程數量

getActiveCount()方法:當前線程池正在執行任務的線程數量

  根據JDK給我們提供這些方法,我們就可以實時的監控線程池的工作狀態。

線程池的創建方式

  一般有兩種方式創建線程池,一種是直接調用構造方法,另一種是使用Executors去創建。《阿里巴巴Java開發手冊》強制不允許使用Executors創建,因爲這樣存在一些弊端。
  通過 ThreadPoolExecutor 的方式,這樣的處理方式讓寫的同學更加明確線程池的運行規則,規避資源耗盡的風險。

Executors 返回線程池對象的弊端如下:
FixedThreadPoolSingleThreadExecutor : 允許請求的隊列長度爲 Integer.MAX_VALUE,可能堆積大量的請求,從而導致OOM。
CachedThreadPoolScheduledThreadPool : 允許創建的線程數量爲 Integer.MAX_VALUE ,可能會創建大量線程,從而導致OOM。

使用Executors 創建線程池:

1.Executors.newCachedThreadPool():
  創建一個可以緩存的線程池,返回一個可根據實際情況調整線程數量的線程池。 線程池的線程數量不確定,但若有空閒線程可以複用,則會優先使用可複用的線程。若所有線程均在工作,又有新的任務提交,則會創建新的線程處理任務。所有線程 在當前任務執行完畢後,將返回線程池進行復用。
2.Executors.newFixedThreadPool(10):
  該方法返回一個固定線程數量的線程池。該線程池中的線程數量始終不變。當有一個新的任務提交時,線程池中若有空閒線程,則立即執行。若沒有,則新的任務會被暫存在一個任務隊列中,待有線程空閒時,便處理在任務隊列中的任務。
3.Executors.newScheduledThreadPool(10):
  該方法返回一個固定線程數量的線程池。支持定長,週期性的任務執行。
4.Executors.newSingleThreadExecutor():
  方法返回一個只有一個線程的線程池。若多餘一個任務被提交到該線程池,任務會被保存在一個任務隊列中,待線程空閒,按先入先出的順序執行隊列中的任務。

CachedThreadPool例子:

@Slf4j
public class ThreadPoolExample1 {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            final int index = i;
            executorService.execute(() -> {
                log.info("task:{}",index);
            });
        }
        executorService.shutdown();
    }
}
結果是不按大小順序打印的,這是因爲newCachedThreadPool沒有限制最大線程數。

FixedThreadPool例子:

@Slf4j
public class ThreadPoolExample2 {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 10; i++) {
            final int index = i;
            executorService.execute(() -> {
                log.info("task:{}",index);
            });
        }
        executorService.shutdown();
    }
}
可以設置一個固定的線程數目。

FixedThreadPool例子:

@Slf4j
public class ThreadPoolExample3 {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 10; i++) {
            final int index = i;
            executorService.execute(() -> {
                log.info("task:{}",index);
            });
        }
        executorService.shutdown();
    }
}
打印結果是有序打印的,因爲只有一個線程

ScheduledThreadPool例子:

@Slf4j
public class ThreadPoolExample4 {
    public static void main(String[] args) {
        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(10);
//        executorService.schedule(() -> {
//            log.warn("schedule run");
//        }, 3, TimeUnit.SECONDS);
        //延遲一秒,每隔三秒執行一次
        executorService.scheduleAtFixedRate(() -> {
            log.warn("schedule run");
        }, 1, 3, TimeUnit.SECONDS);
//        executorService.shutdown();
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                log.warn("timer run");
            }
        }, new Date(), 5 * 1000);
    }
}
有定時器的功能,和Timer類相似。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章