java程序設(shè)計(jì)任務(wù)式教程 課件 6- 多線程_第1頁
java程序設(shè)計(jì)任務(wù)式教程 課件 6- 多線程_第2頁
java程序設(shè)計(jì)任務(wù)式教程 課件 6- 多線程_第3頁
java程序設(shè)計(jì)任務(wù)式教程 課件 6- 多線程_第4頁
java程序設(shè)計(jì)任務(wù)式教程 課件 6- 多線程_第5頁
已閱讀5頁,還剩68頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

JaVa程序設(shè)計(jì)任務(wù)式教程01任務(wù)6-1模擬紅綠燈系統(tǒng)02任務(wù)6-2模擬環(huán)保檢測系統(tǒng)04任務(wù)6-4模擬在線購物網(wǎng)站目錄CONTNETS單元六

多線程03任務(wù)6-3模擬銀行取款系統(tǒng)單元目標(biāo)能夠使用三種方式創(chuàng)建線程。能夠設(shè)置線程的優(yōu)先級(jí)、休眠、讓步、插隊(duì)、同步機(jī)制和鎖機(jī)制。能夠使用線程與線程控制分別實(shí)現(xiàn)模擬紅綠燈系統(tǒng)與環(huán)保檢測系統(tǒng)。能夠靈活運(yùn)用線程的單例模式與線程池。能夠使用線程同步與線程池分別實(shí)現(xiàn)模擬銀行取款系統(tǒng)與在線購物網(wǎng)站。通過對(duì)多線程編程的學(xué)習(xí),培養(yǎng)學(xué)生分析和解決并發(fā)問題的能力。通過模擬現(xiàn)實(shí)生活中的案例,提升學(xué)生的編程能力和邏輯思維能力。知識(shí)目標(biāo)能力目標(biāo)素養(yǎng)目標(biāo)學(xué)習(xí)目標(biāo)理解線程的定義與線程的生命周期。掌握創(chuàng)建線程的三種方式。掌握線程的優(yōu)先級(jí)、休眠、讓步、插隊(duì)的設(shè)置。掌握線程的同步機(jī)制、鎖機(jī)制、雙重檢查枷鎖機(jī)制的設(shè)置。掌握餓漢式與懶漢式的設(shè)置。掌握線程池的原理與創(chuàng)建方式。01任務(wù)6-1模擬紅綠燈系統(tǒng)線程概述繼承Thread類創(chuàng)建線程實(shí)現(xiàn)Runnable接口創(chuàng)建線程實(shí)現(xiàn)Callable接口創(chuàng)建線程線程的生命周期任務(wù)6-1模擬紅綠燈系統(tǒng)-線程的創(chuàng)建與啟動(dòng)線程概述在多任務(wù)操作系統(tǒng)中,每個(gè)運(yùn)行的程序都是一個(gè)進(jìn)程,用來執(zhí)行不同的任務(wù),而在一個(gè)進(jìn)程中還可以有多個(gè)執(zhí)行單元同時(shí)運(yùn)行,來同時(shí)完成一個(gè)或多個(gè)程序任務(wù),這些執(zhí)行單元可以看作程序執(zhí)行的多條線索,稱為線程。操作系統(tǒng)的每一個(gè)進(jìn)程中都至少存在一個(gè)線程,當(dāng)一個(gè)Java程序啟動(dòng)時(shí),就會(huì)產(chǎn)生一個(gè)進(jìn)程,該進(jìn)程中會(huì)默認(rèn)創(chuàng)建一個(gè)線程,在這個(gè)線程上會(huì)運(yùn)行main()方法中的代碼。任務(wù)6-1模擬紅綠燈系統(tǒng)-線程的創(chuàng)建與啟動(dòng)線程概述在多任務(wù)操作系統(tǒng)中,每個(gè)運(yùn)行的程序都是一個(gè)進(jìn)程,用來執(zhí)行不同的任務(wù),而在一個(gè)進(jìn)程中還可以有多個(gè)執(zhí)行單元同時(shí)運(yùn)行,來同時(shí)完成一個(gè)或多個(gè)程序任務(wù),這些執(zhí)行單元可以看作程序執(zhí)行的多條線索,稱為線程。操作系統(tǒng)的每一個(gè)進(jìn)程中都至少存在一個(gè)線程,當(dāng)一個(gè)Java程序啟動(dòng)時(shí),就會(huì)產(chǎn)生一個(gè)進(jìn)程,該進(jìn)程中會(huì)默認(rèn)創(chuàng)建一個(gè)線程,在這個(gè)線程上會(huì)運(yùn)行main()方法中的代碼多線程程序在運(yùn)行時(shí),每個(gè)線程之間都是獨(dú)立的,它們可以并發(fā)執(zhí)行。程序中的單線程和多線程的主要區(qū)別可以通過一張圖示來簡單說明任務(wù)6-1模擬紅綠燈系統(tǒng)-線程的創(chuàng)建與啟動(dòng)繼承Thread類創(chuàng)建線程Thread類是java.lang包下的一個(gè)線程類,用來實(shí)現(xiàn)Java多線程。使用繼承Thread類的方式創(chuàng)建與啟動(dòng)線程的主要步驟如下:(1)創(chuàng)建一個(gè)Thread線程類的子類(子線程),并重寫Thread類的run()方法;(2)創(chuàng)建Thread子類的實(shí)例對(duì)象,并調(diào)用start()方法啟動(dòng)線程。任務(wù)6-1模擬紅綠燈系統(tǒng)-線程的創(chuàng)建與啟動(dòng)繼承Thread類創(chuàng)建線程例6-1所示,通過一個(gè)例子演示如何通過繼承Thread類的方式創(chuàng)建多線程,首先在Eclipse中創(chuàng)建一個(gè)名為Chapter06的程序,在該程序的src文件夾中創(chuàng)建名為com.example.thread的包,在該包中創(chuàng)建ExampleThread類,在該類中實(shí)現(xiàn)創(chuàng)建與啟動(dòng)線程,詳見ExampleThread.java1 packagecom.example.thread;2 classMyThreadextendsThread{3 //創(chuàng)建子線程類的有參構(gòu)造方法,參數(shù)為線程名稱4 publicMyThread(Stringname){5 super(name);6 }7 //重寫Thread類的run()方法8 publicvoidrun(){9 inti=0;10 while(i++<5){11 System.out.println(Thread.currentThread().getName()12 +"的run()方法在運(yùn)行");13 }14 }15 }16 publicclassExampleThread{17 publicstaticvoidmain(String[]args){18 //2.創(chuàng)建MyThread1實(shí)例對(duì)象19 MyThreadthread1=newMyThread("thread1");20 //調(diào)用start()方法啟動(dòng)線程21 thread1.start();22 //創(chuàng)建并啟動(dòng)另一個(gè)線程myThread223 MyThreadthread2=newMyThread("thread2");24 thread2.start();25 }26 }任務(wù)6-1模擬紅綠燈系統(tǒng)-線程的創(chuàng)建與啟動(dòng)繼承Thread類創(chuàng)建線程上述代碼中,第2~15行代碼定義了一個(gè)MyThread類繼承Thread類,并重寫了run()方法,其中currentThread()方法是Thread類的靜態(tài)方法,用于獲取當(dāng)前線程對(duì)象,getName()方法用于獲取線程名稱。第19、23行代碼創(chuàng)建了兩個(gè)線程實(shí)例,并指定線程名稱為thread1和thread2。第21、24行代碼調(diào)用start()方法啟動(dòng)線程。運(yùn)行結(jié)果如圖任務(wù)6-1模擬紅綠燈系統(tǒng)-線程的創(chuàng)建與啟動(dòng)實(shí)現(xiàn)Runnable接口創(chuàng)建線程Java中一個(gè)類只能繼承一個(gè)父類,而通過繼承Thread類來創(chuàng)建線程就意味著將線程的功能與類的繼承耦合在一起,導(dǎo)致無法再繼承其他類。而實(shí)現(xiàn)Runnable接口的方式,可以避免Java單繼承所帶來的局限性,使類能夠繼承其他類,提高代碼的靈活性。使用實(shí)現(xiàn)Runnable接口的方式創(chuàng)建并啟動(dòng)線程的具體步驟如下。(1)定義一個(gè)類實(shí)現(xiàn)Runnable接口,并重寫該接口中的run()方法。(2)創(chuàng)建實(shí)現(xiàn)Runnable接口的類的對(duì)象,將該對(duì)象作為參數(shù)傳入到創(chuàng)建Thread對(duì)象的構(gòu)造方法中,這樣就實(shí)現(xiàn)了將程序的任務(wù)邏輯與線程對(duì)象分離的效果。(3)調(diào)用Thread對(duì)象的start()方法,啟動(dòng)線程。任務(wù)6-1模擬紅綠燈系統(tǒng)-線程的創(chuàng)建與啟動(dòng)例6-2所示,通過一個(gè)例子演示使用Runnable接口的方式來創(chuàng)建和啟動(dòng)線程,首先在Chapter06程序的com.example.thread包中創(chuàng)建ExampleRunnable類,在該類中實(shí)現(xiàn)創(chuàng)建與啟動(dòng)線程,詳見ExampleRunnable.java1 packagecom.example.thread;2 classMyRunnableimplementsRunnable{3 publicvoidrun(){4 for(inti=1;i<=5;i++){5 System.out.println("線程"+Thread.currentThread().getId()+":"+i); 6 try{7 Thread.sleep(1000);//讓線程休眠一段時(shí)間,模擬耗時(shí)操作

8 }catch(InterruptedExceptione){9 e.printStackTrace();10 }11 }12 }13 }14 publicclassExampleRunnable{15 publicstaticvoidmain(String[]args){16 MyRunnablemyRunnable=newMyRunnable();17 Threadthread1=newThread(myRunnable);18 Threadthread2=newThread(myRunnable);19 thread1.start();20 thread2.start();21 }22 }實(shí)現(xiàn)Runnable接口創(chuàng)建線程任務(wù)6-1模擬紅綠燈系統(tǒng)-線程的創(chuàng)建與啟動(dòng)上述代碼中,第5~6行代碼中的“Thread.currentThread().getId()”表示返回當(dāng)前線程的唯一標(biāo)識(shí)符,即線程ID。第18~19行代碼創(chuàng)建了兩個(gè)Thread對(duì)象,并將MyRunnable對(duì)象作為參數(shù)傳遞給它們,然后調(diào)用start()方法啟動(dòng)線程thread1與thread2。運(yùn)行結(jié)果如圖實(shí)現(xiàn)Runnable接口創(chuàng)建線程任務(wù)6-1模擬紅綠燈系統(tǒng)-線程的創(chuàng)建與啟動(dòng)實(shí)現(xiàn)Callable接口創(chuàng)建線程JDK5.0開始,Java提供了Callable接口,允許開發(fā)人員在實(shí)現(xiàn)Callable接口的類中重寫call()方法可以作為線程的執(zhí)行體。與run()方法不同,call()方法有返回值且可以拋出異常。使用實(shí)現(xiàn)Callable接口的方式創(chuàng)建并啟動(dòng)線程的具體步驟如下。(1)定義Callable接口實(shí)現(xiàn)類,指定返回值類型,并重寫call()方法。(2)創(chuàng)建Callable實(shí)現(xiàn)類的實(shí)例,使用FutureTask類包裝Callable對(duì)象,F(xiàn)utureTask對(duì)象封裝了Callable對(duì)象的call()方法的返回值。(3)使用FutureTask對(duì)象作為Thread對(duì)象的target創(chuàng)建并啟動(dòng)新線程。(4)調(diào)用FutureTask對(duì)象的get()方法獲得子線程執(zhí)行結(jié)束后的返回值。Callable接口不是Runnable接口的子接口,因此不能直接作為Thread的目標(biāo)(target)運(yùn)行,因?yàn)閏all()方法是在實(shí)現(xiàn)Callable接口的類中定義的,JDK5.0還提供了一個(gè)Future接口來代表call()方法的返回值。FutureTask類是Future接口的實(shí)現(xiàn)類,同時(shí),它也實(shí)現(xiàn)了Runnable接口,因此可以作為Thread類的target任務(wù)6-1模擬紅綠燈系統(tǒng)-線程的創(chuàng)建與啟動(dòng)實(shí)現(xiàn)Callable接口創(chuàng)建線程Future接口的方法方法聲明功能描述booleancancel(booleanb)試圖取消對(duì)此任務(wù)的執(zhí)行Vget()如有必要,等待計(jì)算完成,然后獲取其結(jié)果Vget(longtimeout,TimeUnitunit)如有必要,最多等待為使計(jì)算完成所給定的時(shí)間之后,獲取其結(jié)果(如果結(jié)果可用)booleanisCancelled()如果在任務(wù)正常完成前將其取消,則返回truebooleanisDone()如果任務(wù)已完成,則返回true任務(wù)6-1模擬紅綠燈系統(tǒng)-線程的創(chuàng)建與啟動(dòng)實(shí)現(xiàn)Callable接口創(chuàng)建線程如例6-3所示,通過一個(gè)例子演示使用實(shí)現(xiàn)Callable接口的方式創(chuàng)建和啟動(dòng)線程,并獲取1~100的整數(shù)之和。首先在Chapter06程序的com.example.thread包中創(chuàng)建ExampleCallable類,在該類中通過FutureTask的get()方法獲得新線程的執(zhí)行結(jié)果,并將1~100的整數(shù)之和的結(jié)果輸出到控制臺(tái)中,詳見ExampleCallable.java1 packagecom.example.thread;2 importjava.util.concurrent.*;3 publicclassExampleCallable{4 publicstaticvoidmain(String[]args)throwsException{5 MyCallablemyCallable=newMyCallable();6 FutureTask<Integer>futureTask=newFutureTask<>(myCallable);7 Threadthread=newThread(futureTask);8 thread.start();9 intresult=futureTask.get();10 System.out.println("計(jì)算結(jié)果:"+result);11 }12 }13 classMyCallableimplementsCallable<Integer>{14 @Override15 publicIntegercall()throwsException{16 intsum=0;17 for(inti=1;i<=100;i++){18 sum+=i;19 }20 returnsum;21 }22 } 任務(wù)6-1模擬紅綠燈系統(tǒng)-線程的創(chuàng)建與啟動(dòng)實(shí)現(xiàn)Callable接口創(chuàng)建線程上述代碼中,第13~22行代碼創(chuàng)建了MyCallable類實(shí)現(xiàn)Callable接口,并在call()方法中使用for循環(huán)實(shí)現(xiàn)了1~100的整數(shù)求和邏輯。第6行代碼使用FutureTask封裝MyCallable對(duì)象,第7~8行代碼通過Thread創(chuàng)建一個(gè)新線程并啟動(dòng)該線程。第9行代碼調(diào)用FutureTask的get()方法獲得子線程的執(zhí)行結(jié)果。運(yùn)行結(jié)果如圖任務(wù)6-1模擬紅綠燈系統(tǒng)-線程的生命周期

線程有新建(New)、就緒(Runnable)、運(yùn)行(Running)、阻塞(Blocked)和死亡(Terminated)五種狀態(tài),線程從新建到死亡的過程稱為線程的生命周期,線程的生命周期及狀態(tài)轉(zhuǎn)換,如圖任務(wù)6-1模擬紅綠燈系統(tǒng)-任務(wù)實(shí)現(xiàn)1.在Chapter06程序中創(chuàng)建com.example.task包,用于存放本單元中每個(gè)任務(wù)的代碼文件。2.在com.example.task包中創(chuàng)建TrafficLight類,用于實(shí)現(xiàn)模擬紅綠燈系統(tǒng)。3.使用3個(gè)常量定義紅燈、黃燈和綠燈亮起后的時(shí)間。4.定義一個(gè)changeLight()方法用于切換紅綠燈的3種狀態(tài)。5.在main()方法中創(chuàng)建TrafficLight類的實(shí)例,并啟動(dòng)一個(gè)線程,在線程中調(diào)用changeLight()方法開啟紅綠燈的狀態(tài)切換。代碼參考教材中的TrafficLight.java任務(wù)6-1模擬紅綠燈系統(tǒng)-任務(wù)實(shí)現(xiàn)模擬紅綠燈系統(tǒng)的運(yùn)行結(jié)果如圖02任務(wù)6-2模擬環(huán)保檢測系統(tǒng)線程優(yōu)先級(jí)線程休眠線程讓步線程插隊(duì)后臺(tái)線程任務(wù)6-2模擬環(huán)保檢測系統(tǒng)-線程控制操作線程優(yōu)先級(jí)所有處于就緒狀態(tài)的線程根據(jù)優(yōu)先級(jí)存放在可運(yùn)行池中,優(yōu)先級(jí)低的線程運(yùn)行機(jī)會(huì)較少,優(yōu)先級(jí)高的線程運(yùn)行機(jī)會(huì)更多。Thread類的setPriority(intnewPriority)方法和getPriority()方法分別用于設(shè)置優(yōu)先級(jí)和讀取優(yōu)先級(jí)。優(yōu)先級(jí)用整數(shù)表示,取值范圍1~10,除了直接用數(shù)字表示線程的優(yōu)先級(jí),還可以用Thread類中提供的三個(gè)靜態(tài)常量來表示線程的優(yōu)先級(jí),如表常量聲明功能描述staticintMAX_PRIORITY取值為10,表示最高優(yōu)先級(jí)staticintNORM_PRIORITY取值為5,表示默認(rèn)優(yōu)先級(jí)staticintMIN_PRIORITY取值為1,表示最低優(yōu)先級(jí)任務(wù)6-2模擬環(huán)保檢測系統(tǒng)-線程控制操作線程優(yōu)先級(jí)例6-4所示,通過一個(gè)例子演示線程優(yōu)先級(jí)的使用。首先在Chapter06程序的com.example.thread包中創(chuàng)建ExamplePriority類,然后在該類中演示線程優(yōu)先級(jí)的使用,詳見ExamplePriority.java1 packagecom.example.thread;2 publicclassExamplePriority{3 publicstaticvoidmain(String[]args){4 //創(chuàng)建SubThread實(shí)例

5 SubThreadst1=newSubThread("優(yōu)先級(jí)低的線程"); 6 SubThreadst2=newSubThread("優(yōu)先級(jí)高的線程");7 //設(shè)置優(yōu)先級(jí)

8 st1.setPriority(Thread.MIN_PRIORITY); 9 st2.setPriority(Thread.MAX_PRIORITY);10 //開啟線程

11 st1.start(); 12 st2.start();13 }14 }15 classSubThreadextendsThread{16 publicSubThread(Stringname){17 super(name);18 }19 publicvoidrun(){//重寫run()方法

20 for(inti=0;i<10;i++){21 if(i%2!=0){22 System.out.println(Thread.23 currentThread().getName()+":"+i);………任務(wù)6-2模擬環(huán)保檢測系統(tǒng)-線程控制操作線程優(yōu)先級(jí)上述代碼中,第15~27行代碼定義了SubThread類繼承Thread類,在該類中重寫了run()方法,在run()方法內(nèi)循環(huán)打印小于10的奇數(shù)。第5~6行代碼創(chuàng)建了兩個(gè)SubThread類的實(shí)例,并指定線程的名分別是“優(yōu)先級(jí)低的線程”與“優(yōu)先級(jí)高的線程”。第8~9行代碼調(diào)用setPriority()方法設(shè)置線程的優(yōu)先級(jí),第11~12行代碼調(diào)用start()方法啟動(dòng)線程。運(yùn)行結(jié)果如圖任務(wù)6-2模擬環(huán)保檢測系統(tǒng)-線程控制操作線程休眠前面講解了線程的優(yōu)先級(jí),可以發(fā)現(xiàn)將需要后執(zhí)行的線程設(shè)置為低優(yōu)先級(jí),也有一定幾率先執(zhí)行該線程,可以用Thread類的靜態(tài)方法sleep()來解決這一問題,sleep()方法有兩種重載形式,具體示例如下:sleep(longmillis)sleep(longmillis,intnanos)上述示例中是sleep()方法的兩種重載形式,前者參數(shù)millis是指定線程休眠的毫秒數(shù),后者參數(shù)millis和nanos分別用于指定線程休眠的毫秒數(shù)和毫微秒數(shù)。正在執(zhí)行的線程調(diào)用sleep()方法可以進(jìn)入阻塞狀態(tài),也叫線程休眠,在休眠時(shí)間內(nèi),即使系統(tǒng)中沒有其他可執(zhí)行的線程,該線程也不會(huì)執(zhí)行,當(dāng)休眠時(shí)間結(jié)束后該線程才可以執(zhí)行任務(wù)6-2模擬環(huán)保檢測系統(tǒng)-線程控制操作線程休眠如例6-5所示,通過一個(gè)例子演示線程的休眠。首先在Chapter06程序的com.example.thread包中創(chuàng)建AlarmClock類,然后在該類中使用線程休眠模擬一個(gè)定時(shí)鬧鐘的場景,詳見AlarmClock.java1 packagecom.example.thread;2 importjava.text.SimpleDateFormat;3 importjava.util.Date;4 publicclassAlarmClock{5 //設(shè)定鬧鐘在5秒后響起

6 privatestaticfinallongWAKE_UP_TIME_MILLIS=5000;7 publicstaticvoidmain(String[]args){8 System.out.println("設(shè)置鬧鐘"+(WAKE_UP_TIME_MILLIS/1000)9 +"秒后響起");10 System.out.println("當(dāng)前時(shí)間:"+newSimpleDateFormat("hh:mm:ss").11 format(newDate()));12 //模擬鬧鐘的線程

13 ThreadalarmClockThread=newThread(()->{14 try{15 //設(shè)置線程休眠5秒

16 Thread.sleep(WAKE_UP_TIME_MILLIS);17 //調(diào)用鬧鐘響起方法

18 ringAlarm();19 }catch(InterruptedExceptione){20 e.printStackTrace();21 }22 });23 alarmClockThread.start();24 }25 //模擬鬧鐘響起

26 privatestaticvoidringAlarm(){27 System.out.println("起床啦,太陽已經(jīng)升起來啦!");28 System.out.println("當(dāng)前時(shí)間:"+newSimpleDateFormat("hh:mm:ss").29 format(newDate()));30 }31 } 任務(wù)6-2模擬環(huán)保檢測系統(tǒng)-線程控制操作線程休眠運(yùn)行結(jié)果如圖任務(wù)6-2模擬環(huán)保檢測系統(tǒng)-線程控制操作線程讓步Thread類還提供一個(gè)yield()方法,它與sleep()方法類似,它也可以讓當(dāng)前正在執(zhí)行的線程暫停,但是yield()方法不會(huì)使線程阻塞,只是將線程轉(zhuǎn)換為就緒狀態(tài),也就是讓當(dāng)前線程暫停一下,線程調(diào)度器重新調(diào)度一次,有可能還會(huì)將暫停的程序調(diào)度出來繼續(xù)執(zhí)行,這也稱為線程讓步。任務(wù)6-2模擬環(huán)保檢測系統(tǒng)-線程控制操作線程讓步如例6-6所示,通過一個(gè)例子演示線程讓步。首先在Chapter06程序的com.example.thread包中創(chuàng)建ExampleYield類,然后在該類中演示線程讓步,詳見ExampleYield.java1 packagecom.example.thread;2 publicclassExampleYield{3 publicstaticvoidmain(String[]args){4 YieldThreadyt=newYieldThread();//創(chuàng)建YieldThread實(shí)例

5 newThread(yt,"線程1").start();//創(chuàng)建并開啟線程

6 newThread(yt,"線程2").start();7 }8 }9 classYieldThreadimplementsRunnable{10 publicvoidrun(){//重寫run()方法

11 for(inti=1;i<=6;i++){12 System.out.println(Thread.currentThread().getName()13 +":"+i);14 if(i%3==0){15 Thread.yield();16 }17 }18 }19 } 任務(wù)6-2模擬環(huán)保檢測系統(tǒng)-線程控制操作線程讓步上述代碼中,第9~19行代碼定義了YieldThread類實(shí)現(xiàn)Runnable接口,并重寫了run()方法,在run()方法內(nèi)循環(huán)打印變量i,當(dāng)變量i能被3整除時(shí),調(diào)用yield()方法讓線程讓步。第4~6行代碼首先創(chuàng)建YieldThread類的實(shí)例,然后創(chuàng)建并開啟兩個(gè)線程。運(yùn)行結(jié)果如圖任務(wù)6-2模擬環(huán)保檢測系統(tǒng)-線程控制操作線程插隊(duì)Thread類提供了一個(gè)join()方法,當(dāng)某個(gè)線程在執(zhí)行中調(diào)用其他線程的join()方法時(shí),此線程將被阻塞,直到被join()方法加入的線程執(zhí)行完為止,也稱為線程插隊(duì)。任務(wù)6-2模擬環(huán)保檢測系統(tǒng)-線程控制操作線程插隊(duì)如例6-7所示,首先在Chapter06程序的com.example.thread包中創(chuàng)建ExampleJoin類,然后在該類中使用線程插隊(duì)模擬烤面包機(jī)工作的過程,將每個(gè)烤面包周期看作是一個(gè)線程的運(yùn)行,而sleep()方法用來模擬烤面包所需的時(shí)間,join()方法用來等待烤面包機(jī)線程結(jié)束。詳見ExampleJoin.java1packagecom.example.thread;2publicclassExampleJoin{3 publicstaticvoidmain(String[]args){4 //創(chuàng)建并啟動(dòng)一個(gè)烤面包機(jī)線程

5 ThreadtoasterThread=newThread(newToasterRunnable());6 toasterThread.start();7 //主線程等待烤面包機(jī)線程完成

8 try{9 toasterThread.join();10 }catch(InterruptedExceptione){11 e.printStackTrace();12 }13 System.out.println("所有面包片都已經(jīng)烤好!");14 }15 //創(chuàng)建一個(gè)實(shí)現(xiàn)了Runnable接口的烤面包機(jī)類ToasterRunnable16 staticclassToasterRunnableimplementsRunnable{17 @Override18 publicvoidrun(){19 //假設(shè)我們要烤4片面包

20 for(inti=0;i<4;i++){21 //模擬放入面包片

22 System.out.println("放入第"+(i+1)+"片面包");23 try{24 Thread.sleep(3000);//模擬烤面包所需的時(shí)間為3秒

25 }catch(InterruptedExceptione){26 e.printStackTrace();27 return;28 }29 //模擬取出烤好的面包片

30 System.out.println("第"+(i+1)+"片面包已經(jīng)烤好");31 }32 }33 }34} 任務(wù)6-2模擬環(huán)保檢測系統(tǒng)-線程控制操作線程插隊(duì)上述代碼中,第16~33行代碼定義了ToasterRunnable類實(shí)現(xiàn)Runnable接口,在該類中實(shí)現(xiàn)了run()方法,在run()方法中通過for循環(huán)模擬烤4片面包,在for循環(huán)中調(diào)用sleep()方法模擬烤面包片需要的時(shí)間。第5~6行代碼首先創(chuàng)建一個(gè)線程對(duì)象toasterThread,然后開啟該線程。第9行代碼調(diào)用join()方法等待toasterThread線程執(zhí)行結(jié)束,toasterThread線程執(zhí)行結(jié)束后,主線程才繼續(xù)執(zhí)行,程序調(diào)用println()方法輸出“所有面包片都已經(jīng)烤好!”信息。運(yùn)行結(jié)果如圖任務(wù)6-2模擬環(huán)保檢測系統(tǒng)-線程控制操作后臺(tái)線程線程中還有一種后臺(tái)線程,它是為其他線程提供服務(wù)的,又稱為“守護(hù)線程”或“精靈線程”,JVM的垃圾回收線程就是典型的后臺(tái)線程。如果所有的前臺(tái)線程都死亡,后臺(tái)線程會(huì)自動(dòng)死亡。當(dāng)整個(gè)虛擬機(jī)中只剩下后臺(tái)線程,程序就沒有繼續(xù)運(yùn)行的必要了,所以虛擬機(jī)也就退出了。若想要將一個(gè)線程設(shè)置為后臺(tái)線程,可以調(diào)用Thread類的setDaemon(booleanon)方法,將參數(shù)指定為true即可,Thread類還提供了一個(gè)isDaemon()方法,用于判斷一個(gè)線程是否是后臺(tái)線程。任務(wù)6-2模擬環(huán)保檢測系統(tǒng)-線程控制操作后臺(tái)線程如例6-8所示,通過一個(gè)例子演示后臺(tái)線程。首先在Chapter06程序的com.example.thread包中創(chuàng)建ExampleBack類,然后在該類中使用后臺(tái)線程模擬一個(gè)智能溫度控制系統(tǒng),這個(gè)系統(tǒng)會(huì)在后臺(tái)運(yùn)行,不斷地檢查當(dāng)前室內(nèi)溫度,并根據(jù)預(yù)設(shè)規(guī)則調(diào)整室內(nèi)溫度。詳見ExampleBack.java......45publicstaticvoidmain(String[]args){46 //創(chuàng)建并啟動(dòng)后臺(tái)線程

47 ThreadmonitorThread=newTemperatureMonitorThread();48 monitorThread.setDaemon(true);//設(shè)置為守護(hù)線程

49 monitorThread.start();50 //模擬用戶輸入來改變房間溫度

51@SuppressWarnings("resource")52 Scannerscanner=newScanner(System.in);53 while(true){54 System.out.println("請(qǐng)輸入房間溫度(0-100,或輸入'exit'退出):");55 Stringinput=scanner.nextLine();56 if("exit".equalsIgnoreCase(input)){57 System.exit(0);//退出程序

58 }59 try{60 setRoomTemperature(Integer.parseInt(input));61 }catch(NumberFormatExceptione){62 System.out.println("輸入無效,請(qǐng)輸入一個(gè)整數(shù)。");63 }64 }65 }66}任務(wù)6-2模擬環(huán)保檢測系統(tǒng)-線程控制操作后臺(tái)線程上述代碼中,第10~35行代碼定義了TemperatureMonitorThread類繼承Thread類,并重寫run()方法,在該方法中調(diào)用while循環(huán)與sleep()方法實(shí)現(xiàn)每隔5秒檢查一次房間內(nèi)的溫度。第37~44行代碼定義了setRoomTemperature()方法,用于輸出更新后的房間溫度。第47~49行代碼首先創(chuàng)建TemperatureMonitorThread類的對(duì)象monitorThread,然后調(diào)用setDaemon()方法將monitorThread線程設(shè)置為后臺(tái)線程,最后調(diào)用start()方法開啟該線程。后臺(tái)線程的運(yùn)行結(jié)果如圖1.在com.example.task包中創(chuàng)建EnProSystem類,用于實(shí)現(xiàn)模擬環(huán)保檢測系統(tǒng)。2.創(chuàng)建一個(gè)PollutionSource類繼承Thread類,在該類的run()方法中模擬檢測環(huán)境的污染級(jí)別。3.在EnProSystem類中創(chuàng)建三個(gè)不同級(jí)別的污染源,每個(gè)污染源都是一個(gè)線程。4.設(shè)置三個(gè)污染源線程的優(yōu)先級(jí)并啟動(dòng)線程。5.調(diào)用join()方法等待所有線程執(zhí)行完成后,輸出“所有污染源檢測完成”。代碼參考教材中的EnProSystem.java任務(wù)6-2模擬環(huán)保檢測系統(tǒng)-線程控制操作模擬環(huán)保檢測系統(tǒng)的運(yùn)行結(jié)果如圖任務(wù)6-2模擬環(huán)保檢測系統(tǒng)-線程控制操作03任務(wù)6-3模擬銀行取款系統(tǒng)線程安全線程同步機(jī)制鎖機(jī)制任務(wù)6-3模擬銀行取款系統(tǒng)-線程同步線程安全線程安全是指當(dāng)多個(gè)線程并發(fā)訪問共享資源時(shí),如果對(duì)這些資源的訪問是線程安全的,那么就可以保證在任何時(shí)候,只有一個(gè)線程能夠修改這些資源,從而避免了數(shù)據(jù)不一致或臟讀等問題。任務(wù)6-3模擬銀行取款系統(tǒng)-線程同步線程安全如例6-9所示,演示窗口賣票的經(jīng)典問題,假如總票數(shù)為6,有4個(gè)窗口在賣票。首先在Chapter06程序的com.example.thread包中創(chuàng)建ExampleTicket類,然后在該類中創(chuàng)建并開啟4個(gè)線程模擬4個(gè)賣票的窗口,詳見ExampleTicket.java……4 Ticketticket=newTicket();5 Threadt1=newThread(ticket,"火車站窗口1");6 Threadt2=newThread(ticket,"火車站窗口2");7 Threadt3=newThread(ticket,"火車站窗口3");8 Threadt4=newThread(ticket,"火車站窗口4");9 t1.start();10 t2.start();11 t3.start();12 t4.start();13 }14}15classTicketimplementsRunnable{16 privateintticket=6;17 publicvoidrun(){18 for(inti=0;i<6;i++){19 if(ticket>0){20 try{21 Thread.sleep(100);22 }catch(InterruptedExceptione){23 e.printStackTrace();24 }25 System.out.println(Thread.currentThread().getName()+"賣出第"+ticket+"張票,還剩"+--ticket+"張票");……任務(wù)6-3模擬銀行取款系統(tǒng)-線程同步線程安全上述代碼中,第21行代碼調(diào)用sleep()方法讓當(dāng)前線程睡眠100毫秒,當(dāng)前線程處于休眠狀態(tài)時(shí),讓其他線程去搶資源,可以讓線程安全問題更明顯。在實(shí)際項(xiàng)目中,sleep()方法經(jīng)常用來模擬網(wǎng)絡(luò)延遲。運(yùn)行結(jié)果如圖任務(wù)6-3模擬銀行取款系統(tǒng)-線程同步線程同步機(jī)制同步代碼塊同步代碼塊是指在代碼塊前加上synchronized關(guān)鍵字,用于解決多線程并發(fā)執(zhí)行時(shí)可能產(chǎn)生的資源沖突問題。同步代碼塊表示同一時(shí)間只能有一個(gè)線程進(jìn)入到該代碼塊中執(zhí)行,從而確保共享資源的唯一性和準(zhǔn)確性。同步代碼塊的語法格式如下。synchronized(this){ //操作共享數(shù)據(jù)的代碼}上述語法格式中,synchronized關(guān)鍵字后括號(hào)里的this就是同步鎖,當(dāng)線程執(zhí)行同步代碼塊時(shí),首先會(huì)檢查同步鎖的標(biāo)志位,默認(rèn)情況下標(biāo)志位為1,線程會(huì)執(zhí)行同步代碼塊,同時(shí)將標(biāo)志位改為0,當(dāng)?shù)诙€(gè)線程執(zhí)行同步代碼塊前,檢查到標(biāo)志位為0,第二個(gè)線程會(huì)進(jìn)入阻塞狀態(tài),直到前一個(gè)線程執(zhí)行完同步代碼塊內(nèi)的操作,標(biāo)志位重新改為1,第二個(gè)線程才有可能進(jìn)入同步代碼塊。任務(wù)6-3模擬銀行取款系統(tǒng)-線程同步線程同步機(jī)制同步代碼塊通過修改例6-11中的代碼來演示使用同步代碼塊解決線程安全問題的方式,修改后的主要代碼如下所示1......2classTicketimplementsRunnable{3privateintticket=6;4publicvoidrun(){5for(inti=0;i<6;i++){6synchronized(this){7if(ticket>0){8try{9Thread.sleep(100);10}catch(InterruptedExceptione){11e.printStackTrace();12}13System.out.println(14Thread.currentThread().getName()+"賣出第"15+ticket+"張票,還剩"+--ticket+"張票");16}17}18}19}20}任務(wù)6-3模擬銀行取款系統(tǒng)-線程同步線程同步機(jī)制同步代碼塊上述代碼中,在run()方法的循環(huán)中,將變量ticket的操作都放在同步代碼塊中,當(dāng)使用同步代碼塊時(shí)必須指定一個(gè)需要同步的對(duì)象作為同步鎖,一般使用當(dāng)前對(duì)象(this)即可。運(yùn)行結(jié)果如圖任務(wù)6-3模擬銀行取款系統(tǒng)-線程同步線程同步機(jī)制同步方法除了用同步代碼塊解決線程安全問題之外,Java還提供了同步方法,即使用synchronized關(guān)鍵字修飾方法,該方法就是同步方法。已知Java的每個(gè)對(duì)象都可以作為一個(gè)內(nèi)置鎖,當(dāng)用synchronized關(guān)鍵字修飾方法時(shí),內(nèi)置鎖會(huì)保護(hù)整個(gè)方法,在調(diào)用該方法前,需要獲得內(nèi)置鎖,否則當(dāng)前線程就處于阻塞狀態(tài)任務(wù)6-3模擬銀行取款系統(tǒng)-線程同步線程同步機(jī)制同步方法通過修改例6-11的代碼來演示使用同步方法解決線程安全問題的方式,修改后的代碼如下所示1......2classTicketimplementsRunnable{3privateintticket=6;4publicsynchronizedvoidrun(){5for(inti=0;i<6;i++){6if(ticket>0){7try{8Thread.sleep(100);9}catch(InterruptedExceptione){10e.printStackTrace();11}12System.out.println(13Thread.currentThread().getName()+"賣出第"14+ticket+"張票,還剩"+--ticket+"張票");15}16}17}18}任務(wù)6-3模擬銀行取款系統(tǒng)-線程同步線程同步機(jī)制同步方法上述代碼中,將run()方法用synchronized關(guān)鍵字修飾,此時(shí)run()方法就為同步方法。運(yùn)行結(jié)果如圖任務(wù)6-3模擬銀行取款系統(tǒng)-線程同步鎖機(jī)制由于synchronized有一個(gè)缺點(diǎn),那就是一個(gè)線程必須等待前一個(gè)線程執(zhí)行完之后才能去執(zhí)行,如果前一個(gè)線程有耗時(shí)操作,則后一個(gè)線程一直在等待的狀態(tài)中,這就導(dǎo)致程序不靈活且效率低下,所以在Java6中加入了Lock來解決這個(gè)問題。Lock接口是Java并發(fā)編程中提供的一個(gè)更靈活的鎖機(jī)制,它作為synchronized的一個(gè)替代,提供了更廣泛的鎖定操作。Lock接口由ReentrantLock類實(shí)現(xiàn),同步代碼塊和同步方法具有的功能Lock都有,除此之外Lock更強(qiáng)大,更體現(xiàn)面向?qū)ο蟆H蝿?wù)6-3模擬銀行取款系統(tǒng)-線程同步鎖機(jī)制例6-10所示,演示鎖機(jī)制解決線程安全的問題,首先創(chuàng)建ExampleLockTicket類,然后在該類中使用鎖機(jī)制解決4個(gè)窗口賣票的線程安全問題,詳見ExampleLockTicket.java4publicclassExampleLockTicket{5 privateinttickets=6;//假設(shè)總共有6張票

6 //使用ReentrantLock作為鎖

7 privatefinalLocklock=newReentrantLock();8 //售票方法

9 publicvoidsellTicket(){10 lock.lock();//獲取鎖

11 try{12 if(tickets>0){13 System.out.println(Thread.currentThread().getName()14+"賣出第"+tickets+"張票,還剩"+--tickets+"張票");15 }else{16 System.out.println(Thread.currentThread().getName()17+"票已售完");18 }19 }finally{20 lock.unlock();//釋放鎖

21 }22 }23 publicstaticvoidmain(String[]args){24 ExampleLockTicketseller=newExampleLockTicket();25 //創(chuàng)建并啟動(dòng)4個(gè)線程來模擬4個(gè)售票窗口

26 for(inti=0;i<4;i++){27 newThread(()->{28 while(true){//循環(huán)賣票直到票售完

29 seller.sellTicket();30 if(seller.tickets<=0){31 break;//票售完則退出循環(huán)

32 }33 try{34 Thread.sleep(100);//模擬售票間隔

35 }catch(InterruptedExceptione){36 e.printStackTrace();37 }38 }39 },"火車站窗口"+(i+1)).start();40 }41 }42}

任務(wù)6-3模擬銀行取款系統(tǒng)-線程同步鎖機(jī)制鎖機(jī)制解決線程安全的運(yùn)行結(jié)果如圖1.在com.example.task包中創(chuàng)建BankWithdrawal類,在該類中創(chuàng)建1個(gè)銀行賬戶和3個(gè)客戶線程,并啟動(dòng)3個(gè)客戶線程。2.創(chuàng)建一個(gè)Customer類繼承Thread類,表示一個(gè)取款客戶,每個(gè)客戶都有一個(gè)銀行賬戶和要取款的金額,在run()方法中調(diào)用withdraw()方法進(jìn)行取款操作。3.創(chuàng)建一個(gè)BankAccount類,表示一個(gè)銀行賬戶,在該類中定義1個(gè)變量balance,表示銀行賬戶余額;定義withdraw()方法用于執(zhí)行取款操作,該方法用synchronized修飾,以確保任何時(shí)候都只有一個(gè)客戶在執(zhí)行取款操作。代碼參考教材中的BankWithdrawal.java任務(wù)6-3模擬銀行取款系統(tǒng)-線程控制操作模擬銀行取款系統(tǒng)的運(yùn)行結(jié)果如圖任務(wù)6-3模擬銀行取款系統(tǒng)-線程控制操作04任務(wù)6-4模擬在線購物網(wǎng)站單例模式概述餓漢式懶漢式雙重檢查加鎖機(jī)制任務(wù)6-4模擬在線購物網(wǎng)站-單例模式單例模式概述單例模式是面向?qū)ο缶幊讨凶畛R姷脑O(shè)計(jì)模式之一。其核心思想是確保一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)全局訪問點(diǎn)來訪問這個(gè)實(shí)例。單例模式的主要優(yōu)點(diǎn)在于它可以避免由于多個(gè)實(shí)例導(dǎo)致的資源消耗和數(shù)據(jù)不一致等問題。任務(wù)6-4模擬在線購物網(wǎng)站-單例模式單例模式概述1.單例模式的實(shí)現(xiàn)方式單例模式的實(shí)現(xiàn)方式有以下5種:(1) 懶漢式:在第一次調(diào)用getInstance()方法(該方法在后續(xù)會(huì)講)時(shí)創(chuàng)建實(shí)例。這種方式需要處理同步問題來確保線程安全。(2) 餓漢式:在類加載時(shí)創(chuàng)建實(shí)例,這種方式是線程安全的,但如果實(shí)例一直未使用,可能會(huì)浪費(fèi)一些內(nèi)存。(3) 雙重檢查鎖定:結(jié)合了懶漢式和餓漢式的優(yōu)點(diǎn),既保證了線程安全,又避免了在類加載時(shí)創(chuàng)建實(shí)例。(4) 靜態(tài)內(nèi)部類:利用了類加載機(jī)制保證初始化實(shí)例時(shí)只有一個(gè)線程,一般推薦這種方式實(shí)現(xiàn)單例模式,因?yàn)樗群啙嵱指咝?。?) 枚舉:在Java中,枚舉類型是單例的,并且絕對(duì)線程安全。任務(wù)6-4模擬在線購物網(wǎng)站-單例模式單例模式概述2.單例模式的使用場景單例模式的使用場景有以下3種:(1) 想要確保某個(gè)類只有一個(gè)實(shí)例,并且提供一個(gè)全局訪問點(diǎn)。(2) 頻繁實(shí)例化一個(gè)對(duì)象并銷毀它會(huì)造成大量性能開銷。(3) 對(duì)象需要被共享,并且在整個(gè)系統(tǒng)中只需要一個(gè)實(shí)例。任務(wù)6-4模擬在線購物網(wǎng)站-單例模式單例模式概述3.單例模式使用時(shí)的注意事項(xiàng)單例模式使用時(shí)有以下3個(gè)注意事項(xiàng):(1) 不要在單例類中提供公開的setXX()方法,因?yàn)檫@可能會(huì)破壞單例的約束。(2) 如果需要序列化和反序列化,請(qǐng)確保在反序列化過程中不會(huì)創(chuàng)建新的實(shí)例。(3) 在多線程環(huán)境下,確保單例模式的實(shí)現(xiàn)是線程安全的。任務(wù)6-4模擬在線購物網(wǎng)站-單例模式餓漢模式餓漢式單例模式是設(shè)計(jì)模式中的一種,主要用于確保一個(gè)類在任何情況下都有且僅有一個(gè)實(shí)例,并提供一個(gè)全局訪問點(diǎn)。其特點(diǎn)在于當(dāng)類加載時(shí)就已經(jīng)完成了類的實(shí)例化,避免了線程同步的問題。餓漢式單例模式的示例代碼如下1publicclassSingleton{2//當(dāng)類加載時(shí)就完成了類的實(shí)例化,保證了線程安全

3privatestaticfinalSingletonINSTANCE=newSingleton();4//構(gòu)造函數(shù)私有,防止其他類創(chuàng)建該類的實(shí)例

5privateSingleton(){}6/**7 *公有靜態(tài)方法,提供全局訪問點(diǎn)

8 */9publicstaticSingletongetInstance(){10returnINSTANCE;11}12}任務(wù)6-4模擬在線購物網(wǎng)站-單例模式餓漢模式例6-11所示,通過智能門鎖系統(tǒng)演示餓漢式單例模式。首先創(chuàng)建HungryDoorLock類,然后在該類中使用餓漢式單例模式可以在家庭中的任何地方獲取到同一個(gè)門鎖系統(tǒng)實(shí)例,并進(jìn)行開啟門鎖、關(guān)閉門鎖和記錄門鎖訪問日志等操作。詳見HungryDoorLock.java1packagecom.example.thread;2publicclassHungryDoorLock{3 //餓漢式單例,在類加載時(shí)創(chuàng)建實(shí)例

4 privatestaticfinalHungryDoorLockINSTANCE=newHungryDoorLock();5 privateHungryDoorLock(){6 //初始化門鎖系統(tǒng),比如加載門鎖配置、連接門鎖硬件等

7 System.out.println("初始化門鎖系統(tǒng)");8 }9 /**10 *公有靜態(tài)方法,用于獲取門鎖系統(tǒng)實(shí)例

11 */12 publicstaticHungryDoorLockgetInstance(){13 returnINSTANCE;14 }15 /**16 *控制門鎖開啟的方法

17 */18 publicvoidunlock(){19 System.out.println("開啟門鎖");20 }21 /**22 *控制門鎖關(guān)閉的方法

23 */24 publicvoidlock(){25 System.out.println("關(guān)閉門鎖");26 }27 /**28 *記錄門鎖訪問日志的方法

29 */30 publicvoidlogAccess(Stringname,Stringaction){31 System.out.println("用戶"+name+action+"門鎖");32 }33 publicstaticvoidmain(String[]args){34 //獲取智能門鎖系統(tǒng)實(shí)例

35 HungryDoorLockdoorLock=HungryDoorLock.getInstance();36 doorLock.unlock();//模擬用戶開啟門鎖

37 doorLock.lock();//模擬用戶關(guān)閉門鎖

38 //記錄用戶訪問日志

39 doorLock.logAccess("小明","開啟");40 }41}任務(wù)6-4模擬在線購物網(wǎng)站-單例模式餓漢模式餓漢式單例模式的運(yùn)行結(jié)果如圖任務(wù)6-4模擬在線購物網(wǎng)站-單例模式懶漢模式懶漢式單例模式是一種延遲初始化的單例模式,即在第一次使用該類時(shí)才創(chuàng)建實(shí)例,相對(duì)餓漢式顯得“不急迫”,所以被叫做懶漢式。懶漢式單例模式的示例代碼如下1publicclassSingleton{2 //私有靜態(tài)成員變量,用于存儲(chǔ)唯一的實(shí)例

3 privatestaticSingletoninstance;4 //私有構(gòu)造方法,防止外部實(shí)例化

5 privateSingleton(){6 }7 /**8 *公有靜態(tài)方法,提供全局訪問點(diǎn)

9 */10 publicstaticSingletongetInstance(){11 //檢查實(shí)例是否已經(jīng)被創(chuàng)建

12 if(instance==null){13 //如果沒有被創(chuàng)建,則創(chuàng)建實(shí)例

14 instance=newSingleton();15 }16 returninstance;//返回實(shí)例

17 }18}任務(wù)6-4模擬在線購物網(wǎng)站-單例模式雙重檢查加鎖機(jī)制餓漢式和懶漢式的單例模式都有多線程不安全的缺點(diǎn),雙重檢查加鎖機(jī)制解決了這兩者的缺點(diǎn)。雙重檢查加鎖機(jī)制也被稱為雙重檢查鎖定或雙重檢查鎖定模式,它是一種用于多線程編程的同步機(jī)制,旨在減少鎖競爭的開銷,提高程序的性能,這種機(jī)制通常用于延遲初始化單例模式。雙重檢查加鎖機(jī)制的工作流程如下所示。1.并不是每次進(jìn)入相關(guān)方法(如getInstance()方法)都需要同步,而是首先在不進(jìn)行同步的情況下進(jìn)入相關(guān)方法。2.在相關(guān)方法內(nèi)部,首先檢查所需的實(shí)例是否存在(第一重檢查)。3.如果實(shí)例不存在,則進(jìn)入同步塊。在同步塊內(nèi)部,再次檢查實(shí)例是否存在(第二重檢查)。4.如果實(shí)例在同步塊內(nèi)部仍然不存在,則在同步的情況下創(chuàng)建一個(gè)實(shí)例任務(wù)6-4模擬在線購物網(wǎng)站-單例模式雙重檢查加鎖機(jī)制雙重檢查加鎖機(jī)制的示例代碼如下1publicclassSingleton{2//使用volatile關(guān)鍵字防止指令重排

3privatevolatilestaticSingletoninstance;4privateSingleton(){}5publicstaticSingletongetInstance(){6//第一次檢查實(shí)例是否已經(jīng)被創(chuàng)建

7if(instance==null){8//同步塊,防止多個(gè)線程同時(shí)進(jìn)入

9synchronized(Singleton.class){10//第二次檢查實(shí)例是否已經(jīng)被其他線程創(chuàng)建

11if(instance==null){12//如果沒有被創(chuàng)建,則在此處創(chuàng)建實(shí)例

13instance=newSingleton();14}15}16}17returninstance;//返回單例實(shí)例

18}19}任務(wù)6-4模擬在線購物網(wǎng)站-單例模式雙重檢查加鎖機(jī)制雙重檢查加鎖機(jī)制的示例代碼如下1publicclassSingleton{2//使用volatile關(guān)鍵字防止指令重排

3privatevolatilestaticSingletoninstance;4privateSingleton(){}5publicstaticSingletongetInstance(){6//第一次檢查實(shí)例是否已經(jīng)被創(chuàng)建

7if(instance==null){8//同步塊,防止多個(gè)線程同時(shí)進(jìn)入

9synchronized(Singleton.class){10//第二次檢查實(shí)例是否已經(jīng)被其他線程創(chuàng)建

11if(instance==null){12//如果沒有被創(chuàng)建,則在此處創(chuàng)建實(shí)例

13instance=newSingleton();14}15}16}17returninstance;//返回單例實(shí)例

18}19}任務(wù)6-4模擬在線購物網(wǎng)

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(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ǔ)空間,僅對(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ì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論