




版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、線程或者說(shuō)多線程,是我們處理多任務(wù)的強(qiáng)大工具。線程和進(jìn)程是不同的,每個(gè)進(jìn)程都是一個(gè)獨(dú)立運(yùn)行的程序,擁有自己的變量,且不同進(jìn)程間的變量不能共享;而線程是運(yùn)行在進(jìn)程內(nèi)部的,每個(gè)正在運(yùn)行的進(jìn)程至少有一個(gè)線程,而且不同的線程之間可以在進(jìn)程范圍內(nèi)共享數(shù)據(jù)。也就是說(shuō)進(jìn)程有自己獨(dú)立的存儲(chǔ)空間,而線程是和它所屬的進(jìn)程內(nèi)的其他線程共享一個(gè)存儲(chǔ)空間。線程的使用可以使我們能夠并行地處理一些事情。線程通過(guò)并行的處理給用戶帶來(lái)更好的使用體驗(yàn),比如你使用的郵件系統(tǒng)(outlook、Thunderbird、foxmail等),你當(dāng)然不希望它們?cè)谑杖⌒锣]件的時(shí)候,導(dǎo)致你連已經(jīng)收下來(lái)的郵件都無(wú)法閱讀,而只能等待收取郵件操作執(zhí)行
2、完畢。這正是線程的意義所在。實(shí)現(xiàn)線程的方式實(shí)現(xiàn)線程的方式有兩種:1,繼承java.lang.Thread,并重寫它的run()方法,將線程的執(zhí)行主體放入其中。2.實(shí)現(xiàn)java.lang.Runnable接口,實(shí)現(xiàn)它的run()方法,并將線程的執(zhí)行主體放入其中。這是繼承Thread類實(shí)現(xiàn)線程的示例:javaviewplaincopyprint?1.publicclassThreadTestextendsThreadpublicvoidrun()/這里編寫線程執(zhí)行的主體dosomething這是實(shí)現(xiàn)Runnable接口實(shí)現(xiàn)多線程的示例:javaviewplaincopyprint?1.public
3、classRunnableTestimplementsRunnablepublicvoidrun()/在這里編寫線程執(zhí)行的主體dosomething這兩種實(shí)現(xiàn)方式的區(qū)別并不大。繼承Thread類的方式實(shí)現(xiàn)起來(lái)較為簡(jiǎn)單,但是繼承它的類就不能再繼承別的類了,因此也就不能繼承別的類的有用的方法了。而使用是想Runnable接口的方式就不存在這個(gè)問(wèn)題了,而且這種實(shí)現(xiàn)方式將線程主體和線程對(duì)象本身分離開來(lái),邏輯上也較為清晰,所以推薦大家更多地采用這種方式。如何啟動(dòng)線程我們通過(guò)以上兩種方式實(shí)現(xiàn)了一個(gè)線程之后,線程的實(shí)例并沒(méi)有被創(chuàng)建,因此它們也并沒(méi)有被運(yùn)行。我們要啟動(dòng)一個(gè)線程,必須調(diào)用方法來(lái)啟動(dòng)它,這個(gè)方法就
4、是Thread類的start()方法,而不是run()方法(既不是我們繼承Thread類重寫的run()方法,也不是實(shí)現(xiàn)Runnable接口的run()方法)。run()方法中包含的是線程的主體,也就是這個(gè)線程被啟動(dòng)后將要運(yùn)行的代碼,它跟線程的啟動(dòng)沒(méi)有任何關(guān)系。上面兩種實(shí)現(xiàn)線程的方式在啟動(dòng)時(shí)會(huì)有所不同。繼承Thread類的啟動(dòng)方式:javaviewplaincopyprint?1.publicclassThreadStartTestpublicstaticvoidmain(String口args)創(chuàng)建一個(gè)線程實(shí)例ThreadTesttt=newThreadTest();啟動(dòng)線程tt.start
5、();實(shí)現(xiàn)Runnable接口的啟動(dòng)方式:javaviewplaincopyprint?1.publicclassRunnableStartTestpublicstaticvoidmain(Stringargs)/創(chuàng)建一個(gè)線程實(shí)例Threadt=newThread(newRunnableTest();/啟動(dòng)線程t.start();實(shí)際上這兩種啟動(dòng)線程的方式原理是一樣的。首先都是調(diào)用本地方法啟動(dòng)一個(gè)線程,其次是在這個(gè)線程里執(zhí)行目標(biāo)對(duì)象的run()方法。那么這個(gè)目標(biāo)對(duì)象是什么呢?為了弄明白這個(gè)問(wèn)題,我們來(lái)看看Thread類的run()方法的實(shí)現(xiàn):javaviewplaincopyprint?1.p
6、ublicvoidrun()if(target!=null)target.run();當(dāng)我們采用實(shí)現(xiàn)Runnable接口的方式來(lái)實(shí)現(xiàn)線程的情況下,在調(diào)用newThread(Runnabletarget)構(gòu)造器時(shí),將實(shí)現(xiàn)Runnable接口的類的實(shí)例設(shè)置成了線程要執(zhí)行的主體所屬的目標(biāo)對(duì)象target,當(dāng)線程啟動(dòng)時(shí),這個(gè)實(shí)例的run()方法就被執(zhí)行了。當(dāng)我們采用繼承Thread的方式實(shí)現(xiàn)線程時(shí),線程的這個(gè)run()方法被重寫了,所以當(dāng)線程啟動(dòng)時(shí),執(zhí)行的是這個(gè)對(duì)象自身的run()方法??偨Y(jié)起來(lái)就一句話,線程類有一個(gè)Runnable類型的target屬性,它是線程啟動(dòng)后要執(zhí)行的run()方法所屬的主體
7、,如果我們采用的是繼承Thread類的方式,那么這個(gè)target就是線程對(duì)象自身,如果我們采用的是實(shí)現(xiàn)Runnable接口的方式,那么這個(gè)target就是實(shí)現(xiàn)了Runnable接口的類的實(shí)例線程的狀態(tài)在Java1.4及以下的版本中,每個(gè)線程都具有新建、可運(yùn)行、阻塞、死亡四種狀態(tài),但是在Java5.0及以上版本中,線程的狀態(tài)被擴(kuò)充為新建、可運(yùn)行、阻塞、等待、定時(shí)等待、死亡六種。線程的狀態(tài)完全包含了一個(gè)線程從新建到運(yùn)行,最后到結(jié)束的整個(gè)生命周期。線程狀態(tài)的具體信息如下:1. NEW(新建狀態(tài)、初始化狀態(tài)):線程對(duì)象已經(jīng)被創(chuàng)建,但是還沒(méi)有被啟動(dòng)時(shí)的狀態(tài)。這段時(shí)間就是在我們調(diào)用new命令之后,調(diào)用st
8、art()方法之前。2. RUNNABLE(可運(yùn)行狀態(tài)、就緒狀態(tài)):在我們調(diào)用了線程的start()方法之后線程所處的狀態(tài)。處于RUNNABLE狀態(tài)的線程在JAVA虛擬機(jī)(JVM)上是運(yùn)行著的,但是它可能還正在等待操作系統(tǒng)分配給它相應(yīng)的運(yùn)行資源以得以運(yùn)行。3. BLOCKED(阻塞狀態(tài)、被中斷運(yùn)行):線程正在等待其它的線程釋放同步鎖,以進(jìn)入一個(gè)同步塊或者同步方法繼續(xù)運(yùn)行;或者它已經(jīng)進(jìn)入了某個(gè)同步塊或同步方法,在運(yùn)行的過(guò)程中它調(diào)用了某個(gè)對(duì)象繼承自java.lang.Object的wait()方法,正在等待重新返回這個(gè)同步塊或同步方法。4. WAITING(等待狀態(tài)):當(dāng)前線程調(diào)用了java.la
9、ng.Object.wait()、java.lang.Thread.join()或者java.util.concurrent.locks.LockSupport.park()三個(gè)中的任意一個(gè)方法,正在等待另外一個(gè)線程執(zhí)行某個(gè)操作。比如一個(gè)線程調(diào)用了某個(gè)對(duì)象的wait()方法,正在等待其它線程調(diào)用這個(gè)對(duì)象的notify()或者notifyAll()(這兩個(gè)方法同樣是繼承自O(shè)bject類)方法來(lái)喚醒它;或者一個(gè)線程調(diào)用了另一個(gè)線程的join()(這個(gè)方法屬于Thread類)方法,正在等待這個(gè)方法運(yùn)行結(jié)束。5. TIMED_WAITING(定時(shí)等待狀態(tài)):當(dāng)前線程調(diào)用了java.lang.Objec
10、t.wait(longtimeout)、java.lang.Thread.join(longmillis)、java.util.concurrent.locks.LockSupport.packNanos(longnanos)、java.util.concurrent.locks.LockSupport.packUntil(longdeadline)四個(gè)方法中的任意個(gè),進(jìn)入等待狀態(tài),但是與WAITING狀態(tài)不同的是,它有一個(gè)最大等待時(shí)間,即使等待的條件仍然沒(méi)有滿足,只要到了這個(gè)時(shí)間它就會(huì)自動(dòng)醒來(lái)。6. TERMINATED(死亡狀態(tài)、終止?fàn)顟B(tài)):線程完成執(zhí)行后的狀態(tài)。線程執(zhí)行完run()方法中
11、的全部代碼,從該方法中退出,進(jìn)入TERMINATED狀態(tài)。還有一種情況是run()在運(yùn)行過(guò)程中拋出了一個(gè)異常,而這個(gè)異常沒(méi)有被程序捕獲,導(dǎo)致這個(gè)線程異常終止進(jìn)入TERMINATED狀態(tài)。在Java5.0及以上版本中,線程的全部六種狀態(tài)都以枚舉類型的形式定義在java.lang.Thread類中了,代碼如下:javaviewplaincopyprint?1.publicenumStateNEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING,TERMINATED;sleep()和wait()的區(qū)別sleep()方法和wait()方法都成產(chǎn)生讓當(dāng)前運(yùn)行的線程停止運(yùn)行的
12、效果,這是它們的共同點(diǎn)。下面我們來(lái)詳細(xì)說(shuō)說(shuō)它們的不同之處。sleep()方法是本地方法,屬于Thread類,它有兩種定義:javaviewplaincopyprint?1.publicstaticnativevoidsleep(longmillis)throwsInterruptedException;publicstaticvoidsleep(longmillis,intnanos)throwsInterruptedException/othercode其中的參數(shù)millis代表毫秒數(shù)(千分之一秒),nanos代表納秒數(shù)(十億分之一秒)。這兩個(gè)方法都可以讓調(diào)用它的線程沉睡(停止運(yùn)行)指定的時(shí)
13、間,到了這個(gè)時(shí)間,線程就會(huì)自動(dòng)醒來(lái),變?yōu)榭蛇\(yùn)行狀態(tài)(RUNNABLE),但這并不表示它馬上就會(huì)被運(yùn)行,因?yàn)榫€程調(diào)度機(jī)制恢復(fù)線程的運(yùn)行也需要時(shí)間。調(diào)用sleep()方法并不會(huì)讓線程釋放它所持有的同步鎖;而且在這期間它也不會(huì)阻礙其它線程的運(yùn)行。上面的連個(gè)方法都聲明拋出一個(gè)InterruptedException類型的異常,這是因?yàn)榫€程在sleep()期間,有可能被持有它的引用的其它線程調(diào)用它的interrupt。方法而中斷。中斷一個(gè)線程會(huì)導(dǎo)致一個(gè)InterruptedException異常的產(chǎn)生,如果你的程序不捕獲這個(gè)異常,線程就會(huì)異常終止,進(jìn)入TERMINATED狀態(tài),如果你的程序捕獲了這個(gè)異常
14、,那么程序就會(huì)繼續(xù)執(zhí)行catch語(yǔ)句塊(可能還有finally語(yǔ)句塊)以及以后的代碼。為了更好地理解interrupt()效果,我們來(lái)看一下下面這個(gè)例子:javaviewplaincopyprint?1.publicclassInterruptTestpublicstaticvoidmain(Stringargs)Threadt=newThread()publicvoidrun()trySystem.out.println(我被執(zhí)行了-在sleep()方法前)停止運(yùn)行10分鐘Thread.sleep(1000*60*60*10);System.out.println(我被執(zhí)行了-在sleep(
15、)方法后);catch(InterruptedExceptione)System.out.println(我被執(zhí)行了-在catch語(yǔ)句塊中);System.out.println(我被執(zhí)行了-在try語(yǔ)句塊后);啟動(dòng)線程t.start();在sleep()結(jié)束前中斷它errupt();運(yùn)行結(jié)果:1 .我被執(zhí)行了-在sleep()方法前2 .我被執(zhí)行了-在catch語(yǔ)句塊中3 .我被執(zhí)行了-在try語(yǔ)句塊后wait()方法也是本地方法,屬于Object類,有三個(gè)定義:javaviewplaincopyprint?1. publicfinalvoidwait()throwsInterru
16、ptedException/dosomethingpublicfinalnativevoidwait(longtimeout)throwsInterruptedException;publicfinalvoidwait(longtimeout,intnanos)throwsInterruptedException/dosomethingwari()和wait(longtimeout,intnanos)方法者B是基于wait(longtimeout)方法實(shí)現(xiàn)的。同樣地,timeout代表毫秒數(shù),nanos代表納秒數(shù)。當(dāng)調(diào)用了某個(gè)對(duì)象的wait()方法時(shí),當(dāng)前運(yùn)行的線程就會(huì)轉(zhuǎn)入等待狀態(tài)(WAITI
17、NG),等待別的線程再次調(diào)用這個(gè)對(duì)象的notify()或者notifyAll()方法(這兩個(gè)方法也是本地方法)喚醒它,或者到了指定的最大等待時(shí)間,線程自動(dòng)醒來(lái)。如果線程擁有某個(gè)或某些對(duì)象的同步鎖,那么在調(diào)用了wait()后,這個(gè)線程就會(huì)釋放它持有的所有同步資源,而不限于這個(gè)被調(diào)用了wait()方法的對(duì)象。wait()方法同樣會(huì)被Thread類的interrupt()方法中斷,并產(chǎn)生一個(gè)InterruptedException異常,效果同sleep()方法被中斷一樣。實(shí)現(xiàn)同步的方式同步是多線程中的重要概念。同步的使用可以保證在多線程運(yùn)行的環(huán)境中,程序不會(huì)產(chǎn)生設(shè)計(jì)之外的錯(cuò)誤結(jié)果。同步的實(shí)現(xiàn)方式有兩
18、種,同步方法和同步塊,這兩種方式都要用到synchronized關(guān)鍵字。給一個(gè)方法增加synchronized修飾符之后就可以使它成為同步方法,這個(gè)方法可以是靜態(tài)方法和非靜態(tài)方法,但是不能是抽象類的抽象方法,也不能是接口中的接口方法。下面代碼是一個(gè)同步方法的示例:1.publicsynchronizedvoidaMethod()/dosomethingpublicstaticsynchronizedvoidanotherMethod()/dosomething線程在執(zhí)行同步方法時(shí)是具有排它性的。當(dāng)任意一個(gè)線程進(jìn)入到一個(gè)對(duì)象的任意一個(gè)同步方法時(shí),這個(gè)對(duì)象的所有同步方法都被鎖定了,在此期間,其他任
19、何線程都不能訪問(wèn)這個(gè)對(duì)象的任意一個(gè)同步方法,直到這個(gè)線程執(zhí)行完它所調(diào)用的同步方法并從中退出,從而導(dǎo)致它釋放了該對(duì)象的同步鎖之后。在一個(gè)對(duì)象被某個(gè)線程鎖定之后,其他線程是可以訪問(wèn)這個(gè)對(duì)象的所有非同步方法的。同步塊的形式雖然與同步方法不同,但是原理和效果是一致的。同步塊是通過(guò)鎖定一個(gè)指定的對(duì)象,來(lái)對(duì)同步塊中包含的代碼進(jìn)行同步;而同步方法是對(duì)這個(gè)方法塊里的代碼進(jìn)行同步,而這種情況下鎖定的對(duì)象就是同步方法所屬的主體對(duì)象自身。如果這個(gè)方法是靜態(tài)同步方法呢?那么線程鎖定的就不是這個(gè)類的對(duì)象了,也不是這個(gè)類自身,而是這個(gè)類對(duì)應(yīng)的java.lang.Class類型的對(duì)象。同步方法和同步塊之間的相互制約只限于同
20、一個(gè)對(duì)象之間,所以靜態(tài)同步方法只受它所屬類的其它靜態(tài)同步方法的制約,而跟這個(gè)類的實(shí)例(對(duì)象)沒(méi)有關(guān)系。下面這段代碼演示了同步塊的實(shí)現(xiàn)方式:javaviewplaincopyprint?1.publicvoidtest()/同步鎖Stringlock=LOCK;同步塊synchronized(lock)/dosomethinginti=0;/.對(duì)于作為同步鎖的對(duì)象并沒(méi)有什么特別要求,任意一個(gè)對(duì)象都可以。如果一個(gè)對(duì)象既有同步方法,又有同步塊,那么當(dāng)其中任意一個(gè)同步方法或者同步塊被某個(gè)線程執(zhí)行時(shí),這個(gè)對(duì)象就被鎖定了,其他線程無(wú)法在此時(shí)訪問(wèn)這個(gè)對(duì)象的同步方法,也不能執(zhí)行同步塊。synchronized
21、和LockLock是一個(gè)接口,它位于Java5.0新增的java.utils.concurrent包的子包locks中。concurrent包及其子包中的類都是用來(lái)處理多線程編程的。實(shí)現(xiàn)Lock接口的類具有與synchronized關(guān)鍵字同樣的功能,但是它更加強(qiáng)大一些。java.utils.concurrent.locks.ReentrantLock是較常用的實(shí)現(xiàn)了Lock接口的類。下面是ReentrantLock類的一個(gè)應(yīng)用.實(shí)例:javaviewplaincopyprint?1.privateLocklock=newReentrantLock();publicvoidtestLock()/
22、鎖定對(duì)象lock.lock();try/dosomethingfinally/釋放對(duì)對(duì)象的鎖定lock.unlock();lock()方法用于鎖定對(duì)象,unlock()方法用于釋放對(duì)對(duì)象的鎖定,他們都是在Lock接口中定義的方法。位于這兩個(gè)方法之間的代碼在被執(zhí)行時(shí),效果等同于被放在synchronized同步塊中。一般用法是將需要在lock()和unlock()方法之間執(zhí)行的代碼放在try塊中,并且在finally。塊中調(diào)用unlock()方法,這樣就可以保證即使在執(zhí)行代碼拋出異常的情況下,對(duì)象的鎖也總是會(huì)被釋放,否則的話就會(huì)為死鎖的產(chǎn)生增加可能。使用synchronized關(guān)鍵字實(shí)現(xiàn)的同步,
23、會(huì)把一個(gè)對(duì)象的所有同步方法和同步塊看做一個(gè)整體,只要有一個(gè)被某個(gè)線程調(diào)用了,其他的就無(wú)法被別的線程執(zhí)行,即使這些方法或同步塊與被調(diào)用的代碼之間沒(méi)有任何邏輯關(guān)系,這顯然降低了程序的運(yùn)行效率。而使用Lock就能夠很好地解決這個(gè)問(wèn)題。我們可以把一個(gè)對(duì)象中按照邏輯關(guān)系把需要同步的方法或代碼進(jìn)行分組,為每個(gè)組創(chuàng)建一個(gè)Lock類型的對(duì)象,對(duì)實(shí)現(xiàn)同步。那么,當(dāng)一個(gè)同步塊被執(zhí)行時(shí),這個(gè)線程只會(huì)鎖定與當(dāng)前運(yùn)行代碼相關(guān)的其他代碼最小集合,而并不影響其他線程對(duì)其余同步代碼的調(diào)用執(zhí)行。關(guān)于死鎖死鎖就是一個(gè)進(jìn)程中的每個(gè)線程都在等待這個(gè)進(jìn)程中的其他線程釋放所占用的資源,從而導(dǎo)致所有線程都無(wú)法繼續(xù)執(zhí)行的情況。死鎖是多線程編
24、程中一個(gè)隱藏的陷阱,它經(jīng)常發(fā)生在多個(gè)線程共用資源的時(shí)候。在實(shí)際開發(fā)中,死鎖一般隱藏的較深,不容易被發(fā)現(xiàn),一旦死鎖現(xiàn)象發(fā)生,就必然會(huì)導(dǎo)致程序的癱瘓。因此必須避免它的發(fā)生。程序中必須同時(shí)滿足以下四個(gè)條件才會(huì)引發(fā)死鎖:1 .互斥(Mutualexclusion):線程所使用的資源中至少有一個(gè)是不能共享的,它在同一時(shí)刻只能由一個(gè)線程使用。2 .持有與等待(Holdandwait):至少有一個(gè)線程已經(jīng)持有了資源,并且正在等待獲取其他的線程所持有的資源。3 .非搶占式(Nopre-emption):如果一個(gè)線程已經(jīng)持有了某個(gè)資源,那么在這個(gè)線程釋放這個(gè)資源之前,別的線程不能把它搶奪過(guò)去使用。4 .循環(huán)等待
25、(Circularwait):假設(shè)有N個(gè)線程在運(yùn)行,第一個(gè)線程持有了一個(gè)資源,并且正在等待獲取第二個(gè)線程持有的資源,而第二個(gè)線程正在等待獲取第三個(gè)線程持有的資源,依此類推第N個(gè)線程正在等待獲取第一個(gè)線程持有的資源,由此形成一個(gè)循環(huán)等待。線程池線程池就像數(shù)據(jù)庫(kù)連接池一樣,是一個(gè)對(duì)象池。所有的對(duì)象池都有一個(gè)共同的目的,那就是為了提高對(duì)象的使用率,從而達(dá)到提高程序效率的目的。比如對(duì)于Servlet,它被設(shè)計(jì)為多線程的(如果它是單線程的,你就可以想象,當(dāng)1000個(gè)人同時(shí)請(qǐng)求一個(gè)網(wǎng)頁(yè)時(shí),在第一個(gè)人獲得請(qǐng)求結(jié)果之前,其它999個(gè)人都在郁悶地等待),如果為每個(gè)用戶的每一次請(qǐng)求都創(chuàng)建一個(gè)新的線程對(duì)象來(lái)運(yùn)行的話
26、,系統(tǒng)就會(huì)在創(chuàng)建線程和銷毀線程上耗費(fèi)很大的開銷,大大降低系統(tǒng)的效率。因此,Servlet多線程機(jī)制背后有一個(gè)線程池在支持,線程池在初始化初期就創(chuàng)建了一定數(shù)量的線程對(duì)象,通過(guò)提高對(duì)這些對(duì)象的利用率,避免高頻率地創(chuàng)建對(duì)象,從而達(dá)到提高程序的效率的目的。下面實(shí)現(xiàn)一個(gè)最簡(jiǎn)單的線程池,從中理解它的實(shí)現(xiàn)原理。為此我們定義了四個(gè)類,它們的用途及具體實(shí)現(xiàn)如下:1. Task(任務(wù)):這是個(gè)代表任務(wù)的抽象類,其中定義了一個(gè)deal()方法,繼承Task抽象類的子類需要實(shí)現(xiàn)這個(gè)方法,并把這個(gè)任務(wù)需要完成的具體工作在deal()方法編碼實(shí)現(xiàn)。線程池中的線程之所以被創(chuàng)建,就是為了執(zhí)行各種各樣數(shù)量繁多的任務(wù)的,為了方便
27、線程對(duì)任務(wù)的處理,我們需要用Task抽象類來(lái)保證任務(wù)的具體工作統(tǒng)一放在deal()方法里來(lái)完成,這樣也使代碼更加規(guī)范。Task的定義如下:javaviewplaincopyprint?1. publicabstractclassTaskpublicenumState/*新建*/NEW,/*執(zhí)行中7RUNNING,/*已完成*/FINISHED任務(wù)狀態(tài)privateStatestate=State.NEW;publicvoidsetState(Statestate)this.state=state;publicStategetState()returnstate;publicabstractvo
28、iddeal();2. TaskQueue(任務(wù)隊(duì)列):在同一時(shí)刻,可能有很多任務(wù)需要執(zhí)行,而程序在同一時(shí)刻只能執(zhí)行一定數(shù)量的任務(wù),當(dāng)需要執(zhí)行的任務(wù)數(shù)超過(guò)了程序所能承受的任務(wù)數(shù)時(shí)怎么辦呢?這就有了先執(zhí)行哪些任務(wù),后執(zhí)行哪些任務(wù)的規(guī)則。TaskQueue類就定義了這些規(guī)則中的一種,它采用的是FIFO(先進(jìn)先出,英文名是FirstInFirstOut)的方式,也就是按照任務(wù)到達(dá)的先后順序執(zhí)行。TaskQueue類的定義如下:javaviewplaincopyprint?1. importjava.util.Iterator;importjava.util.LinkedList;importjava
29、.util.List;publicclassTaskQueueprivateListqueue=newLinkedList();添加一項(xiàng)任務(wù)publicsynchronizedvoidaddTask(Tasktask)if(task!=null)queue.add(task);完成任務(wù)后將它從任務(wù)隊(duì)列中刪除publicsynchronizedvoidfinishTask(Tasktask)if(task!=null)task.setState(Task.State.FINISHED);queue.remove(task);/取得一項(xiàng)待執(zhí)行任務(wù)publicsynchronizedTaskgetT
30、ask()Iteratorit=queue.iterator();Tasktask;while(it.hasNext()task=it.next();/尋找一個(gè)新建的任務(wù)if(Task.State.NEW.equals(task.getState()/把任務(wù)狀態(tài)置為運(yùn)行中task.setState(Task.State.RUNNING);returntask;returnnull;addTask(Tasktask)方法用于當(dāng)一個(gè)新的任務(wù)到達(dá)時(shí),將它添加到任務(wù)隊(duì)列中。這里使用了LinkedList類來(lái)保存任務(wù)到達(dá)的先后順序。finishTask(Tasktask)方法用于任務(wù)被執(zhí)行完畢時(shí),將它從
31、任務(wù)隊(duì)列中清除出去。getTask()方法用于取得當(dāng)前要執(zhí)行的任務(wù)。3. TaskThread(執(zhí)行任務(wù)的線程):它繼承自Thread類,專門用于執(zhí)行任務(wù)隊(duì)列中的待執(zhí)行任務(wù)。javaviewplaincopyprint?1. publicclassTaskThreadextendsThread/該線程所屬的線程池privateThreadPoolServiceservice;publicTaskThread(ThreadPoolServicetps)service=tps;publicvoidrun()/在線程池運(yùn)行的狀態(tài)下執(zhí)行任務(wù)隊(duì)列中的任務(wù)while(service.isRunning()
32、TaskQueuequeue=service.getTaskQueue();Tasktask=queue.getTask();if(task!=null)task.deal();queue.finishTask(task);4. ThreadPoolService(線程池服務(wù)類):這是線程池最核心的一個(gè)類。它在被創(chuàng)建了時(shí)候就創(chuàng)建了幾個(gè)線程對(duì)象,但是這些線程并沒(méi)有啟動(dòng)運(yùn)行,但調(diào)用了start()方法啟動(dòng)線程池服務(wù)時(shí),它們才真正運(yùn)行。stop()方法可以停止線程池服務(wù),同時(shí)停止池中所有線程的運(yùn)行。而runTask(Tasktask)方法是將一個(gè)新的待執(zhí)行任務(wù)交與線程池來(lái)運(yùn)行。ThreadPoolS
33、ervice類的定義如下:javaviewplaincopyprint?1. importjava.util.ArrayList;importjava.util.List;publicclassThreadPoolService線程數(shù)publicstaticfinalintTHREAD_COUNT=5;線程池狀態(tài)privateStatusstatus=Status.NEW;privateTaskQueuequeue=newTaskQueue();publicenumStatus/*新建*/NEW,/*提供服務(wù)中7RUNNING,/*停止服務(wù)*/TERMINATED,privateListthr
34、eads=newArrayList();publicThreadPoolService。for(inti=0;iThreadt=newTaskThread(this);threads.add(t);/啟動(dòng)服務(wù)publicvoidstart()this.status=Status.RUNNING;for(inti=0;iTHREAD_COUNT;i+)threads.get(i).start();/停止服務(wù)publicvoidstop()this.status=Status.TERMINATED;/是否正在運(yùn)行publicbooleanisRunning()returnstatus=Status
35、.RUNNING;/執(zhí)行任務(wù)publicvoidrunTask(Tasktask)queue.addTask(task);protectedTaskQueuegetTaskQueue()returnqueue;完成了上面四個(gè)類,我們就實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的線程池?,F(xiàn)在我們就可以使用它了,下面的代碼做了一個(gè)簡(jiǎn)單的示例:javaviewplaincopyprint?1.publicclassSimpleTaskTestextendsTaskOverridepublicvoiddeal()/dosomethingpublicstaticvoidmain(Stringargs)throwsInterrupt
36、edExceptionThreadPoolServiceservice=newThreadPoolService();service.start();/執(zhí)行十次任務(wù)for(inti=0;i10;i+)service.runTask(newSimpleTaskTest();/睡眠1秒鐘,等待所有任務(wù)執(zhí)行完畢Thread.sleep(1000);service.stop();當(dāng)然,我們實(shí)現(xiàn)的是最簡(jiǎn)單的,這里只是為了演示線程池的實(shí)現(xiàn)原理。在實(shí)際應(yīng)用中,根據(jù)情況的不同,可以做很多優(yōu)化。比如: 調(diào)整任務(wù)隊(duì)列的規(guī)則,給任務(wù)設(shè)置優(yōu)先級(jí),級(jí)別高的任務(wù)優(yōu)先執(zhí)行。 動(dòng)態(tài)維護(hù)線程池,當(dāng)待執(zhí)行任務(wù)數(shù)量較多時(shí),增加線程
37、的數(shù)量,加快任務(wù)的執(zhí)行速度;當(dāng)任務(wù)較少時(shí),回收一部分長(zhǎng)期閑置的線程,減少對(duì)系統(tǒng)資源的消耗。事實(shí)上Java5.0及以上版本已經(jīng)為我們提供了線程池功能,無(wú)需再重新實(shí)現(xiàn)。這些類位于java.util.concurrent包中。Executors類提供了一組創(chuàng)建線程池對(duì)象的方法,常用的有一下幾個(gè):javaviewplaincopyprint?1.publicstaticExecutorServicenewCachedThreadPool()/othercodepublicstaticExecutorServicenewFixedThreadPool(intnThreads)/othercodepubl
38、icstaticExecutorServicenewSingleThreadExecutor()/othercodenewCachedThreadPool()方法創(chuàng)建一個(gè)動(dòng)態(tài)的線程池,其中線程的數(shù)量會(huì)根據(jù)實(shí)際需要來(lái)創(chuàng)建和回收,適合于執(zhí)行大量短期任務(wù)的情況;newFixedThreadPool(intnThreads)方法創(chuàng)建一個(gè)包含固定數(shù)量線程對(duì)象的線程池,nThreads代表要?jiǎng)?chuàng)建的線程數(shù),如果某個(gè)線程在運(yùn)行的過(guò)程中因?yàn)楫惓6K止了,那么一個(gè)新的線程會(huì)被創(chuàng)建和啟動(dòng)來(lái)代替它;而newSingleThreadExecutor()方法則只在線程池中創(chuàng)建一個(gè)線程,來(lái)執(zhí)行所有的任務(wù)。這三個(gè)方法都返回了一個(gè)ExecutorService類型的對(duì)象。實(shí)際上,ExecutorService是一個(gè)接口,它的submit()方法負(fù)責(zé)接收任務(wù)并交與線程池中的線程去運(yùn)行。submit()方法能夠接受Callable和Runnable兩種類型的對(duì)象。它們的用法和區(qū)別如下:1. Runnable接口:繼承Runnable接口的類要實(shí)現(xiàn)它的run()方法,并將執(zhí)行任務(wù)的代碼放入其中,run()方法沒(méi)有返回值。適合于只做某種操作,不關(guān)心運(yùn)行結(jié)果的情況。2. Callable接口:繼承Callable接口的類要實(shí)現(xiàn)它的ca
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025臨時(shí)建筑買賣合同樣本
- 2025辦公設(shè)備租賃服務(wù)合同范本
- 2025年氣液動(dòng)閥門、電磁閥、自鎖閥合作協(xié)議書
- 2025年浸酸劑項(xiàng)目合作計(jì)劃書
- 2025年航空地面試驗(yàn)設(shè)備項(xiàng)目建議書
- 高校實(shí)驗(yàn)室安全管理的改善計(jì)劃
- 人才培養(yǎng)在工作計(jì)劃中的重要地位
- 游玩廣勝寺的作文500
- 2025-2030中國(guó)鍛鋼行業(yè)市場(chǎng)分析及競(jìng)爭(zhēng)形勢(shì)與發(fā)展前景預(yù)測(cè)研究報(bào)告
- 2025-2030中國(guó)鑄造鋁合金車輪行業(yè)市場(chǎng)發(fā)展趨勢(shì)與前景展望戰(zhàn)略研究報(bào)告
- 專題08 八年級(jí)下冊(cè)易混易錯(cuò)總結(jié)-備戰(zhàn)2024年中考道德與法治一輪復(fù)習(xí)知識(shí)清單(全國(guó)通用)
- 浙江宇翔職業(yè)技術(shù)學(xué)院?jiǎn)握新殰y(cè)參考試題庫(kù)(含答案)
- 提高手衛(wèi)生正確率品管圈課件
- 醫(yī)院勞務(wù)派遣投標(biāo)方案(技術(shù)方案)
- 高中數(shù)學(xué)開放題賞析
- 非工傷人道主義賠償協(xié)議(標(biāo)準(zhǔn)版)
- 中華民族的復(fù)興
- 品質(zhì)部工作計(jì)劃
- 《浙江省工業(yè)建設(shè)項(xiàng)目用地控制指標(biāo)》(修訂)
- 【區(qū)域地理】《日本》【公開課教學(xué)PPT課件】高中地理
- 配對(duì)齒輪參數(shù)全程計(jì)算(史上最全最好用的齒輪計(jì)算表格)
評(píng)論
0/150
提交評(píng)論