九、線程 start()對(duì)我們唯一的保證:每個(gè)線程都將運(yùn)行,每個(gè)線程都將運(yùn)行至結(jié)束 一旦start(),就永遠(yuǎn)不能重新start()哪怕是它已經(jīng)死去,否則導(dǎo)致運(yùn)行時(shí)異常 需要熟悉的方法: 靜態(tài)yield(),大多數(shù)情況下使當(dāng)前線程轉(zhuǎn)入可運(yùn)行狀態(tài),本意是使得具有相同優(yōu)先級(jí)的其他線程獲得運(yùn)行機(jī)會(huì),這同樣無(wú)法得到保證 靜態(tài)sleep(),轉(zhuǎn)入可運(yùn)行狀態(tài)休眠一段時(shí)間,不放任何鎖;用法Thread.sleep(long),必須包圍在try-catch中 join(),保證在調(diào)用join()的線程結(jié)束前,當(dāng)前進(jìn)程停止運(yùn)行,也即當(dāng)前執(zhí)行線程內(nèi)join()之后的語(yǔ)句保證在指定線程run()完之后運(yùn)行 靜態(tài)Thread.currentThread(),返回對(duì)當(dāng)前執(zhí)行線程的引用 isAlive(),已經(jīng)啟動(dòng),未結(jié)束run() start()的調(diào)用需要Thread的實(shí)例,不可以是runnable 使一個(gè)實(shí)現(xiàn)runnable接口的類(lèi)的實(shí)例啟動(dòng),可以做一個(gè)Thread,也可以直接調(diào)用run方法 Runnable只有一個(gè)run方法,public void run();若沒(méi)有重寫(xiě)這樣一個(gè)方法,將在聲明實(shí)現(xiàn)接口的地方報(bào)錯(cuò):未能實(shí)現(xiàn)該接口 線程的啟動(dòng)應(yīng)調(diào)用start(),若直接調(diào)用run()則表示從當(dāng)前正在運(yùn)行的類(lèi)調(diào)用一個(gè)普通的方法,run()進(jìn)入當(dāng)前調(diào)用棧,而不會(huì)啟動(dòng)新的線程;重載的run()只能作為一般方法手動(dòng)調(diào)用 語(yǔ)法上,將線程傳遞給線程的構(gòu)造器是合法的 對(duì)線程進(jìn)行setPriority()是沒(méi)有保證的。默認(rèn)的優(yōu)先級(jí)是5 保護(hù)數(shù)據(jù)的操作:變量標(biāo)識(shí)為private,同步訪問(wèn)這些變量的方法 在java中,每一個(gè)對(duì)象都有一個(gè)內(nèi)置的鎖,鎖表現(xiàn)出作用的唯一情況是:對(duì)象具有同步方法代碼。當(dāng)使用一個(gè)實(shí)例調(diào)用非靜態(tài)同步方法時(shí),就會(huì)索取該實(shí)例的鎖 對(duì)一個(gè)實(shí)例,某一時(shí)刻只能有一個(gè)線程鎖定它;拿到鎖的線程可以訪問(wèn)該實(shí)例的任意同步方法/塊,其他線程可以任意訪問(wèn)非同步方法 為了減少同步對(duì)并發(fā)的影響,可以只將方法的一部分代碼放入同步塊中實(shí)現(xiàn)同步——同步塊應(yīng)當(dāng)指定這部分代碼執(zhí)行時(shí)要鎖定的對(duì)象是誰(shuí):當(dāng)指定this時(shí)可以寫(xiě)成一個(gè)普通的同步方法的形式;對(duì)于靜態(tài)方法,在外圍聲明為synchronized或在block中使用LockTargetClass.class的形式指示鎖定對(duì)象,因?yàn)殪o態(tài)成員只有一份拷貝,要將整個(gè)類(lèi)所有靜態(tài)成員聲明為同步 當(dāng)對(duì)象的鎖被取走之后,其他試圖訪問(wèn)同步方法的線程被阻塞在鎖上(進(jìn)入阻塞狀態(tài))。他們?cè)谀硞€(gè)特定的池等待對(duì)象的鎖被釋放,返回可運(yùn)行狀態(tài) 關(guān)于線程在同步上的互相阻塞: 引用同一實(shí)例訪問(wèn)非靜態(tài)同步方法的線程彼此阻塞 訪問(wèn)同一類(lèi)中靜態(tài)方法的線程彼此阻塞——他們都在索取同一個(gè)Class實(shí)例的鎖 訪問(wèn)同一類(lèi)靜態(tài)與非靜態(tài)同步方法的兩個(gè)線程不會(huì)彼此阻塞——一個(gè)在鎖定this,一個(gè)在鎖定class 同步不同對(duì)象的兩個(gè)方法不會(huì)彼此阻塞 保持鎖的方法:join(),sleep(),yield(),notify() 放棄鎖的方法:wait() Access to static fields should be done from static synchronized methods. Access to non-static fields should be done from non-static synchronized methods 線程安全類(lèi):不要把同步放在較高的級(jí)別上 兩個(gè)線程互相等待對(duì)方拿到的鎖——死鎖 Wait()、notify()等方法是Object類(lèi)的方法,它們只能放入同步塊,這就保證了在獲得同步對(duì)象的鎖之前,不能在對(duì)象上調(diào)用這些方法 每一個(gè)對(duì)象都可以有一個(gè)表,放置等待它信號(hào)的線程;一旦線程調(diào)用該對(duì)象的wait(),他們就進(jìn)入這個(gè)列表之中,在目標(biāo)對(duì)象調(diào)用notify()之前,這些線程什么都不做——也就是說(shuō),看到wait()但找不到notify(),則wait()之后的東西永遠(yuǎn)不會(huì)發(fā)生(假如可以正確編譯的話)在wait時(shí),線將程釋放鎖 a waiting thread will not return to runnable when the lock is released, unless a notification occurs 考慮:有時(shí)notify()可能會(huì)先于wait()而發(fā)生調(diào)用。這樣notify()不會(huì)再發(fā)生,而后開(kāi)始的wait()等不到結(jié)果。所以在等待之前,應(yīng)當(dāng)檢查notify()是否已經(jīng)發(fā)生。 阻止線程運(yùn)行總結(jié): 睡眠:睡眠指定的時(shí)間,醒來(lái)時(shí)是可運(yùn)行狀態(tài),也即不保證醒來(lái)就是運(yùn)行狀態(tài);sleep()是一個(gè)靜態(tài)方法,因此在不能有一種做法可以讓一個(gè)線程使另一個(gè)線程睡眠——當(dāng)前運(yùn)行線程的代碼看到sleep()時(shí),即刻睡去 等待: 因?yàn)樾枰粋€(gè)對(duì)象的鎖定而被阻塞