天天看點

java多線程面試_Java多線程面試題

java多線程面試_Java多線程面試題

1、啟動一個線程是調用run()方法還是start()方法?

啟動一個線程是調用start()方法,是線程所代表的虛拟處理機處于可運作狀态,這意味着它可以由JVM排程并執行,這并不意味着線程就會立即執行

2、請說出同步線程及線程排程相關的方法?

wait():是一個線程等待(阻塞bolcked)狀态,并且釋放所持有的對象的鎖

sleep():是一個正在運作狀态的線程處于睡眠狀态,是一個靜态方法,調用此方法要處理InterruptedException異常;

notify():喚醒一個處于等待狀态的線程,當然在調用此方法的時候,并不能确切的喚醒某一等待狀态的線程,而是由JVM确定喚醒哪個線程,而且與優先級無關。

notifyAll():喚醒所有處于等待狀态的線程,該方法并不是将對象的鎖給所有線程,而是讓它們競争,隻有獲得了鎖的線程才能進入就緒狀态。

注意:Java5通過Lock接口提供了顯式的鎖機制,Lock接口中定義了加鎖(lock()方法)和解鎖(unlock()方法),增強了多線程程式設計的靈活性及對線程的協調。???

3、線程和程序的差別?

程序:具有一定獨立功能的程式關于某個資料集合上的一次運作活動,是作業系統進行資源配置設定和排程的一個獨立機關。

線程:是程序的一個實體,是CPU排程和分派的基本機關,是比程序更小的可以獨立運作的基本機關。

特點:線程的劃分尺度小于程序,這使多線程程式擁有高并發性,程序在運作時各自記憶體單元互相獨立,線程之間記憶體共享,這是多線程程式設計可以擁有更好的相能和使用者體驗。

注意:多線程對于其它程式是不友好的,占據大量CPU資源(共享記憶體的原因?)

4、多線程的建立方式?

1):繼承Thread類:但Thread本質上也是實作了Runnable接口的一個執行個體,他代表了一個線程的執行個體,并且,啟動線程的唯一方法就是通過Thread類的start()執行個體方法。start()方法是一個native方法(本地方法),它将啟動一個新線程,并執行run()方法。這種方法實作多線程很簡單,通過自己的類直接extend Thread,并複寫run()方法,就可以啟動新線程并執行自己定義的run()方法。例如:繼承Thread類實作多線程,并在适合的地方啟動線程。

java多線程面試_Java多線程面試題

2):實作Runnable接口的方式實作多線程,并且執行個體化Thread,傳入自己的Thread執行個體,調用run()方法

java多線程面試_Java多線程面試題

3):使用ExecutorService、Callable、Future實作有傳回結果的多線程:ExecutorService、Callable、Future這個對象實際上都是屬于Executor架構中的功能類。

傳回結果的線程實在JDK1.5引入;

可傳回值的任務必須實作Callable接口,無傳回值的任務必須實作Runnable接口。執行Callable任務後,可以擷取一個Future的對象,在該對象上調用get()方法就可以擷取到Callable任務傳回的Object了,再結合線程池接口ExecutorService就可以實作傳說中有傳回結果的多線程了。

java多線程面試_Java多線程面試題

5、在Java中wait和sleep方法的不同?

最大的不同是在等待wait會是釋放鎖,而sleep一直持有鎖。wait通常被用于線程間互動,sleep通常被用于暫停執行。

6、synchronized和volatile關鍵字的差別?

一旦一個共享變量(類的成員變量、類的靜态成員變量)被volatile修飾之後,那麼就具備了兩層語義:

1)保證了不同線程對這個變量進行操作時的可見性,即一個線程修改了某個變量的值,這新值對其它線程來說也是立即可見的。

2)禁止進行指令重排序

volatile本質是告訴JVM目前變量在寄存器(工作記憶體)中的值是不确定的,需要從主存中讀取;

synchronized則是鎖定目前變量,隻有目前線程可以通路該變量,其他線程被阻塞住。

a)volatile僅能使用在變量級别:

synchronized則可以使用在變量、方法和類級别的

b)volatile僅能實作變量的修改可見性,并不能保證原子性;

synchronized則可以保證變量的修改可見性和原子性;

c)volatile不會造成線程的阻塞

synchronized可能會造成線程阻塞

d)volatile标記的變量不會被編譯器優化

synchronized标記的變量可以被編譯器優化(指令重排序?)

6、什麼是線程池,如何使用?

線程屬于重量級資源,線程池就是事先将多個線程對象放到一個容器中,當使用的時候就不用new線程而是直接去池中拿線程即可,節省了開辟子線程的時間,提高了代碼執行效率。

在JDK的java.util.concurrnet.Executors中提供了生成多種線程池的靜态方法。

java多線程面試_Java多線程面試題

一般我們去自己實作Executor接口,自定義線程池。

7、常用的線程池有哪些?

newSingleThreadExeCutor:建立一個單線程的線程池,此線程保證所有任務的執行順序按照任務的送出順序執行。

newFixedThreadPool:建立固定大小的線程池,每次送出(submit()方法)一個任務就建立一個線程,直到線程達到線程池的最大大小。

newCachedThreadPool:建立一個可緩存的線程池,此線程池不會對線程池大小做限制,線程池大小完全依賴于作業系統(或者說JVM)能夠建立的最大線程大小。

newScheduledThreadPool:建立一個大小無限的線程池,此線程池支援定時以及周期性執行任務的需求。

8、對線程池的了解?

從線程池如何使用、線程池的好處、線程池的啟動政策三方面回答

合理利用線程池的三個好處

1):減低資源消耗。通過重複利用已建立的線程來降低線程建立和銷毀造成的消耗。

2):提高響應速度。當任務到達時,任務可以不需要等到線程建立就能立即執行。

3):提高線程的可管理性。線程是稀缺資源,如果無限制的建立,不僅會消耗系統資源,還會降低系統的穩定性(?),使用線程池可以進行同一的配置設定,調優和監控。

線程池的啟動政策:

java多線程面試_Java多線程面試題

1):線程池剛剛建立時,裡面沒有一個線程。任務隊列是作為參數傳進來的。不過,就算隊列裡有任務,線程池也不會馬上執行它們。

2):當調用execute()方法添加一個任務時,線程池會做如下判斷:

a):如果正在運作的線程數量小于corePoolSize,那麼馬上建立線程運作這個任務

b):如果正在運作的線程數量大于或等于corePoolSize,那麼将這個任務放入隊列。

c):如果這時候隊列滿了,而且正在運作的線程數量小于maximumPoolSize,那麼還是要建立線程運作這個任務;

d):如果隊列滿了,而且正在運作的線程數量大于或等于maximumPoolSize,那麼線程池會派出異常,告訴調用者“我不能在接收任務了”。

3):當一個線程完成任務時,它會從隊列中取下一個任務來執行。

4)當一個線程無事可做,超過一定的時間(keepAliveTime)時,線程池會判斷,如果目前運作的線程數大于corePoolSize,那麼這個線程就會被停掉。是以線程池的所有任務完成後,它會最終收縮到corePoolSize的大小。

java多線程面試_Java多線程面試題