成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

線程池你真不來了解一下嗎?

stdying / 1430人閱讀

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

前言
只有光頭才能變強

回顧前面:

ThreadLocal就是這么簡單

多線程三分鐘就可以入個門了!

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

Java鎖機制了解一下

AQS簡簡單單過一遍

Lock鎖子類了解一下

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

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

聲明:本文使用JDK1.8
一、線程池簡介

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

我們來看看如果沒有使用線程池的情況是這樣的:

為每個請求都新開一個線程

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

為每個請求都開一個新的線程雖然理論上是可以的,但是會有缺點

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

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

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

二、JDK提供的線程池API

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

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

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

接下來我們把這些API都過一遍看看:

Executor接口:

ExcutorService接口:

AbstractExecutorService類:

ScheduledExecutorService接口:

ThreadPoolExecutor類:

ScheduledThreadPoolExecutor類:

2.1ForkJoinPool線程池

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

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

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

來源:

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

2.2補充:Callable和Future

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

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

其實它們也不是什么高深的東西~~~

我們可以簡單認為:Callable就是Runnable的擴展。

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

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

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

簡單來看一下他們的用法:

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

        // 可以執(zhí)行Runnable對象或者Callable對象代表的線程
        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詳解

這是用得最多的線程池,所以本文會重點講解它。

我們來看看頂部注釋:

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

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

線程的狀態(tài):

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

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

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

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

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

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

3.2已默認實現(xiàn)的池

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

newFixedThreadPool

newCachedThreadPool

SingleThreadExecutor

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

3.2.1newFixedThreadPool

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

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

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

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

使用單個worker線程的Executor

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

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

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

    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ù)量

允許線程空閑時間

時間對象

阻塞隊列

線程工廠

任務(wù)拒絕策略

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

線程數(shù)量要點

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

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

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

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

線程空閑時間要點:

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

排隊策略要點

同步移交:不會放到隊列中,而是等待線程執(zhí)行它。如果當前線程沒有執(zhí)行,很可能會新開一個線程執(zhí)行。

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

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

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

拒絕任務(wù)策略:

直接拋出異常

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

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

丟掉最老的任務(wù)

四、execute執(zhí)行方法

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

    public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        int c = ctl.get();
        //如果線程池中運行的線程數(shù)量=corePoolSize,且線程池處于RUNNING狀態(tài),且把提交的任務(wù)成功放入阻塞隊列中,就再次檢查線程池的狀態(tài),
            // 1.如果線程池不是RUNNING狀態(tài),且成功從阻塞隊列中刪除任務(wù),則該任務(wù)由當前 RejectedExecutionHandler 處理。
            // 2.否則如果線程池中運行的線程數(shù)量為0,則通過addWorker(null, false)嘗試新建一個線程,新建線程對應(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不成立,即沒能將任務(wù)成功放入阻塞隊列中,且addWoker新建線程失敗,則該任務(wù)由當前 RejectedExecutionHandler 處理。
        else if (!addWorker(command, false))
            reject(command);
    }
五、線程池關(guān)閉

ThreadPoolExecutor提供了shutdown()shutdownNow()兩個方法來關(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é)構(gòu)體系過了一篇,講了最常用的ThreadPoolExecutor線程池是怎么使用的~~~

明天希望可以把死鎖寫出來,敬請期待~~~

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

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ā)編程實戰(zhàn)》

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

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

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

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

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

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

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

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/69288.html

相關(guān)文章

  • 線程之死鎖就是這么簡單

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

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

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

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

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

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

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

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

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

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

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<