小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Java多線程編程-(9)-使用線程池實(shí)現(xiàn)線程的復(fù)用和一些坑的避免

 漢無為 2018-08-26

線程復(fù)用:線程池

首先舉個(gè)例子:

假設(shè)這里有一個(gè)系統(tǒng),大概每秒需要處理5萬條數(shù)據(jù),這5萬條數(shù)據(jù)為一個(gè)批次,而這沒秒發(fā)送的5萬條數(shù)據(jù)數(shù)據(jù)需要經(jīng)過兩個(gè)處理過程,第一步是數(shù)據(jù)存入數(shù)據(jù)庫,第二步是對數(shù)據(jù)進(jìn)行其他業(yè)務(wù)的分析,假設(shè)第一步我是用的是普通的JDBC插入數(shù)據(jù),為了不影響程序的繼續(xù)執(zhí)行,我寫了一個(gè)線程,讓這個(gè)子線程不阻塞主線程,繼續(xù)處理第二步驟的數(shù)據(jù),我們知道插入5萬條數(shù)據(jù)大概需要2至3秒的時(shí)間,如果每一批次插入數(shù)據(jù)庫的時(shí)候,就創(chuàng)建一個(gè)線程進(jìn)行處理,可想而知,由于插入數(shù)據(jù)庫的時(shí)間較久,不能很快的處理,這樣的話,一段時(shí)間之后,系統(tǒng)中就會(huì)有很多的這種插入數(shù)據(jù)的線程(PS:只是假設(shè)場景,方案設(shè)計(jì)的可能不合理)。

Java多線程編程-(9)-使用線程池實(shí)現(xiàn)線程的復(fù)用和一些坑的避免

如果,我們使用上述的方式去創(chuàng)建線程,使用start()方法啟動(dòng)線程,該線程會(huì)在run()方法結(jié)束后,自動(dòng)回收該線程。雖然如此,在上邊的場景中線程中業(yè)務(wù)的處理速度完全達(dá)不到我們的要求,系統(tǒng)中的線程會(huì)逐漸變大,進(jìn)而消耗CPU資源,大量的線程搶占寶貴的內(nèi)存資源,可能還會(huì)出現(xiàn)OOM,即便沒有出現(xiàn),大量的線程回收也會(huì)個(gè)GC帶來很大的壓力。

可想而知,雖然多線程技術(shù)可以充分發(fā)揮多核處理器的計(jì)算能力,提高生產(chǎn)系統(tǒng)的吞吐量和性能。但是,若不加控制和管理的隨意使用線程,對系統(tǒng)的性能反而會(huì)產(chǎn)生不利的影響。

還拿上邊的例子說,如果我們使用線程池的方式的話,可以實(shí)現(xiàn)最多創(chuàng)建愛你線程的數(shù)量,這樣的話就算再多的數(shù)據(jù)需要入庫,只需要排隊(duì)等待線程池的線程即可,就不會(huì)出現(xiàn)線程池過多而消耗系統(tǒng)資源的情況,當(dāng)然這只是意見簡單的場景。

Java多線程編程-(9)-使用線程池實(shí)現(xiàn)線程的復(fù)用和一些坑的避免

說到這里,有人要說了線程不是攜帶資源的最小單位,操作系統(tǒng)的書籍中還給我們說了線程之間的切換消耗很小嗎?雖然如此,線程是一種輕量級的工具(或者稱之為:輕量級進(jìn)程),但其創(chuàng)建和關(guān)閉依然需要花費(fèi)時(shí)間,如果為了一個(gè)很簡單的任務(wù)就去創(chuàng)建一個(gè)線程,很有可能出現(xiàn)創(chuàng)建和銷毀線程所占用的時(shí)間大于該線程真實(shí)工作所消耗的時(shí)間,反而得不償失。

那么什么是線程池?

為了避免系統(tǒng)頻繁的創(chuàng)建和銷毀線程,我們可以將創(chuàng)建的線程進(jìn)行復(fù)用。數(shù)據(jù)庫中的數(shù)據(jù)庫連接池也是此意。

Java多線程編程-(9)-使用線程池實(shí)現(xiàn)線程的復(fù)用和一些坑的避免

在線程池中總有那么幾個(gè)活躍的線程,也有一定的最大值限制,一個(gè)業(yè)務(wù)使用完線程之后,不是立即銷毀而是將其放入到線程池中,從而實(shí)現(xiàn)線程的復(fù)用。簡而言之:創(chuàng)建線程變成了從線程池獲取空閑的線程,關(guān)閉線程變成了向池子中歸還線程。

再多的概念,不過多解釋,因?yàn)楹芑A(chǔ),也不是本文的重點(diǎn)。

JDK對線程池的支持

JDK提供的Eexecutor框架

JDK提供了Executor框架,可以讓我們有效的管理和控制我們的線程,其實(shí)質(zhì)也就是一個(gè)線程池。Executor下的接口和類繼承關(guān)系如下:

Java多線程編程-(9)-使用線程池實(shí)現(xiàn)線程的復(fù)用和一些坑的避免

其中,ExecutorService接口定義如下:

Java多線程編程-(9)-使用線程池實(shí)現(xiàn)線程的復(fù)用和一些坑的避免

如果使用Executor框架的話,Executors類是常用的,其方法如下:

Java多線程編程-(9)-使用線程池實(shí)現(xiàn)線程的復(fù)用和一些坑的避免

其中常用幾類如下:

Java多線程編程-(9)-使用線程池實(shí)現(xiàn)線程的復(fù)用和一些坑的避免

1、newFixedThreadPool:該方法返回一個(gè)固定線程數(shù)量的線程池;

2、newSingleThreadExecutor:該方法返回一個(gè)只有一個(gè)現(xiàn)成的線程池;

3、newCachedThreadPool:返回一個(gè)可以根據(jù)實(shí)際情況調(diào)整線程數(shù)量的線程池;

4、newSingleThreadScheduledExecutor:該方法和newSingleThreadExecutor的區(qū)別是給定了時(shí)間執(zhí)行某任務(wù)的功能,可以進(jìn)行定時(shí)執(zhí)行等;

5、newScheduledThreadPool:在4的基礎(chǔ)上可以指定線程數(shù)量。

創(chuàng)建線程池是指調(diào)用的還是ThreadPoolExecutor

在Executors類中,我們拿出來一個(gè)方法簡單分析一下:

Java多線程編程-(9)-使用線程池實(shí)現(xiàn)線程的復(fù)用和一些坑的避免

可以看出,類似的其他方法一樣,在Executors內(nèi)部創(chuàng)建線程池的時(shí)候,實(shí)際創(chuàng)建的都是一個(gè)ThreadPoolExecutor對象,只是對ThreadPoolExecutor構(gòu)造方法,進(jìn)行了默認(rèn)值的設(shè)定。ThreadPoolExecutor的構(gòu)造方法如下:

Java多線程編程-(9)-使用線程池實(shí)現(xiàn)線程的復(fù)用和一些坑的避免

參數(shù)含義如下:

Java多線程編程-(9)-使用線程池實(shí)現(xiàn)線程的復(fù)用和一些坑的避免

Eexecutor框架實(shí)例

1、實(shí)例一:

Java多線程編程-(9)-使用線程池實(shí)現(xiàn)線程的復(fù)用和一些坑的避免

submit(Runnable task)方法提交一個(gè)線程。

但是使用最新的“阿里巴巴編碼規(guī)范插件”檢測一下會(huì)發(fā)現(xiàn):

Java多線程編程-(9)-使用線程池實(shí)現(xiàn)線程的復(fù)用和一些坑的避免

Java多線程編程-(9)-使用線程池實(shí)現(xiàn)線程的復(fù)用和一些坑的避免

阿里巴巴編碼規(guī)范插件地址:https://github.com/alibaba/p3c

2、實(shí)例二:

遵循阿里巴巴編碼規(guī)范的提示,示例如下:

Java多線程編程-(9)-使用線程池實(shí)現(xiàn)線程的復(fù)用和一些坑的避免

或者這樣:

Java多線程編程-(9)-使用線程池實(shí)現(xiàn)線程的復(fù)用和一些坑的避免

3、實(shí)例三:

自定義ThreadFactory、自定義線程拒絕策略

Java多線程編程-(9)-使用線程池實(shí)現(xiàn)線程的復(fù)用和一些坑的避免

更多實(shí)例代碼,可參考:

https:///xuliugen/codes/ta5dbsge0kvhy62qu8li157

使用submit的坑

首先看一下實(shí)例:

Java多線程編程-(9)-使用線程池實(shí)現(xiàn)線程的復(fù)用和一些坑的避免

運(yùn)行結(jié)果:

Java多線程編程-(9)-使用線程池實(shí)現(xiàn)線程的復(fù)用和一些坑的避免

上述代碼,可以看出運(yùn)行結(jié)果為4個(gè),因該是有5個(gè)的,但是當(dāng)i=0的時(shí)候,100/0是會(huì)報(bào)錯(cuò)的,但是日志信息中沒有任何信息,是為什么那?如果使用了submit(Runnable task) 就會(huì)出現(xiàn)這種情況,任何的錯(cuò)誤信息都出現(xiàn)不了!

這是因?yàn)槭褂胹ubmit(Runnable task) 的時(shí)候,錯(cuò)誤的堆棧信息跑出來的時(shí)候會(huì)被內(nèi)部捕獲到,所以打印不出來具體的信息讓我們查看,解決的方法有如下兩種:

1、使用execute()代替submit();

Java多線程編程-(9)-使用線程池實(shí)現(xiàn)線程的復(fù)用和一些坑的避免

運(yùn)行結(jié)果:

Java多線程編程-(9)-使用線程池實(shí)現(xiàn)線程的復(fù)用和一些坑的避免

2、使用Future

Java多線程編程-(9)-使用線程池實(shí)現(xiàn)線程的復(fù)用和一些坑的避免

運(yùn)行結(jié)果:

Java多線程編程-(9)-使用線程池實(shí)現(xiàn)線程的復(fù)用和一些坑的避免

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多