自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

我們一起深入多線程面試連環(huán)炮

系統(tǒng)
線程的創(chuàng)建和銷毀是一個(gè)“重”操作,所以我們需要避免線程頻繁地創(chuàng)建與銷毀,因此我們需要緩存一批線程,讓它們時(shí)刻準(zhǔn)備著執(zhí)行任務(wù)

[[440236]]

1、什么是線程池

線程的創(chuàng)建和銷毀是一個(gè)“重”操作,所以我們需要避免線程頻繁地創(chuàng)建與銷毀,因此我們需要緩存一批線程,讓它們時(shí)刻準(zhǔn)備著執(zhí)行任務(wù)

目標(biāo)已經(jīng)很清晰了,弄一個(gè)池子,里面存放約定數(shù)量的線程,這就是線程池,一種池化技術(shù)

如果線程數(shù)太少無(wú)法充分利用 CPU ,太多的話由于上下文切換的消耗又得不償失,所以我們需要評(píng)估系統(tǒng)所要承載的并發(fā)量和所執(zhí)行任務(wù)的特性,得出大致需要多少個(gè)線程數(shù)才能充分利用 CPU,因此需要控制線程數(shù)量

多線程技術(shù)主要解決處理器單元內(nèi)多個(gè)線程執(zhí)行的問題,它可以顯著減少處理器單元的閑置時(shí)間,增加處理器單元的吞吐能力

假設(shè)一個(gè)服務(wù)器完成一項(xiàng)任務(wù)所需時(shí)間為:T1 創(chuàng)建線程時(shí)間,T2 在線程中執(zhí)行任務(wù)的時(shí)間,T3 銷毀線程時(shí)間

如果:T1 + T3 遠(yuǎn)大于 T2,則可以采用線程池,以提高服務(wù)器性能

線程池技術(shù)正是關(guān)注如何縮短或調(diào)整T1,T3時(shí)間的技術(shù),從而提高服務(wù)器程序性能的。它把T1,T3分別安排在服務(wù)器程序的啟動(dòng)和結(jié)束的時(shí)間段或者一些空閑的時(shí)間段,這樣在服務(wù)器程序處理客戶請(qǐng)求時(shí),不會(huì)有T1,T3的開銷了

線程池不僅調(diào)整T1,T3產(chǎn)生的時(shí)間段,而且它還顯著減少了創(chuàng)建線程的數(shù)目

2、線程池優(yōu)點(diǎn),為什么要使用線程池

new Thread 缺點(diǎn)

每次new Thread新建對(duì)象性能差

線程缺乏統(tǒng)一管理,可能無(wú)限制新建線程,相互之間競(jìng)爭(zhēng),及可能占用過多系統(tǒng)資源導(dǎo)致死機(jī)或oom

缺乏更多功能,如定時(shí)執(zhí)行、定期執(zhí)行、線程中斷

為什么要用線程池

減少了創(chuàng)建和銷毀線程的次數(shù),每個(gè)工作線程都可以被重復(fù)利用,可執(zhí)行多個(gè)任務(wù)。

可以根據(jù)系統(tǒng)的承受能力,調(diào)整線程池中工作線線程的數(shù)目,防止因?yàn)橄倪^多的內(nèi)存,而把服務(wù)器累趴下(每個(gè)線程需要大約1MB內(nèi)存,線程開的越多,消耗的內(nèi)存也就越大,最后死機(jī))。

ThreadPool優(yōu)點(diǎn)

減少了創(chuàng)建和銷毀線程的次數(shù),每個(gè)工作線程都可以被重復(fù)利用,可執(zhí)行多個(gè)任務(wù)

可以根據(jù)系統(tǒng)的承受能力,調(diào)整線程池中工作線線程的數(shù)目,防止因?yàn)橐驗(yàn)橄倪^多的內(nèi)存,而把服務(wù)器累趴下(每個(gè)線程需要大約1MB內(nèi)存,線程開的越多,消耗的內(nèi)存也就越大,最后死機(jī))

減少在創(chuàng)建和銷毀線程上所花的時(shí)間以及系統(tǒng)資源的開銷

如不使用線程池,有可能造成系統(tǒng)創(chuàng)建大量線程而導(dǎo)致消耗完系統(tǒng)內(nèi)存

3、常用的線程池

第1種是:固定大小線程池,特點(diǎn)是線程數(shù)固定,使用無(wú)界隊(duì)列,適用于任務(wù)數(shù)量不均勻的場(chǎng)景、對(duì)內(nèi)存壓力不敏感,但系統(tǒng)負(fù)載比較敏感的場(chǎng)景

第2種是:Cached線程池,特點(diǎn)是不限制線程數(shù),適用于要求低延遲的短期任務(wù)場(chǎng)景

第3種是:?jiǎn)尉€程線程池,也就是一個(gè)線程的固定線程池,適用于需要異步執(zhí)行但需要保證任務(wù)順序的場(chǎng)景

第4種是:Scheduled線程池,適用于定期執(zhí)行任務(wù)場(chǎng)景,支持按固定頻率定期執(zhí)行和按固定延時(shí)定期執(zhí)行兩種方式

第5種是:工作竊取線程池,使用的ForkJoinPool,是固定并行度的多任務(wù)隊(duì)列,適合任務(wù)執(zhí)行時(shí)長(zhǎng)不均勻的場(chǎng)景

4、聽說過Executors嗎

Java里面線程池的頂級(jí)接口是Executor,但是嚴(yán)格意義上講Executor并不是一個(gè)線程池,而只是一個(gè)執(zhí)行線程的工具。真正的線程池接口是ExecutorService

Executors是一個(gè)工具類,類里面提供了一些靜態(tài)工廠,生成一些常用的線程池

Executors提供四種線程池

newCachedThreadPool創(chuàng)建一個(gè)可緩存線程池,如果線程池長(zhǎng)度超過處理需要,可靈活回收空閑線程,若無(wú)可回收,則新建線程

newFixedThreadPool 創(chuàng)建一個(gè)定長(zhǎng)線程池,可控制線程最大并發(fā)數(shù),超出的線程會(huì)在隊(duì)列中等待

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

newSingleThreadExecutor 創(chuàng)建一個(gè)單線程化的線程池,它只會(huì)用唯一的工作線程來執(zhí)行任務(wù),保證所有任務(wù)按照指定順序(FIFO, LIFO, 優(yōu)先級(jí))執(zhí)行

一般都不用Executors提供的線程創(chuàng)建方式,使用ThreadPoolExecutor創(chuàng)建線程池

5、那你說說為什么阿里巴巴不建議使用Executors靜態(tài)工廠構(gòu)建線程池

在阿里巴巴Java開發(fā)手冊(cè)中提到,使用Executors創(chuàng)建線程池可能會(huì)導(dǎo)致OOM(OutOfMemory ,內(nèi)存溢出),真正的導(dǎo)致OOM的其實(shí)是LinkedBlockingQueue.offer方法

底層是通過LinkedBlockingQueue實(shí)現(xiàn)的, LinkedBlockingQueue是一個(gè)用鏈表實(shí)現(xiàn)的有界阻塞隊(duì)列,容量可以選擇進(jìn)行設(shè)置,不設(shè)置的話,將是一個(gè)無(wú)邊界的阻塞隊(duì)列,最大長(zhǎng)度為Integer.MAX_VALUE

問題就出在:不設(shè)置的話,將是一個(gè)無(wú)邊界的阻塞隊(duì)列,最大長(zhǎng)度為Integer.MAX_VALUE。也就是說,如果我們不設(shè)置LinkedBlockingQueue的容量的話,其默認(rèn)容量將會(huì)是Integer.MAX_VALUE

對(duì)于一個(gè)無(wú)邊界隊(duì)列來說,是可以不斷的向隊(duì)列中加入任務(wù)的,這種情況下就有可能因?yàn)槿蝿?wù)過多而導(dǎo)致內(nèi)存溢出問題

避免使用Executors創(chuàng)建線程池,主要是避免使用其中的默認(rèn)實(shí)現(xiàn),那么我們可以自己直接調(diào)用ThreadPoolExecutor的構(gòu)造函數(shù)來自己創(chuàng)建線程池。在創(chuàng)建的同時(shí),給BlockQueue指定容量就可以了

6、線程池核心參數(shù)有哪些

第1個(gè)參數(shù):設(shè)置核心線程數(shù)。默認(rèn)情況下核心線程會(huì)一直存活

第2個(gè)參數(shù):設(shè)置最大線程數(shù)。決定線程池最多可以創(chuàng)建的多少線程

第3個(gè)參數(shù)和第4個(gè)參數(shù):用來設(shè)置線程空閑時(shí)間,和空閑時(shí)間的單位,當(dāng)線程閑置超過空閑時(shí)間就會(huì)被銷毀??梢酝ㄟ^AllowCoreThreadTimeOut方法來允許核心線程被回收

第5個(gè)參數(shù):設(shè)置緩沖隊(duì)列,圖中左下方的三個(gè)隊(duì)列是設(shè)置線程池時(shí)常使用的緩沖隊(duì)列

其中Array Blocking Queue是一個(gè)有界隊(duì)列,就是指隊(duì)列有最大容量限制。Linked Blocking Queue是無(wú)界隊(duì)列,就是隊(duì)列不限制容量。最后一個(gè)是Synchronous Queue,是一個(gè)同步隊(duì)列,內(nèi)部沒有緩沖區(qū)

第6個(gè)參數(shù):設(shè)置線程池工廠方法,線程工廠用來創(chuàng)建新線程,可以用來對(duì)線程的一些屬性進(jìn)行定制,例如線程的Group、線程名、優(yōu)先級(jí)等。一般使用默認(rèn)工廠類即可

第7個(gè)參數(shù):設(shè)置線程池滿時(shí)的拒絕策略

ThreadPoolExecutor默認(rèn)有四個(gè)拒絕策略:

ThreadPoolExecutor.AbortPolicy() 直接拋出異常RejectedExecutionException,這個(gè)是默認(rèn)的拒絕策略

ThreadPoolExecutor.CallerRunsPolicy() 直接在提交失敗時(shí),由提交任務(wù)的線程直接執(zhí)行提交的任務(wù)

ThreadPoolExecutor.DiscardPolicy() 直接丟棄后來的任務(wù)

ThreadPoolExecutor.DiscardOldestPolicy() 丟棄在隊(duì)列中最早提交的任務(wù)

7、線程池的工作原理

我們向線程提交任務(wù)時(shí)可以使用Execute和Submit,區(qū)別就是Submit可以返回一個(gè)Future對(duì)象,通過Future對(duì)象可以了解任務(wù)執(zhí)行情況,可以取消任務(wù)的執(zhí)行,還可獲取執(zhí)行結(jié)果或執(zhí)行異常。Submit最終也是通過Execute執(zhí)行的

線程池提交任務(wù)時(shí)的執(zhí)行順序如下:

向線程池提交任務(wù)時(shí),會(huì)首先判斷線程池中的線程數(shù)是否大于設(shè)置的核心線程數(shù),如果不大于,就創(chuàng)建一個(gè)核心線程來執(zhí)行任務(wù)

如果大于核心線程數(shù),就會(huì)判斷緩沖隊(duì)列是否滿了,如果沒有滿,則放入隊(duì)列,等待線程空閑時(shí)執(zhí)行任務(wù)

如果隊(duì)列已經(jīng)滿了,則判斷是否達(dá)到了線程池設(shè)置的最大線程數(shù),如果沒有達(dá)到,就創(chuàng)建新線程來執(zhí)行任務(wù)

如果已經(jīng)達(dá)到了最大線程數(shù),則執(zhí)行指定的拒絕策略。這里需要注意隊(duì)列的判斷與最大線程數(shù)判斷的順序,不要搞反

如果你提交任務(wù)時(shí),線程池隊(duì)列已滿,這時(shí)會(huì)發(fā)生什么?

如果你使用的LinkedBlockingQueue,也就是無(wú)界隊(duì)列的話,沒關(guān)系,繼續(xù)添加任務(wù)到阻塞隊(duì)列中等待執(zhí)行,因?yàn)長(zhǎng)inkedBlockingQueue可以近乎認(rèn)為是一個(gè)無(wú)窮大的隊(duì)列,可以無(wú)限存放任務(wù)

如果你使用的是有界隊(duì)列比方說ArrayBlockingQueue的話,任務(wù)首先會(huì)被添加到ArrayBlockingQueue中,ArrayBlockingQueue滿了,則會(huì)使用拒絕策略RejectedExecutionHandler處理滿了的任務(wù),默認(rèn)是AbortPolicy

8、高并發(fā)、任務(wù)執(zhí)行時(shí)間短的業(yè)務(wù)怎樣使用線程池?并發(fā)不高、任務(wù)執(zhí)行時(shí)間長(zhǎng)的業(yè)務(wù)怎樣使用線程池?并發(fā)高、業(yè)務(wù)執(zhí)行時(shí)間長(zhǎng)的業(yè)務(wù)怎樣使用線程池?

高并發(fā)、任務(wù)執(zhí)行時(shí)間短的業(yè)務(wù),線程池線程數(shù)可以設(shè)置為CPU核數(shù)+1,減少線程上下文的切換

并發(fā)不高、任務(wù)執(zhí)行時(shí)間長(zhǎng)的業(yè)務(wù)要分情況來討論

假如是業(yè)務(wù)時(shí)間長(zhǎng)集中在IO操作上,也就是IO密集型的任務(wù),因?yàn)镮O操作并不占用CPU,所以不要讓所有的CPU閑下來,可以加大線程池中的線程數(shù)目,讓CPU處理更多的業(yè)務(wù)

假如是業(yè)務(wù)時(shí)間長(zhǎng)集中在計(jì)算操作上,也就是計(jì)算密集型任務(wù),這個(gè)就沒辦法了,線程數(shù)設(shè)置為CPU核數(shù)+1,線程池中的線程數(shù)設(shè)置得少一些,減少線程上下文的切換

并發(fā)高、業(yè)務(wù)執(zhí)行時(shí)間長(zhǎng),解決這種類型任務(wù)的關(guān)鍵不在于線程池而在于整體架構(gòu)的設(shè)計(jì),看看這些業(yè)務(wù)里面某些數(shù)據(jù)是否能做緩存是第一步,增加服務(wù)器是第二步,至于線程池的設(shè)置,參考上面的設(shè)置即可

最后,業(yè)務(wù)執(zhí)行時(shí)間長(zhǎng)的問題,也可能需要分析一下,看看能不能使用中間件對(duì)任務(wù)進(jìn)行拆分和解耦

9、聽說過ThreadLocal嗎

看我的這一篇介紹

10、簡(jiǎn)單介紹下阻塞隊(duì)列吧

阻塞隊(duì)列是一個(gè)在隊(duì)列基礎(chǔ)上又支持了兩個(gè)附加操作的隊(duì)列

支持阻塞的插入方法:隊(duì)列滿時(shí),隊(duì)列會(huì)阻塞插入元素的線程,直到隊(duì)列不滿。支持阻塞的移除方法:隊(duì)列空時(shí),獲取元素的線程會(huì)等待隊(duì)列變?yōu)榉强?/p>

阻塞隊(duì)列的應(yīng)用場(chǎng)景

阻塞隊(duì)列常用于生產(chǎn)者和消費(fèi)者的場(chǎng)景,生產(chǎn)者是向隊(duì)列里添加元素的線程,消費(fèi)者是從隊(duì)列里取元素的線程。簡(jiǎn)而言之,阻塞隊(duì)列是生產(chǎn)者用來存放元素、消費(fèi)者獲取元素的容器

1、ArrayBlockingQueue 數(shù)組結(jié)構(gòu)組成的有界阻塞隊(duì)列

此隊(duì)列按照先進(jìn)先出(FIFO)的原則對(duì)元素進(jìn)行排序,但是默認(rèn)情況下不保證線程公平的訪問隊(duì)列,即如果隊(duì)列滿了,那么被阻塞在外面的線程對(duì)隊(duì)列訪問的順序是不能保證線程公平(即先阻塞,先插入)的。

2、LinkedBlockingQueue一個(gè)由鏈表結(jié)構(gòu)組成的有界阻塞隊(duì)列,此隊(duì)列按照先出先進(jìn)的原則對(duì)元素進(jìn)行排序

3、PriorityBlockingQueue支持優(yōu)先級(jí)的無(wú)界阻塞隊(duì)列

4、DelayQueue支持延時(shí)獲取元素的無(wú)界阻塞隊(duì)列,即可以指定多久才能從隊(duì)列中獲取當(dāng)前元素

5、SynchronousQueue不存儲(chǔ)元素的阻塞隊(duì)列,每一個(gè)put必須等待一個(gè)take操作,否則不能繼續(xù)添加元素。并且支持公平訪問隊(duì)列。

6、LinkedTransferQueue由鏈表結(jié)構(gòu)組成的無(wú)界阻塞TransferQueue隊(duì)列。相對(duì)于其他阻塞隊(duì)列,多了tryTransfer和transfer方法

transfer方法

如果當(dāng)前有消費(fèi)者正在等待接收元素(take或者待時(shí)間限制的poll方法),transfer可以把生產(chǎn)者傳入的元素立刻傳給消費(fèi)者。如果沒有消費(fèi)者等待接收元素,則將元素放在隊(duì)列的tail節(jié)點(diǎn),并等到該元素被消費(fèi)者消費(fèi)了才返回

tryTransfer方法

用來試探生產(chǎn)者傳入的元素能否直接傳給消費(fèi)者。,如果沒有消費(fèi)者在等待,則返回false。和上述方法的區(qū)別是該方法無(wú)論消費(fèi)者是否接收,方法立即返回。而transfer方法是必須等到消費(fèi)者消費(fèi)了才返回

11、LinkedBlockingDeque鏈表結(jié)構(gòu)的雙向阻塞隊(duì)列,優(yōu)勢(shì)在于多線程入隊(duì)時(shí),減少一半的競(jìng)爭(zhēng)

本文轉(zhuǎn)載自微信公眾號(hào)「Java賊船」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系Java賊船公眾號(hào)。

 

責(zé)任編輯:武曉燕 來源: Java賊船
相關(guān)推薦

2021-12-07 08:31:48

線程池中間件開源

2024-06-04 07:52:04

2024-03-28 08:50:58

Flink分配方式后端

2023-07-11 08:34:25

參數(shù)流程類型

2024-04-17 09:52:00

操作系統(tǒng)多線程內(nèi)存

2021-01-19 09:11:35

Zookeeper面試分布式

2025-02-28 08:46:24

框架微服務(wù)架構(gòu)

2024-12-10 00:00:25

2023-10-31 09:04:21

CPU調(diào)度Java

2023-04-03 14:20:44

面試C++函數(shù)

2021-10-27 06:49:34

線程池Core函數(shù)

2022-01-17 06:59:40

Grep指令linux

2021-12-29 08:27:05

ByteBuffer磁盤服務(wù)器

2021-08-27 07:06:10

IOJava抽象

2024-02-20 21:34:16

循環(huán)GolangGo

2022-03-08 17:52:58

TCP格式IP

2021-07-28 07:53:20

Github ActiDotnet 應(yīng)用

2023-06-07 15:29:33

MySQL事務(wù)面試

2023-08-04 08:20:56

DockerfileDocker工具

2021-01-12 05:08:49

DHCP協(xié)議模型
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)