
? ? ? ? ? ? ? ? ? ? 過硬的技術(shù)?+?透徹的金融業(yè)務(wù) + 心理學(xué) =?互聯(lián)網(wǎng)金融專家
寫在文章前面的:在之前的Java中級甚至Java的高級開發(fā)面試中,一般java的多線程開發(fā)就是問問基本問題,但今年隨著社會大經(jīng)濟環(huán)境的變化,和過剩的開發(fā)人員的涌現(xiàn),所以市場要求也越來越高,多線程也成了必須要重點掌握的知識點。
多線程和多任務(wù)往往是使用多處理器系統(tǒng)的最合理方式。因為并發(fā)在單處理器上執(zhí)行是沒有意義的,在單處理器上并發(fā)和順序的執(zhí)行并沒有什么本質(zhì)的區(qū)別。
使用多線程的好處就是更好的利用CPU的性能,更好的用戶體驗等。
一、線程的基本知識
了解線程之前必須要了解進程了,進程是指運行中的應(yīng)用程序,每個進程都有自己獨立的地址空間(內(nèi)存空間),比如用戶點擊桌面的IE瀏覽器,就啟動了一個進程,操作系統(tǒng)就會為該進程分配獨立的地址空間。當(dāng)用戶再次點擊左面的IE瀏覽器,又啟動了一個進程,操作系統(tǒng)將為新的進程分配新的獨立的地址空間。目前操作系統(tǒng)都支持多進程。
而線程是進程的一個實體,是被系統(tǒng)獨立調(diào)度和分派的基本單位,線程自己不擁有系統(tǒng)資源,只擁有在運行中必不可少的資源,但它可與同屬一個進程的其他線程共享進程所擁有的全部資源。一個線程可以創(chuàng)建和撤銷另一個線程,同一個進程中的多個線程之間可以并發(fā)執(zhí)行。
二、線程的狀態(tài)
線程一共有五種狀態(tài)(等待和超時等待歸屬于等待):New(新建),Runnable(可運行),Blocked(阻塞狀態(tài)),Waiting(等待狀態(tài) 和? Timed Waiting(超時等待)) ,Terminated(終止)

三、常用方法詳解
常用方法有:start(),run(),wait(),sleep(),notify(),notifyAll(),join(),yield(),park(),unpark(),join(),synchronized 方法或方法塊。
1、start() :啟動相應(yīng)線程,該方法的返回并不代表相應(yīng)的線程被啟動。一個Thread實例的start方法只能夠被調(diào)用一次,多次調(diào)用會導(dǎo)致異常的拋出。
2、run():用于實現(xiàn)線程的任務(wù)處理邏輯。該方法是由Java虛擬機直接調(diào)用的,一般情況下應(yīng)用程序不應(yīng)該調(diào)用該方法。
3、wait():讓線程等待或者使用wait(3000)的方式將線程阻塞3秒鐘,sleep()方法也是可以將線程休眠或者休眠一定時間的,兩個方法都可以引起阻塞。
4、notify() 是喚醒線程,API文檔:Wakes up a single thread that is waiting on this object's monitor。 NotifyAll() 在API文檔中解釋為:Wakes up all threads that are waiting on this object's monitor.(歡迎所有線程,可以作用于wait(),當(dāng)然也可以作用于sleep()的線程)。
notify():喚醒一個處于等待狀態(tài)的線程,在調(diào)用此方法的時候,并不能確切的喚醒某一個等待狀態(tài)的線程,而是由JVM確定喚醒哪個線程,而且與優(yōu)先級無關(guān);
notityAll():喚醒所有處于等待狀態(tài)的線程,該方法并不是將對象的鎖給所有線程,而是讓它們競爭,只有獲得鎖的線程才能進入就緒狀態(tài);
5、park() 和unpark(),unpark函數(shù)為線程提供“許可(permit)”,線程調(diào)用park函數(shù)則等待“許可”。這個有點像信號量,但是這個“許可”是不能疊加的,“許可”是一次性的。比如線程B連續(xù)調(diào)用了三次unpark函數(shù),當(dāng)線程A調(diào)用park函數(shù)就使用掉這個“許可”,如果線程A再次調(diào)用park,則進入等待狀態(tài)。注意,unpark函數(shù)可以先于park調(diào)用。比如線程B調(diào)用unpark函數(shù),給線程A發(fā)了一個“許可”,那么當(dāng)線程A調(diào)用park時,它發(fā)現(xiàn)已經(jīng)有“許可”了,那么它會馬上再繼續(xù)運行。
6、join(),該方法只會使主線程進入等待池并等待t線程執(zhí)行完畢后才會被喚醒。并不影響同一時刻處在運行狀態(tài)的其他線程。
7、yield(),調(diào)用yield方法會讓當(dāng)前線程交出CPU權(quán)限,讓CPU去執(zhí)行其他的線程。它跟sleep方法類似,同樣不會釋放鎖。但是yield不能控制具體的交出CPU的時間,另外,yield方法只能讓擁有相同優(yōu)先級的線程有獲取CPU執(zhí)行時間的機會。而且,調(diào)用yield方法并不會讓線程進入阻塞狀態(tài),而是讓線程重回就緒狀態(tài),它只需要等待重新獲取CPU執(zhí)行時間,這一點是和sleep方法不一樣的。
wait()和sleep()的區(qū)別是:
? ? ?a:wait方法是作用在Object上的,而sleep是作用在線程上的,當(dāng)調(diào)用Thread.sleep時,并不能改變對象的狀態(tài)。
證據(jù)如下:

? b:最主要是sleep方法沒有釋放鎖,而wait方法釋放了鎖,使得其他線程可以使用同步控制塊或者方法(鎖代碼塊和方法鎖)。
? c:wait,notify和notifyAll只能在同步控制方法或者同步控制塊里面使用,而sleep可以在任何地方使用(使用范圍)?
? d:sleep必須捕獲異常,而wait,notify和notifyAll不需要捕獲異常?
sleep相當(dāng)于讓線程睡眠,交出CPU,讓CPU去執(zhí)行其他的任務(wù)。
注意:sleep方法不會釋放鎖,也就是說如果當(dāng)前線程持有對某個對象的鎖,則即使調(diào)用sleep方法,其他線程也無法訪問這個對象。如果調(diào)用了sleep方法,必須捕獲InterruptedException異?;蛘邔⒃摦惓O蛏蠈訏伋?。當(dāng)線程睡眠時間滿后,不一定會立即得到執(zhí)行,因為此時可能CPU正在執(zhí)行其他的任務(wù)。所以說調(diào)用sleep方法相當(dāng)于讓線程進入阻塞狀態(tài)。