線程是一個(gè)程序的多個(gè)執(zhí)行路徑辑甜,執(zhí)行調(diào)度的單位懈涛,依托于進(jìn)程存在。 線程不僅可以共享進(jìn)程的內(nèi)存,而且還擁有一個(gè)屬于自己的內(nèi)存空間檩赢,這段內(nèi)存空間也叫做線程棧搬卒,是在建立線程時(shí)由系統(tǒng)分配的瑟俭,主要用來保存線程內(nèi)部所使用的數(shù)據(jù),如線程執(zhí)行函數(shù)中所定義的變量契邀。
注意:Java中的多線程是一種搶占機(jī)制而不是分時(shí)機(jī)制摆寄。搶占機(jī)制指的是有多個(gè)線程處于可運(yùn)行狀態(tài),但是只允許一個(gè)線程在運(yùn)行,他們通過競(jìng)爭(zhēng)的方式搶占CPU微饥。
定義一個(gè)線程(Defining a Thread)有兩種方法
/**
* 使用繼承java.lang.Thread類的方式創(chuàng)建一個(gè)線程
*
*@authorDreamSea 2011-12-29 20:17:06
*/
publicclassThreadTestextendsThread {
/**
* 重寫(Override)run()方法 JVM會(huì)自動(dòng)調(diào)用該方法
*/
publicvoidrun() {
System.out.println("I'm running!");
}
}
注意:重寫(override)run()方法在該線程的start()方法被調(diào)用后逗扒,JVM會(huì)自動(dòng)調(diào)用run方法來執(zhí)行任務(wù);但是重載(overload)run()方法欠橘,該方法和普通的成員方法一樣矩肩,并不會(huì)因調(diào)用該線程的start()方法而被JVM自動(dòng)運(yùn)行。 例如:
publicclassThreadTestextendsThread {
/**
* 重寫(Override)run()方法 JVM會(huì)自動(dòng)調(diào)用該方法
*/
@Override
publicvoidrun() {
System.out.println("I'm running!");
}
/**
* 重載(Overload)run()方法 和普通的方法一樣肃续,并不會(huì)在該線程的start()方法被調(diào)用后被JVM自動(dòng)運(yùn)行
*/
publicvoidrun(inttimes) {
System.out.println("I'm running!(Overload)");
}
}
不建議使用此方法定義線程黍檩,因?yàn)椴捎美^承Thread的方式定義線程后,你不能在繼承其他的類了始锚,導(dǎo)致程序的可擴(kuò)展性大大降低刽酱。
2) 實(shí)現(xiàn)java.lang.Runnable接口
/**
* 通過實(shí)現(xiàn)Runnable接口創(chuàng)建一個(gè)線程
*@authorDreamSea
*/
publicclassThreadTestimplementsRunnable {
publicvoidrun() {
System.out.println("I'm running!");
}
}
任何一個(gè)線程的執(zhí)行的前提都是必須有Thread class的實(shí)例存在,并且通過調(diào)用run()方法啟動(dòng)線程瞧捌。
1)如果線程是繼承Thread類棵里,則創(chuàng)建方式如下:
ThreadTest1 tt =newThreadTest1();
tt.start();
2)如果是實(shí)現(xiàn)Runnable接口,則創(chuàng)建方式如下:
ThreadTest2 tt =newThreadTest2();
Thread t =newThread(tt);
t.start();
線程狀態(tài)圖
每個(gè)類都有自己的優(yōu)先級(jí),一般property用1-10的整數(shù)表示驮樊,默認(rèn)優(yōu)先級(jí)是5,優(yōu)先級(jí)最高是10片酝;優(yōu)先級(jí)高的線程并不一定比優(yōu)先級(jí)低的線程執(zhí)行的機(jī)會(huì)高囚衔,只是執(zhí)行的機(jī)率高;默認(rèn)一個(gè)線程的優(yōu)先級(jí)和創(chuàng)建他的線程優(yōu)先級(jí)相同雕沿;
2)Thread.sleep()/sleep(long millis)
當(dāng)前線程睡眠/millis的時(shí)間(millis指定睡眠時(shí)間是其最小的不執(zhí)行時(shí)間练湿,因?yàn)閟leep(millis)休眠到達(dá)后,無法保證會(huì)被JVM立即調(diào)度)审轮;sleep()是一個(gè)靜態(tài)方法(static method) 肥哎,所以他不會(huì)停止其他的線程也處于休眠狀態(tài);線程sleep()時(shí)不會(huì)失去擁有的對(duì)象鎖疾渣。 作用:保持對(duì)象鎖篡诽,讓出CPU,調(diào)用目的是不讓當(dāng)前線程獨(dú)自霸占該進(jìn)程所獲取的CPU資源榴捡,以留一定的時(shí)間給其他線程執(zhí)行的機(jī)會(huì)杈女;
讓出CPU的使用權(quán),給其他線程執(zhí)行機(jī)會(huì)吊圾、讓同等優(yōu)先權(quán)的線程運(yùn)行(但并不保證當(dāng)前線程會(huì)被JVM再次調(diào)度达椰、使該線程重新進(jìn)入Running狀態(tài)),如果沒有同等優(yōu)先權(quán)的線程项乒,那么yield()方法將不會(huì)起作用啰劲。
使用該方法的線程會(huì)在此之間執(zhí)行完畢后再往下繼續(xù)執(zhí)行。
當(dāng)一個(gè)線程執(zhí)行到wait()方法時(shí)檀何,他就進(jìn)入到一個(gè)和該對(duì)象相關(guān)的等待池(Waiting Pool)中蝇裤,同時(shí)失去了對(duì)象的機(jī)鎖—暫時(shí)的廷支,wait后還要返還對(duì)象鎖。當(dāng)前線程必須擁有當(dāng)前對(duì)象的鎖猖辫,如果當(dāng)前線程不是此鎖的擁有者酥泞,會(huì)拋出IllegalMonitorStateException異常,所以wait()必須在synchronized block中調(diào)用。
喚醒在當(dāng)前對(duì)象等待池中等待的第一個(gè)線程/所有線程啃憎。notify()/notifyAll()也必須擁有相同對(duì)象鎖芝囤,否則也會(huì)拋出IllegalMonitorStateException異常。
Synchronized Block/方法控制對(duì)類成員變量的訪問辛萍;Java中的每一個(gè)對(duì)象都有唯一的一個(gè)內(nèi)置的鎖悯姊,每個(gè)Synchronized Block/方法只有持有調(diào)用該方法被鎖定對(duì)象的鎖才可以訪問,否則所屬線程阻塞贩毕;機(jī)鎖具有獨(dú)占性悯许、一旦被一個(gè)Thread持有,其他的Thread就不能再擁有(不能訪問其他同步方法)辉阶,方法一旦執(zhí)行先壕,就獨(dú)占該鎖,直到從該方法返回時(shí)才將鎖釋放谆甜,此后被阻塞的線程方能獲得該鎖垃僚,重新進(jìn)入可執(zhí)行狀態(tài)。