Java程序設(shè)計(jì)項(xiàng)目式教程 課件 單元6 多線程_第1頁
Java程序設(shè)計(jì)項(xiàng)目式教程 課件 單元6 多線程_第2頁
Java程序設(shè)計(jì)項(xiàng)目式教程 課件 單元6 多線程_第3頁
Java程序設(shè)計(jì)項(xiàng)目式教程 課件 單元6 多線程_第4頁
Java程序設(shè)計(jì)項(xiàng)目式教程 課件 單元6 多線程_第5頁
已閱讀5頁,還剩33頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

§6-1多窗口售票模擬Java語言程序設(shè)計(jì)教學(xué)目標(biāo)任務(wù)分析大家乘坐高鐵出行前會(huì)在網(wǎng)上訂票或在高鐵站窗口買票,因?yàn)槎鄠€(gè)窗口可能會(huì)在同一時(shí)間售賣同一車次的火車票,必須保證數(shù)據(jù)一致性。本任務(wù)便是利用Java多線程機(jī)制,模擬高鐵站多個(gè)窗口進(jìn)行售票的過程。目錄1線程的創(chuàng)建與啟動(dòng)什么是多線程23線程的同步線程狀態(tài)與線程控制4一、什么是多線程進(jìn)程:正在運(yùn)行著的程序,計(jì)算機(jī)來說一個(gè)任務(wù)就是一個(gè)進(jìn)程程序:一組寫好了的靜態(tài)代碼塊“多任務(wù)”:指操作系統(tǒng)能同時(shí)運(yùn)行多個(gè)進(jìn)程(程序)。如Windows系統(tǒng)可以同時(shí)運(yùn)行寫字板程序、畫圖程序、WORD、EXCEL等。1.幾個(gè)概念線程:線程是進(jìn)程執(zhí)行的一個(gè)路徑單線程:一個(gè)進(jìn)程中只包含一個(gè)線程,也就是說一個(gè)程序只有一條執(zhí)行路線。多線程:在單個(gè)進(jìn)程中可以同時(shí)運(yùn)行多個(gè)不同的線程執(zhí)行不同的任務(wù)。執(zhí)行多線程的時(shí)候,Java虛擬處理機(jī)在多個(gè)線程之間輪流切換,不過每個(gè)時(shí)刻只能有一個(gè)線程在執(zhí)行。main方法是Java的入口程序,一旦進(jìn)入就啟動(dòng)了一個(gè)main線程,所以main線程也稱為主線程。一、什么是多線程在Java中,要想創(chuàng)建多線程,有兩種方式:一種是繼承Thread類,一種是實(shí)現(xiàn)Runnable接口。

線程的啟動(dòng)要通過Thread類的start()方法

二、線程的創(chuàng)建與啟動(dòng)1.繼承Thread類創(chuàng)建多線程步驟1)創(chuàng)建類,使其繼承自Thread類publicclassMyThreadextendsThread{ publicMyThread(){//編寫子類的構(gòu)造方法}

publicvoidrun(){//編寫自己的線程代碼}}2)創(chuàng)建一個(gè)線程對象MyThreadthreadObj=newMyThread();二、線程的創(chuàng)建與啟動(dòng)1.繼承Thread類創(chuàng)建多線程步驟3)啟動(dòng)線程threadObj.start();需要注意的是,不要調(diào)用Thread類的run()方法。直接調(diào)用run()方法只會(huì)在當(dāng)前線程中執(zhí)行任務(wù),并不會(huì)啟動(dòng)新的線程。正確的做法是調(diào)用Thread類的start()方法,它會(huì)創(chuàng)建一個(gè)新的線程來執(zhí)行run()方法。二、線程的創(chuàng)建與啟動(dòng)2.實(shí)現(xiàn)Runnable接口創(chuàng)建多線程步驟1)實(shí)現(xiàn)一個(gè)使用Runnable接口的類。publicclassMyRunnableThreadimplementsRunnable{ publicMyRunnableThread(){//編寫子類的構(gòu)造方法}

publicvoidrun(){//編寫自己的線程代碼}}2)創(chuàng)建一個(gè)Runnable對象。Runnabler=newMyRunnableThread();3)以Runnable對象做為參數(shù)創(chuàng)建一個(gè)線程對象。Threadt=newThread(r);二、線程的創(chuàng)建與啟動(dòng)4)啟動(dòng)線程。t.start();publicclassSimpleThreadextendsThread{ privateintcount=2;//循環(huán)次數(shù) publicSimpleThread(){//調(diào)用父類無帶參構(gòu)造 }

publicSimpleThread(Stringname){//n super(name); //指定調(diào)用父類帶參構(gòu)造,設(shè)定線程名 } publicvoidrun(){ for(inti=0;i<count;i++){ //getName()獲得當(dāng)前線程名 System.out.println(getName()+":"+i); } }} publicstaticvoidmain(String[]args){

////創(chuàng)建自定義線程類simpleThread1對象,不指定線程名 SimpleThreadsimpleThread1=newSimpleThread(); //使用帶名字String參的構(gòu)造方法創(chuàng)建線程對象 SimpleThreadsimpleThread2=newSimpleThread("新線程2");

simpleThread1.start(); simpleThread2.start(); }示例代碼classMyRunnableThreadimplementsRunnable{ privateintcount=2;//循環(huán)次數(shù) @Override publicvoidrun(){ for(inti=0;i<count;i++){

//用靜態(tài)方法currentThread()獲得當(dāng)前線程 System.out.println(Thread.currentThread().getName()+":"+i); } }}

publicstaticvoidmain(String[]args){ //創(chuàng)建自定義線程類myRunnableThread對象,不指定線程名

MyRunnableThreadmyRunnableThread=newMyRunnableThread(); //使用帶myRunnableThread參數(shù)的構(gòu)造方法創(chuàng)建線程對象

Threadthread3=newThread(myRunnableThread); //使用帶兩個(gè)參的構(gòu)造方法創(chuàng)建線程對象

Threadthread4=newThread(myRunnableThread,"新線程4");

thread3.start(); thread4.start(); }示例代碼使用繼承Thread類的方法創(chuàng)建線程,可以在子類中增加新的成員變量和新的成員函數(shù),使得線程具有新的屬性和功能,還可以直接操作線程,但由Java中不支持多繼承,因此Thread子類不能擴(kuò)展其他的類。利用Runnable接口,線程的創(chuàng)建可以從其它類繼承,使得代碼和數(shù)據(jù)分開,不過需要使用Thread對象來操縱線程。二、線程的創(chuàng)建與啟動(dòng)三、線程狀態(tài)與線程同步線程從創(chuàng)建到最終的消亡稱為線程的生命周期。線程的整個(gè)生命周期包括以下五個(gè)狀態(tài):新建(生)狀態(tài)(New)就緒狀態(tài)(Runnable)運(yùn)行狀態(tài)(Running)被阻塞狀態(tài)(Blocked)死亡狀態(tài)(Dead)1)新建狀態(tài)(New):新創(chuàng)建了一個(gè)線程對象,這時(shí)線程還沒工作。2)就緒狀態(tài)(Runnable):線程對象創(chuàng)建后,其他線程調(diào)用了該對象的start()方法,該狀態(tài)的線程處于可運(yùn)行狀態(tài),等待獲取CPU的使用權(quán)。3)運(yùn)行狀態(tài)(Running):就緒狀態(tài)的線程獲取了CPU,程序代碼得以執(zhí)行,線程進(jìn)入運(yùn)行狀。4)阻塞狀態(tài)(Blocked):阻塞狀態(tài)是線程因?yàn)槟撤N原因放棄CPU使用權(quán),暫時(shí)停止運(yùn)行。直到線程進(jìn)入就緒狀態(tài),才有機(jī)會(huì)轉(zhuǎn)到運(yùn)行狀態(tài)。5)死亡狀態(tài)(Dead):線程執(zhí)行了或者因異常退出了run()方法,該線程結(jié)束生命周期。三、線程狀態(tài)與線程同步方法(public)功能應(yīng)用示例staticvoidsleep(longmillis)throwsInterruptedException在指定的毫秒數(shù)內(nèi)讓當(dāng)前正在執(zhí)行的線程休眠(暫停執(zhí)行),該線程不丟失任何監(jiān)視器的所屬權(quán)??梢员籭nterrupt()方法中斷Thread.sleep(1000);//讓線程休眠1秒,將線程轉(zhuǎn)換成阻塞狀態(tài)。staticvoidyield()暫停當(dāng)前正在執(zhí)行的線程對象,并執(zhí)行其他線程Thread.yield();//暫停線程執(zhí)行,將線程轉(zhuǎn)換成就緒狀態(tài)。voidsetPriority(intnewPriority)更改線程的優(yōu)先級,可以設(shè)置為在MAX_PRIORITY(定義為10)與MIN_PRIORITY(定義為1)之間的任何值,NORM_PRIORITY被定義為5。MyThreadthreadObj=newMyThread();threadObj.setPriority(10);//線程的優(yōu)先級是高度依賴于系統(tǒng)的。并不是設(shè)為最高一定最先執(zhí)行intgetPriority()返回線程的優(yōu)先級intpriority=threadObj.getPriority();voidsetDaemon()將該線程標(biāo)記為守護(hù)線程或用戶線程,在程序運(yùn)行的時(shí)候在后臺提供一種通用服務(wù)的線程,并且這種線程并不屬于程序中不可或缺的部分。threadObj.setDaemon();//必須在線程啟動(dòng)之前調(diào)用setDaemon()方法,才能把它設(shè)置為后臺線程。當(dāng)所有的非后臺線程結(jié)束時(shí),程序也就終止了。boolean

isDaemon()測試該線程是否為守護(hù)線程booleanflag=threadObj.isDaemon();voidjoin()加入線程,等待該線程終止threadObj.join();//voidinterrupt()

中斷線程threadOerrupt();booleaninterrupted()測試線程是否已經(jīng)中斷booleanflag=threadObj.interrupted();三、線程狀態(tài)與線程同步在多線程的環(huán)境中,可以同時(shí)做多件事情。但是,兩個(gè)或多個(gè)線程同時(shí)使用一個(gè)受限資源的問題也出現(xiàn)了,有可能一個(gè)線程正在使用某個(gè)資源,而另一個(gè)線程卻在更新它,這樣,會(huì)造成數(shù)據(jù)的不正確。例如一個(gè)銀行賬戶同時(shí)被兩個(gè)線程操作,一個(gè)線程要實(shí)現(xiàn)取100元,一個(gè)線程實(shí)現(xiàn)轉(zhuǎn)賬匯入100元。假設(shè)賬戶原本有1000元,如果取錢線程和轉(zhuǎn)賬匯入線程同時(shí)發(fā)生,會(huì)出現(xiàn)什么結(jié)果呢?如果不進(jìn)行任何控制則有可能出現(xiàn)取錢成功,賬戶余額是1100。對于多個(gè)線程共享的資源,必須采取措施,使得每次只有一個(gè)線程能使用它,這就是多線程中的同步(synchronization)問題。四、線程同步

多線程模式在解決線程沖突問題的時(shí)候,多數(shù)都是采用序列化訪問共享資源的方案。即在給定時(shí)刻只允許一個(gè)線程訪問共享資源。通常這是通過在代碼前面加上一條鎖語句來實(shí)現(xiàn)的,這就保證了在一段時(shí)間內(nèi)只有一個(gè)線程運(yùn)行這段代碼。因?yàn)殒i語句產(chǎn)生了一種互相排斥的效果,所以這種機(jī)制常常稱為“互斥量”(mutex)。

四、線程同步1)同步方法Java以提供關(guān)鍵字synchronized的形式,為防止資源沖突提供了內(nèi)置支持??梢酝ㄟ^把方法標(biāo)記為synchronized的方式來防止資源沖突,下面是聲明同步方法的語法。訪問控制符synchronized返回值類型方法名稱(參數(shù)){//方法體;}例:publicsynchronizedvoidmethod1(){}注:每個(gè)對象都含有單一的鎖(也稱為監(jiān)視器),這個(gè)鎖本身就是對象的一部分。當(dāng)在對象上調(diào)用其任意synchronized方法的時(shí)候,此對象都被加鎖,這時(shí)該對象上其它synchronized方法只有等到前一個(gè)方法調(diào)用完成并釋放了鎖之后才能被調(diào)用。四、線程同步

2)同步代碼塊同步代碼塊防止多個(gè)線程同時(shí)訪問方法內(nèi)部的部分代碼,而不是防止訪問整個(gè)方法。synchronized被用來指定某個(gè)對象,syncObject對象的鎖被用來對花括號內(nèi)的代碼進(jìn)行同步控制。synchronized(syncObject){ //編寫自己的代碼}四、線程同步

3)鎖對象除了使用synchronized關(guān)鍵字外,JavaSE5.0中引入了ReentrantLock類。使用ReentrantLock類保護(hù)代碼塊的基本結(jié)構(gòu)如下:myLock.lock();try{ //被保護(hù)的代碼塊;}finally{ myLock.unlock();}這一結(jié)構(gòu)確保任何時(shí)候只有一個(gè)線程訪問代碼塊。解鎖操作要放在finally語句。四、線程同步任務(wù)實(shí)施為實(shí)現(xiàn)多窗口售票,需要?jiǎng)?chuàng)建多個(gè)線程對象模擬多個(gè)窗口,實(shí)現(xiàn)步驟如下:創(chuàng)建一個(gè)線程類SaleTicketWindow,該類實(shí)現(xiàn)Runnable接口,該類中定義一個(gè)成員變量ticket,ticket代表當(dāng)前車次剩余票數(shù)。SaleTicketWindow類實(shí)現(xiàn)run方法,在run方法體中編寫while循環(huán),在循環(huán)體中對當(dāng)前剩余票數(shù)ticket進(jìn)行判斷,如果大于零,則表示依然可以售出。調(diào)用sleep方法,每隔1秒將當(dāng)前票數(shù)減1,表示售賣一張。為保證同時(shí)只有一個(gè)線程可執(zhí)行票數(shù)減1操作,將該操作放置在同步代碼塊中。通過SaleTicketWindow類實(shí)現(xiàn)創(chuàng)建多個(gè)線程對象,每個(gè)線程對象模擬為一個(gè)售票窗口,本任務(wù)中我們創(chuàng)建三個(gè)窗口用于售票。已知銀行賬戶類BankCount,該類有一個(gè)成員變量balance表示賬戶余額。定義線程類,用于對銀行賬戶進(jìn)行存錢及取錢操作。同時(shí)創(chuàng)建多個(gè)線程對象,在多個(gè)線程對象中對同一銀行賬戶進(jìn)行存錢及取錢操作,要求加入同步處理,保證數(shù)據(jù)的一致性。按“工單6-1”要求完成任務(wù)同步訓(xùn)練§6-2餐館點(diǎn)餐場景模擬Java語言程序設(shè)計(jì)教學(xué)目標(biāo)任務(wù)分析

某個(gè)餐館,有一個(gè)廚師和一個(gè)服務(wù)員,服務(wù)員必須等待廚師準(zhǔn)備好食物才能上菜。當(dāng)廚師準(zhǔn)備好食物時(shí),他通知服務(wù)員,后者將得到食物,然后回去繼續(xù)等待。多個(gè)線程在處理同一個(gè)資源,并且任務(wù)不同時(shí),為了避免對同一共享資源的爭奪,需要使用線程間通信機(jī)制。目錄1線程通信機(jī)制為什么要線程通信23死鎖一、為什么要線程通信

多個(gè)線程并發(fā)執(zhí)行時(shí),在默認(rèn)情況下CPU是隨機(jī)切換線程的,當(dāng)需要多個(gè)線程來共同完成一件任務(wù),并且希望它們有規(guī)律的執(zhí)行,那么多線程之間需要一些協(xié)調(diào)通信,以此來達(dá)到多線程共同操作一份數(shù)據(jù)。多線程之間的通信能夠避免對同一共享變量的爭奪。二、線程通信機(jī)制

線程通信機(jī)制通過線程之間的“握手機(jī)制”來進(jìn)行的,這種握手可以通過Object的方法wait()和notify()來安全的實(shí)現(xiàn),也可以通過條件對象來實(shí)現(xiàn)。

在一個(gè)線程進(jìn)行了規(guī)定操作后,就進(jìn)入等待狀態(tài)(wait),等待其他線程執(zhí)行完他們的指定代碼過后再將其喚醒(notify)。典型應(yīng)用:生產(chǎn)者/消費(fèi)者模式wait(longmills):接受毫秒數(shù)作參數(shù),含義與sleep()方法里參數(shù)的意思相同,都是指“在此期間停止”。不同之處在于,對于wait(longmills)而言:1)在wait()調(diào)用期間對象鎖是釋放的。2)可以通過notify()、notifyAll(),或者時(shí)間到期,從wait()中恢復(fù)執(zhí)行。無參wait():wait()將無限等待下去,直到線程接收到notify()或notifyAll()消息。一般情況下,在等待某個(gè)條件時(shí)(這個(gè)條件必須由當(dāng)前方法以外的因素才能改變,一般由另一個(gè)線程所改變),就應(yīng)該使用wait()。因?yàn)槿绻诰€程里測試條件的時(shí)候空等會(huì)極大的占用CPU時(shí)間,而wait()允許在等待外部條件的時(shí)候讓線程休眠,只有在收到notify()或notifyAll()的時(shí)候線程才喚醒,并對變化進(jìn)行檢查。二、線程通信機(jī)制注意:wait()、notify()以及notifyAll()是Object類的方法,wait()可以放進(jìn)任何同步控制方法里,也必須放在同步方法或代碼塊里。sleep()是Thread類的方法,可以在非同步控制方法里調(diào)用二、線程通信機(jī)制二、線程通信機(jī)制

條件對象(Condition)是在JavaSE5.0中引入的。條件對象與鎖對象一起使用,一個(gè)鎖對象可以有一個(gè)或多個(gè)相關(guān)的條件對象,通過鎖對象的newCondition()方法可以獲得一個(gè)條件對象。Condition接口為它的子類提供了await()、signal()和signalAll()三個(gè)方法,它們的使用方法與wait()、notify()和notifyAll(

溫馨提示

  • 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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論