面試官因為線程池,讓我出門左拐!
前幾天阿粉的朋友面試,在面試的時候,面試官問到了框架,項目,JVM還有一些關于線程池的內(nèi)容,而這個線程池,讓阿粉的朋友分分鐘被面試官吊打,只能出門左拐,地鐵站回家了。為什么呢?因為線程池他是真的沒有下功夫去準備,只能涼涼了。
前序說實話,阿粉在面試的時候,最開始的時候的面試,面試官只是會問實現(xiàn)多線程的方式都有哪些,但是你說到關于線程池的內(nèi)容的時候,都是一句帶過,而有些面試官對這個也不是很細抓,但是自從阿里的面試官開始問關于線程池的問題之后,這個問題就成了高頻熱點了。
那么接下來,阿粉就繼續(xù)帶給大家關于這個線程池,如何分分鐘擺平面試官。
1.什么是線程池
java.util.concurrent.Executors 這個類大家不知道有沒有仔細的去看過這個,而這個類中給我提供了很多方法來創(chuàng)建線程池。
在代碼的開頭的注釋上就寫明了,它可以創(chuàng)建重復使用固定數(shù)量線程的線程池,如果在所有線程都處于活動狀態(tài)時提交了其他任務,那么他們將在隊列中等待線程可用。
- public static ExecutorService newFixedThreadPool(int nThreads) {
- return new ThreadPoolExecutor(nThreads, nThreads,
- 0L, TimeUnit.MILLISECONDS,
- new LinkedBlockingQueue<Runnable>());
- }
而我們創(chuàng)建線程池就是為了解決處理器單元內(nèi)多個線程執(zhí)行的問題,它可以顯著減少處理器單元的閑置時間,增加處理器單元的吞吐能力。
而面試的時候,我們肯定不能這么說,面試的時候我們可以這么說:
做Java的,當然知道線程池,我們在做開發(fā)的時候有時候需要做的任務慢慢的增多,復雜性也會變得越來越強,所以線程的個數(shù)就會一點點的往上增加,而對應的線程占用的資源也就越來越多,多個線程占用資源的釋放與注銷需要維護,這時候多個線程的管理就顯得有尤為重要。針對這一情況,sun公司提供了線程池,對線程集合的管理工具。所以線程池就出現(xiàn)了,接下來面試官的問題就是比較狠了,你平常是怎么使用的,幾種常見的都有哪些,畢竟面試官的套路一環(huán)套一環(huán)。
2.常見的線程池都有哪些,使用的場景是哪里呢?
這時候這個java.util.concurrent.Executors 類大家就排上用場了,比如:
(1) newSingleThreadExecutor
- 單個線程的線程池,即線程池中每次只有一個線程工作,單線程串行執(zhí)行任務
- public ThreadPoolExecutor(int corePoolSize,
- int maximumPoolSize,
- long keepAliveTime,
- TimeUnit unit,
- BlockingQueue<Runnable> workQueue,
- ThreadFactory threadFactory) {
- this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
- threadFactory, defaultHandler);
- }
(2)newFixedThreadPool
下面的兩個方法是這個方法的重載,而它的意思很明確,建立一個線程數(shù)量固定的線程池,規(guī)定的最大線程數(shù)量,超過這個數(shù)量之后進來的任務,會放到等待隊列中,如果有空閑線程,則在等待隊列中獲取,遵循先進先出原則。
- public static ExecutorService newFixedThreadPool(int nThreads) {
- return new ThreadPoolExecutor(nThreads, nThreads,
- 0L, TimeUnit.MILLISECONDS,
- new LinkedBlockingQueue<Runnable>());
- }
- public static ExecutorService newFixedThreadPool(int nThreads) {
- return new ThreadPoolExecutor(nThreads, nThreads,
- 0L, TimeUnit.MILLISECONDS,
- new LinkedBlockingQueue<Runnable>());
- }
(3)newCacheThreadExecutor
緩存型線程池,這個線程池的意思是在核心線程達到最大值之前,如果繼續(xù)有任務進來就會創(chuàng)建新的核心線程,并加入核心線程池,即使有空閑的線程,也不會復用。
而達到最大核心線程數(shù)后,新任務進來,如果有空閑線程,則直接拿來使用,如果沒有空閑線程,則新建臨時線程.
而緩存型的線程池使用的是SynchronousQueue作為等待隊列,他不保存任何的任務,新的任務加入進來之后,他會創(chuàng)建臨時線程來進行使用
- public static ExecutorService newCachedThreadPool() {
- return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
- 60L, TimeUnit.SECONDS,
- new SynchronousQueue<Runnable>());
- }
(4)newScheduledThreadPool
計劃型線程池,在它的注釋中給出的很明確的解釋,創(chuàng)建一個線程池,該線程池可以計劃在給定的延遲,或周期性地執(zhí)行。
也就是說,在新任務到達的時候,我們看到底有沒有空閑線程,如果有,直接拿來使用,如果沒有,則新建線程加入池。而這里面使用的就是DelayedWorkQueue作為等待隊列,中間進行了一定的等待,等待時間過后,繼續(xù)執(zhí)行任務。
- public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
- return new ScheduledThreadPoolExecutor(corePoolSize);
- }
- public static ScheduledExecutorService newScheduledThreadPool(
- int corePoolSize, ThreadFactory threadFactory) {
- return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
- }
3.你看過阿里巴巴開發(fā)手冊么?里面對線程是怎么說的?說實話,阿粉是一開始真的沒怎么注意過這個在阿里巴巴開發(fā)手冊上關于線程的使用,是怎么做的,而面試官很明顯,問出這個問題的時候,肯定是看過了,之后阿粉看了阿里巴巴開發(fā)手冊,不得不感慨,阿里巴巴,真的是..
我們在日常使用都是會出現(xiàn)這段代碼:
- ExecutorService cachedThreadPool=Executors.newFixedThreadPool();
但是阿里巴巴說,不好意思呀,強制線程池不允許使用 Executors 去創(chuàng)建
那你說嘛,我該怎么辦,而推薦的卻是 ThreadPoolExecutor
- public ThreadPoolExecutor(int corePoolSize,
- int maximumPoolSize,
- long keepAliveTime,
- TimeUnit unit,
- BlockingQueue<Runnable> workQueue) {
- this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
- Executors.defaultThreadFactory(), defaultHandler);
- }
這個方法里面有幾個參數(shù)
- corePoolSize 要保留在池中的線程數(shù),也就是線程池核心池的大小
- maximumPoolSize 最大線程數(shù)
- keepAliveTime 當線程數(shù)大于核心時,此為終止前多余的空閑線程等待新任務的最長時間。
- unit keepAliveTime 參數(shù)的時間單位
- workQueue 用來儲存等待執(zhí)行任務的隊列。
- threadFactory 線程工廠
- handler 默認的拒絕執(zhí)行處理程序
而這些參數(shù)也是面試中經(jīng)常會問到的呦,而如何選擇合適的線程池,如何合理的配置線程池大小,請繼續(xù)關注阿粉,阿粉將會在最近幾天帶個大家,點個再看再走唄