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

Java多線程面試問題集錦

移動開發(fā) Android
本文只是一些針對初學(xué)者或者新手的問題,如果你已經(jīng)具備良好的基礎(chǔ),那么你可以跳過本文,直接嘗試針對進(jìn)階水平的Java多線程編程問題及解答。

英文原文:java-success.blogspot,編譯:王曉杰

如果你即將去一家從事大型系統(tǒng)研發(fā)的公司進(jìn)行Java面試,不可避免的會有多線程相關(guān)的問題。下面是一些針對初學(xué)者或者新手的問題,如果你已經(jīng)具備良好的基礎(chǔ),那么你可以跳過本文,直接嘗試針對進(jìn)階水平的Java多線程編程問題及解答。

問題:進(jìn)程和線程的區(qū)別

解答:一個進(jìn)程對應(yīng)一個程序的執(zhí)行,而一個線程則是進(jìn)程執(zhí)行過程中的一個單獨(dú)的執(zhí)行序列,一個進(jìn)程可以包含多個線程。線程有時候也被稱為輕量級進(jìn)程.

一個Java虛擬機(jī)的實(shí)例運(yùn)行在一個單獨(dú)的進(jìn)程中,不同的線程共享Java虛擬機(jī)進(jìn)程所屬的堆內(nèi)存。這也是為什么不同的線程可以訪問同一個對象。線程彼此共 享堆內(nèi)存并保有他們自己獨(dú)自的??臻g。這也是為什么當(dāng)一個線程調(diào)用一個方法時,他的局部變量可以保證線程安全。但堆內(nèi)存并不是線程安全的,必須通過顯示的聲明同步來確保線程安全。

問題:列舉幾種不同的創(chuàng)建線程的方法.

解答:可以通過如下幾種方式:

繼承Thread 類

實(shí)現(xiàn)Runnable 接口

使用Executor framework (這會創(chuàng)建一個線程池)

 
  1. classCounter extendsThread { 
  2. //method where the thread execution will start  
  3. publicvoidrun(){ 
  4. //logic to execute in a thread     
  5. //let’s see how to start the threads 
  6. publicstaticvoidmain(String[] args){ 
  7. Thread t1 = newCounter(); 
  8. Thread t2 = newCounter(); 
  9. t1.start();  //start the first thread. This calls the run() method. 
  10. t2.start(); //this starts the 2nd thread. This calls the run() method.   
 
 
  1. classCounter extendsBase implementsRunnable{ 
  2. //method where the thread execution will start  
  3. publicvoidrun(){ 
  4. //logic to execute in a thread     
  5. //let us see how to start the threads 
  6. publicstaticvoidmain(String[] args){ 
  7. Thread t1 = newThread(newCounter()); 
  8. Thread t2 = newThread(newCounter()); 
  9. t1.start();  //start the first thread. This calls the run() method. 
  10. t2.start();  //this starts the 2nd thread. This calls the run() method.   
 

通過線程池來創(chuàng)建更有效率。

問題:推薦通過哪種方式創(chuàng)建線程,為什么?

解答:最好使用Runnable接口,這樣你的類就不必繼承Thread類,不然當(dāng)你需要多重繼承的時候,你將一籌莫展(我們都知道Java中的類只能繼承自一個 類,但可以同時實(shí)現(xiàn)多個接口)。在上面的例子中,因?yàn)槲覀円^承Base類,所以實(shí)現(xiàn)Runnable接口成了顯而易見的選擇。同時你也要注意到在不同的 例子中,線程是如何啟動的。按照面向?qū)ο蟮姆椒ㄕ?,你?yīng)該只在希望改變父類的行為的時候才去繼承他。通過實(shí)現(xiàn)Runnable接口來代替繼承Thread 類可以告訴使用者Counter是Base類型的一個對象,并會作為線程執(zhí)行。

問題:簡要的說明一下高級線程狀態(tài).

解答:下圖說明了線程的各種狀態(tài).

可執(zhí)行(Runnable):當(dāng)調(diào)用start()方法后,一個線程變?yōu)榭蓤?zhí)行狀態(tài),但是并不意味著他會立刻開始真正地執(zhí)行。而是被放入線程池,由線程調(diào)度器根據(jù)線程優(yōu)先級決定何時掛起執(zhí)行。

 
  1. MyThread aThread = newMyThread(); 
  2. aThread.start();                   //becomes runnable 
 

執(zhí)行中(Running):處理器已經(jīng)在執(zhí)行線程的代碼。他會一直運(yùn)行直到被阻斷,或者通過靜態(tài)方法Thread.yield()自行放棄執(zhí)行的機(jī)會,考慮到場景切換所帶來的開銷,yield()方法不應(yīng)該被經(jīng)常調(diào)用。

等待中(Waiting):線程由于等待I/O等外部進(jìn)程的處理結(jié)果而處于被阻斷的狀態(tài),調(diào)用currObject.wait( )方法會使得當(dāng)前線程進(jìn)入等待狀態(tài),直到其它線程調(diào)用currObject.notify() 或者currObject.notifyAll() 。

睡眠中(Sleeping):重載方法Thread.sleep(milliseconds),Thread.sleep(milliseconds, nanoseconds)可以迫使Java線程進(jìn)入睡眠狀態(tài)(掛起)。

由于I/O阻塞(Blocked on I/O):當(dāng)I/O條件發(fā)生變化時(例如讀取了幾個字節(jié)的數(shù)據(jù))會遷移到可執(zhí)行狀態(tài)。

由于同步阻塞中(Blocked on synchronization): 當(dāng)獲取鎖之后會進(jìn)入執(zhí)行中狀態(tài)。

Thread.State  枚舉類型包含了Java虛擬機(jī)支持的全部的線程狀態(tài)類型,下面幾點(diǎn)Java的線程宗旨確保了這些線程狀態(tài)成為可能。

對象可以被任何線程共享和修改。

線程調(diào)度器的搶占性特性,使得線程可以隨時在/不在多核處理之間切換處理器內(nèi)核,這意味著方法可以在執(zhí)行的過程中切換狀態(tài)。否則方法中的死循環(huán)將永遠(yuǎn)阻塞CPU,并且使得不同線程的其他方法始終得不到執(zhí)行。

為了防止線程安全問題,那些脆弱的方法或者代碼塊可以被鎖定。這使得線程可以處于被鎖定或者加鎖請求處理中兩種狀態(tài)。

線程在處理I/O資源(如Sockets,文件句柄,數(shù)據(jù)庫連接等)時會進(jìn)入等待狀態(tài),

處于I/O讀寫中的線程不能被切換,因此他們或者以成功/失敗的結(jié)果正常完成處理,或者其它線程關(guān)閉了相應(yīng)的資源,迫使他進(jìn)入死亡或者完成的狀態(tài)。這也是為什么一個合理的超時時間可以避免線程由于I/O處理而被永遠(yuǎn)阻塞,從而導(dǎo)致嚴(yán)重的性能問題。

線程可以進(jìn)入睡眠狀態(tài),以使得其他處于等待狀態(tài)的線程有機(jī)會執(zhí)行。

問題:yield和sleeping有何區(qū)別,sleep()和wait()有何區(qū)別?

解答:當(dāng)一個任務(wù)調(diào)用了yield()方法,它將從執(zhí)行中狀態(tài)轉(zhuǎn)變?yōu)榭蓤?zhí)行。而當(dāng)一個任務(wù)調(diào)用了sleep(),則將從執(zhí)行中狀態(tài)轉(zhuǎn)變?yōu)榈却?睡眠中狀態(tài)。

方法wait(1000)使得當(dāng)前線程睡眠1秒鐘,但調(diào)用notify() 或者notifyAll()會隨時喚醒線程。而sleep(1000)則會導(dǎo)致當(dāng)前線程休眠1秒鐘。

問題:為什么為了線程安全而鎖定一個方法或者一個代碼塊稱為“同步”而不是“鎖定”或者“被鎖定”

解答:當(dāng)某個方法或者代碼塊被聲明為”synchronized”后,保存數(shù)據(jù)的內(nèi)存空間(例如堆內(nèi)存)將保持被同步狀態(tài)。

這意味著:當(dāng)一個線程獲取鎖并且執(zhí)行到已被聲明為synchronized的方法或者代碼塊時,該線程首先從主堆內(nèi)存空間中讀取該鎖定對象的所有變化,以確保其在開始執(zhí)行之前擁有最新的信息。在synchronized部分執(zhí)行完畢,線程準(zhǔn)備釋放鎖的時候,所有針對被鎖定對象的修改都將為寫入主堆內(nèi)存中。這樣其他線程在請求鎖的時候就可以獲取最新的信息。

問題:線程如何進(jìn)行的同步處理?你可以列舉出那些同步級別?同步方法和代碼塊如何區(qū)別?

解答:在Java語言中,每個對象都有一個鎖,一個線程可以通過關(guān)鍵字synchronized來申請獲取某個對象的鎖,關(guān)鍵字synchronized可以被用于方法(粗粒度鎖,對性能影響較大)或代碼塊(細(xì)粒度鎖)級別。鎖定方法往往不是一個很好的選擇,取而代之的我們應(yīng)該只鎖定那些訪問共享資源的代碼塊,因 為每一個對象都有一個鎖,所以可以通過創(chuàng)建虛擬對象來實(shí)現(xiàn)代碼塊級別的同步,方法塊級別的鎖比鎖定整個方法更有效。

 

 

 

 

 

Java虛擬機(jī)靈活的使用鎖和監(jiān)視器,一個監(jiān)視器總體來說就是一個守衛(wèi)者,他負(fù)責(zé)確保只有一個線程會在同一時間執(zhí)行被同步的代碼。每個監(jiān)視器對應(yīng)一個對象的引用, 在線程執(zhí)行代碼塊的第一條指令之前,他必須持有該引用對象的鎖,否則他將無法執(zhí)行這段代碼。一旦他獲得鎖,該線程就可以進(jìn)入這段受到保護(hù)的代碼。當(dāng)線程不 論以何種方式退出代碼塊時,他都將釋放關(guān)聯(lián)對象的鎖。對于靜態(tài)方法,需要請求類級別的鎖。

責(zé)任編輯:閆佳明 來源: importnew
相關(guān)推薦

2019-07-19 08:10:47

JavaScript代碼語言

2019-07-15 11:04:37

Spring BootTomcat開發(fā)

2017-09-27 15:50:42

Java多線程并發(fā)

2009-03-03 09:33:13

面試ORACLE

2018-08-21 13:25:01

編程語言Java面試題

2015-05-11 14:02:21

JavaJava集合面試問題答案

2023-09-13 08:37:56

程序員面試catch

2019-07-31 09:06:35

Java跳槽那些事兒文章

2010-03-16 19:29:26

Java多線程操作

2015-12-22 10:39:52

Java多線程問題

2017-01-19 10:24:38

Java多線程問題

2013-09-30 09:08:30

面試創(chuàng)業(yè)

2010-02-01 17:25:09

Python多線程

2019-12-19 09:23:45

Java多線程數(shù)據(jù)

2011-06-22 13:57:54

Java多線程

2010-05-24 14:04:48

JavaSwing多線程

2011-06-22 13:47:16

Java多線程

2011-04-01 13:55:24

Java

2013-12-03 10:11:41

LinuxLinux面試題

2018-07-25 14:27:43

Redis數(shù)據(jù)架構(gòu)存儲
點(diǎn)贊
收藏

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