1. public final void join() throws InterruptedException {
->Waits for this thread to die
2.public final synchronized void join(long millis) throws InterruptedException {
->Waits at most {@code millis} milliseconds for this thread to die. A timeout of {@code 0} means to wait forever.
{@link Object#wait}
3.public void interrupt()
-> Interrupts this thread
-> If this thread is blocked in an invocation of the {@linkObject#wait() wait()}, {@link Object#wait(long) wait(long)}, or {@link Object#wait(long, int) wait(long, int)} methods of the {@link Object} class, or of the {@link #join()}, {@link #join(long)}, {@link #join(long, int)}, {@link #sleep(long)}, or {@link #sleep(long, int)},methods of this class, then its interrupt status will be cleared and it will receive an {@link InterruptedException}.
->If this thread is blocked in an I/O operation upon an {@link java.nio.channels.InterruptibleChannel </code>interruptible channel<code>} then the channel will be closed, the thread's interrupt status will be set, and the thread will receive a {@link java.nio.channels.ClosedByInterruptException}.
-> If this thread is blocked in a {@link java.nio.channels.Selector}then the thread's interrupt status will be set and it will return immediately from the selection operation, possibly with a non-zero value, just as if the selector's {@link java.nio.channels.Selector#wakeup wakeup} method were invoked.
2.Object API
1.public final void wait() throws InterruptedException
->Causes the current thread to wait until another thread invokes the {@link java.lang.Object#notify()} method or the{@link java.lang.Object#notifyAll()} method for this object. In other words, this method behaves exactly as if it simply performs the call {@code wait(0)}.
->The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the {@code notify} method or the{@code notifyAll} method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.
2.public final native void notify()
->Wakes up a single thread that is waiting on this object's monitor. If any threads are waiting on this object, one of them is chosen to be awakened.
3.多線程之間協(xié)作
1.Object.wait()在釋放CPU同時(shí),釋放了對(duì)象鎖的控制;
2.Obj.wait(),與Obj.notify()必須要與synchronized(Obj)一起使用,也就是wait,與notify是針對(duì)已經(jīng)獲取了Obj鎖進(jìn)行操作,從語法角度來說就是Obj.wait(),Obj.notify必須在synchronized(Obj){...}語句塊內(nèi)。從功能上來說wait就是說線程在獲取對(duì)象鎖后,主動(dòng)釋放對(duì)象鎖,同時(shí)本線程休眠。直到有其它線程調(diào)用對(duì)象的notify()喚醒該線程,才能繼續(xù)獲取對(duì)象鎖,并繼續(xù)執(zhí)行;
3.a.調(diào)用obj.wait()后,線程A就釋放了obj的鎖,否則線程B無法獲得obj鎖,也就無法在synchronized(obj) {...} 代碼段內(nèi)喚醒A
b.當(dāng)obj.wait()方法返回后,線程A需要再次獲得obj鎖,才能繼續(xù)執(zhí)行
c.如果A1,A2,A3都在obj.wait(),則B調(diào)用obj.notify()只能喚醒A1,A2,A3中的一個(gè),JVM決定
d.obj.notifyAll()則能全部喚醒A1,A2,A3,但是要繼續(xù)執(zhí)行obj.wait()的下一條語句,必須獲得obj鎖,因此,A1,A2,A3只有一個(gè)有機(jī)會(huì)獲得鎖繼續(xù)執(zhí)行如A1,其余的需要等待A1釋放obj鎖之后才能繼續(xù)執(zhí)行
e.當(dāng)B調(diào)用obj.notify/notifyAll的時(shí)候,B正持有obj鎖,因此,A1,A2,A3雖被喚醒,但是仍無法獲得obj鎖。直到B退出synchronized塊,釋放obj鎖后A1,A2,A3中的一個(gè)才有機(jī)會(huì)獲得鎖繼續(xù)執(zhí)行
4.Java的synchronized類似于操作系統(tǒng)概念中的互斥內(nèi)存塊->JAVA中對(duì)象內(nèi)存鎖->線程獲取該內(nèi)存鎖后,其它線程無法訪問該內(nèi)存->(static(所有對(duì)象共享的內(nèi)存)和對(duì)象的區(qū)別)
5.當(dāng)一個(gè)線程請(qǐng)求其它的線程已經(jīng)占有的鎖時(shí),請(qǐng)求線程將被阻塞。然而內(nèi)部鎖是可重進(jìn)入的,因此線程在試圖獲得它自己占用的鎖時(shí)請(qǐng)求會(huì)成功->重進(jìn)入的實(shí)現(xiàn)是通過為每一個(gè)鎖關(guān)聯(lián)一個(gè)請(qǐng)求計(jì)數(shù)器和一個(gè)占有他的線程->當(dāng)計(jì)數(shù)為0時(shí),認(rèn)為鎖是未被占用的->線程請(qǐng)求一個(gè)未被占有的鎖時(shí)候,JVM將記錄鎖的占有者,并且將請(qǐng)求計(jì)數(shù)設(shè)置為1->如果同一個(gè)線程再次請(qǐng)求這個(gè)鎖,計(jì)數(shù)將遞增->每次占用線程退出語句塊時(shí),計(jì)數(shù)器值將遞減,直到計(jì)數(shù)器達(dá)到0時(shí)候,鎖被釋放.
4.方法理解
1.join->A線程中調(diào)用->B線程的join方法B.join()->B線程繼續(xù)運(yùn)行,A線程停止(進(jìn)入阻塞狀態(tài))->等B運(yùn)行完畢A再繼續(xù)運(yùn)行,中途B線程不受影響->A線程停止的位置就在調(diào)用join方法處->后續(xù)代碼不執(zhí)行->要等B完了以后再執(zhí)行->
->join,合并->調(diào)用b.join->b線程合并到a線程->a線程等待b線程運(yùn)行完再運(yùn)行.(landon理解:之所以稱為join,合并->將t.join的線程t合并到調(diào)用的當(dāng)前線程->因?yàn)楹喜⒘藅->所以要先執(zhí)行t(相當(dāng)于在當(dāng)前線程的執(zhí)行過程中插播了一段t[合并了t]))->
2.sleep->
1.public static native void sleep(long millis) throws InterruptedException->靜態(tài)方法->
2.當(dāng)前線程進(jìn)入暫停狀態(tài)->指定的sleep時(shí)間內(nèi)都不會(huì)獲得執(zhí)行->
3.可以使優(yōu)先級(jí)低的線程 | 同優(yōu)先級(jí)的線程 | 高優(yōu)先級(jí)的線程 獲得執(zhí)行的機(jī)會(huì)(是否取決于當(dāng)前線程的優(yōu)先級(jí))
3.yield->
1.public static native void yield()->靜態(tài)方法->
2.線程讓步->如果具有相同優(yōu)先級(jí)的其他線程處于就緒狀態(tài)->yield()方法將把當(dāng)前運(yùn)行的線程放到可運(yùn)行池中并使另一個(gè)線程運(yùn)行->如果沒有相同優(yōu)先級(jí)的可運(yùn)行進(jìn)程->yield什么都不做->
3.yield->使當(dāng)前線程重新回到可執(zhí)行狀態(tài)->執(zhí)行yield()的線程有可能在進(jìn)入到可運(yùn)行狀態(tài)后->馬上又被運(yùn)行->
4.interrupt->
1.interrupt->不會(huì)中斷一個(gè)正在運(yùn)行的線程->這一方法實(shí)際上完成的是->在線程受到阻塞時(shí)拋出一個(gè)中斷信號(hào)->這樣線程就得以退出阻塞的狀態(tài)->如果線程被Object.wait, Thread.join和Thread.sleep三種方法之一阻塞->它將接收到一個(gè)中斷異常(InterruptedException)->從而提早地終結(jié)被阻塞狀態(tài)->
2.線程被上述幾種方法阻塞->正確的停止線程方式是設(shè)置共享變量->并調(diào)用interrupt()(注意變量應(yīng)該先設(shè)置)->如果線程沒有被阻塞,這時(shí)調(diào)用interrupt()將不起作用->否則線程就將得到異常(該線程必須事先預(yù)備好處理此狀況->try/catch(InterruptedException)),接著逃離阻塞狀態(tài)->在任何一種情況中,最后線程都將檢查共享變量然后再停止->
(landon理解:之前我停止線程的方法是向主線程消息隊(duì)列投遞一個(gè)停止消息->即不通過多線程的方式->而是全部通過單線程消息隊(duì)列投遞消息->然后在單線程消息處理器中將stopFlag置為true)
3.public final void join() throws InterruptedException
public static native void sleep(long millis) throws InterruptedException
public final void join() throws InterruptedException
LinkedBlockingQueue#public E take() throws InterruptedException->
public final void wait() throws InterruptedException
->目前上述方法在其線程上調(diào)用interrupt方法->都會(huì)拋出InterruptedException
4.每個(gè)線程都有一個(gè)與之相關(guān)聯(lián)的 boolean 屬性->用于表示線程的中斷狀態(tài)(interrupted status)->中斷狀態(tài)初始時(shí)為 false->當(dāng)另一個(gè)線程通過調(diào)用 Thread.interrupt() 中斷一個(gè)線程時(shí),會(huì)出現(xiàn)以下兩種情況之一->如果那個(gè)線程在執(zhí)行一個(gè)低級(jí)可中斷阻塞方法,例如 Thread.sleep()、 Thread.join() 或 Object.wait(),那么它將取消阻塞并拋出 InterruptedException->否則 interrupt() 只是設(shè)置線程的中斷狀態(tài)-> 在被中斷線程中運(yùn)行的代碼以后可以輪詢中斷狀態(tài),看看它是否被請(qǐng)求停止正在做的事情->中斷狀態(tài)可以通過 Thread.isInterrupted() 來讀取,并且可以通過一個(gè)名為 Thread.interrupted() 的操作讀取和清除->
public static boolean interrupted() { return currentThread().isInterrupted(true);}
5.中斷是一種協(xié)作機(jī)制->當(dāng)一個(gè)線程中斷另一個(gè)線程時(shí),被中斷的線程不一定要立即停止正在做的事情->相反,中斷是禮貌地請(qǐng)求另一個(gè)線程在它愿意并且方便的時(shí)候停止它正在做的事情。有些方法,例如 Thread.sleep(),很認(rèn)真地對(duì)待這樣的請(qǐng)求,但每個(gè)方法不是一定要對(duì)中斷作出響應(yīng)->
6.并非所有的阻塞方法都拋出 InterruptedException。輸入和輸出流類會(huì)阻塞等待 I/O 完成,但是它們不拋出 InterruptedException,而且在被中斷的情況下也不會(huì)提前返回(輪詢中斷狀態(tài)?)->對(duì)于套接字 I/O,如果一個(gè)線程關(guān)閉套接字,則那個(gè)套接字上的阻塞 I/O 操作將提前結(jié)束,并拋出一個(gè) SocketException。java.nio 中的非阻塞 I/O 類也不支持可中斷 I/O,但是同樣可以通過關(guān)閉通道或者請(qǐng)求 Selector 上的喚醒來取消阻塞操作->嘗試獲取一個(gè)內(nèi)部鎖的操作(進(jìn)入一個(gè) synchronized 塊)是不能被中斷的,但是 ReentrantLock 支持可中斷的獲取模式->
5.推薦的一篇文章
http://www.ibm.com/developerworks/cn/java/j-jtp05236.html
6.線程狀態(tài)
1.New(初始狀態(tài))->t.start->Runnable(可運(yùn)行狀態(tài)/就緒狀態(tài))->os時(shí)間片輪轉(zhuǎn),t獲得cpu時(shí)間片->Running(運(yùn)行狀態(tài))->run結(jié)束->Dead(死亡狀態(tài))
2.Running(運(yùn)行狀態(tài))->t2.join/sleep/io->Blocked(阻塞狀態(tài))->sleep結(jié)束/t2終止/io完成->Runnable(可運(yùn)行狀態(tài)/就緒狀態(tài))
3.Running(運(yùn)行狀態(tài))->時(shí)間片用完/t.yield->Runnable(可運(yùn)行狀態(tài)/就緒狀態(tài))
4.Running(運(yùn)行狀態(tài))->t線程調(diào)用o.wait->等待隊(duì)列->其他線程調(diào)用o.notify/o.nonifyAll->鎖池隊(duì)列->拿到對(duì)象的鎖->Runnable(可運(yùn)行狀態(tài)/就緒狀態(tài))
5.Running(運(yùn)行狀態(tài))->執(zhí)行synchronized塊->鎖池隊(duì)列->拿到對(duì)象的鎖->Runnable(可運(yùn)行狀態(tài)/就緒狀態(tài))
{@link Thread#State}
































































7.守護(hù)線程
public final void setDaemon(boolean on)->
1.->Marks this thread as either a daemon thread(守護(hù)線程) or a user thread(用戶線程). The Java Virtual Machine exits when the only threads running are all daemon threads.
2.守護(hù)線程為用戶線程服務(wù)->JVM的垃圾回收、內(nèi)存管理等線程都是守護(hù)線程->還有就是在做數(shù)據(jù)庫應(yīng)用時(shí)候,使用的數(shù)據(jù)庫連接池,連接池本身也包含著很多后臺(tái)線程,監(jiān)控連接個(gè)數(shù)、超時(shí)時(shí)間、狀態(tài)等->User Thread已經(jīng)全部退出運(yùn)行了->只剩下Daemon Thread存在了->虛擬機(jī)退出->因?yàn)闆]有被守護(hù)的用戶線程了->守護(hù)線程存在就無意義了->
3.thread.setDaemon(true)必須在thread.start()之前設(shè)置->否則會(huì)跑出一個(gè)IllegalThreadStateException異常->你不能把正在運(yùn)行的常規(guī)線程設(shè)置為守護(hù)線程
4.在Daemon線程中產(chǎn)生的新線程也是Daemon的->
5.通常server shutdown的線程設(shè)置為守護(hù)線程->該首付線程負(fù)責(zé)shutdown所有的用戶線程->在用戶線程shutdown ok->jvm退出->shutdown的守護(hù)線程自然退出->不要把一些應(yīng)用的業(yè)務(wù)放在守護(hù)線程做->否則當(dāng)用戶線程結(jié)束的時(shí)候,jvm就退出了->而此時(shí)可能守護(hù)線程的task還未執(zhí)行完畢->
8.關(guān)于阻塞IO
線程阻塞->放棄CPU,暫停運(yùn)行->只有等待導(dǎo)致阻塞的原因消除->或者被其他線程中斷->則退出阻塞狀態(tài)->并拋出InterruptedException.
線程阻塞原因:
1.Thread.sleep(long n)->線程放棄CPU->睡眠n毫秒,然后恢復(fù)運(yùn)行->
2.線程執(zhí)行一段同步代碼->由于無法獲得同步鎖->阻塞->直到獲得同步鎖->恢復(fù)運(yùn)行->
3.線程執(zhí)行了一個(gè)對(duì)象的wait->進(jìn)入阻塞->等待其他線程執(zhí)行了該對(duì)象的notify()或notifyAll喚醒
4.線程執(zhí)行io操作或遠(yuǎn)程通信->會(huì)因?yàn)榈却嚓P(guān)的資源而進(jìn)入阻塞狀態(tài)->如System.in.read()->
遠(yuǎn)程通信,Client可能進(jìn)入阻塞狀態(tài)->
1.Socket#connect->阻塞->直到連接成功
2.Socket#read->沒有足夠的數(shù)據(jù)->阻塞->讀到了足夠的數(shù)據(jù)/輸入流末尾/異常->才會(huì)返回或者異常中斷-> read()->輸入流中只需要一個(gè)字節(jié)就足夠->read(byte[] buff)->只要輸入流中的字節(jié)數(shù)目與buff數(shù)組的長(zhǎng)度相同即足夠->readLine->只要輸入流中有一行字符串就足夠(BufferedReader)
3.Socket#write->阻塞->直到輸出了所有的數(shù)據(jù)或者出現(xiàn)異常->才返回或者異常中斷
4.Socket#setSoLinger->設(shè)置關(guān)閉Socket延遲時(shí)間->Socket#close->進(jìn)入阻塞->直到底層Socket發(fā)送完所有剩余數(shù)據(jù)或者到了SoLinger的超時(shí)時(shí)間->返回
Server也可能進(jìn)入阻塞狀態(tài)->
1.ServerSocket#accept->直到接收到了Client連接才返回
2.#read->如果輸入流沒有足夠的數(shù)據(jù)->阻塞
3.#write->阻塞->直到輸出了所有數(shù)據(jù)或出現(xiàn)異常->
->無論是Client還是Server->通過Socket輸入輸出流讀寫數(shù)據(jù)->都可能進(jìn)入阻塞狀態(tài)->阻塞IO->如果執(zhí)行輸入輸出操作時(shí)->不發(fā)生阻塞->非阻塞IO