亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

線程池你真不來(lái)了解一下嗎?

stdying / 1475人閱讀

摘要:所以說(shuō)我們的線程最好是交由線程池來(lái)管理,這樣可以減少對(duì)線程生命周期的管理,一定程度上提高性能。線程池不接收新任務(wù),不處理已添加的任務(wù),并且會(huì)中斷正在處理的任務(wù)。當(dāng)所有的任務(wù)已終止,記錄的任務(wù)數(shù)量為,線程池會(huì)變?yōu)闋顟B(tài)。線程池徹底終止的狀態(tài)。

前言
只有光頭才能變強(qiáng)

回顧前面:

ThreadLocal就是這么簡(jiǎn)單

多線程三分鐘就可以入個(gè)門了!

多線程基礎(chǔ)必要知識(shí)點(diǎn)!看了學(xué)習(xí)多線程事半功倍

Java鎖機(jī)制了解一下

AQS簡(jiǎn)簡(jiǎn)單單過(guò)一遍

Lock鎖子類了解一下

本篇主要是講解線程池,這是我在多線程的倒數(shù)第二篇了,后面還會(huì)有一篇死鎖。主要將多線程的基礎(chǔ)過(guò)一遍,以后有機(jī)會(huì)再繼續(xù)深入

那么接下來(lái)就開始吧,如果文章有錯(cuò)誤的地方請(qǐng)大家多多包涵,不吝在評(píng)論區(qū)指正哦~

聲明:本文使用JDK1.8
一、線程池簡(jiǎn)介

線程池可以看做是線程的集合。在沒(méi)有任務(wù)時(shí)線程處于空閑狀態(tài),當(dāng)請(qǐng)求到來(lái):線程池給這個(gè)請(qǐng)求分配一個(gè)空閑的線程,任務(wù)完成后回到線程池中等待下次任務(wù)(而不是銷毀)。這樣就實(shí)現(xiàn)了線程的重用。

我們來(lái)看看如果沒(méi)有使用線程池的情況是這樣的:

為每個(gè)請(qǐng)求都新開一個(gè)線程

public class ThreadPerTaskWebServer {
    public static void main(String[] args) throws IOException {
        ServerSocket socket = new ServerSocket(80);
        while (true) {
            // 為每個(gè)請(qǐng)求都創(chuàng)建一個(gè)新的線程
            final Socket connection = socket.accept();
            Runnable task = () -> handleRequest(connection);
            new Thread(task).start();
        }
    }
    private static void handleRequest(Socket connection) {
        // request-handling logic here
    }
}

為每個(gè)請(qǐng)求都開一個(gè)新的線程雖然理論上是可以的,但是會(huì)有缺點(diǎn)

線程生命周期的開銷非常高。每個(gè)線程都有自己的生命周期,創(chuàng)建和銷毀線程所花費(fèi)的時(shí)間和資源可能比處理客戶端的任務(wù)花費(fèi)的時(shí)間和資源更多,并且還會(huì)有某些空閑線程也會(huì)占用資源

程序的穩(wěn)定性和健壯性會(huì)下降,每個(gè)請(qǐng)求開一個(gè)線程。如果受到了惡意攻擊或者請(qǐng)求過(guò)多(內(nèi)存不足),程序很容易就奔潰掉了。

所以說(shuō):我們的線程最好是交由線程池來(lái)管理,這樣可以減少對(duì)線程生命周期的管理,一定程度上提高性能。

二、JDK提供的線程池API

JDK給我們提供了Excutor框架來(lái)使用線程池,它是線程池的基礎(chǔ)。

Executor提供了一種將“任務(wù)提交”與“任務(wù)執(zhí)行”分離開來(lái)的機(jī)制(解耦)

下面我們來(lái)看看JDK線程池的總體api架構(gòu):

接下來(lái)我們把這些API都過(guò)一遍看看:

Executor接口:

ExcutorService接口:

AbstractExecutorService類:

ScheduledExecutorService接口:

ThreadPoolExecutor類:

ScheduledThreadPoolExecutor類:

2.1ForkJoinPool線程池

除了ScheduledThreadPoolExecutor和ThreadPoolExecutor類線程池以外,還有一個(gè)是JDK1.7新增的線程池:ForkJoinPool線程池

于是我們的類圖就可以變得完整一些:

JDK1.7中新增的一個(gè)線程池,與ThreadPoolExecutor一樣,同樣繼承了AbstractExecutorService。ForkJoinPool是Fork/Join框架的兩大核心類之一。與其它類型的ExecutorService相比,其主要的不同在于采用了工作竊取算法(work-stealing):所有池中線程會(huì)嘗試找到并執(zhí)行已被提交到池中的或由其他線程創(chuàng)建的任務(wù)。這樣很少有線程會(huì)處于空閑狀態(tài),非常高效。這使得能夠有效地處理以下情景:大多數(shù)由任務(wù)產(chǎn)生大量子任務(wù)的情況;從外部客戶端大量提交小任務(wù)到池中的情況。

來(lái)源:

https://blog.csdn.net/panweiwei1994/article/details/78969238

2.2補(bǔ)充:Callable和Future

學(xué)到了線程池,我們可以很容易地發(fā)現(xiàn):很多的API都有Callable和Future這么兩個(gè)東西。

    Future submit(Runnable task)
     Future submit(Callable task)

其實(shí)它們也不是什么高深的東西~~~

我們可以簡(jiǎn)單認(rèn)為:Callable就是Runnable的擴(kuò)展。

Runnable沒(méi)有返回值,不能拋出受檢查的異常,而Callable可以!

也就是說(shuō):當(dāng)我們的任務(wù)需要返回值的時(shí),我們就可以使用Callable!

Future一般我們認(rèn)為是Callable的返回值,但他其實(shí)代表的是任務(wù)的生命周期(當(dāng)然了,它是能獲取得到Callable的返回值的)

簡(jiǎn)單來(lái)看一下他們的用法:

public class CallableDemo {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        // 創(chuàng)建線程池對(duì)象
        ExecutorService pool = Executors.newFixedThreadPool(2);

        // 可以執(zhí)行Runnable對(duì)象或者Callable對(duì)象代表的線程
        Future f1 = pool.submit(new MyCallable(100));
        Future f2 = pool.submit(new MyCallable(200));

        // V get()
        Integer i1 = f1.get();
        Integer i2 = f2.get();

        System.out.println(i1);
        System.out.println(i2);

        // 結(jié)束
        pool.shutdown();
    }
}

Callable任務(wù):

public class MyCallable implements Callable {

    private int number;

    public MyCallable(int number) {
        this.number = number;
    }

    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int x = 1; x <= number; x++) {
            sum += x;
        }
        return sum;
    }

}

執(zhí)行完任務(wù)之后可以獲取得到任務(wù)返回的數(shù)據(jù)

三、ThreadPoolExecutor詳解

這是用得最多的線程池,所以本文會(huì)重點(diǎn)講解它。

我們來(lái)看看頂部注釋:

3.1內(nèi)部狀態(tài)

變量ctl定義為AtomicInteger,記錄了“線程池中的任務(wù)數(shù)量”和“線程池的狀態(tài)”兩個(gè)信息。

線程的狀態(tài):

RUNNING:線程池能夠接受新任務(wù),以及對(duì)新添加的任務(wù)進(jìn)行處理。

SHUTDOWN:線程池不可以接受新任務(wù),但是可以對(duì)已添加的任務(wù)進(jìn)行處理。

STOP:線程池不接收新任務(wù),不處理已添加的任務(wù),并且會(huì)中斷正在處理的任務(wù)

TIDYING:當(dāng)所有的任務(wù)已終止,ctl記錄的"任務(wù)數(shù)量"為0,線程池會(huì)變?yōu)門IDYING狀態(tài)。當(dāng)線程池變?yōu)門IDYING狀態(tài)時(shí),會(huì)執(zhí)行鉤子函數(shù)terminated()。terminated()在ThreadPoolExecutor類中是空的,若用戶想在線程池變?yōu)門IDYING時(shí),進(jìn)行相應(yīng)的處理;可以通過(guò)重載terminated()函數(shù)來(lái)實(shí)現(xiàn)。

TERMINATED:線程池徹底終止的狀態(tài)

各個(gè)狀態(tài)之間轉(zhuǎn)換:

3.2已默認(rèn)實(shí)現(xiàn)的池

下面我就列舉三個(gè)比較常見的實(shí)現(xiàn)池:

newFixedThreadPool

newCachedThreadPool

SingleThreadExecutor

如果讀懂了上面對(duì)應(yīng)的策略呀,線程數(shù)量這些,應(yīng)該就不會(huì)太難看懂了。

3.2.1newFixedThreadPool

一個(gè)固定線程數(shù)的線程池,它將返回一個(gè)corePoolSize和maximumPoolSize相等的線程池

   public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue());
    }
3.2.2newCachedThreadPool

非常有彈性的線程池,對(duì)于新的任務(wù),如果此時(shí)線程池里沒(méi)有空閑線程,線程池會(huì)毫不猶豫的創(chuàng)建一條新的線程去處理這個(gè)任務(wù)

    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue());
    }
3.2.3SingleThreadExecutor

使用單個(gè)worker線程的Executor

public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue()));
    }
3.3構(gòu)造方法

我們讀完上面的默認(rèn)實(shí)現(xiàn)池還有對(duì)應(yīng)的屬性,再回到構(gòu)造方法看看

構(gòu)造方法可以讓我們自定義(擴(kuò)展)線程池

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

指定核心線程數(shù)量

指定最大線程數(shù)量

允許線程空閑時(shí)間

時(shí)間對(duì)象

阻塞隊(duì)列

線程工廠

任務(wù)拒絕策略

再總結(jié)一遍這些參數(shù)的要點(diǎn):

線程數(shù)量要點(diǎn)

如果運(yùn)行線程的數(shù)量少于核心線程數(shù)量,則創(chuàng)建新的線程處理請(qǐng)求

如果運(yùn)行線程的數(shù)量大于核心線程數(shù)量,小于最大線程數(shù)量,則當(dāng)隊(duì)列滿的時(shí)候才創(chuàng)建新的線程

如果核心線程數(shù)量等于最大線程數(shù)量,那么將創(chuàng)建固定大小的連接池

如果設(shè)置了最大線程數(shù)量為無(wú)窮,那么允許線程池適合任意的并發(fā)數(shù)量

線程空閑時(shí)間要點(diǎn):

當(dāng)前線程數(shù)大于核心線程數(shù),如果空閑時(shí)間已經(jīng)超過(guò)了,那該線程會(huì)銷毀。

排隊(duì)策略要點(diǎn)

同步移交:不會(huì)放到隊(duì)列中,而是等待線程執(zhí)行它。如果當(dāng)前線程沒(méi)有執(zhí)行,很可能會(huì)新開一個(gè)線程執(zhí)行。

無(wú)界限策略:如果核心線程都在工作,該線程會(huì)放到隊(duì)列中。所以線程數(shù)不會(huì)超過(guò)核心線程數(shù)

有界限策略:可以避免資源耗盡,但是一定程度上減低了吞吐量

當(dāng)線程關(guān)閉或者線程數(shù)量滿了和隊(duì)列飽和了,就有拒絕任務(wù)的情況了:

拒絕任務(wù)策略:

直接拋出異常

使用調(diào)用者的線程來(lái)處理

直接丟掉這個(gè)任務(wù)

丟掉最老的任務(wù)

四、execute執(zhí)行方法

execute執(zhí)行方法分了三步,以注釋的方式寫在代碼上了~

    public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        int c = ctl.get();
        //如果線程池中運(yùn)行的線程數(shù)量=corePoolSize,且線程池處于RUNNING狀態(tài),且把提交的任務(wù)成功放入阻塞隊(duì)列中,就再次檢查線程池的狀態(tài),
            // 1.如果線程池不是RUNNING狀態(tài),且成功從阻塞隊(duì)列中刪除任務(wù),則該任務(wù)由當(dāng)前 RejectedExecutionHandler 處理。
            // 2.否則如果線程池中運(yùn)行的線程數(shù)量為0,則通過(guò)addWorker(null, false)嘗試新建一個(gè)線程,新建線程對(duì)應(yīng)的任務(wù)為null。
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        // 如果以上兩種case不成立,即沒(méi)能將任務(wù)成功放入阻塞隊(duì)列中,且addWoker新建線程失敗,則該任務(wù)由當(dāng)前 RejectedExecutionHandler 處理。
        else if (!addWorker(command, false))
            reject(command);
    }
五、線程池關(guān)閉

ThreadPoolExecutor提供了shutdown()shutdownNow()兩個(gè)方法來(lái)關(guān)閉線程池

shutdown() :

shutdownNow():

區(qū)別:

調(diào)用shutdown()后,線程池狀態(tài)立刻變?yōu)镾HUTDOWN,而調(diào)用shutdownNow(),線程池狀態(tài)立刻變?yōu)镾TOP

shutdown()等待任務(wù)執(zhí)行完才中斷線程,而shutdownNow()不等任務(wù)執(zhí)行完就中斷了線程。

六、總結(jié)

本篇博文主要簡(jiǎn)單地將多線程的結(jié)構(gòu)體系過(guò)了一篇,講了最常用的ThreadPoolExecutor線程池是怎么使用的~~~

明天希望可以把死鎖寫出來(lái),敬請(qǐng)期待~~~

還有剩下的幾個(gè)線程池(給出了參考資料):

ScheduledThreadPoolExecutor

https://blog.csdn.net/panweiwei1994/article/details/78997029

http://cmsblogs.com/?p=2451

ForkJoinPool

https://blog.csdn.net/panweiwei1994/article/details/78992098

參考資料:

《Java核心技術(shù)卷一》

《Java并發(fā)編程實(shí)戰(zhàn)》

http://cmsblogs.com/?page_id=111

https://blog.csdn.net/panweiwei1994/article/details/78483167

https://zhuanlan.zhihu.com/p/35382932

如果文章有錯(cuò)的地方歡迎指正,大家互相交流。習(xí)慣在微信看技術(shù)文章,想要獲取更多的Java資源的同學(xué),可以關(guān)注微信公眾號(hào):Java3y。為了大家方便,剛新建了一下qq群:742919422,大家也可以去交流交流。謝謝支持了!希望能多介紹給其他有需要的朋友

文章的目錄導(dǎo)航

https://zhongfucheng.bitcron.com/post/shou-ji/wen-zhang-dao-hang

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/69288.html

相關(guān)文章

  • 線程之死鎖就是這么簡(jiǎn)單

    摘要:此時(shí)線程需要鎖才能繼續(xù)往下執(zhí)行。但是線程的鎖并沒(méi)有釋放,線程的鎖也沒(méi)有釋放。 前言 只有光頭才能變強(qiáng) 回顧前面: ThreadLocal就是這么簡(jiǎn)單 多線程三分鐘就可以入個(gè)門了! 多線程基礎(chǔ)必要知識(shí)點(diǎn)!看了學(xué)習(xí)多線程事半功倍 Java鎖機(jī)制了解一下 AQS簡(jiǎn)簡(jiǎn)單單過(guò)一遍 Lock鎖子類了解一下 線程池你真不來(lái)了解一下嗎? 本篇主要是講解死鎖,這是我在多線程的最后一篇了。主要將多線程...

    winterdawn 評(píng)論0 收藏0
  • 給女朋友講解什么是代理模式

    摘要:受知乎文章和設(shè)計(jì)模式之禪的啟發(fā),我也來(lái)搞一篇腦洞小開的文章由標(biāo)題可知,這篇文章是寫給我女朋友看的。于是這就讓經(jīng)紀(jì)人對(duì)粉絲說(shuō)只有萬(wàn),我才會(huì)寫代碼。 前言 只有光頭才能變強(qiáng) 回顧前面: ThreadLocal就是這么簡(jiǎn)單 多線程三分鐘就可以入個(gè)門了! 多線程基礎(chǔ)必要知識(shí)點(diǎn)!看了學(xué)習(xí)多線程事半功倍 Java鎖機(jī)制了解一下 AQS簡(jiǎn)簡(jiǎn)單單過(guò)一遍 Lock鎖子類了解一下 線程池你真不來(lái)了解一下...

    stormgens 評(píng)論0 收藏0
  • 【Java】幾道讓你拿offer的面試題

    摘要:的方法,的默認(rèn)實(shí)現(xiàn)會(huì)判斷是否是類型注意自動(dòng)拆箱,自動(dòng)裝箱問(wèn)題。適應(yīng)自旋鎖鎖競(jìng)爭(zhēng)是下的,會(huì)經(jīng)過(guò)用戶態(tài)到內(nèi)核態(tài)的切換,是比較花時(shí)間的。在中引入了自適應(yīng)的自旋鎖,說(shuō)明自旋的時(shí)間不固定,要不要自旋變得越來(lái)越聰明。 前言 只有光頭才能變強(qiáng) 之前在刷博客的時(shí)候,發(fā)現(xiàn)一些寫得比較好的博客都會(huì)默默收藏起來(lái)。最近在查閱補(bǔ)漏,有的知識(shí)點(diǎn)比較重要的,但是在之前的博客中還沒(méi)有寫到,于是趁著閑整理一下。 文本的...

    張春雷 評(píng)論0 收藏0
  • Java開發(fā) 大廠面試整理

    摘要:用戶態(tài)不能干擾內(nèi)核態(tài)所以指令就有兩種特權(quán)指令和非特權(quán)指令不同的狀態(tài)對(duì)應(yīng)不同的指令。非特權(quán)指令所有程序均可直接使用。用戶態(tài)常態(tài)目態(tài)執(zhí)行非特權(quán)指令。 這是我今年從三月份開始,主要的大廠面試經(jīng)過(guò),有些企業(yè)面試的還沒(méi)來(lái)得及整理,可能有些沒(méi)有帶答案就發(fā)出來(lái)了,還請(qǐng)各位先思考如果是你怎么回答面試官?這篇文章會(huì)持續(xù)更新,請(qǐng)各位持續(xù)關(guān)注,希望對(duì)你有所幫助! 面試清單 平安產(chǎn)險(xiǎn) 飛豬 上汽大通 浩鯨科...

    Scorpion 評(píng)論0 收藏0
  • 關(guān)于線程池你不得不知道的一些設(shè)置

    摘要:有細(xì)心的網(wǎng)友早就想到了這個(gè)問(wèn)題在線程池中,還有一些不常用的設(shè)置。所以該方法會(huì)在線程池總預(yù)先創(chuàng)建沒(méi)有任務(wù)執(zhí)行的線程,數(shù)量為。下面我們測(cè)試一下從測(cè)試結(jié)果來(lái)看,線程池中已經(jīng)預(yù)先創(chuàng)建了數(shù)量的空閑線程。 微信公眾號(hào)「后端進(jìn)階」,專注后端技術(shù)分享:Java、Golang、WEB框架、分布式中間件、服務(wù)治理等等。 老司機(jī)傾囊相授,帶你一路進(jìn)階,來(lái)不及解釋了快上車! 看完我上一篇文章「你都理解創(chuàng)建線...

    余學(xué)文 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<