最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中該如何優(yōu)雅的使用線(xiàn)程池詳解

 更新時(shí)間:2021年12月15日 09:10:02   作者:細(xì)思極恐  
在java開(kāi)發(fā)中我們對(duì)“池”的概念并不陌生,常見(jiàn)的有數(shù)據(jù)庫(kù)連接池、線(xiàn)程池、對(duì)象池、常量池等等,其作用基本上就是避免頻繁的創(chuàng)建和回收,造成資源浪費(fèi),線(xiàn)程池也不例外,這篇文章主要給大家介紹了關(guān)于Java中該如何優(yōu)雅的使用線(xiàn)程池的相關(guān)資料,需要的朋友可以參考下

為什么要用線(xiàn)程池?

線(xiàn)程是不是越多越好?

  1. 線(xiàn)程在java中是一個(gè)對(duì)象,更是操作系統(tǒng)的資源,線(xiàn)程創(chuàng)建、銷(xiāo)毀需要時(shí)間。如果創(chuàng)建時(shí)間+小會(huì)時(shí)間>執(zhí)行任務(wù)時(shí)間就很不合算。
  2. java對(duì)象占用堆內(nèi)存,操作系統(tǒng)線(xiàn)程占用系統(tǒng)內(nèi)存,根據(jù)jvm規(guī)范,一個(gè)線(xiàn)程默認(rèn)最大棧大小1M,這個(gè)??臻g是需要從系統(tǒng)內(nèi)存中分配的。線(xiàn)程過(guò)多,會(huì)消耗很多的內(nèi)存。
  3. 操作系統(tǒng)需要頻繁切換線(xiàn)程上下文(每個(gè)線(xiàn)都想被運(yùn)行),影響性能。

線(xiàn)程池的推出,就是為了方便邊的控制線(xiàn)程數(shù)量。

線(xiàn)程池

線(xiàn)程池基本概念

線(xiàn)程池包括以下四個(gè)基本組成部分:

  1. 線(xiàn)程池管理器:用于創(chuàng)建并管理線(xiàn)程池,包括創(chuàng)建線(xiàn)程池,銷(xiāo)毀線(xiàn)程池,添加新任務(wù);
  2. 工作線(xiàn)程:線(xiàn)程池中線(xiàn)程,在沒(méi)有任務(wù)時(shí)處于等待狀態(tài),可以循環(huán)的執(zhí)行任務(wù);
  3. 任務(wù)接口:每個(gè)任務(wù)必須實(shí)現(xiàn)的借口,以供工作線(xiàn)程調(diào)度任務(wù)的執(zhí)行,它主要規(guī)定了任務(wù)的入口,任務(wù)執(zhí)行完后的收尾工作,任務(wù)的執(zhí)行狀態(tài)等;
  4. 任務(wù)隊(duì)列:用于存放沒(méi)有處理的任務(wù)。提供一種緩沖機(jī)制。

線(xiàn)程池接口定義和實(shí)現(xiàn)類(lèi)

可以認(rèn)為ScheduledThreadPoolExector是最豐富的實(shí)現(xiàn)類(lèi)。

ExecutorService

public interface ExecutorService extends Executor {
    /**
     * 優(yōu)雅關(guān)閉線(xiàn)程池,之前提交的任務(wù)將被執(zhí)行,但是不會(huì)接受新的任務(wù)。
     */
    void shutdown();

    /**
     * 嘗試停止所有正在執(zhí)行的任務(wù),停止等待任務(wù)的處理,并返回等待執(zhí)行任務(wù)的列表。
     */
    List<Runnable> shutdownNow();

    /**
     * 如果此線(xiàn)程池已關(guān)閉,則返回true.
     */
    boolean isShutdown();

    /**
     * 如果關(guān)閉后的所有任務(wù)都已完成,則返回true
     */
    boolean isTerminated();

    /**
     * 監(jiān)測(cè)ExecutorService是否已經(jīng)關(guān)閉,直到所有任務(wù)完成執(zhí)行,或超時(shí)發(fā)生,或當(dāng)前線(xiàn)程被中斷。
     */
    boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;

    /**
     * 提交一個(gè)用于執(zhí)行的Callable返回任務(wù),并返回一個(gè)Future,用于獲取Callable執(zhí)行結(jié)果。
     */
    <T> Future<T> submit(Callable<T> task);

    /**
     * 提交可運(yùn)行任務(wù)以執(zhí)行,并返回Future,執(zhí)行結(jié)果為傳入的result
     */
    <T> Future<T> submit(Runnable task, T result);

    /**
     * 提交可運(yùn)行任務(wù)以執(zhí)行,并返回Future對(duì)象,執(zhí)行結(jié)果為null
     */
    Future<?> submit(Runnable task);

    /**
     * 執(zhí)行給定的任務(wù)集合,執(zhí)行完畢后,則返回結(jié)果。
     */
    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException;

    /**
     * 執(zhí)行給定的任務(wù)集合,執(zhí)行完畢或者超時(shí)后,則返回結(jié)果,其他任務(wù)終止。
     */
    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException;

    /**
     * 執(zhí)行給定的任務(wù),任意一個(gè)執(zhí)行成功則返回結(jié)果,其他任務(wù)終止。
     */
    <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException;

    /**
     * 執(zhí)行給定的任務(wù),任意一個(gè)執(zhí)行成功或者超時(shí)后,則返回結(jié)果,其他任務(wù)終止
     */
    <T> T invokeAny(Collection<? extends Callable<T>> tasks,long timeout, TimeUnit unit)throws InterruptedException, ExecutionException, TimeoutException;
}

ScheduledExecutorService

public interface ScheduledExecutorService extends ExecutorService {

    /**
     * 創(chuàng)建并執(zhí)行一個(gè)一次性任務(wù),過(guò)了延遲時(shí)間就會(huì)被執(zhí)行
     */
    public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit);

    /**
     * 創(chuàng)建并執(zhí)行一個(gè)一次性任務(wù),過(guò)了延遲時(shí)間就會(huì)被執(zhí)行
     */
    public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit);

    /**
     * 創(chuàng)建并執(zhí)行一個(gè)周期性任務(wù),過(guò)了給定的初始化延遲時(shí)間,會(huì)第一次被執(zhí)行。執(zhí)行過(guò)程中發(fā)生了異常,那么任務(wù)停止
     * 一次任務(wù)執(zhí)行時(shí)長(zhǎng)超過(guò)了周期時(shí)間,下一次任務(wù)會(huì)等到該次任務(wù)執(zhí)行結(jié)束后,立刻執(zhí)行,這也是它和scheduleWithTixedDelay的重要區(qū)別
     */
    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                                  long initialDelay,
                                                  long period,
                                                  TimeUnit unit);

    /**
     * 創(chuàng)建并執(zhí)行一個(gè)周期性任務(wù),過(guò)了給定的初始化延遲時(shí)間,會(huì)第一次被執(zhí)行。執(zhí)行過(guò)程中發(fā)生了異常,那么任務(wù)停止
     * 一次任務(wù)執(zhí)行時(shí)長(zhǎng)超過(guò)了周期時(shí)間,下一次任務(wù)會(huì)在該次任務(wù)執(zhí)行結(jié)束的時(shí)間基礎(chǔ)上,計(jì)算執(zhí)行延時(shí)。
     * 對(duì)于超時(shí)周期的長(zhǎng)時(shí)間處理任務(wù)的不同處理方式,這是它和scheduleAtFixedRate的重要區(qū)別
     */
    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                                                     long initialDelay,
                                                     long delay,
                                                     TimeUnit unit);

}

線(xiàn)程池工具類(lèi)

在使用過(guò)程中,可以自己實(shí)例化線(xiàn)程池,也可以用Executors創(chuàng)建線(xiàn)程池的工廠(chǎng)累,常用方法如下:

newFixedThreadPool(int nThreads)

創(chuàng)建一個(gè)固定大小、任務(wù)隊(duì)列容量誤解的線(xiàn)程池。核心線(xiàn)程數(shù)=最大線(xiàn)程數(shù)。

newCachedThreadPool()

創(chuàng)建的是一個(gè)大小無(wú)界的緩沖線(xiàn)程池。它的任務(wù)隊(duì)列是一個(gè)同步隊(duì)列。任務(wù)加入到池中,如果池中有空閑線(xiàn)程,則用空閑線(xiàn)程執(zhí)行,如無(wú)則創(chuàng)建新線(xiàn)程執(zhí)行。池中的線(xiàn)程空閑時(shí)間超過(guò)60秒,將被銷(xiāo)毀釋放。線(xiàn)程數(shù)隨任務(wù)的多少變化。適用于執(zhí)行耗時(shí)較小的異步任務(wù)。池的核心線(xiàn)程數(shù)=0,最大線(xiàn)程=Integer.MAX_VALUE

newSingleThreadExecutor()

只有一個(gè)線(xiàn)程來(lái)執(zhí)行無(wú)界任務(wù)隊(duì)列的單一線(xiàn)程池。該線(xiàn)程池確保任務(wù)加入的順序一個(gè)一個(gè)一次執(zhí)行。當(dāng)唯一的線(xiàn)程因任務(wù)異常中止時(shí),將創(chuàng)建一個(gè)新的線(xiàn)程來(lái)繼續(xù)執(zhí)行后續(xù)的任務(wù)。與newFixedThreadPool(1)的區(qū)別在于,單一線(xiàn)程池的池大小在newSingleThreadExecutor方法中硬編碼,不能再改變的。

newScheduledThreadPool(int corePoolSize)

能定時(shí)執(zhí)行任務(wù)的線(xiàn)程池。該池的核心線(xiàn)程數(shù)由參數(shù)指定,最大線(xiàn)程數(shù)=Integer.MAX_VALUE

任務(wù)線(xiàn)程池執(zhí)行過(guò)程

如何確認(rèn)合適的線(xiàn)程數(shù)量?

  • 如果是CPU密集型應(yīng)用,則線(xiàn)程池大小設(shè)置為N+1 (N為CPU總核數(shù))
  • 如果是IO密集型應(yīng)用,則線(xiàn)程池大小設(shè)置為2N+1 (N為CPU總核數(shù))
  • 線(xiàn)程等待時(shí)間(IO)所占比例越高,需要越多線(xiàn)程。
  • 線(xiàn)程CPU時(shí)間所占比例越高,需要越少線(xiàn)程。

一個(gè)系統(tǒng)最快的部分是CPU,所以決定一個(gè)系統(tǒng)吞吐量上限的是CPU。增強(qiáng)CPU處理能力,可以提高系統(tǒng)吞吐量上限。但根據(jù)短板效應(yīng),真實(shí)的系統(tǒng)吞吐量并不能單純根據(jù)CPU來(lái)計(jì)算。那要提高系統(tǒng)吞吐量,就需要從“系統(tǒng)短板”(比如網(wǎng)絡(luò)延遲、IO)著手:

  1. 盡量提高短板操作的并行化比率,比如多線(xiàn)程下載技術(shù);
  2. 增強(qiáng)短板能力,比如用NIO替代IO;

線(xiàn)程池的使用分析

public class ExecutorsUse {
    /**
     * 測(cè)試: 提交15 個(gè)執(zhí)行時(shí)間需要3秒的任務(wù),看線(xiàn)程池的狀況
     *
     * @param threadPoolExecutor 傳入不同的線(xiàn)程池,看不同的結(jié)果
     * @throws Exception
     */
    public void testCommon(ThreadPoolExecutor threadPoolExecutor) throws Exception {
        // 測(cè)試: 提交15個(gè)執(zhí)行時(shí)間需要3秒的任務(wù),看超過(guò)大小的2個(gè),對(duì)應(yīng)的處理情況
        for (int i = 0; i < 15; i++) {
            int n = i;
            threadPoolExecutor.submit(() -> {
                        try {
                            System.out.println("開(kāi)始執(zhí)行:" + n);
                            Thread.sleep(3000L);
                            System.err.println("執(zhí)行結(jié)束:" + n);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
            );
            System.out.println("任務(wù)提交成功 :" + i);
        }
        // 查看線(xiàn)程數(shù)量,查看隊(duì)列等待數(shù)量
        Thread.sleep(500L);
        System.out.println("當(dāng)前線(xiàn)程池線(xiàn)程數(shù)量為:" + threadPoolExecutor.getPoolSize());
        System.out.println("當(dāng)前線(xiàn)程池等待的數(shù)量為:" + threadPoolExecutor.getQueue().size());
        // 等待15秒,查看線(xiàn)程數(shù)量和隊(duì)列數(shù)量(理論上,會(huì)被超出核心線(xiàn)程數(shù)量的線(xiàn)程自動(dòng)銷(xiāo)毀)
        Thread.sleep(15000L);
        System.out.println("當(dāng)前線(xiàn)程池線(xiàn)程數(shù)量為:" + threadPoolExecutor.getPoolSize());
        System.out.println("當(dāng)前線(xiàn)程池等待的數(shù)量為:" + threadPoolExecutor.getQueue().size());
    }

    /**
     * 1、線(xiàn)程池信息: 核心線(xiàn)程數(shù)量5,最大數(shù)量10,無(wú)界隊(duì)列,超出核心線(xiàn)程數(shù)量的線(xiàn)程存活時(shí)間:5秒, 指定拒絕策略
     *
     * @throws Exception
     */
    private void threadPoolExecutorTest1() throws Exception {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>());
        testCommon(threadPoolExecutor);
        // 預(yù)計(jì)結(jié)果:線(xiàn)程池線(xiàn)程數(shù)量為:5,超出數(shù)量的任務(wù),其他的進(jìn)入隊(duì)列中等待被執(zhí)行
    }

    /**
     * 2、 線(xiàn)程池信息: 核心線(xiàn)程數(shù)量5,最大數(shù)量10,隊(duì)列大小3,超出核心線(xiàn)程數(shù)量的線(xiàn)程存活時(shí)間:5秒, 指定拒絕策略的
     *
     * @throws Exception
     */
    private void threadPoolExecutorTest2() throws Exception {
        // 創(chuàng)建一個(gè) 核心線(xiàn)程數(shù)量為5,最大數(shù)量為10,等待隊(duì)列最大是3 的線(xiàn)程池,也就是最大容納13個(gè)任務(wù)。
        // 默認(rèn)的策略是拋出RejectedExecutionException異常,java.util.concurrent.ThreadPoolExecutor.AbortPolicy
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>(3), new RejectedExecutionHandler() {
            @Override
            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                System.err.println("有任務(wù)被拒絕執(zhí)行了");
            }
        });
        testCommon(threadPoolExecutor);
        // 預(yù)計(jì)結(jié)果:
        // 1、 5個(gè)任務(wù)直接分配線(xiàn)程開(kāi)始執(zhí)行
        // 2、 3個(gè)任務(wù)進(jìn)入等待隊(duì)列
        // 3、 隊(duì)列不夠用,臨時(shí)加開(kāi)5個(gè)線(xiàn)程來(lái)執(zhí)行任務(wù)(5秒沒(méi)活干就銷(xiāo)毀)
        // 4、 隊(duì)列和線(xiàn)程池都滿(mǎn)了,剩下2個(gè)任務(wù),沒(méi)資源了,被拒絕執(zhí)行。
        // 5、 任務(wù)執(zhí)行,5秒后,如果無(wú)任務(wù)可執(zhí)行,銷(xiāo)毀臨時(shí)創(chuàng)建的5個(gè)線(xiàn)程
    }

    /**
     * 3、 線(xiàn)程池信息: 核心線(xiàn)程數(shù)量5,最大數(shù)量5,無(wú)界隊(duì)列,超出核心線(xiàn)程數(shù)量的線(xiàn)程存活時(shí)間:5秒
     *
     * @throws Exception
     */
    private void threadPoolExecutorTest3() throws Exception {
        // 和Executors.newFixedThreadPool(int nThreads)一樣的
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>());
        testCommon(threadPoolExecutor);
        // 預(yù)計(jì)結(jié):線(xiàn)程池線(xiàn)程數(shù)量為:5,超出數(shù)量的任務(wù),其他的進(jìn)入隊(duì)列中等待被執(zhí)行
    }

    /**
     * 4、 線(xiàn)程池信息:
     * 核心線(xiàn)程數(shù)量0,最大數(shù)量Integer.MAX_VALUE,SynchronousQueue隊(duì)列,超出核心線(xiàn)程數(shù)量的線(xiàn)程存活時(shí)間:60秒
     *
     * @throws Exception
     */
    private void threadPoolExecutorTest4() throws Exception {

        // SynchronousQueue,實(shí)際上它不是一個(gè)真正的隊(duì)列,因?yàn)樗粫?huì)為隊(duì)列中元素維護(hù)存儲(chǔ)空間。與其他隊(duì)列不同的是,它維護(hù)一組線(xiàn)程,這些線(xiàn)程在等待著把元素加入或移出隊(duì)列。
        // 在使用SynchronousQueue作為工作隊(duì)列的前提下,客戶(hù)端代碼向線(xiàn)程池提交任務(wù)時(shí),
        // 而線(xiàn)程池中又沒(méi)有空閑的線(xiàn)程能夠從SynchronousQueue隊(duì)列實(shí)例中取一個(gè)任務(wù),
        // 那么相應(yīng)的offer方法調(diào)用就會(huì)失敗(即任務(wù)沒(méi)有被存入工作隊(duì)列)。
        // 此時(shí),ThreadPoolExecutor會(huì)新建一個(gè)新的工作者線(xiàn)程用于對(duì)這個(gè)入隊(duì)列失敗的任務(wù)進(jìn)行處理(假設(shè)此時(shí)線(xiàn)程池的大小還未達(dá)到其最大線(xiàn)程池大小maximumPoolSize)。

        // 和Executors.newCachedThreadPool()一樣的
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS,
                new SynchronousQueue<Runnable>());
        testCommon(threadPoolExecutor);
        // 預(yù)計(jì)結(jié)果:
        // 1、 線(xiàn)程池線(xiàn)程數(shù)量為:15,超出數(shù)量的任務(wù),其他的進(jìn)入隊(duì)列中等待被執(zhí)行
        // 2、 所有任務(wù)執(zhí)行結(jié)束,60秒后,如果無(wú)任務(wù)可執(zhí)行,所有線(xiàn)程全部被銷(xiāo)毀,池的大小恢復(fù)為0
        Thread.sleep(60000L);
        System.out.println("60秒后,再看線(xiàn)程池中的數(shù)量:" + threadPoolExecutor.getPoolSize());
    }

    /**
     * 5、 定時(shí)執(zhí)行線(xiàn)程池信息:3秒后執(zhí)行,一次性任務(wù),到點(diǎn)就執(zhí)行 <br/>
     * 核心線(xiàn)程數(shù)量5,最大數(shù)量Integer.MAX_VALUE,DelayedWorkQueue延時(shí)隊(duì)列,超出核心線(xiàn)程數(shù)量的線(xiàn)程存活時(shí)間:0秒
     *
     * @throws Exception
     */
    private void threadPoolExecutorTest5() throws Exception {
        // 和Executors.newScheduledThreadPool()一樣的
        ScheduledThreadPoolExecutor threadPoolExecutor = new ScheduledThreadPoolExecutor(5);
        threadPoolExecutor.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("任務(wù)被執(zhí)行,現(xiàn)在時(shí)間:" + System.currentTimeMillis());
            }
        }, 3000, TimeUnit.MILLISECONDS);
        System.out.println(
                "定時(shí)任務(wù),提交成功,時(shí)間是:" + System.currentTimeMillis() + ", 當(dāng)前線(xiàn)程池中線(xiàn)程數(shù)量:" + threadPoolExecutor.getPoolSize());
        // 預(yù)計(jì)結(jié)果:任務(wù)在3秒后被執(zhí)行一次
    }

    /**
     * 6、 定時(shí)執(zhí)行線(xiàn)程池信息:線(xiàn)程固定數(shù)量5 ,<br/>
     * 核心線(xiàn)程數(shù)量5,最大數(shù)量Integer.MAX_VALUE,DelayedWorkQueue延時(shí)隊(duì)列,超出核心線(xiàn)程數(shù)量的線(xiàn)程存活時(shí)間:0秒
     *
     * @throws Exception
     */
    private void threadPoolExecutorTest6() throws Exception {
        ScheduledThreadPoolExecutor threadPoolExecutor = new ScheduledThreadPoolExecutor(5);
        // 周期性執(zhí)行某一個(gè)任務(wù),線(xiàn)程池提供了兩種調(diào)度方式,這里單獨(dú)演示一下。測(cè)試場(chǎng)景一樣。
        // 測(cè)試場(chǎng)景:提交的任務(wù)需要3秒才能執(zhí)行完畢。看兩種不同調(diào)度方式的區(qū)別
        // 效果1: 提交后,2秒后開(kāi)始第一次執(zhí)行,之后每間隔1秒,固定執(zhí)行一次(如果發(fā)現(xiàn)上次執(zhí)行還未完畢,則等待完畢,完畢后立刻執(zhí)行)。
        // 也就是說(shuō)這個(gè)代碼中是,3秒鐘執(zhí)行一次(計(jì)算方式:每次執(zhí)行三秒,間隔時(shí)間1秒,執(zhí)行結(jié)束后馬上開(kāi)始下一次執(zhí)行,無(wú)需等待)
        threadPoolExecutor.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("任務(wù)-1 被執(zhí)行,現(xiàn)在時(shí)間:" + System.currentTimeMillis());
            }
        }, 2000, 1000, TimeUnit.MILLISECONDS);

        // 效果2:提交后,2秒后開(kāi)始第一次執(zhí)行,之后每間隔1秒,固定執(zhí)行一次(如果發(fā)現(xiàn)上次執(zhí)行還未完畢,則等待完畢,等上一次執(zhí)行完畢后再開(kāi)始計(jì)時(shí),等待1秒)。
        // 也就是說(shuō)這個(gè)代碼鐘的效果看到的是:4秒執(zhí)行一次。 (計(jì)算方式:每次執(zhí)行3秒,間隔時(shí)間1秒,執(zhí)行完以后再等待1秒,所以是 3+1)
        threadPoolExecutor.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("任務(wù)-2 被執(zhí)行,現(xiàn)在時(shí)間:" + System.currentTimeMillis());
            }
        }, 2000, 1000, TimeUnit.MILLISECONDS);
    }

    /**
     * 7、 終止線(xiàn)程:線(xiàn)程池信息: 核心線(xiàn)程數(shù)量5,最大數(shù)量10,隊(duì)列大小3,超出核心線(xiàn)程數(shù)量的線(xiàn)程存活時(shí)間:5秒, 指定拒絕策略的
     *
     * @throws Exception
     */
    private void threadPoolExecutorTest7() throws Exception {
        // 創(chuàng)建一個(gè) 核心線(xiàn)程數(shù)量為5,最大數(shù)量為10,等待隊(duì)列最大是3 的線(xiàn)程池,也就是最大容納13個(gè)任務(wù)。
        // 默認(rèn)的策略是拋出RejectedExecutionException異常,java.util.concurrent.ThreadPoolExecutor.AbortPolicy
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>(3), new RejectedExecutionHandler() {
            @Override
            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                System.err.println("有任務(wù)被拒絕執(zhí)行了");
            }
        });
        // 測(cè)試: 提交15個(gè)執(zhí)行時(shí)間需要3秒的任務(wù),看超過(guò)大小的2個(gè),對(duì)應(yīng)的處理情況
        for (int i = 0; i < 15; i++) {
            int n = i;
            threadPoolExecutor.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println("開(kāi)始執(zhí)行:" + n);
                        Thread.sleep(3000L);
                        System.err.println("執(zhí)行結(jié)束:" + n);
                    } catch (InterruptedException e) {
                        System.out.println("異常:" + e.getMessage());
                    }
                }
            });
            System.out.println("任務(wù)提交成功 :" + i);
        }
        // 1秒后終止線(xiàn)程池
        Thread.sleep(1000L);
        threadPoolExecutor.shutdown();
        // 再次提交提示失敗
        threadPoolExecutor.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("追加一個(gè)任務(wù)");
            }
        });
        // 結(jié)果分析
        // 1、 10個(gè)任務(wù)被執(zhí)行,3個(gè)任務(wù)進(jìn)入隊(duì)列等待,2個(gè)任務(wù)被拒絕執(zhí)行
        // 2、調(diào)用shutdown后,不接收新的任務(wù),等待13任務(wù)執(zhí)行結(jié)束
        // 3、 追加的任務(wù)在線(xiàn)程池關(guān)閉后,無(wú)法再提交,會(huì)被拒絕執(zhí)行
    }

    /**
     * 8、 立刻終止線(xiàn)程:線(xiàn)程池信息: 核心線(xiàn)程數(shù)量5,最大數(shù)量10,隊(duì)列大小3,超出核心線(xiàn)程數(shù)量的線(xiàn)程存活時(shí)間:5秒, 指定拒絕策略的
     *
     * @throws Exception
     */
    private void threadPoolExecutorTest8() throws Exception {
        // 創(chuàng)建一個(gè) 核心線(xiàn)程數(shù)量為5,最大數(shù)量為10,等待隊(duì)列最大是3 的線(xiàn)程池,也就是最大容納13個(gè)任務(wù)。
        // 默認(rèn)的策略是拋出RejectedExecutionException異常,java.util.concurrent.ThreadPoolExecutor.AbortPolicy
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>(3), new RejectedExecutionHandler() {
            @Override
            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                System.err.println("有任務(wù)被拒絕執(zhí)行了");
            }
        });
        // 測(cè)試: 提交15個(gè)執(zhí)行時(shí)間需要3秒的任務(wù),看超過(guò)大小的2個(gè),對(duì)應(yīng)的處理情況
        for (int i = 0; i < 15; i++) {
            int n = i;
            threadPoolExecutor.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println("開(kāi)始執(zhí)行:" + n);
                        Thread.sleep(3000L);
                        System.err.println("執(zhí)行結(jié)束:" + n);
                    } catch (InterruptedException e) {
                        System.out.println("異常:" + e.getMessage());
                    }
                }
            });
            System.out.println("任務(wù)提交成功 :" + i);
        }
        // 1秒后終止線(xiàn)程池
        Thread.sleep(1000L);
        List<Runnable> shutdownNow = threadPoolExecutor.shutdownNow();
        // 再次提交提示失敗
        threadPoolExecutor.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("追加一個(gè)任務(wù)");
            }
        });
        System.out.println("未結(jié)束的任務(wù)有:" + shutdownNow.size());

        // 結(jié)果分析
        // 1、 10個(gè)任務(wù)被執(zhí)行,3個(gè)任務(wù)進(jìn)入隊(duì)列等待,2個(gè)任務(wù)被拒絕執(zhí)行
        // 2、調(diào)用shutdownnow后,隊(duì)列中的3個(gè)線(xiàn)程不再執(zhí)行,10個(gè)線(xiàn)程被終止
        // 3、 追加的任務(wù)在線(xiàn)程池關(guān)閉后,無(wú)法再提交,會(huì)被拒絕執(zhí)行
    }

    public static void main(String[] args) throws Exception {
//        new ExecutorsUse().threadPoolExecutorTest1();
//        new ExecutorsUse().threadPoolExecutorTest2();
//          new ExecutorsUse().threadPoolExecutorTest3();
        new ExecutorsUse().threadPoolExecutorTest4();
//        new ExecutorsUse().threadPoolExecutorTest5();
//        new ExecutorsUse().threadPoolExecutorTest6();
//        new ExecutorsUse().threadPoolExecutorTest7();
//        new ExecutorsUse().threadPoolExecutorTest8();
    }
}

合理配置線(xiàn)程池大小

如果想合理設(shè)置線(xiàn)程池的線(xiàn)程數(shù)量需要考慮兩個(gè)問(wèn)題:

1、需要分析線(xiàn)程池執(zhí)行的任務(wù)的特性: CPU 密集型還是 IO 密集型。

2、每個(gè)任務(wù)執(zhí)行的平均時(shí)長(zhǎng)大概是多少,這個(gè)任務(wù)的執(zhí)行時(shí)長(zhǎng)可能還跟任務(wù)處理邏輯是否涉及到網(wǎng)絡(luò)傳輸以及底層系統(tǒng)資源依賴(lài)有關(guān)系。

如果是 CPU 密集型,那線(xiàn)程池的最大線(xiàn)程數(shù)可以配置為 cpu 核心數(shù)+1;如果是 IO 密集型,線(xiàn)程池設(shè)定最佳線(xiàn)程數(shù)目 = ((線(xiàn)程池設(shè)定的線(xiàn)程等待時(shí)間+線(xiàn)程 CPU 時(shí)間)/線(xiàn)程 CPU 時(shí)間 )* CPU 數(shù)目。

線(xiàn)程池的關(guān)閉

ThreadPoolExecutor 提供了兩個(gè)方法 ,用于線(xiàn)程池的關(guān)閉 ,分 別 是 shutdown() 和shutdownNow(),其中:shutdown():不會(huì)立即終止線(xiàn)程池,而是要等所有任務(wù)緩存隊(duì)列中的任務(wù)都執(zhí)行完后才終止,但再也不會(huì)接受新的任務(wù) shutdownNow():立即終止線(xiàn)程池,并嘗試打斷正在執(zhí)行的任務(wù),并且清空任務(wù)緩存隊(duì)列,返回尚未執(zhí)行的任務(wù)。

總結(jié)

到此這篇關(guān)于Java中該如何優(yōu)雅的使用線(xiàn)程池的文章就介紹到這了,更多相關(guān)Java優(yōu)雅使用線(xiàn)程池內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • MybatisPlus中的save方法詳解

    MybatisPlus中的save方法詳解

    save方法是Mybatis-plus框架提供的一個(gè)添加記錄的方法,它用于將一個(gè)實(shí)體對(duì)象插入到數(shù)據(jù)庫(kù)表中,這篇文章主要介紹了MybatisPlus中的save方法,需要的朋友可以參考下
    2023-11-11
  • 如何搭建一個(gè)完整的Java開(kāi)發(fā)環(huán)境

    如何搭建一個(gè)完整的Java開(kāi)發(fā)環(huán)境

    這篇文章主要教大家如何搭建一個(gè)完整的Java開(kāi)發(fā)環(huán)境,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • Java使用Flyway實(shí)現(xiàn)數(shù)據(jù)庫(kù)版本控制的技術(shù)指南

    Java使用Flyway實(shí)現(xiàn)數(shù)據(jù)庫(kù)版本控制的技術(shù)指南

    在現(xiàn)代應(yīng)用開(kāi)發(fā)中,數(shù)據(jù)庫(kù)結(jié)構(gòu)經(jīng)常隨著業(yè)務(wù)需求不斷演變,使用手動(dòng)SQL腳本管理數(shù)據(jù)庫(kù)版本,不僅容易出現(xiàn)錯(cuò)誤,還難以跟蹤和回滾,Flyway是一個(gè)強(qiáng)大的數(shù)據(jù)庫(kù)遷移工具,能夠幫助開(kāi)發(fā)者高效管理和自動(dòng)化數(shù)據(jù)庫(kù)的版本控制,本文將介紹Flyway的基本功能及其在SpringBoot項(xiàng)目中的實(shí)踐
    2025-02-02
  • java實(shí)現(xiàn)拼圖游戲

    java實(shí)現(xiàn)拼圖游戲

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)拼圖游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-12-12
  • 基于maven中多個(gè)子模塊的構(gòu)建順序

    基于maven中多個(gè)子模塊的構(gòu)建順序

    這篇文章主要介紹了maven中多個(gè)子模塊的構(gòu)建順序,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Mybatis如何構(gòu)建SQL語(yǔ)句

    Mybatis如何構(gòu)建SQL語(yǔ)句

    這篇文章主要介紹了Mybatis如何構(gòu)建SQL語(yǔ)句問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • java socket編程實(shí)例代碼講解

    java socket編程實(shí)例代碼講解

    這篇文章主要介紹了java socket編程示例講解,大家參考使用吧
    2013-12-12
  • SpringBoot實(shí)現(xiàn)JWT token自動(dòng)續(xù)期的示例代碼

    SpringBoot實(shí)現(xiàn)JWT token自動(dòng)續(xù)期的示例代碼

    本文主要介紹了SpringBoot實(shí)現(xiàn)JWT token自動(dòng)續(xù)期的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-01-01
  • Spring?Security權(quán)限管理實(shí)現(xiàn)接口動(dòng)態(tài)權(quán)限控制

    Spring?Security權(quán)限管理實(shí)現(xiàn)接口動(dòng)態(tài)權(quán)限控制

    這篇文章主要為大家介紹了Spring?Security權(quán)限管理實(shí)現(xiàn)接口動(dòng)態(tài)權(quán)限控制,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • Java及nginx實(shí)現(xiàn)文件權(quán)限控制代碼實(shí)例

    Java及nginx實(shí)現(xiàn)文件權(quán)限控制代碼實(shí)例

    這篇文章主要介紹了Java及nginx實(shí)現(xiàn)文件權(quán)限控制代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-06-06

最新評(píng)論

慈溪市| 定结县| 罗江县| 鄱阳县| 健康| 阿拉善盟| 津南区| 宝山区| 普兰店市| 丽水市| 汉寿县| 莒南县| 博爱县| 红安县| 明溪县| 竹山县| 依安县| 泰州市| 开鲁县| 库车县| 南岸区| 澄迈县| 高安市| 岢岚县| 巧家县| 泸溪县| 繁昌县| 房山区| 碌曲县| 婺源县| 喀什市| 上栗县| 隆德县| 沙坪坝区| 霍山县| 禄丰县| 宁德市| 称多县| 渝北区| 玛多县| 沭阳县|