溫馨提示×

溫馨提示×

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

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

使用Java線程池的方法步驟

發(fā)布時間:2021-10-11 17:49:32 來源:億速云 閱讀:156 作者:iii 欄目:編程語言

這篇文章主要介紹“使用Java線程池的方法步驟”,在日常操作中,相信很多人在使用Java線程池的方法步驟問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”使用Java線程池的方法步驟”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

使用Java線程池的方法步驟

1.為什么使用線程池

1.頻繁創(chuàng)建和銷毀單個線程,浪費資源,并且還會出現(xiàn)頻繁GC

2.缺乏統(tǒng)一管理,各線程相互競爭

2.ThreadPoolExecutor

ThreadPoolExecutor有四個重載的構(gòu)造方法,我們這里來說說參數(shù)最多的那一個重載的構(gòu)造方法,這樣大家就知道其他方法參數(shù)的含義了,如下:

public ThreadPoolExecutor(int corePoolSize,

                              int maximumPoolSize,

                              long keepAliveTime,

                              TimeUnit unit,

                              BlockingQueue<Runnable> workQueue,

                              ThreadFactory threadFactory,

                              RejectedExecutionHandler handler) 

  • 各參數(shù)詳細(xì)說明:

這里是7個參數(shù)(我們在開發(fā)中用的更多的是5個參數(shù)的構(gòu)造方法),OK,那我們來看看這里七個參數(shù)的含義:

corePoolSize 線程池中核心線程的數(shù)量

maximumPoolSize 線程池中最大線程數(shù)量

keepAliveTime 非核心線程的超時時長,當(dāng)系統(tǒng)中非核心線程閑置時間超過keepAliveTime之后,則會被回收。如果ThreadPoolExecutor的allowCoreThreadTimeOut屬性設(shè)置為true,則該參數(shù)也表示核心線程的超時時長

unit 第三個參數(shù)的單位,有納秒、微秒、毫秒、秒、分、時、天等

workQueue 線程池中的任務(wù)隊列,該隊列主要用來存儲已經(jīng)被提交但是尚未執(zhí)行的任務(wù)。存儲在這里的任務(wù)是由ThreadPoolExecutor的execute方法提交來的。

threadFactory 為線程池提供創(chuàng)建新線程的功能,這個我們一般使用默認(rèn)即可

handler 拒絕策略,當(dāng)線程無法執(zhí)行新任務(wù)時(一般是由于線程池中的線程數(shù)量已經(jīng)達(dá)到最大數(shù)或者線程池關(guān)閉導(dǎo)致的),默認(rèn)情況下,當(dāng)線程池?zé)o法處理新線程時,會拋出一個RejectedExecutionException。

  • workQueue介紹

1.ArrayBlockingQueue:這個表示一個規(guī)定了大小的BlockingQueue,ArrayBlockingQueue的構(gòu)造函數(shù)接受一個int類型的數(shù)據(jù),該數(shù)據(jù)表示BlockingQueue的大小,存儲在ArrayBlockingQueue中的元素按照FIFO(先進(jìn)先出)的方式來進(jìn)行存取。

2.LinkedBlockingQueue:這個表示一個大小不確定的BlockingQueue,在LinkedBlockingQueue的構(gòu)造方法中可以傳一個int類型的數(shù)據(jù),這樣創(chuàng)建出來的LinkedBlockingQueue是有大小的,也可以不傳,不傳的話,LinkedBlockingQueue的大小就為Integer.MAX_VALUE,源碼如下:

3.PriorityBlockingQueue:這個隊列和LinkedBlockingQueue類似,不同的是PriorityBlockingQueue中的元素不是按照FIFO來排序的,而是按照元素的Comparator來決定存取順序的(這個功能也反映了存入PriorityBlockingQueue中的數(shù)據(jù)必須實現(xiàn)了Comparator接口)。

4.SynchronousQueue:這個是同步Queue,屬于線程安全的BlockingQueue的一種,在SynchronousQueue中,生產(chǎn)者線程的插入操作必須要等待消費者線程的移除操作,Synchronous內(nèi)部沒有數(shù)據(jù)緩存空間,因此我們無法對SynchronousQueue進(jìn)行讀取或者遍歷其中的數(shù)據(jù),元素只有在你試圖取走的時候才有可能存在。我們可以理解為生產(chǎn)者和消費者互相等待,等到對方之后然后再一起離開。

  • 拒絕策略

AbortPolicy:直接拒絕,并拋出異常,這也是默認(rèn)的策略。

CallerRunsPolicy:直接讓調(diào)用execute方法的線程去執(zhí)行此任務(wù)。

DiscardOldestPolicy:丟棄最老的未處理的任務(wù),然后重新嘗試執(zhí)行當(dāng)前的新任務(wù)。

DiscardPolicy:直接丟棄當(dāng)前任務(wù),但是不拋異常

3.執(zhí)行過程

當(dāng)線程數(shù)量未達(dá)到corePoolSize的時候,就會創(chuàng)建新的線程來執(zhí)行任務(wù)。

當(dāng)核心線程數(shù)已滿,就會把任務(wù)放到阻塞隊列。

當(dāng)隊列已滿,并且未達(dá)到最大線程數(shù),就會新建非核心線程來執(zhí)行任務(wù)(重要)。

當(dāng)隊列已滿,并且達(dá)到了最大線程數(shù),則選擇一種拒絕策略來執(zhí)行。

4.其他線程池

1.FixedThreadPool

使用Java線程池的方法步驟

固定大小的線程池,可以指定線程池的大小,該線程池corePoolSize和maximumPoolSize相等,阻塞隊列使用的是LinkedBlockingQueue,大小為整數(shù)最大值。

該線程池中的線程數(shù)量始終不變,當(dāng)有新任務(wù)提交時,線程池中有空閑線程則會立即執(zhí)行,如果沒有,則會暫存到阻塞隊列。對于固定大小的線程池,不存在線程數(shù)量的變化。

同時使用無界的LinkedBlockingQueue來存放執(zhí)行的任務(wù)。當(dāng)任務(wù)提交十分頻繁的時候,LinkedBlockingQueue迅速增大,存在著耗盡系統(tǒng)資源的問題。

而且在線程池空閑時,即線程池中沒有可運行任務(wù)時,它也不會釋放工作線程,還會占用一定的系統(tǒng)資源,需要shutdown

2.SingleThreadExecutor

使用Java線程池的方法步驟

可以看到阻塞隊例 使用的是LinkedBolckingQueue,且默認(rèn)大小為Integer.MAX_VALUE,這樣的話,如果有大量請求到來,會放入到這個任務(wù)隊列里,可能會導(dǎo)致OOM;

3.Executors.newCachedThreadPool()

使用Java線程池的方法步驟

可緩存線程池,先查看線程池中有沒有以前建立的線程,如果有就直接使用,如果沒有新建一個線程加入線程池中,可緩存線程池

通常用于執(zhí)行一些生存期很短的異步型任務(wù);線程池為無限大,當(dāng)執(zhí)行當(dāng)前任務(wù)時上一個任務(wù)已經(jīng)完成,會復(fù)用執(zhí)行上一個任務(wù)的線程,而不用每次新建線程

緩存的線程默認(rèn)存活60秒。線程的核心池corePoolSize大小為0,核心池最大為Integer.MAX_VALUE,阻塞隊列使用的是SynchronousQueue。

是一個直接提交的阻塞隊列,他總會迫使線程池增加新的線程去執(zhí)行新的任務(wù)。

在沒有任務(wù)執(zhí)行時,當(dāng)線程的空閑時間超過keepAliveTime(60秒),則工作線程將會終止被回收,當(dāng)提交新任務(wù)時,

如果沒有空閑線程,則創(chuàng)建新線程執(zhí)行任務(wù),會導(dǎo)致一定的系統(tǒng)開銷。

如果同時又大量任務(wù)被提交,而且任務(wù)執(zhí)行的時間不是特別快,那么線程池便會新增出等量的線程池處理任務(wù),這很可能會很快耗盡系統(tǒng)的資源。

4.ScheduledThreadPool

使用Java線程池的方法步驟

創(chuàng)建一個定長線程池,支持定時及周期性任務(wù)執(zhí)行

定時線程池,該線程池可用于周期性地去執(zhí)行任務(wù),通常用于周期性的同步數(shù)據(jù)。

scheduleAtFixedRate:是以固定的頻率去執(zhí)行任務(wù),周期是指每次執(zhí)行任務(wù)成功執(zhí)行之間的間隔。

schedultWithFixedDelay:是以固定的延時去執(zhí)行任務(wù),延時是指上一次執(zhí)行成功之后和下一次開始執(zhí)行的之前的時間。

5.為什么阿里推薦自定義線程池

通過上述源碼分析,我們發(fā)現(xiàn)newFixedThreadPool和newSingleThreadExecutor方法他們都使用了LinkedBlockingQueue的任務(wù)隊列,LinkedBlockingQueue的默認(rèn)大小為Integer.MAX_VALUE。而newCachedThreadPool中定義的線程池大小為Integer.MAX_VALUE。

所以阿里禁止使用Executors創(chuàng)建線程池的原因就是FixedThreadPool和SingleThreadPool的請求隊列長度為Integer.MAX_VALUE,可能會堆積大量的請求,從而導(dǎo)致OOM。

CachedThreadPool允許的創(chuàng)建線程數(shù)量為Integer.MAX_VALUE,可能會創(chuàng)建大量的線程,從而導(dǎo)致OOM。

6.其他

1.shutDown() 關(guān)閉線程池,不影響已經(jīng)提交的任務(wù)

2.shutDownNow() 關(guān)閉線程池,并嘗試去終止正在執(zhí)行的線程

3.allowCoreThreadTimeOut(boolean value) 允許核心線程閑置超時時被回收

4.單例模式創(chuàng)建線程池

import com.google.common.util.concurrent.ThreadFactoryBuilder;

import java.util.concurrent.*;

/**

 * 異步任務(wù)處理器

 */

public class AsyncTaskExecutor {

    /** 線程池保持ALIVE狀態(tài)線程數(shù) */

    public static final int                 CORE_POOL_SIZE      = 10;

    /** 線程池最大線程數(shù) */

    public static final int                 MAX_POOL_SIZE       = 40;

    /** 空閑線程回收時間 */

    public static final int                 KEEP_ALIVE_TIME     = 1000;

    /** 線程池等待隊列 */

    public static final int                 BLOCKING_QUEUE_SIZE = 1000;

    /** 業(yè)務(wù)請求異步處理線程池 */

    private static final ThreadPoolExecutor processExecutor = new ThreadPoolExecutor(

            CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.MICROSECONDS,

            new LinkedBlockingQueue<Runnable>(BLOCKING_QUEUE_SIZE),

       new TreadFactoryBuilder.setNameFormat("boomoom-thread-pool-%d").build(),

       new TreadPoolExecutor.DiscardPolicy());

    private AsyncTaskExecutor() {}; 

    /**

     * 異步任務(wù)處理

     *

     * @param task 任務(wù)

     */

    public void execute(Runnable task) {

        processExecutor.submit(task);

    }

}

懶漢式和饑漢式區(qū)別

1.餓漢式是線程安全的,在類創(chuàng)建的同時就已經(jīng)創(chuàng)建好一個靜態(tài)的對象供系統(tǒng)使用,以后不再改變。

2.懶漢式如果想要線程安全必須用雙重檢驗鎖并且對象還必須是volatile,防止對象指令重排

到此,關(guān)于“使用Java線程池的方法步驟”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

向AI問一下細(xì)節(jié)

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

AI