溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何理解Java常見知識點中的線程池

發(fā)布時間:2021-11-20 15:46:13 來源:億速云 閱讀:109 作者:柒染 欄目:軟件技術(shù)

這期內(nèi)容當中小編將會給大家?guī)碛嘘P(guān)如何理解Java常見知識點中的線程池,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

線程池的基本思想是一種對象池,在程序啟動時就開辟一塊內(nèi)存空間,里面存放了眾多(未死亡)的線程,池中線程執(zhí)行調(diào)度由池管理器來處理。當有線程任務(wù)時,從池中取一個,執(zhí)行完成后線程對象歸池,這樣可以避免反復(fù)創(chuàng)建線程對象所帶來的性能開銷,節(jié)省了系統(tǒng)的資源。

一. 使用線程池的好處

降低資源消耗:通過重復(fù)利用已創(chuàng)建的線程降低線程創(chuàng)建和銷毀造成的消耗(每個線程需要大約1MB內(nèi)存,線程開的越多,消耗的內(nèi)存也就越大,最后死機)。;

提高響應(yīng)速度:當任務(wù)到達時,任務(wù)可以不需要等到線程創(chuàng)建就能立即執(zhí)行;

提高線程的可管理性:線程是稀缺資源,如果無限制的創(chuàng)建,不僅會消耗系統(tǒng)資源,還會降低系統(tǒng)的穩(wěn)定性,使用線程池可以進行統(tǒng)一的分配,調(diào)優(yōu)和監(jiān)控。

對線程進行一些簡單的管理,比如:延時執(zhí)行、定時循環(huán)執(zhí)行的策略等,運用線程池都能進行很好的實現(xiàn)

一個線程池包括以下四個基本組成部分

  • 線程池管理器(ThreadPool):用于創(chuàng)建并管理線程池,包括 創(chuàng)建線程池,銷毀線程池,添加新任務(wù);

  • 工作線程(WorkThread):線程池中線程,在沒有任務(wù)時處于等待狀態(tài),可以循環(huán)的執(zhí)行任務(wù);

  • 任務(wù)接口(Task):每個任務(wù)必須實現(xiàn)的接口,以供工作線程調(diào)度任務(wù)的執(zhí)行,它主要規(guī)定了任務(wù)的入口,任務(wù)執(zhí)行完后的收尾工作,任務(wù)的執(zhí)行狀態(tài)等;

  • 任務(wù)隊列(taskQueue):用于存放沒有處理的任務(wù)。提供一種緩沖機制。

二. ThreadPoolExecutor類

講到線程池,要重點介紹java.uitl.concurrent.ThreadPoolExecutor類,ThreadPoolExecutor是線程池中最核心的一個類。

我們可以通過ThreadPoolExecutor來創(chuàng)建一個線程池

new ThreadPoolExecutor(corePoolSize, maximumPoolSize,keepAliveTime, 
milliseconds,runnableTaskQueue, threadFactory,handler);
  • corePoolSize(線程池的基本大?。?/strong>:當提交一個任務(wù)到線程池時,線程池會創(chuàng)建一個線程來執(zhí)行任務(wù),即使其他空閑的基本線程能夠執(zhí)行新任務(wù)也會創(chuàng)建線程,等到需要執(zhí)行的任務(wù)數(shù)大于線程池基本大小時就不再創(chuàng)建。如果調(diào)用了線程池的prestartAllCoreThreads方法,線程池會提前創(chuàng)建并啟動所有基本線程。

  • maximumPoolSize(線程池最大大小):線程池允許創(chuàng)建的最大線程數(shù)。如果隊列滿了,并且已創(chuàng)建的線程數(shù)小于最大線程數(shù),則線程池會再創(chuàng)建新的線程執(zhí)行任務(wù)。值得注意的是如果使用了無界的任務(wù)隊列這個參數(shù)就沒什么效果。

  • runnableTaskQueue(任務(wù)隊列):用于保存等待執(zhí)行的任務(wù)的阻塞隊列。

  • ThreadFactory:用于設(shè)置創(chuàng)建線程的工廠,可以通過線程工廠給每個創(chuàng)建出來的線程設(shè)置更有意義的名字,Debug和定位問題時非常又幫助。

  • RejectedExecutionHandler(拒絕策略):當隊列和線程池都滿了,說明線程池處于飽和狀態(tài),那么必須采取一種策略處理提交的新任務(wù)。這個策略默認情況下是AbortPolicy,表示無法處理新任務(wù)時拋出異常。以下是JDK1.5提供的四種策略。n AbortPolicy:直接拋出異常。

  • keepAliveTime(線程活動保持時間):線程池的工作線程空閑后,保持存活的時間。所以如果任務(wù)很多,并且每個任務(wù)執(zhí)行的時間比較短,可以調(diào)大這個時間,提高線程的利用率。

  • TimeUnit(線程活動保持時間的單位):可選的單位有天(DAYS),小時(HOURS),分鐘(MINUTES),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)。

向線程池提交任務(wù)

我們可以通過execute()或submit()兩個方法向線程池提交任務(wù),不過它們有所不同

  • execute()方法沒有返回值,所以無法判斷任務(wù)知否被線程池執(zhí)行成功

    threadsPool.execute(new Runnable() {
      
    @Override
      public void run() {
      // TODO Auto-generated method stub
     }
    });
  • submit()方法返回一個future,那么我們可以通過這個future來判斷任務(wù)是否執(zhí)行成功,通過future的get方法來獲取返回值

    try {
       Object s = future.get();
     } catch (InterruptedException e) {
     // 處理中斷異常
     } catch (ExecutionException e) {
     // 處理無法執(zhí)行任務(wù)異常
     } finally {
     // 關(guān)閉線程池
     executor.shutdown();
    }

    線程池的關(guān)閉

我們可以通過shutdown()或shutdownNow()方法來關(guān)閉線程池,不過它們也有所不同

  • shutdown的原理是只是將線程池的狀態(tài)設(shè)置成SHUTDOWN狀態(tài),然后中斷所有沒有正在執(zhí)行任務(wù)的線程。

  • shutdownNow的原理是遍歷線程池中的工作線程,然后逐個調(diào)用線程的interrupt方法來中斷線程,所以無法響應(yīng)中斷的任務(wù)可能永遠無法終止。shutdownNow會首先將線程池的狀態(tài)設(shè)置成STOP,然后嘗試停止所有的正在執(zhí)行或暫停任務(wù)的線程,并返回等待執(zhí)行任務(wù)的列表。

ThreadPoolExecutor執(zhí)行的策略

線程數(shù)量未達到corePoolSize,則新建一個線程(核心線程)執(zhí)行任務(wù)

線程數(shù)量達到了corePools,則將任務(wù)移入隊列等待

隊列已滿,新建線程(非核心線程)執(zhí)行任務(wù)

隊列已滿,總線程數(shù)又達到了maximumPoolSize,就會由(RejectedExecutionHandler)拋出異常

四種拒絕策略

  • ThreadPoolExecutor.AbortPolicy() 拋出java.util.concurrent.RejectedExecutionException異常

  • ThreadPoolExecutor.DiscardPolicy() 拋棄當前的任務(wù)

  • ThreadPoolExecutor.DiscardOldestPolicy() 拋棄舊的任務(wù) (隊列中的第一個任務(wù)替換為當前新進來的任務(wù)執(zhí)行)

  • ThreadPoolExecutor.CallerRunsPolicy() 重試添加當前的任務(wù),他會自動重復(fù)調(diào)用execute()方法

三. Java通過Executors提供四種線程池

1. CachedThreadPool():可緩存線程池。

  • 線程數(shù)無限制

  • 有空閑線程則復(fù)用空閑線程,若無空閑線程則新建線程 一定程序減少頻繁創(chuàng)建/銷毀線程,減少系統(tǒng)開銷

CachedThreadPool創(chuàng)建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閑線程,若無可回收,則新建線程

2. FixedThreadPool():定長線程池。

  • 可控制線程最大并發(fā)數(shù)(同時執(zhí)行的線程數(shù))

  • 超出的線程會在隊列中等待

  • 如果某個線程因為執(zhí)行異常而結(jié)束,那么線程池會補充一個新線程。

3. ScheduledThreadPool()

  • 定時線程池。

  • 支持定時及周期性任務(wù)執(zhí)行。

newscheduledThreadPool創(chuàng)建一個定長線程池,支持定時及周期性任務(wù)執(zhí)行。延遲執(zhí)行示例代碼如下.表示延遲1秒后每3秒執(zhí)行一次

public class ThreadPoolExecutorTest3 {
    public static void main(String[] args) {
        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
        scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
            public void run() {
                System.out.println(Thread.currentThread().getName() + ": delay 1 seconds, and excute every 3 seconds");
            }
        }, 1, 3, TimeUnit.SECONDS);// 表示延遲1秒后每3秒執(zhí)行一次
    }
}

4. SingleThreadExecutor():單線程化的線程池。

  • 有且僅有一個工作線程執(zhí)行任務(wù)

  • 所有任務(wù)按照指定順序執(zhí)行,即遵循隊列的入隊出隊規(guī)則

newSingleThreadExecutor創(chuàng)建一個單線程化的線程池,它只會用唯一的工作線程來執(zhí)行任務(wù),保證所有任務(wù)按照指定順序(FIFO, LIFO, 優(yōu)先級)執(zhí)行,如果這個唯一的線程因為異常結(jié)束,那么會有一個新的線程來替代它。此線程池保證所有任務(wù)的執(zhí)行順序按照任務(wù)的提交順序執(zhí)行

四. 線程池的監(jiān)控

通過繼承線程池并重寫線程池的beforeExecute,afterExecute和terminated方法,我們可以在任務(wù)執(zhí)行前,執(zhí)行后和線程池關(guān)閉前干一些事情。如監(jiān)控任務(wù)的平均執(zhí)行時間,最大執(zhí)行時間和最小執(zhí)行時間等。這幾個方法在線程池里是空方法。

上述就是小編為大家分享的如何理解Java常見知識點中的線程池了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI