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

線程池的幾個面試重要考點(diǎn)

開發(fā) 前端
如果你能把這些在面試的時候說清楚,那么至少在線程池這個知識點(diǎn)上,你是沒有任何問題了,這樣就可以愉快并且開心的走下一個知識點(diǎn)了。

阿粉有點(diǎn)驚嘆最近的面試題,因?yàn)閺闹暗幕A(chǔ)的面試題,到之后的一些涉及到分布式和微服務(wù)的面試題,再到現(xiàn)在的線程池的一些面試題,反正不同的面試官,就有不同的針對方向,可能現(xiàn)在的面試官比較想考驗(yàn)?zāi)愕亩喾矫娴哪芰Π?,而最近,一個讀者就反饋給了阿粉說,面試官全程就從線程這塊入手,整的自己有點(diǎn)尷尬,但是好在有驚無險的入職了,我們來看看面試官都問了什么內(nèi)容?

進(jìn)程和線程的概念,你能說一下自己的理解么?這個問題,有點(diǎn)基礎(chǔ),不過肯定是之后的開胃小菜。

進(jìn)程和線程的關(guān)系

進(jìn)程就是應(yīng)用程序在內(nèi)存中分配的空間,也就是正在運(yùn)行的程序,各個進(jìn)程之間互不干擾。同時進(jìn)程保存著程序每一個時刻運(yùn)行的狀態(tài)。

讓一個線程執(zhí)行一個子任務(wù),這樣一個進(jìn)程就包含了多個線程,每個線程負(fù)責(zé)一個單獨(dú)的子任務(wù)。

進(jìn)程是一個獨(dú)立的運(yùn)行環(huán)境,而線程是在進(jìn)程中執(zhí)行的一個任務(wù)。他們兩個本質(zhì)的區(qū)別是是否單獨(dú)占有內(nèi)存地址空間及其它系統(tǒng)資源(比如I/O)

總得來說就是,線程是屬于進(jìn)程中的一個任務(wù),應(yīng)該算是包含的關(guān)系。

進(jìn)程是操作系統(tǒng)進(jìn)行資源分配的基本單位,而線程是操作系統(tǒng)進(jìn)行調(diào)度的基本單位。

多進(jìn)程的方式也可以實(shí)現(xiàn)并發(fā),為什么我們要使用多線程?這個問題就有意思了,你如果不是很了解的話,這個問題還真不好回答。

多進(jìn)程方式確實(shí)可以實(shí)現(xiàn)并發(fā),但使用多線程,是比多進(jìn)程有好處的。

1.進(jìn)程間的通信比較復(fù)雜,而線程間的通信比較簡單,通常情況下,我們需要使用共享資源,這些資源在線程間的通信比較容易。

2.進(jìn)程是重量級的,而線程是輕量級的,故多線程方式的系統(tǒng)開銷更小。

資源浪費(fèi)屬于一方面的有點(diǎn),通信簡單也是另外一方面的優(yōu)點(diǎn),就憑借這兩點(diǎn)的內(nèi)容,還能選擇多進(jìn)程?

圖片

線程池的內(nèi)容

你在工作中使用過線程池么?為什么使用線程池?這個問題有點(diǎn)尷尬,為什么這么說?

如果你說你沒用過,那你這在面試官這里就相當(dāng)于只寫 CRUD 的邏輯業(yè)務(wù)了,也不整點(diǎn)其他的內(nèi)容。

如果你說你用過,你就得回答接下來的一系列關(guān)于線程池的問題了。這個阿粉還是推薦,實(shí)話實(shí)話,就算你沒用過,那么也別瞎扯,不然你這給自己挖的坑,肯定自己得跳下去。

那么我們就從為什么使用線程池來入手分析唄。

首先我們就要思考一件事,不使用線程池的話,創(chuàng)建線程有什么弊端么?

在java中,如果每個請求到達(dá)就創(chuàng)建一個新線程,那對服務(wù)器的資源消耗是不是有點(diǎn)大,創(chuàng)建線程,銷毀線程,創(chuàng)建線程,銷毀線程,然后再各種線程之間來回的切換,這一來一回,是不是感覺資源浪費(fèi)就體現(xiàn)出來了。

那么線程池會避免這個情況么?

這就出來了優(yōu)點(diǎn)1了

創(chuàng)建/銷毀線程需要消耗系統(tǒng)資源,線程池可以復(fù)用已創(chuàng)建的線程。

雖然這個優(yōu)點(diǎn)很明確,但是還不是主要原因,主要原因如下:

控制并發(fā)的數(shù)量。并發(fā)數(shù)量過多,可能會導(dǎo)致資源消耗過多,從而造成服務(wù)器崩潰。(主要原因)

可以對線程做統(tǒng)一管理

分析一下線程池的原理 Java中的線程池頂層接口是Executor接口,但是使用的肯定不是這個,是 ThreadPoolExecutor

我們看看 ThreadPoolExecutor 構(gòu)造函數(shù)

public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}

竟然參數(shù)這么多,分別都代表什么意思呢?

int corePoolSize:該線程池中核心線程數(shù)最大值。

int maximumPoolSize:該線程池中線程總數(shù)最大值。

long keepAliveTime:非核心線程閑置超時時長。

TimeUnit unit:keepAliveTime的單位。

BlockingQueue workQueue:阻塞隊列,維護(hù)著等待執(zhí)行的Runnable任務(wù)對象。

corePoolSize核心線程最大值:這個值怎么確定?

一般這個問題是相對來說比較棘手的,如果面試官問這個問題,那一般的同學(xué)肯定頭大,我知道啥意思,但是這個怎么設(shè)置,我怎么定義呢?

其實(shí)有個計算公式:

最佳線程數(shù)目 = ((線程等待時間+線程CPU時間)/線程CPU時間 )* CPU數(shù)目

= (線程等待時間與線程CPU時間之比 + 1* CPU數(shù)目

線程等待時間所占比例越高,需要越多線程。線程CPU時間所占比例越高,需要越少線程

maximumPoolSize :線程池中線程總數(shù)最大值

這個值實(shí)際上就是 核心線程數(shù) + 非核心線程數(shù)量

keepAliveTime: 這個值如果設(shè)定了,那么非核心線程如果處于閑置狀態(tài)超過該值,就會被銷毀。

BlockingQueue:阻塞隊列

看樣子感覺像 MQ 里面的東西,想到隊列,我們就又能聯(lián)想到生產(chǎn)者和消費(fèi)者,這時候就出現(xiàn)了個問題,為什么要有阻塞隊列呢?

是不是就出現(xiàn)了消費(fèi)者模式,生產(chǎn)者一直生產(chǎn)資源,消費(fèi)者一直消費(fèi)資源,資源存儲在一個緩沖池中。

我們在實(shí)現(xiàn)這個模式的時候,多個線程操作共享變量,于是就帶來了線程安全性的問題,造成重復(fù)消費(fèi)和死鎖,這時候阻塞隊列就出現(xiàn)了,當(dāng)緩沖池空了,我們需要阻塞消費(fèi)者,喚醒生產(chǎn)者;當(dāng)緩沖池滿了,我們需要阻塞生產(chǎn)者,喚醒消費(fèi)者。

而BlockingQueue提供了線程安全的隊列訪問方式,并發(fā)包下很多高級同步類的實(shí)現(xiàn)都是基于BlockingQueue實(shí)現(xiàn)的。

也就是說,你就只負(fù)責(zé)生產(chǎn)和消費(fèi),安全問題,JDK 來給你保證。

說到這里,我們不在繼續(xù)往下延伸了,等下次阿粉直接在吧 BlockingQueue 完全的分析一波,應(yīng)為 BlockingQueue 絕對得需要一個長篇的內(nèi)容才能解釋清楚。

分析完里面的參數(shù),這時候,就得來看看線程池是怎么處理線程任務(wù)的,不然那怎么和面試官battle。

線程池是如何處理內(nèi)部的線程任務(wù)的

public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
// 1.當(dāng)前線程數(shù)小于corePoolSize,則調(diào)用addWorker創(chuàng)建核心線程執(zhí)行任務(wù)
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
// 2.如果不小于corePoolSize,則將任務(wù)添加到workQueue隊列。
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
//如果isRunning返回false(狀態(tài)檢查),則remove這個任務(wù),然后執(zhí)行拒絕策略。
if (! isRunning(recheck) && remove(command))
reject(command);
//線程池處于running狀態(tài),但是沒有線程,則創(chuàng)建線程
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
//如果放入workQueue失敗,則創(chuàng)建非核心線程執(zhí)行任務(wù),
//如果這時創(chuàng)建非核心線程失敗(當(dāng)前線程總數(shù)不小于maximumPoolSize時),就會執(zhí)行拒絕策略。
else if (!addWorker(command, false))
reject(command);
}

在 execute 方法中,ctl.get()是獲取線程池狀態(tài)。

流程如下:

1,首先線程池判斷基本線程池是否已滿,沒滿,創(chuàng)建一個工作線程來執(zhí)行任務(wù)。滿了,則進(jìn)入下個流程。

2,其次線程池判斷工作隊列是否已滿?沒滿,則將新提交的任務(wù)存儲在工作隊列里。滿了,則進(jìn)入下個流程。

3,最后線程池判斷整個線程池是否已滿,沒滿,則創(chuàng)建一個新的工作線程來執(zhí)行任務(wù),滿了,則交給飽和策略來處理這個任務(wù)。

圖片

如果你能把這些在面試的時候說清楚,那么至少在線程池這個知識點(diǎn)上,你是沒有任何問題了,這樣就可以愉快并且開心的走下一個知識點(diǎn)了。

責(zé)任編輯:武曉燕 來源: Java極客技術(shù)
相關(guān)推薦

2021-02-05 12:34:33

線程池系統(tǒng)

2024-03-11 18:18:58

項目Spring線程池

2024-04-02 09:45:27

線程池Executors開發(fā)

2024-09-12 08:35:06

2024-01-12 10:05:32

線程池代碼

2022-03-02 07:36:37

池化技術(shù)Java線程池

2019-01-25 08:15:22

Redis命令內(nèi)存

2021-11-29 10:55:11

線程池Java面試

2024-10-31 09:30:05

線程池工具Java

2012-05-15 02:18:31

Java線程池

2024-09-09 15:09:30

2022-09-05 17:49:53

Java線程池

2022-03-14 07:32:06

線程池拒絕策略自定義

2022-03-23 08:51:21

線程池Java面試題

2024-11-11 00:00:01

線程池工具

2020-02-18 14:25:51

Java線程池拒絕策略

2022-03-28 08:31:29

線程池定時任務(wù)

2010-06-25 10:36:27

Java連接池

2022-06-24 06:43:57

線程池線程復(fù)用

2023-05-19 08:01:24

Key消費(fèi)場景
點(diǎn)贊
收藏

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