創(chuàng)建線程
建議不要通過構(gòu)建Thread子類對(duì)象捐凭,并調(diào)用start方法洒嗤。應(yīng)該從運(yùn)行機(jī)制上減少需要并行運(yùn)行的任務(wù)數(shù)量改艇。如果有很多任務(wù)秀又,要為每個(gè)任務(wù)創(chuàng)建一個(gè)獨(dú)立的線程付出的代價(jià)太大媒惕,可以使用線程池來解決這個(gè)問題帝簇。(參考14.9)
java.lang.Thread
- Thread(Runnable target) 構(gòu)造一個(gè)新線程用于調(diào)用給定target的run方法徘郭。
- void start() 啟動(dòng)此線程靠益,將引發(fā)調(diào)用run()方法,這個(gè)方法會(huì)立即返回残揉,并且新線程將并行運(yùn)行胧后。
- void run() 調(diào)用關(guān)聯(lián)Runnable的run方法。
java.lang.Runnable
- void run() 必須覆蓋這個(gè)方法抱环,并在這個(gè)方法中提供所需要執(zhí)行的任務(wù)指令壳快。
中斷線程
早期java使用stop()方法可以強(qiáng)制線程中止,現(xiàn)在已經(jīng)被棄用镇草;
interrupt() 方法可以用來請(qǐng)求中止線程眶痰。但是如果線程被阻塞,就無法檢測(cè)中斷狀態(tài)陶夜。這是產(chǎn)生InterruptedException異常的地方凛驮,當(dāng)在一個(gè)被阻塞的線程(調(diào)用sleep或wait)上調(diào)用interrupt方法時(shí),阻塞調(diào)用將會(huì)被InterruptedException異常中斷条辟,這里指會(huì)進(jìn)入catch代碼塊執(zhí)行
(存在不能被中斷的阻塞I/O調(diào)用黔夭,應(yīng)該考慮選擇可中斷的調(diào)用。細(xì)節(jié)參考卷二 第一章和第三章)
java.lang.Thread
- void interrupt() 向線程發(fā)送中斷請(qǐng)求羽嫡,線程的
中斷狀態(tài)
將被設(shè)置為true.
如果目前線程被一個(gè)sleep調(diào)用阻塞本姥,那么InterruptedException異常被拋出,此外中斷狀態(tài)將被清除
- static boolean interrupted() 測(cè)試正在執(zhí)行這一方法的線程是否被中斷杭棵,注意這是一個(gè)靜態(tài)方法婚惫,調(diào)用會(huì)產(chǎn)生副作用,它將當(dāng)前線程的
中斷狀態(tài)
重置為false.(線程的中斷狀態(tài)被清除
)- boolean isInterrupted() 測(cè)試線程是否終止魂爪,不像靜態(tài)的中斷方法先舷,這一調(diào)用不改變線程的中斷狀態(tài)。
- static Thread currentThread() 返回代表當(dāng)前執(zhí)行線程的Thread對(duì)象滓侍。
- static void sleep(long millis) 休眠給定的毫秒數(shù)
void interrupt() 中斷此線程蒋川。(谷歌翻譯)
線程用一個(gè)變量來標(biāo)志中斷狀態(tài),private volatile Interruptible blocker;
除非當(dāng)前線程正在中斷自身(始終允許)撩笆,否則將調(diào)用此線程的checkAccess方法捺球,這可能導(dǎo)致拋出SecurityException。
如果在調(diào)用Object類的wait()夕冲,wait(long)或wait(long氮兵,int)方法或者join(),join(long)歹鱼,join(long泣栈,int)的方法中阻塞了這個(gè)線程,sleep(long)或sleep(long,int)南片,這個(gè)類的方法篙悯,然后它的中斷狀態(tài)將被清除,它將收到InterruptedException铃绒。
如果此線程在可中斷通道上的I / O操作中被阻塞,則通道將被關(guān)閉螺捐,線程的中斷狀態(tài)將被設(shè)置颠悬,并且線程將收到ClosedByInterruptException。
如果此線程在Selector中被阻塞定血,則線程的中斷狀態(tài)將被設(shè)置赔癌,并且它將立即從選擇操作返回,可能具有非零值澜沟,就像調(diào)用選擇器的喚醒方法一樣灾票。
如果以前的條件都不成立,則將設(shè)置該線程的中斷狀態(tài)茫虽。
中斷不活動(dòng)的線程不會(huì)產(chǎn)生任何影響刊苍。
public class TestRun implements Runnable {
private boolean flag = true;
@Override
public void run() {
try {
while (!Thread.currentThread().isInterrupted() && flag) {
// do more work
Thread.currentThread().sleep(1000);
}
}
catch (InterruptedException e) {
// thread was interrupted during sleep or wait
}
finally {
//cleanup,if required
}
//exiting the run method terminates the thread
}
void mySubTask() {
try {
Thread.currentThread().sleep(1000);
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
void mySubTask2() throws InterruptedException {
Thread.currentThread().sleep(1000);
}
}
線程狀態(tài)
- 新建 New
new Thread(r)/new MyThread() - 可運(yùn)行 Runnable
thread.start()
(搶占式調(diào)度系統(tǒng)
;協(xié)作式調(diào)度系統(tǒng)中,一個(gè)線程只有在調(diào)用yield方法或者被阻塞或等待時(shí),線程才會(huì)失去控制權(quán)
)
任何時(shí)刻濒析,一個(gè)可運(yùn)行的線程可能正在運(yùn)行正什,也可能沒有運(yùn)行
- 被阻塞 Blocked
一個(gè)線程試圖獲取一個(gè)內(nèi)部對(duì)象鎖,而該鎖被其它對(duì)象持有号杏,則線程進(jìn)入阻塞狀態(tài)婴氮。
- 等待 Waiting/ 計(jì)時(shí)等待 Timed waiting
Thread.sleep
Object.wait
Thread.join
Lock.tryLock
Condition.await
- 被中止 Terminated
因?yàn)閞un方法正常退出而自然死亡
因?yàn)橐粋€(gè)沒有捕獲的異常中止了run方法而意外死亡
stop方法已過時(shí),不要在代碼中使用
- 相關(guān)的API
java.lang.Thread
6.1
void join():等待中止指定的線程即等待指定的線程終止后再繼續(xù)當(dāng)前線程
6.2void join(long millis):等待指定的線程死亡盾致,或者經(jīng)過指定的毫秒數(shù)
6.3Thread.State getState():獲取線程的狀態(tài)
6.4void stop():停止線程主经,已過時(shí)
6.5void suspend:暫停線程執(zhí)行,已過時(shí)
6.6void resume:調(diào)用suspend之后調(diào)用庭惜,已過時(shí)
線程屬性
- 優(yōu)先級(jí)
高優(yōu)先級(jí)只代表線程優(yōu)先獲取時(shí)間片的可能性比較大罩驻,不是必然
- API
java.lang.Thread
2.1
void setPriority(int newPriority):設(shè)置優(yōu)先級(jí),必須在Thread.MIN_PRIORITY與Thread.MAX_PRIORITY之間蜈块,一般使用Thread.NORM_PRIORITY優(yōu)先級(jí)鉴腻。
2.2static int MIN_PRIORITY:線程最小優(yōu)先級(jí)1.
2.3static int MAX_PRIORITY:線程最大優(yōu)先級(jí)10.
2.4static int NORM_PRIORITY:線程默認(rèn)優(yōu)先級(jí)5.
2.5static void yield():導(dǎo)致當(dāng)前執(zhí)行線程處于讓步狀態(tài),如果有其他可運(yùn)行的線程具有至少與此線程同樣高的優(yōu)先級(jí)百揭,那么這些線程接下來會(huì)被調(diào)度爽哎。注意,這是一個(gè)靜態(tài)方法器一。
3.守護(hù)線程/API
3.守護(hù)線程優(yōu)先級(jí)很低课锌,當(dāng)同一應(yīng)用程序中沒有其他線程在運(yùn)行的時(shí)候,守護(hù)線程才運(yùn)行。當(dāng)守護(hù)線程是程序中唯一運(yùn)行的線程時(shí)渺贤,守護(hù)線程執(zhí)行結(jié)束后雏胃,JVM也就結(jié)束了這個(gè)程序。
3.2守護(hù)線程的作用:通常作為同一程序中普通線程的服務(wù)提供者志鞍,它們通常是無限循環(huán)的瞭亮,以等待服務(wù)請(qǐng)求或者執(zhí)行線程的任務(wù)。此外我們不太可能知道守護(hù)線程什么時(shí)候能夠獲取CPU時(shí)鐘固棚,并且沒有其它線程運(yùn)行的時(shí)候统翩,守護(hù)線程隨時(shí)可能結(jié)束。一個(gè)典型的守護(hù)線程是Java的垃圾回收器此洲。
java.lang.Thread
3.3
void setDaemon(boolean isDaemon):標(biāo)識(shí)該線程為守護(hù)線程或用戶線程厂汗。這一方法必須在線程啟動(dòng)之前調(diào)用
4未捕獲異常處理器
4.1未捕獲異常處理器介紹
線程的run方法不能拋出任何被檢測(cè)的異常,但是呜师,不被檢測(cè)的異常會(huì)導(dǎo)致線程終止娶桦。在這種情況下,線程就死亡了汁汗。就作線程死亡之前衷畦,異
常被傳遞到一個(gè)用于未捕獲異常的處理器。
該處理器必須屬于一個(gè)實(shí)現(xiàn)Thread.UncaughtExceptionHandler
接口的類碰酝。
這個(gè)接口只有一個(gè)方法霎匈。
void uncauqhtException(Thread t, Throwable e)
可以用 setUncaughtExceptionHandler
方法為任何線程安裝一個(gè)處理器。也可以用 Thread類的靜態(tài)方法setDefaultUncaughtExceptionHandlcr
為所有線程安裝一個(gè)默認(rèn)的處理器送爸。如果不安裝默認(rèn)的處理器铛嘱,默認(rèn)的處理器為空。但是袭厂,如果沒有設(shè)置UncaughtExceptionHandler
墨吓,那么默認(rèn)將會(huì)把異常棧信息輸出到System.err
,此時(shí)的處理器就足該線程的ThreadGroup對(duì)象
纹磺。
線程組是一個(gè)可以統(tǒng)一管理的線程集合帖烘。默認(rèn)情況下,創(chuàng)建的所有線程屬于相同的線程組橄杨,但是秘症,也可能會(huì)建立其他的組。現(xiàn)在引入了更好的特性用于線程集合的操作式矫,所以建議不要在自己的程序中使用線程組乡摹。
ThreadGroup 類實(shí)現(xiàn) Thread.UncaughtException 接口
。它的uncaughtException方法如下:
/**
* Called by the Java Virtual Machine when a thread in this
* thread group stops because of an uncaught exception, and the thread
* does not have a specific {@link Thread.UncaughtExceptionHandler}
* installed.
* <p>
* The <code>uncaughtException</code> method of
* <code>ThreadGroup</code> does the following:
* <ul>
* <li>If this thread group has a parent thread group, the
* <code>uncaughtException</code> method of that parent is called
* with the same two arguments.
* <li>Otherwise, this method checks to see if there is a
* {@linkplain Thread#getDefaultUncaughtExceptionHandler default
* uncaught exception handler} installed, and if so, its
* <code>uncaughtException</code> method is called with the same
* two arguments.
* <li>Otherwise, this method determines if the <code>Throwable</code>
* argument is an instance of {@link ThreadDeath}. If so, nothing
* special is done. Otherwise, a message containing the
* thread's name, as returned from the thread's {@link
* Thread#getName getName} method, and a stack backtrace,
* using the <code>Throwable</code>'s {@link
* Throwable#printStackTrace printStackTrace} method, is
* printed to the {@linkplain System#err standard error stream}.
* </ul>
* <p>
* Applications can override this method in subclasses of
* <code>ThreadGroup</code> to provide alternative handling of
* uncaught exceptions.
*
* @param t the thread that is about to exit.
* @param e the uncaught exception.
* @since JDK1.0
*/
public void uncaughtException(Thread t, Throwable e) {
if (parent != null) {
parent.uncaughtException(t, e);
} else {
Thread.UncaughtExceptionHandler ueh =
Thread.getDefaultUncaughtExceptionHandler();
if (ueh != null) {
ueh.uncaughtException(t, e);
} else if (!(e instanceof ThreadDeath)) {
System.err.print("Exception in thread \""
+ t.getName() + "\" ");
e.printStackTrace(System.err);
}
}
}
4.2相關(guān)API
java.lang.Thread
4.2.1 public static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler)
4.2.2 public static Thread.UncaughtExceptionHandler getDefaultUncaughtExceptionHandler()
4.3.3 public void setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
4.4.4 public Thread.UncaughtExceptionHandler getUncaughtExceptionHandler()
java.lang.Thread.UncaughtExceptionHandler
4.2.5 void uncaughtException(Thread t,Throwable e)當(dāng)給定線程因給定的未捕獲異常而終止時(shí)采转,調(diào)用該方法聪廉。 Java 虛擬機(jī)將忽略該方法拋出的任何異常瞬痘。
java.lang.ThreadGroup
4.2.6 public void uncaughtException(Thread t,Throwable e)當(dāng)此線程組中的線程因?yàn)橐粋€(gè)未捕獲的異常而停止,并且線程沒有安裝特定 Thread.UncaughtExceptionHandler 時(shí)板熊,由 Java Virtual Machine 調(diào)用此方法框全。
ThreadGroup 的 uncaughtException 方法執(zhí)行以下操作:
1.如果此線程組有一個(gè)父線程組,那么調(diào)用此父線程組的 uncaughtException 方法時(shí)帶有兩個(gè)相同的參數(shù)干签。
2.否則津辩,此方法將查看是否安裝了默認(rèn)的未捕獲異常處理程序,如果是容劳,則在調(diào)用其 uncaughtException 方法時(shí)帶有兩個(gè)相同的參數(shù)丹泉。
3.否則,此方法將確認(rèn) Throwable 參數(shù)是否為一個(gè) ThreadDeath 實(shí)例鸭蛙。如果是,則不會(huì)做任何特殊的操作筋岛。否則娶视,在從線程的 getName 方法返回時(shí),會(huì)使用 Throwable 的 printStackTrace 方法睁宰,將包含線程名稱的消息和堆棧跟蹤信息輸出到標(biāo)準(zhǔn)錯(cuò)誤流肪获。
應(yīng)用程序可以重寫 ThreadGroup 的子類中的方法,以提供處理未捕獲異常的替代辦法柒傻。