




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
第12章
多
線
程第12章
多
線
程主要內(nèi)容線程的概念線程的生命周期Java中多線程的編程繼承Thread類與使用Runnable接口Thread類的主要方法線程的同步與死鎖第12章
多
線
程基本概念之一:進(jìn)程進(jìn)程是正在運(yùn)行的一個(gè)程序程序:靜態(tài)對象--進(jìn)程:動(dòng)態(tài)過程操作系統(tǒng)為每個(gè)進(jìn)程分配一段內(nèi)存空間,包括:代碼、數(shù)據(jù)以及堆棧等資源多任務(wù)的操作系統(tǒng)(OS)中,進(jìn)程切換對CPU資源消耗較大第12章
多
線
程基本概念之二:多線程單線程多線程進(jìn)程傳統(tǒng)進(jìn)程多線程進(jìn)程第12章
多
線
程基本概念之二:多線程線程是比進(jìn)程更小一級的執(zhí)行單元線程不能獨(dú)立存在,必須存在于進(jìn)程中,各線程間共享進(jìn)程空間的數(shù)據(jù)線程創(chuàng)建、銷毀和切換的負(fù)荷遠(yuǎn)小于進(jìn)程,又稱為輕量級進(jìn)程(lightweightprocess)。第12章
多
線
程線程的概念程序是一段靜態(tài)的代碼,它是應(yīng)用程序執(zhí)行的藍(lán)本一個(gè)進(jìn)程既包括其所要執(zhí)行的指令,也包括了執(zhí)行指令所需的任何系統(tǒng)資源,如CPU、內(nèi)存空間、I/O端口等,不同進(jìn)程所占用的系統(tǒng)資源相對獨(dú)立線程是進(jìn)程執(zhí)行過程中產(chǎn)生的多條執(zhí)行線索,是比進(jìn)程單位更小的執(zhí)行單位第12章
多
線
程線程的結(jié)構(gòu)CPUCodeData虛擬CPU,封裝在
java.lang.Thread類中,它控制著整個(gè)線程的運(yùn)行執(zhí)行的代碼,傳遞給Thread類,由
Thread類控制順序執(zhí)行處理的數(shù)據(jù),傳遞給
Thread類,是在代碼執(zhí)行過程中所要處理的數(shù)據(jù)第12章
多
線
程線程與進(jìn)程線程在形式上同進(jìn)程十分相似—都是用一個(gè)順序執(zhí)行的語句序列來完成特定的功能不同之處:線程沒有入口,也沒有出口,因此其自身不能自動(dòng)運(yùn)行,而必須棲身于某一進(jìn)程之中,由進(jìn)程觸發(fā)執(zhí)行在系統(tǒng)資源的使用上,屬于同一進(jìn)程的所有線程共享該進(jìn)程的系統(tǒng)資源,但是線程之間切換的速度比進(jìn)程切換要快得多第12章
多
線
程進(jìn)程與線程的區(qū)別文件輸入輸出裝置各種系統(tǒng)資源數(shù)據(jù)區(qū)段程序區(qū)段只有一個(gè)地方在執(zhí)行文件輸入輸出裝置各種系統(tǒng)資源數(shù)據(jù)區(qū)段程序區(qū)段同時(shí)有數(shù)個(gè)地方在執(zhí)行傳統(tǒng)的進(jìn)程多線程的任務(wù)第12章
多
線
程多線程的優(yōu)勢多線程編程簡單,效率高。使用多線程可以在線程間直接共享數(shù)據(jù)和資源,而多進(jìn)程之間不能做到這一點(diǎn)適合于開發(fā)服務(wù)程序–如Web服務(wù)、聊天服務(wù)等適合于開發(fā)有多種交互接口的程序–如聊天程序的客戶端、網(wǎng)絡(luò)下載工具適合于有人機(jī)交互又有計(jì)算量的程序–如字處理程序Word、Excel等第12章
多
線
程線程的調(diào)度調(diào)度策略–時(shí)間片–搶占式:高優(yōu)先級的線程搶占CPUJava的調(diào)度方法同優(yōu)先級線程組成先進(jìn)先出隊(duì)列,使用時(shí)間片策略對高優(yōu)先級,使用優(yōu)先調(diào)度的搶占式策略12第12章
多
線
程線程的狀態(tài)Java的線程是通過Java的軟件包java.lang中定義的類
Thread來實(shí)現(xiàn)的–當(dāng)生成一個(gè)Thread類的對象之后,就產(chǎn)生了一個(gè)線程。通過該對象實(shí)例,可以啟動(dòng)線程、終止線程,或者暫時(shí)掛起線程等Thread類本身只是線程的虛擬CPU,線程所執(zhí)行的代碼是通過方法run()
來完成的,方法run()稱為線程體–在一個(gè)線程被建立并初始化以后,Java的運(yùn)行時(shí)系統(tǒng)就自動(dòng)調(diào)用run()方法,正是通過run()方法才使得建立線程的目的得以實(shí)現(xiàn)第12章
多
線
程線程的狀態(tài)線程一共有四種狀態(tài):新建(new)、可運(yùn)行狀態(tài)(runnable)、死亡(dead)及堵塞(blocked)new
Thread()創(chuàng)建新線程可運(yùn)行態(tài)start()不可運(yùn)行態(tài)stop()stop()死亡yield()stop()run()exitsuspend()sleep()wait()I/O流阻塞resume()notify()/notifyAll()I/O指令等待睡眠掛起阻塞就緒運(yùn)行第12章
多
線
程線程的生命周期(續(xù))Newborn:線程已創(chuàng)建,但尚未執(zhí)行Runnable:(就緒)線程已被調(diào)度,按優(yōu)先級和先到先服務(wù)原則在隊(duì)列中排隊(duì)等待CPU時(shí)間片資源Runnnig:正在運(yùn)行Blocked:(阻塞)因某事件或睡眠而被暫時(shí)性地掛起Dead:正常/強(qiáng)行中斷,退出運(yùn)行狀態(tài)第12章
多
線
程12.1 Java中的多線程實(shí)現(xiàn)技術(shù)12.1.1
線程的生命周期每個(gè)Java程序都有一個(gè)缺省的主線程,對于Application,主線程是main()方法執(zhí)行的線索。對于Applet,主線程指揮瀏覽器加載并執(zhí)行Java小程序。要想實(shí)現(xiàn)多線程,必須在主線程中創(chuàng)建新的線程對象。Java語言使用Thread類及其子類的對象來表示線程。新建的線程在它的一個(gè)完整的生命周期中通常要經(jīng)歷新生、就緒、運(yùn)行、阻塞和死亡等五種狀態(tài),這五種狀態(tài)之間的轉(zhuǎn)換關(guān)系和轉(zhuǎn)換條件如圖12.1所示。第12章
多
線
程等待睡眠掛起阻塞死亡圖12.1
線程的生命周期新建start就緒運(yùn)行第12章
多
線
程1.新生狀態(tài)當(dāng)用new關(guān)鍵字和某線程類的構(gòu)造方法創(chuàng)建一個(gè)線程對象后,這個(gè)線程對象處于新生狀態(tài),此時(shí)它已經(jīng)有了相應(yīng)的內(nèi)存空間,并已被初始化。處于該狀態(tài)的線程可通過調(diào)用start()方法進(jìn)入就緒狀態(tài)。第12章
多
線
程2.就緒狀態(tài)處于就緒狀態(tài)的線程已經(jīng)具備了運(yùn)行的條件,但尚未分配到CPU資源,因而它將進(jìn)入線程隊(duì)列排隊(duì),等待系統(tǒng)為它分配
CPU。一旦獲得CPU資源,則該線程就進(jìn)入運(yùn)行狀態(tài),并自動(dòng)地調(diào)用自己的run方法。此時(shí),它脫離創(chuàng)建它的主線程,獨(dú)立開始了自己的生命周期。第12章
多
線
程3.運(yùn)行狀態(tài)進(jìn)入運(yùn)行狀態(tài)的線程執(zhí)行自己的run方法中的代碼。若遇到下列情況之一,則將終止run方法的執(zhí)行。終止操作。調(diào)用當(dāng)前線程的stop方法或destroy方法進(jìn)入死亡狀態(tài)。等待操作。調(diào)用當(dāng)前線程的join(millis)方法或wait(millis)方法進(jìn)入阻塞狀態(tài)。當(dāng)線程進(jìn)入阻塞狀態(tài)時(shí),在millis毫秒內(nèi)可由其他線程調(diào)用notify或notifyAll方法將其喚醒,進(jìn)入就緒狀態(tài)。在millis毫秒內(nèi)若不喚醒則須等待到當(dāng)前線程結(jié)束。第12章多線程睡眠操作。調(diào)用sleep(millis)方法來實(shí)現(xiàn)。當(dāng)前線程停止執(zhí)行后,則處于阻塞狀態(tài),睡眠millis毫秒之后重新進(jìn)入就緒狀態(tài)。掛起操作。通過調(diào)用suspend方法來實(shí)現(xiàn)。將當(dāng)前線程掛起,進(jìn)入阻塞狀態(tài),之后當(dāng)其他線程調(diào)用當(dāng)前線程的resume方法后,才能使其進(jìn)入就緒狀態(tài)。退讓操作。通過調(diào)用yield方法來實(shí)現(xiàn)。當(dāng)前線程放棄執(zhí)行,進(jìn)入就緒狀態(tài)。當(dāng)前線程要求I/O時(shí),則進(jìn)入阻塞狀態(tài)。若分配給當(dāng)前線程的時(shí)間片用完時(shí),當(dāng)前線程進(jìn)入就緒狀態(tài)。如當(dāng)前線程的run方法執(zhí)行完,則線程進(jìn)入死亡狀態(tài)。第12章
多
線
程4.阻塞狀態(tài)一個(gè)正在執(zhí)行的線程在某些特殊情況下,如執(zhí)行了suspend、join或sleep方法,或等待I/O設(shè)備的使用權(quán),那么它將讓出CPU并暫時(shí)中止自己的執(zhí)行,進(jìn)入阻塞狀態(tài)。阻塞時(shí)它不能進(jìn)入就緒隊(duì)列,只有當(dāng)引起阻塞的原因被消除時(shí),線程才可以轉(zhuǎn)入就緒狀態(tài),重新進(jìn)到線程隊(duì)列中排隊(duì)等待CPU資源,以便從原來終止處開始繼續(xù)運(yùn)行。第12章
多
線
程5.死亡狀態(tài)處于死亡狀態(tài)的線程將永遠(yuǎn)不再執(zhí)行。線程死亡有兩個(gè)原因:一是正常運(yùn)行的線程完成了它的全部工作;二是線程被提前強(qiáng)制性地終止,例如,通過執(zhí)行stop或destroy方法來終止線程。第12章
多
線
程創(chuàng)建線程的方法創(chuàng)建線程的方法一——繼承Thread類–定義一個(gè)線程類,它繼承類Thread并重寫其中的方法
run()。在初始化這個(gè)類的實(shí)例時(shí),目標(biāo)對象target可以為null,表示這個(gè)實(shí)例本身具有線程體創(chuàng)建線程的方法二——實(shí)現(xiàn)Runnable接口–
Runnable是Java中用以實(shí)現(xiàn)線程的接口,從根本上講,任何實(shí)現(xiàn)線程功能的類都必須實(shí)現(xiàn)該接口實(shí)現(xiàn)Runnable接口的方式創(chuàng)建線程與用繼承Thread類的方式創(chuàng)建線程無本質(zhì)差別,但是,由于Java不支持多繼承,所以任何類如果已經(jīng)繼承了某一類時(shí),就無法再繼承Thread類,這時(shí)只能通過實(shí)現(xiàn)接口
Runnable的方式創(chuàng)建線程對象。例如,小應(yīng)用程序已經(jīng)繼承了Applet類,不能再繼承Thread類,只能通過Runnable接口實(shí)現(xiàn)多線程。第12章
多
線
程12.1.3創(chuàng)建Thread類的子類,首先是聲明子類的構(gòu)造方法,其次是用自己定義的run()方法去覆蓋Thread類的run()方法,即將自己要執(zhí)行的程序區(qū)塊寫入run()方法中。Thread類的重要方法:run()定義線程的具體操作系統(tǒng)調(diào)度此線程時(shí)自動(dòng)執(zhí)行
如何編程呢?初始時(shí)無具體操作內(nèi)容方法一通過繼承Thread類方式創(chuàng)建線程-繼承Thread類,定義run()方法第12章
多
線
程表12.1
Java.lang.Thread的構(gòu)造方法構(gòu)造方法說
明public
Thread(
)構(gòu)造一個(gè)新線程,用此方式創(chuàng)建的線程必須覆蓋run()方法public
Thread(Runnable
target)構(gòu)造一個(gè)新線程,使用指定對象target的run()方法publicThread(ThreadGroup
group,Runnable
target)在指定的線程組group中構(gòu)造一個(gè)新的線程,使用指定對象target的run()方法public
Thread(String
name)用指定字符串名name構(gòu)造一個(gè)新線程public
Thread(ThreadGroup
group,String
name)在指定的線程組group中用指定字符串名name構(gòu)造一個(gè)新線程public
Thread(Runnable
target,String
name)用指定字符串名name構(gòu)造一個(gè)新線程,使用指定對象target的run()方法public
Thread(ThreadGroup
group,Runnable
target,Stringname)在指定的線程組group中使用字符串名
name構(gòu)造一個(gè)新線程,并使用指定對象
target的run()方法第12章
多
線
程12.1.2
Thread類的方法Thread類(線程類)是java.lang包中的一個(gè)專門用來創(chuàng)建線程和對線程進(jìn)行操作的類。Java在Thread類中定義了許多方法,幫助我們運(yùn)用和處理線程。這些方法可分為四組:構(gòu)造方法。用于創(chuàng)建用戶的線程對象,表12.1列出了Thread類的構(gòu)造方法。run()方法。用于定義用戶線程所要執(zhí)行的的操作。改變線程狀態(tài)的方法。如start()、sleep()、stop()、suspend()、resume()、yield()和wait()方法等。這是最常用的一組方法。其他方法。如setPriority()、setName()等。第12章
多
線
程Thread類的有關(guān)方法start():由Newborn到Runnable啟動(dòng)線程run():線程在被調(diào)度時(shí)執(zhí)行的操作sleep(指定時(shí)間):令當(dāng)前活動(dòng)線程在指定時(shí)間段內(nèi)放棄對CPU控制,使其他線程有機(jī)會(huì)被執(zhí)行,時(shí)間到后重排隊(duì)產(chǎn)生例外InterruptedException用try塊調(diào)用sleep(),用catch塊處理例外第12章
多
線
程Thread類的有關(guān)方法(續(xù))suspend()
:掛起線程,處于阻塞狀態(tài)resume():恢復(fù)掛起的線程,重新進(jìn)入就緒隊(duì)列排隊(duì)?wèi)?yīng)用:可控制某線程的暫停與繼續(xù)方法:設(shè)一狀態(tài)變量suspendStatus=false(初始)暫停:if(!suspendStatus){T.suspend();
suspendStatus=true;}繼續(xù):if(suspendStatus){T.resume();
suspendStatus=false;}第12章
多
線
程Thread類的有關(guān)方法(續(xù))yield():對正在執(zhí)行的線程若就緒隊(duì)列中有與當(dāng)前線程同優(yōu)先級的排隊(duì)線程,則當(dāng)前線程讓出CPU控制權(quán),移到隊(duì)尾若隊(duì)列中沒有同優(yōu)先級的線程,忽略此方法stop()強(qiáng)制線程生命期結(jié)束isAlive():返回boolean,表明是否還存在第12章
多
線
程Thread類方法總結(jié)啟動(dòng)線程:start()有關(guān)線程執(zhí)行的控制:stop()、suspend()、resume()有關(guān)調(diào)度控制Thread.sleep(10);//低優(yōu)先級的線程也可以獲得執(zhí)行Thread.yield();//同優(yōu)先級的線程可以獲得執(zhí)行suspend();//暫停本線程第12章
多
線
程表12.2
Java.lang.Thread的常用方法常用方法說
明public
void
run(
)此線程的線程體,在啟動(dòng)該線程后調(diào)用此方法。可以通過使用Thread類的子類來重載此方法public
synchronized
void
start(
)啟動(dòng)線程的執(zhí)行,此方法引起run()方法的調(diào)用,調(diào)用后立即返回。如果已經(jīng)啟動(dòng)此線程,就拋出
IllegalThreadedStateException異常public
static
Thread
currentThread(
)返回當(dāng)前處于運(yùn)行狀態(tài)的Thread對象public
static
void
yield(
)使當(dāng)前執(zhí)行的Thread對象退出運(yùn)行狀態(tài),使其進(jìn)入等待隊(duì)列public
static
void
sleep(longmillis)throwsInterruptedException使當(dāng)前執(zhí)行的線程睡眠millis毫秒。如果另一個(gè)線程已經(jīng)中斷了此線程,就拋出
InterruptedException
異常第12章
多
線
程表12.2
Java.lang.Thread的常用方法常用方法說明public
static
voidsleep(longmillis,int
nanos)throws
InterruptedException使當(dāng)前執(zhí)行的線程睡眠millis毫秒和附加的nanos毫秒。如果另一個(gè)線程已經(jīng)中斷了這個(gè)線程,則拋出InterruptedException
異常public
final
void
stop(
)停止線程的執(zhí)行通過拋出對象停止線程的執(zhí)行。正常情況下,用public
final
synchronized
void戶應(yīng)該在調(diào)用stop方法時(shí)不用任何參數(shù)。但是,在stop(Throwable
o)某些特殊的環(huán)境中,通過stop方法來結(jié)束線程,并可拋出另一個(gè)對象public
void
interrupt(
)中斷一個(gè)線程第12章
多
線
程表12.2
Java.lang.Thread的常用方法public
static
boolean
interrupted(
)詢問線程是否已經(jīng)被中斷public
Boolean
isInterrupted(
)詢問另一個(gè)線程是否已經(jīng)被中斷public
void
destroy(
)消毀一個(gè)線程public
final
boolean
isAlive(
)返回表示該線程活動(dòng)狀態(tài)的boolean值public
final
void
suspend(
)掛起這個(gè)線程的執(zhí)行public
final
void
resume(
)恢復(fù)這個(gè)線程的執(zhí)行,此方法僅在使用suspend()后才有效public
final
void
setPriority(intnewPriority)設(shè)置該線程的優(yōu)先級,如果優(yōu)先級不在MIN-
PRIORITY
到
MAX-PRIORITY
的范圍內(nèi),就拋出IllegalArgumentException異常第12章
多
線
程表12.2
Java.lang.Thread的常用方法public
final
int
getPriority(
)獲取并返回此線程的優(yōu)先級public
final
void
setName(Stringname)設(shè)置該線程名為namepublic
final
String
getName(
)獲取并返回此線程名public
final
ThreadGroup
getThreadGroup(
)獲取并返回此線程組public
static
int
activeCount(
)返回此線程組中當(dāng)前活動(dòng)的線程數(shù)量public
static
int
enumerate(Thread
tarray[
])將此線程組中的每一個(gè)活動(dòng)線程拷貝到指定的數(shù)組tarray中,返回放到此數(shù)組中線程的數(shù)量public
final
synchronized
void
join(longmillis)throws
InterruptedException等待此線程死亡,可以指定一個(gè)以millis給出的等待時(shí)間(以毫秒為單位),如果為0則表示永遠(yuǎn)等待,如果另一個(gè)線程已經(jīng)中斷這個(gè)線程,那么就拋出Interrupted-Exception異常第12章
多
線
程public
final
synchronized
voidjoin(long
millis
,intnanos)throwsInterruptedException等待此線程死亡,可以給出millis等待時(shí)間和nanos附加時(shí)間。如果另一個(gè)線程已經(jīng)中斷此線程,則拋出InterruptedException異常public
final
void
join(
)throwsInterruptedException無限期等待此線程死亡,如果另一個(gè)線程已經(jīng)中斷此線程,則拋出InterruptedException異常public
final
boolean
isDaemon(
)返回線程是否為daemon線程public
void
check
Access(
)檢查當(dāng)前線程是否允許訪問此線程組。如果不允許,就拋出SecurityException異常public
String
toString(
)返回這個(gè)線程的字符串表示,包括該線程的名字,優(yōu)先級和線程組,覆蓋Object類中的toString方法表12.2
Java.lang.Thread的常用方法第12章
多
線
程方法一從Thread類派生出一個(gè)子類,在類中一定要實(shí)現(xiàn)run()class
Lefthand
extends
Thread
{public
void
run(){……}}然后用該類創(chuàng)建一個(gè)對象Lefthand
left
=
newLefthand();用start()方法啟動(dòng)線程
(程序11-1
11-2)left.start();第12章
多
線
程public
class
myThread
extends
Thread{public
void
run(){while(running){……
//執(zhí)行若干操作sleep(100);}}public
static
void
main(String
args[]){Thread
t
=
newmyThread();……
//執(zhí)行若干操作}}第12章
多
線
程class
Lefthand
extends
Thread{public
void
run(){for(inti=0;i<=5;i++){System.out.println("You
are
Students!");try{//sleep((int)(Math.random()
*
1000));sleep(500);}catch(InterruptedException
e){}}}}class
Righthand
extends
Thread{public
void
run(){for(inti=0;i<=5;i++){System.out.println("I
am
a
Teacher!");try{sleep(300);}catch(InterruptedException
e){}}}}第12章
多
線
程public
class
ThreadTest{static
Lefthandleft;static
Righthand
right;public
static
void
main(String[]
args){left
=
newLefthand();right
=
new
Righthand();left.start();right.start();}}第12章
多
線
程【示例程序c12_1.java】 用Thread類的子類創(chuàng)建兩個(gè)線程對象。import
java.util.*;class
c12_1
extends
Thread
{int
pauseTime;String
name;public
c12_1(inthTime,
StringhStr){pauseTime
=hTime;name
=hStr;}public
void
run(
){第12章
多
線
程Calendar
now;//Calendar是Java系統(tǒng)提供的日期時(shí)間類的類型標(biāo)識(shí)符
int
year,month,date,hour,minute,second;for(int
i=1;i<10;i++)
{try
{now=Calendar.getInstance(
);year=now.get(Calendar.YEAR);//取系統(tǒng)時(shí)間//取年值month=now.get(Calendar.MONTH)+1;
//取月值date=now.get(Calendar.DATE);
//取日期值hour=now.get(Calendar.HOUR_OF_DAY);minute=now.get(Calendar.MINUTE);second=now.get(Calendar.SECOND);//取小時(shí)值//取分值//取秒值System.out.println(""+name+"時(shí)間:"+year+"年"+month+"月"+第12章
多
線
程date+"日"+hour+"小時(shí)"+minute+"分"+second+"秒");//顯示時(shí)間
Thread.sleep(pauseTime);}catch(Exception
e){System.out.println("線程錯(cuò)誤:"+e);}}}static
public
void
main(String
args[
])
{c12_1
myThread1=new
c12_1(2000,"線程A");//A線程執(zhí)行一次后睡眠2000毫秒
myThread1.start();c12_1
myThread2=new
c12_1(1000,"線程B");//B線程執(zhí)行一次后睡眠1000毫秒
myThread2.start();}}第12章
多
線
程方法二:通過實(shí)現(xiàn)Runnable接口方式創(chuàng)建線程創(chuàng)建線程對象的另一個(gè)途徑是實(shí)現(xiàn)Runnable接口,而
Runnable接口只有一個(gè)方法run(),用戶新建線程的操作由這個(gè)方法來決定。run()方法必須由實(shí)現(xiàn)此接口的類來實(shí)現(xiàn)。定義好
run()方法之后,當(dāng)用戶程序需要建立新線程時(shí),只要以這個(gè)實(shí)現(xiàn)了run()方法的類為參數(shù)創(chuàng)建系統(tǒng)類Thread的對象,就可以把用戶實(shí)現(xiàn)的run()方法繼承過來。方法二:自定義類實(shí)現(xiàn)Runnable接口使用Thread類的另一構(gòu)造函自定義類實(shí)現(xiàn)Runnable接口數(shù):Thread(Runnable,
String)使用start()啟動(dòng)線程第12章
多
線
程例:class
A
implements
Runnable{public
void
run(){….}}class
B
{public
static
void
main(String[]
arg){Runnable
a=new
A();Thread
t=new
Thread(a);t.start();}}第12章
多
線
程【示例程序c12_2.java】 通過創(chuàng)建線程實(shí)現(xiàn)“Java
Now!”在屏幕上不停地走動(dòng)。importjava.awt.*;import
java.applet.*;public
class
c12_2
extends
Applet
implements
Runnable{Thread
th1=null;String
Message="Java
Now!"; //創(chuàng)建字符串對象Font
f=new
Font("TimesRoman",Font.BOLD,24);體對象int
x,y;public
void
init(
){//創(chuàng)建字第12章
多
線
程x=getSize(
).width; //取applet窗口的寬度,單位為像素y=getSize(
).height/2; //取applet窗口的高度,單位為像素}public
void
start(
){
//創(chuàng)建線程對象實(shí)例
if(th1==null){th1=new
Thread(this);th1.start(
);}}public
void
run(
){while(true){第12章
多
線
程x=x-5;if(x==0)x=getSize(
).width;repaint(); //repaint()方法調(diào)用paint()方法重畫字符串對
try{th1.sleep(500); //使th1線程睡眠500
毫秒}catch(InterruptedException
e){
}}}public
void
paint(Graphics
g){g.setFont(f);//設(shè)置字體
g.drawString(Message,x,y);}}第12章
多
線
程圖12.2
程序c12_2的運(yùn)行中的一個(gè)瞬間第12章
多
線
程模擬小球例子程序11-3是一個(gè)模擬小球平拋和自由落體的例子BallThread.java相應(yīng)的HTML文檔第12章
多
線
程import
java.awt.*;import
java.awt.event.*;import
java.applet.*;public
class
BallThread
extends
Applet
implements
Runnable{Thread
red,
blue;Graphics
redPen,
bluePen;int
t=0;public
void
init(){red
=
new
Thread(this);blue
=
new
Thread(this);redPen
=getGraphics();bluePen
=getGraphics();redPen.setColor(Color.red);bluePen.setColor(Color.blue);}public
void
start(){red.start();blue.start();}第12章public
void
run(){多
線
程while(true){t=t+1;if(Thread.currentThread()==red){if(t>100)t=0;redPen.clearRect(0,0,110,400);redPen.fillOval(50,(int)(1.0/2*t*9.8),15,15);//s=1/2gt2try{red.sleep(40);}catch(InterruptedException
e){}}else
if(Thread.currentThread()==blue){bluePen.clearRect(120,0,900,500);bluePen.fillOval(120+7*t,(int)(1.0/2*t*9.8),15,15);//s=v0t+1/2gt2try{blue.sleep(40);}catch(InterruptedException
e){}}}}}第12章
多
線
程兩種方法的選擇當(dāng)需要從其他類,如Applet類繼承時(shí),使用Runnable當(dāng)編寫簡單的程序時(shí),可考慮使用繼承Thread類例:RaceApplet.java具體運(yùn)行結(jié)果(線程調(diào)度)與平臺(tái)有關(guān)第12章
多
線
程public
class
Runner
extends
Thread
{
//跑者線程類public
int
tick
=
1;public
void
run()
{while
(tick
<
40000000)tick++;}}//Runner.java//RaceApplet是一個(gè)實(shí)現(xiàn)了多線程的Appletpublic
class
RaceApplet
extends
Applet
implements
Runnable
{跑線程的個(gè)數(shù)final
static
int
NUMRUNNERS=2;//定義
final
staticint
SPACING=20;//聲明兩個(gè) 跑線程Runner[]
runners
=
newRunner[NUMRUNNERS];//聲明一個(gè)畫圖線程
Thread
updateThread=null;第12章
多
線
程public
void
init(){
//重載Applet的init()方法
for(int
i=0;
i<NUMRUNNERS;i++){runners[i]
=
newRunner();
//創(chuàng)建 跑線程線程runners[i].setPriority(i+1);
//設(shè)優(yōu)先級first=1,second=2}if
(updateThread
==
null)
{//創(chuàng)建繪圖線程,并設(shè)優(yōu)先級為3updateThread
=
new
Thread(this,
"ThreadRace");updateThread.setPriority(NUMRUNNERS+1);}addMouseListener(new
MyAdapter());//注冊事件監(jiān)聽者}
//end
ofinit()第12章
多
線
程//內(nèi)部事件監(jiān)聽者類,監(jiān)聽鼠標(biāo)事件class
MyAdapter
extends
MouseAdapter
{//鼠標(biāo)點(diǎn)擊后,開始 跑及繪制線程public
void
mouseClicked(MouseEventevt)
{if
(!updateThread.isAlive())updateThread.start();//啟動(dòng)繪制線程
for(int
i=0;
i<NUMRUNNERS;i++){if
(!runners[i].isAlive())runners[i].start();
//啟動(dòng) 跑線程}}}
//end
of
class
MyAdapter第12章
多
線
程public
void
paint(Graphics
g){//paint()方法中繪制框架………}
//end
ofpaint()//update()方法中繪制賽跑者的進(jìn)度,可以消除圖畫的閃爍
public
void
update(Graphics
g){for(int
i=0;
i<NUMRUNNERS;i++){//畫兩條線
g.drawLine(SPACING,(i+1)*SPACING,SPACING
+
(runners[i].tick)/100000,
(i+1)*SPACING);}}
//end
of
update()第12章
多
線
程publicvoid
run(){//實(shí)現(xiàn)Runnable接口的run()方法
while(true){repaint();
//重新繪制,自動(dòng)調(diào)用update()方法
try{Thread.sleep(10);
//休眠,把執(zhí)行機(jī)會(huì)讓給低優(yōu)先級線程}
catch
(InterruptedException
e)
{
}}}
//end
of
run()public
void
stop(){//重載Applet的stop()方法
for(int
i=0;
i<NUMRUNNERS;i++){if
(runners[i].isAlive())runners[i]
=null;
//中止 跑線程}if
(updateThread.isAlive())
updateThread=null;
//中止繪圖線程}
//end
ofstop()}
//RaceApplet.java第12章
多
線
程線程的啟動(dòng)通過Thread類中方法start()來啟動(dòng)在程序11-3中,只要執(zhí)行:red.start();blue.start();第12章
多
線
程線程的操作方法start()啟動(dòng)線程對象;run()用來定義線程對象被調(diào)度之后所執(zhí)行的操作,用戶必須重寫run()方法;yield()強(qiáng)制終止線程的執(zhí)行;isAlive()測試當(dāng)前線程是否在活動(dòng);sleep(int
millsecond)使線程休眠一段時(shí)間,時(shí)間長短由參數(shù)所決定;void
Wait()使線程處于等待狀態(tài);第12章多
線
程線程的調(diào)度線程調(diào)度通常是搶占式,而不是時(shí)間片式–搶占式調(diào)度是指可能有多個(gè)線程準(zhǔn)備運(yùn)行,但只有一個(gè)在真正運(yùn)行。一個(gè)線程獲得執(zhí)行權(quán),這個(gè)線程將持續(xù)運(yùn)行下去,直到它運(yùn)行結(jié)束或因?yàn)槟撤N原因而阻塞,再或者有另一個(gè)高優(yōu)先級線程就緒,最后一種情況中稱為低優(yōu)先級線程被高優(yōu)先級線程所搶占。12.2
多線程的管理第12章
多
線
程優(yōu)先級策略優(yōu)先級高的先執(zhí)行,優(yōu)先級低的后執(zhí)行多線程系統(tǒng)會(huì)自動(dòng)為每個(gè)線程分配一個(gè)優(yōu)先級,缺省時(shí),繼承其父類的優(yōu)先級任務(wù)緊急的線程,其優(yōu)先級較高同優(yōu)先級的線程按“先進(jìn)先出”的原則第12章
多
線
程線程優(yōu)先級Thread類三個(gè)與線程優(yōu)先級有關(guān)的靜態(tài)量MAX_PRIORITY:最大優(yōu)先權(quán),值為10;MIN_PRIORITY:最小優(yōu)先權(quán),值為1;NORM_PRIORITY:默認(rèn)優(yōu)先權(quán),值為5Thread類中幾個(gè)常用的有關(guān)優(yōu)先級的方法Void
setPriority(int
newPriority)
//重置線程優(yōu)先級Int
getPriority()Static
void
yield()//獲得當(dāng)前線程的優(yōu)先級//使當(dāng)前線程放棄執(zhí)行權(quán)第12章
多
線
程【示例程序c12_3.java】 創(chuàng)建三個(gè)線程A、B、C,根據(jù)優(yōu)先級確定線程的執(zhí)行順序。class
c12_3{public
static
void
main(String
args[
]){ Thread
First=new
MyThread("A"); //創(chuàng)建A線程First.setPriority(Thread.MIN_PRIORITY);
//A線程優(yōu)先級為1Thread
Second=newMyThread("B"); //創(chuàng)建B線程Second.setPriority(Thread.NORM_PRIORITY+1); //B線程優(yōu)先級為6Thread
Third=new
MyThread("C"); //創(chuàng)建C線程第12章
多
線
程Third.setPriority(Thread.MAX_PRIORITY);//C線程優(yōu)先級為10First.start();Third.start();Second.start(
);}}class
MyThread
extends
Thread{String
message;MyThread(String
message){
this.message=
message;}public
void
run(
){
for(inti=0;i<2;i++)System.out.println(message+"
"+getPriority(
));}}第12章
多
線
程該程序的運(yùn)行結(jié)果如下:C
10
C
10
B
6
B
6
A
1
A
1從程序的運(yùn)行結(jié)果中可以看出,雖然線程A在程序中最先調(diào)用start()方法進(jìn)入就緒狀態(tài),但由于它的優(yōu)先級是三個(gè)線程中最低的,所以最后才得以執(zhí)行。第12章
多
線
程線程的調(diào)度被阻塞的線程按次序排列,組成一個(gè)阻塞隊(duì)列。所有就緒但沒有運(yùn)行的線程則根據(jù)其優(yōu)先級排入一個(gè)就緒隊(duì)列CPU空閑時(shí),如果就緒隊(duì)列不空,隊(duì)列中第一個(gè)具有最高優(yōu)先級的線程將運(yùn)行當(dāng)一個(gè)線程被搶占而停止運(yùn)行時(shí),它的運(yùn)行態(tài)被改變并放到就緒隊(duì)列的隊(duì)尾;同樣,一個(gè)被阻塞(可能因?yàn)樗呋虻却齀/O設(shè)備)的線程就緒后通常也放到就緒隊(duì)列的隊(duì)尾為保證給其他線程留有執(zhí)行的機(jī)會(huì),可以通過間隔地調(diào)用sleep()第12章
多
線
程線程的調(diào)度例例11-4public
class
xyz
implements
Runnable{public
void
run(){while(true){……
//執(zhí)行若干操作//給其他線程運(yùn)行的機(jī)會(huì)try{Thread.sleep(10);}catch(InterruptedException
e){//該線程為其他線程所中斷}}}}第12章
多
線
程sleep()是靜態(tài)方法,可以通過Thread.sleep(x)直接引用–
x指定了線程在再次啟動(dòng)前必須休眠的最小時(shí)間,毫秒為單位–可能引發(fā)中斷異常InterruptedException,因此要進(jìn)行捕獲和處理–“最小時(shí)間”是因?yàn)檫@個(gè)方法只保證在一段時(shí)間后線程回到就緒態(tài),至于它是否能夠獲得CPU運(yùn)行,則要視線程調(diào)度而定,所以,通常線程實(shí)際被暫停的時(shí)間都比指定的時(shí)間要長第12章
多
線
程yield()可以給其他同等優(yōu)先級線程一個(gè)運(yùn)行的機(jī)會(huì)如果在就緒隊(duì)列中有其他同優(yōu)先級的線程,
yield()把調(diào)用者放入就緒隊(duì)列尾,并允許其他線程運(yùn)行;如果沒有這樣的線程,則yield()不做任何工作sleep()調(diào)用允許低優(yōu)先級進(jìn)程運(yùn)行,而yield()方法只給同優(yōu)先級進(jìn)程以運(yùn)行機(jī)會(huì)第12章
多
線
程線程的基本控制結(jié)束線程–當(dāng)一個(gè)線程從run()方法的結(jié)尾處返回時(shí),它自動(dòng)消亡并不能再被運(yùn)行,可以將其理解為自然死亡–利用stop()方法強(qiáng)制停止,可以將其理解為強(qiáng)迫死亡,這種方法必須用于Thread類的特定實(shí)例中第12章
多
線
程強(qiáng)迫死亡Stoppublic
class
xyz
implements
Runnable{……
//執(zhí)行線程的主要操作}public
class
ThreadTest{public
static
void
main(String
args[]){Runnable
r
=
newxyz();Thread
t
=
newThread(r);t.start();//相應(yīng)的操作if
(time_to_kill){t.stop();}}}第12章
多
線
程結(jié)束線程例利用Thread類中的靜態(tài)方法currentThread()來引用正在運(yùn)行的線程,見例11-6–在這個(gè)例子中,執(zhí)行stop()將破壞當(dāng)前的運(yùn)行環(huán)境,因而run()中的循環(huán)在此情況下將不再運(yùn)行例11-6public
class
xyz
implements
Runnable{public
void
run(){while(true){……//執(zhí)行線程的主要操作if
(time_to_die){Thread.currentThread().stop();}}}}第12章
多
線
程檢查線程isAlive()–獲取一個(gè)線程是否還在活動(dòng)狀態(tài)的信息。–活動(dòng)狀態(tài)不意味著這個(gè)線程正在執(zhí)行,而只說明這個(gè)線程已被啟動(dòng),并且既沒有運(yùn)行
stop(),也尚未運(yùn)行完方法run()。第12章
多
線
程掛起線程暫停一個(gè)線程稱為掛起。在掛起之后,必須重新喚醒線程進(jìn)入運(yùn)行掛起線程的方法sleep()線程不是休眠期滿后就立刻被喚醒,因?yàn)榇藭r(shí)其他線程能正在執(zhí)行,重新調(diào)度只在以下幾種情況下才會(huì)發(fā)生:被喚醒的線程具有更高的優(yōu)先級;正在執(zhí)行的線程因?yàn)槠渌虮蛔枞?;程序處于支持時(shí)間片的系統(tǒng)中suspend()和resume()join()
:引起現(xiàn)行線程等待,直至方法join所調(diào)用的線程結(jié)束第12章
多
線
程程序11-4suspend()和resume()程序11-4說明:線程t在運(yùn)行到suspend()以后被強(qiáng)制掛起,暫停運(yùn)行,直到主線程調(diào)用t.resume()時(shí)才被重新喚醒;一個(gè)線程只能被不同于它自身的線程所喚醒,因?yàn)樵趫?zhí)行suspend()方法以后,這個(gè)線程其后的代碼都不會(huì)被執(zhí)行到,而該線程又依賴于其后的resume語句將其喚醒,所以千萬不能將resume()用在已被掛起的線程語句中第12章
多
線
程class
xyz
implements
Runnable{public
void
run(){……//執(zhí)行線程的主要操作//暫停線程運(yùn)行,直到被其他線程喚醒Thread.currnetThread().suspend();……
//線程繼續(xù)運(yùn)行...}}class
Usexyz{public
static
void
main(String
args[]){Runnable
r
=
newxyz();Thread
t
=
newThread(r);t.start();//暫停當(dāng)前線程運(yùn)行,以使得已經(jīng)被阻塞得xyz的實(shí)例得以運(yùn)行Thread.sleep(1000);//xyz實(shí)例被suspend()方法暫停,將控制權(quán)返還給主線程,//并由主線程重新喚醒線程tt.resume();Thread.yield();}}第12章
多
線
程線程對內(nèi)存、數(shù)據(jù)的共享如push(a):idx++;data[i]=aclass
Stack{int
idx
=
0;char
data[]
=
newchar[6];public
void
push(char
c){data[idx]
=
c;idx
++;}public
charpop(){idx
--;returndata[idx];}}12.2.3
線程同步1、問題的提出線程執(zhí)行的不確定性引起執(zhí)行結(jié)果的不穩(wěn)定如線程A:
A1-A2
線程B:
B1-B2pop():
取出data[i];idx--;第12章
多
線
程一個(gè)代表?xiàng)5念惱?1-8錯(cuò)誤情況1–假設(shè)線程a負(fù)責(zé)加入字符,線程b負(fù)責(zé)移出字符。線程a剛剛加入了一個(gè)字符,例如是r,但是尚未遞增索引值,由于某種原因,恰恰這時(shí)它被搶占了:buffer |
p|
q|
r|
|
|
|idx=2
^idx=3第12章
多
線
程錯(cuò)誤情況2如果此時(shí)線程b正在等待移出一個(gè)字符,當(dāng)線程a處于等待狀態(tài)時(shí),線程b就得到了運(yùn)行機(jī)會(huì)。這樣,在進(jìn)入方法pop()時(shí),數(shù)據(jù)狀態(tài)已經(jīng)是錯(cuò)誤的。pop方法將繼續(xù)遞減索引值,idx變?yōu)?buffer |
p|
q|
r|
|
|
|idx=1
^操作后將返回字符
“q”,而忽略字符
“r”第12章
多
線
程例子說明產(chǎn)生這種問題的原因是對共享資源訪問的不完整性–完整性稱為共享數(shù)據(jù)操作的同步,共享數(shù)據(jù)叫做條件變量解決問題的方法–禁止線程在完成代碼關(guān)鍵部分時(shí)被切換–提供一個(gè)特殊的鎖定標(biāo)志來處理數(shù)據(jù) (Java采用的方法
)第12章
多
線
程對象的鎖定標(biāo)志“對象互斥鎖” (又稱為監(jiān)視器、管程)–實(shí)現(xiàn)不同線程對共享數(shù)據(jù)操作的同步。“對象互斥鎖”阻止多個(gè)線程同時(shí)訪問同一個(gè)條件變量。Java可以為每一個(gè)對象的實(shí)例配有一個(gè)“對象互斥鎖”實(shí)現(xiàn)“對象互斥鎖”兩種方法–用關(guān)鍵字volatile來聲明一個(gè)共享數(shù)據(jù)(變量);–用關(guān)鍵字synchronized來聲明一個(gè)操作共享數(shù)據(jù)的方法或一段代碼。第12章
多
線
程例11-9class
stack{int
idx
=
0;char
data[]
=
newchar[6];public
void
push(char
c){synchronized
(this){data[idx]
=
c;idx
++;}}…………public
charpop(){synchronized
(this){idx
--;returndata[idx];}}}增加了一個(gè)對synchronized(this)的調(diào)用增加了一個(gè)對
synchronized(this)的調(diào)用第12章
多
線
程過程圖示線程1...因等待同步資源而掛起的線程隊(duì)列第12章
多
線
程同步方法用synchronized來標(biāo)識(shí)的代碼段或方法即為“對象互斥鎖
”鎖住的部分。如果一個(gè)程序內(nèi)有兩個(gè)或以上的方法使用synchronized標(biāo)志,則它們在同一個(gè)“對象互斥鎖”管理之下一般情況下,都使用synchronized關(guān)鍵字在方法的層次上實(shí)現(xiàn)對共享資源操作的同步,很少使用volatile關(guān)鍵字聲明共享變量第12章
多
線
程synchronized()語句寫法標(biāo)準(zhǔn)寫法(public
void
push(char
c){}}簡pu潔blic的sy寫nch法ronized
void
push(char
c){……}把synchronized用做方法的修飾synch更ron為ized妥(th字帖is){,)則整個(gè)方法都將視作同步…………塊,這可能會(huì)使持有鎖定標(biāo)記
的時(shí)間比實(shí)際需要的時(shí)間要長,從而降低效率第12章
多
線
程死鎖步以線程運(yùn)行完同繼續(xù)運(yùn)行,所每個(gè)線程都程序塊。而哪個(gè)線程都線程2pen線程1note死鎖情況發(fā)生在一個(gè)線程等待另一個(gè)線程所持有的鎖,而第二個(gè)線程又在等把“待pen第”給一我,個(gè)我線程持有的鎖的時(shí)候。不能繼續(xù)才運(yùn)能給行你,“no除te”非另一恰恰因?yàn)槟膫€(gè)線程都不能無法運(yùn)行完同步程序塊把“note”給我,我才能給你“pen”第12章
多
線
程死鎖問題程序死鎖問題見程序11-6第12章
多
線
程解決死鎖問題的方法給資源施加排序制定一個(gè)規(guī)則來決定以何種順序來獲得這些鎖,并在整個(gè)程序中遵循這個(gè)順序
–參考操作系統(tǒng)方面的相關(guān)書籍第12章
多
線
程線程交互為什么兩個(gè)線程需要交互呢?–涉及到多線程間共享數(shù)據(jù)操作時(shí),除了同步問題之外,還會(huì)遇到如何控制相互交互的線程之間的運(yùn)行進(jìn)度,即多線程的同步問題–生產(chǎn)者——消費(fèi)者問題生產(chǎn)者比消費(fèi)者快時(shí),消費(fèi)者漏掉一些數(shù)據(jù)消費(fèi)者比生產(chǎn)者快時(shí),消費(fèi)者取相同的數(shù)據(jù)生產(chǎn)者消費(fèi)者共享對象putget第12章
多
線
程在這個(gè)問題中,兩個(gè)線程要共享貨架這一臨界資源,需要在某些時(shí)刻(貨空/貨滿)協(xié)調(diào)它們的工作,即貨空時(shí)消費(fèi)者應(yīng)等待,而貨滿時(shí)生產(chǎn)者應(yīng)等待。為了不致于發(fā)生混亂,還可進(jìn)一步規(guī)定:當(dāng)生產(chǎn)者往貨架上放貨物時(shí)不允許消費(fèi)者取貨物,當(dāng)消費(fèi)者從貨架上取貨物時(shí)不允許生產(chǎn)者放貨物。這種機(jī)制在操作系統(tǒng)中稱為線程間的同步。在同步機(jī)制中,將那些訪問臨界資源的程序段稱為臨界區(qū)。第12章
多
線
程問題的解決同步:用synchronized關(guān)鍵字前綴給針對共享資源的操作加鎖;同步方法、同步塊synchronized
void
push() synchronized
int
pop()實(shí)現(xiàn)機(jī)制:管程線程間需協(xié)調(diào)與通訊:生產(chǎn)者/消費(fèi)者問題wait()與notify()Object類的方法:public
final
voidwait():令當(dāng)前線程掛起并放棄管程,同步資源解鎖,使別的線程可訪問并修改共享資源,而當(dāng)前線程排隊(duì)等候再次對資源的訪問notify()喚醒正在排隊(duì)等待資源管程的線程中優(yōu)先級最高者,使之執(zhí)行并擁有資源的管程wait()+notify()+標(biāo)志變量:可協(xié)調(diào)、同步不同線程的工作第12章
多
線
程在Java系統(tǒng)中,臨界區(qū)程序段是用關(guān)鍵字“synchronized”來標(biāo)注,并通過一個(gè)稱為監(jiān)控器的系統(tǒng)軟件來管理的。當(dāng)執(zhí)行被冠以
synchronized的程序段即臨界區(qū)程序時(shí),監(jiān)控器將這段程序(訪問的臨界資源)加鎖,此時(shí),稱該線程占有臨界資源,直到這段程序執(zhí)行完,才釋放鎖。只有鎖被釋放后,其他線程才可以訪問這些臨界資源。用關(guān)鍵字synchronized定義臨界區(qū)的語句形式是:synchronized
(expression)
statement其中,expression代表類的名字,它是可選項(xiàng);statement可以是一個(gè)方法,也可以是一個(gè)語句或一個(gè)語句塊,最常見的是一個(gè)方法。下面通過一個(gè)例子來說明線程的同步問題。第12章
多
線
程Wait_Notify
程序CubbyHole.java創(chuàng)建用戶的線程子類Producer:產(chǎn)生數(shù)據(jù)(存數(shù)據(jù));
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 環(huán)保地板采購合同范本
- 街巷路燈維修合同范本
- 七年級下冊語文期末復(fù)習(xí):現(xiàn)代文+文言文+基礎(chǔ)知識(shí)+綜合性學(xué)習(xí)+作文 試題分類匯編(含答案)
- 便宜倉庫租賃合同范本
- 學(xué)校圖書購書合同范本
- 服裝數(shù)量采購合同范本
- 北京正規(guī)賣房合同范本
- 吉林省吉林市永吉縣2024-2025學(xué)年七年級上學(xué)期期末考試數(shù)學(xué)試卷(含解析)
- 占道經(jīng)營合同范本
- 2025標(biāo)準(zhǔn)版權(quán)合同模板
- 2025年部編版新教材語文一年級下冊期中測試題(有答案)
- 《FAB銷售法則》課件
- 衛(wèi)生院、社區(qū)衛(wèi)生服務(wù)中心《死亡醫(yī)學(xué)證明書》上報(bào)制度
- 大學(xué)兼職申請書
- 狂犬疫苗打完免責(zé)協(xié)議書(2篇)
- 游樂設(shè)備事故應(yīng)急預(yù)案
- 公司第1季度品質(zhì)部工作總結(jié)報(bào)告
- 2025年浙江省金融控股有限公司招聘筆試參考題庫含答案解析
- 新產(chǎn)品開發(fā)流程和步驟
- 大別山精神完整版本
- 2025年蘇美達(dá)股份有限公司招聘筆試參考題庫含答案解析
評論
0/150
提交評論