線程1.JAVA多線程實現(xiàn)方式_第1頁
線程1.JAVA多線程實現(xiàn)方式_第2頁
線程1.JAVA多線程實現(xiàn)方式_第3頁
線程1.JAVA多線程實現(xiàn)方式_第4頁
線程1.JAVA多線程實現(xiàn)方式_第5頁
已閱讀5頁,還剩110頁未讀 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

JAVA多線程實現(xiàn)方JAVAThreadRunnable接口、使用繼承ThreadRunnable接口的一個實例,它代表一個線程的實例,并且,啟動線程的唯一方法就是通Thread類的start()實例方法。start()native方法,它將啟動一個新線run()extendThread,并復(fù)寫run()方法,就可以啟動新線程并執(zhí)行自己定義的run()方法。例如:publicclassMyThreadextendsThread{publicvoidrun(){}}MyThreadmyThread1=newMyThread();MyThreadmyThread2=newMyThread();實現(xiàn)Runnable接口方式實現(xiàn)多extendsextendsThread,此時,必須實現(xiàn)一Runnable接口,如下:publicclassMyThreadextendsOtherClassimplementsRunnable{publicvoidrun(){}}為了啟動MyThread,需要首先實例化一個Thread,并傳入自己的MyThread實例MyThreadmyThread=newMyThread();Threadthread=newThread(myThread);事實上,當(dāng)傳入一個Runnable參數(shù)給Thread后,Thread的run()方法就會調(diào)用.run(),參考JDK源代碼:publicvoidrun()if(!=null)}}ExecutorService、Callable、Future實現(xiàn)有返回結(jié)果的多線程類。想要詳細了解Executor框架的可以http /topic/3691JDK15中引入的新特征,確實很實用,有了這種特征我就不需要再為了得到返回值而大費周折了,而且即便實現(xiàn)了也可能??煞祷刂档娜蝿?wù)必須實現(xiàn)Callable接口,類似的,無返回值的任務(wù)必須Runnable口。執(zhí)行Callable任務(wù)后,可以獲取一個Future的對象,在該對象上調(diào)用get就可以獲取到Callable任務(wù)返回的Object了,再結(jié)合線接口ExecutorService就可以實現(xiàn)JDK1.5importimportjava.util.concurrent.*;importjava.util.Date;importjava.util.List;importjava.util.ArrayList;Java*@authorpublicclassTest{publicstaticvoidmain(String[]args)throwsExecutionException,InterruptedException{System.out.println("程序開始運 Datedate1=newinttaskSize=ExecutorServicepool=List<Future>list=newfor(inti=0;i<taskSize;i++){Callablec=newMyCallable(i+"");FutureFuturef=//System.out.println(">>>"+f.get().toString());}for(Futuref:list)FutureSystem.out.println(">>>"+}Datedate2=newSystem.out.println("程序結(jié)束運 ,程序運行時間【+(date2.getTime()-date1.getTime())}}classMyCallableimplementsCallable<Object>{privateStringtaskNum;MyCallable(StringtaskNum){this.taskNum=taskNum;}publicObjectcall()throwsException{System.out.println(">>>"taskNumDatedateTmp1=newDate();DatedateTmp2=newlongtimedateTmp2.getTime()dateTmp1.getTime();System.out.println(">>>"+taskNum+"任務(wù)終止");returntaskNumtime}}上述代碼中Executors類,提供了一系列工廠方法用于創(chuàng)先線,返回的線都實ExecutoServicepublicstaticExecutorServicenewFixedThreadPool(in創(chuàng)建固定數(shù)目線程的線publicstaticExecutorService創(chuàng)建一個可緩存的線,調(diào)用execute將重用以前構(gòu)造的線程(如果線程可用)。如60publicstaticExecutorService創(chuàng)建一個單線程化的ExecutorpublicstaticScheduledExecutorServicenewScheduledThreadPool(int創(chuàng)建一個支持定時及周期性的任務(wù)執(zhí)行的線,多數(shù)情況下可用來替代Timer類ExecutoreServicesubmit()CallableRunnable,返回象的get()方阻塞直到計算完成。一、多線1、操作系統(tǒng)有兩個容易的概念,進程和線程CPU調(diào)度執(zhí)行的基本單位;線程有自己的程序計數(shù)器、2、Java標(biāo)準(zhǔn)庫提供了進程和線程相關(guān)的API,進程主要包括表示進程java.lang.ThreadJavamain方法這、線程間的可見性:一個線程對進程享的數(shù)據(jù)的修改,是否對另一個線程可可見性問題:[java]viewplaina、CPU采用時間片輪轉(zhuǎn)等不同算法來對[java]viewplain1.publiccla privateintvalue= publicint }}CPU時間來獲取運行機會,CPU切換可能發(fā)生在執(zhí)行間隙。[java]viewplaingetNext()的指令序列:CPU7[java]viewplain.getfield.6.7.putfieldb、CPU緩存CPU一般采用層次結(jié)構(gòu)的多級緩存的架構(gòu)CPUL1、L2L3三級緩存。當(dāng)CPU需要主存中某個位置的數(shù)據(jù)時,會一次檢查各級緩存中是否存在對應(yīng)的數(shù)據(jù)。如果有,直接從緩存中,這比從主存中速度快很多。當(dāng)CPU需要寫入c、指令順二、Java內(nèi)存模型(JavaMemory了U元素;關(guān)注線程間的動作。1、volatile:用來對共享變量的進行同步,上一次寫入操作的結(jié)果對下一次讀取操作是肯定可見的。(volatile變量值之后,CPU緩存中的內(nèi)容會被寫回內(nèi)存;在volatile變量時,CPU緩存中的對應(yīng)內(nèi)容會被置為失效,重新從主存中進行讀?。?,volatile不使用鎖,性能優(yōu)于synchronized。[java]viewplainpublicclassprivatevolatile[java]viewplainpublicclassprivatevolatilebooleanpublicvoidsetDone(booleanthis.done= publicvoid [java]viewplain例子:錯誤使用。因為沒有鎖的支持,volatile[java]viewplain1.publicclassCounter publicvolatilestaticintcount= publicvoidinc() 1 try }catch(InterruptedExceptione) publicstaticvoidmain(String[]args) for(inti=0;i<1000;i++) newThread(newRunnable() publicvoidrun() System.out.println("運行結(jié)果:Counter.count 2、finalfinal的域的值只能被初始化一次,一般在構(gòu)造方法中初始化(在多線程開發(fā)中,final域通常用來實現(xiàn)不可變對象)另外,在代碼執(zhí)行時,final域的值可以被保存在寄存器中,而不用從主存中頻繁重新讀3、java基本類型的原子基本類型,類型的是原子操作;(即一條指令完成long與double的賦值,是可以分割的,非原子操作要程間共享long或double的字段時,必須在synchronized中操作,或是三、Java提供的線程同步方1、synchronized所有的Java對象都有一個與synchronzied關(guān)聯(lián)的監(jiān)視器對象(monitor),允許線該a、靜態(tài)方法:JavaClassc、代碼塊:代碼塊中的對象所關(guān)聯(lián)的監(jiān)視器對象注:當(dāng)鎖被,對共享變量的修改會寫入主存;當(dāng)活得鎖,CPU緩存中的內(nèi)容被置為無synchronized方法或代碼塊,不會把其中包含的代碼移動到synchronized方法或代碼塊之外,從而避免了由于代碼重排而造成的問題。[java]viewplain1.[java]viewplain1.publicclasspublicsynchronizedint}} returnpublicintreturnprivateintvalue=2、Objectwait、notifynotifyAll方whilevolatileCPU時間,對性能造waitABwait()A進入B對象的等待池,并且B的鎖。(這里,線程A必須持有B的鎖,所以調(diào)用的synchronizedjava.lang.IllegalMonitorStateException放掉鎖,鎖池中的線程即可競爭對象的鎖來獲得執(zhí)行機會。(notify鎖喚醒的線程選擇由虛擬機實現(xiàn)來決定,不能保證一個對象鎖關(guān)聯(lián)的等待集合中notifyAll方法,不過該方導(dǎo)致線沒有必要的情況下被喚醒,之后又馬上進入等待池,對性能有影a、ConsumerAwait()A進入產(chǎn)b、ProducerBnotifyAll(),ConsumerA從產(chǎn)品的等待池進入鎖池,Producer線程B生產(chǎn)產(chǎn)品,然后退出鎖。[java]viewplainc、Consumer[java]viewplain1.publicsynchronizedString this.notifyAll喚醒對象等待池中的所有線程,可能喚醒的就是生產(chǎn)者(發(fā)現(xiàn)產(chǎn)品滿,就會進入對象的等待池,這里代碼省略,基本略同 while(index==-1){//如果發(fā)現(xiàn)沒產(chǎn)品,就鎖,進入對象等待 當(dāng)生產(chǎn)者生產(chǎn)完后,消費者從一產(chǎn)品還是為空,則再等待,所以這里必須用while循環(huán),不能用 Stringgood= buffer[index]= returngood3、線程狀態(tài)轉(zhuǎn)換已經(jīng)廢棄的方法:st、sus、rsume、stroy、E、BLOKE、WAITITIMED_AITIN(有超時a、方法sleep()進入的阻塞狀態(tài),不會對象的鎖(即大家,誰也別想執(zhí)行代碼),sleepsynchronized方法或代碼塊中,否則造成其他等待獲取bjoin()main[java]view[java]viewplain2.Threadt1=newThread(new1.publicstatic2.Threadt1=newThread(new3.Threadt2=newThread(new.t1.join等t16.7.t2.join8.8.cinterrupt()ABd的interruptB來處理這個請求,當(dāng)然也可以忽略,這不是必須的。Objectwait()、Threadjoin()sleep方法都會拋出受檢異常java.lang.InterruptedExceptioninterrupt方法中斷該線程會導(dǎo)致線程離開等待狀I(lǐng)nterruptedException異常,并致以異常的處理邏輯。ThreadisInterrupted方法來判斷是否有中斷請求發(fā)生,通常可以利用這個方法來判斷是否退出線程(volatitle修飾符的例子);ThreadInterrupted(),該方法不但可以判斷當(dāng)前線程是否被中斷,還會清楚線程的中斷標(biāo)記,如果返回true,即曾被請求中斷,同時調(diào)用完后,清除中斷標(biāo)記。如果一個線某個對象的等待池,那么notify和interrupt都可以使該線程從等待池中被notify先,那照常喚醒,沒影響。如interruptnofity,也會忽略該線程,而e、yield()CPU資源,讓其他線程獲取運行機會,對操作系統(tǒng)上的調(diào)度器來說是一個信號,不一定立即切換線程。(yeid方四、非阻塞方線程之間同步機制的是監(jiān)視對象上的鎖,競爭鎖來獲得執(zhí)行代碼的機會。當(dāng)一個對象程度限制了多線程程序的吞吐量和性能(線程阻塞),且會帶來死鎖(A有a對象bB有ba對象鎖)和優(yōu)先級倒置(優(yōu)先級CPU本身實現(xiàn)將這三步合起來形成一個原子操作,無需線程鎖機制干預(yù),常見的指令是“比較和替換”(compareandswap,CAS),這個指令會先比較某個內(nèi)存地址的當(dāng)前CASCASCAS指令成功完成修改。java.util.concurrent.atomicCAS指令。(CPUCAS,在某些平臺,java.util.concurrent.atomic的實現(xiàn)仍然是鎖機制)atomic包中提供的Java類分成三類1、支持以原子操作來進行更新的數(shù)據(jù)類型Java類(AtomicBoolean、AtomicInteger、AtomicReference),volatile變量。 pareAndSet:效果同compareAndSet(JSR中表示weak原子方式和有條件地寫入變量但不創(chuàng)建任何happen-before排序,但在源代碼中和compareAndSet完全一樣,所以并沒有按JSR實現(xiàn))c、getsetd、lazySetsetlazySet方法的調(diào)用與后面的指令進行重排,因[java][java]viewplain1.publicclass privatefinalAtomicIntercounter=new publicint }}7.7.//getAndIncrement方法 intnext=currentreturn intcurrent=8.publicfinalintaomiaymicLong和ominy(素索引的參數(shù))[java]viewplain3、通過反射的方式對任何對象中包volatitle變量使CAS方法,他們提供了式把CAS的功能擴展到了任何Java類中為volatitle的域上。(靈[java]viewplain1.publicclass privatevolatileTreeNode3.// privatestaticfinalAtomicReferenceFieldUpdater<TreeNode,TreeNode>parentUpdater=5.publicbooleancompareAndSetParent(TreeNodeexpect,TreeNode pareAndSet(this,expect,7.8.java.util.concurrent.atomic包中的Java類屬于比較底層的實現(xiàn),一般作為AtomicBoolean、AtomicInteger、AtomicLongAtomicReference。在實現(xiàn)線程安全的計數(shù)器時,AtomicIntegerAtomicLong類時最佳的選擇。五、高級同步機制(synchronized更靈活的加鎖synchronizedvolatilewait、notify等方法抽象層次低,在程序開發(fā)中使用比較繁這些模式抽象成API,使用起來會非常方便。java.util.concurrent包為多線程提供了的API,滿足日常開發(fā)中的常見需求。1、Lock接口,表示一個鎖方法b、unlock(),鎖。(一般放在finally代碼塊中)(d、tryLock()false。(tryLock()的另一2、ReadWriock接口,表示兩個鎖,的共享鎖和寫入的排他鎖。(適合常見的讀ReadWriockreadLockwriockLock接口的實現(xiàn)。3、ReentrantLock類和ReentrantReadWriock,分別為上面兩個接口的實現(xiàn)類。[java]viewplain同一個線程每次獲取鎖,加鎖數(shù)+1,每次鎖,加鎖數(shù)-1,到0[java]viewplain1.publicclass2.//newReentrantLock(true)是重載,使用更加公平的加鎖機制,在鎖被后,會優(yōu)先給 privateintReentrantLocklock= privafteintvalue= publicint returnvalue++;// shMapxt(鎖之后可以保證一個線程一口氣完成便利而不會每次xt(之后鎖然后和(成任務(wù),再把鎖傳遞給其他線程。注:與Object類的wait()相同,await()會其所持有的鎖[java]viewplaine、signal()[java]viewplain1.Locklock=new2.Conditioncondition=3.4. 8. 六、底層同步Java標(biāo)準(zhǔn)庫提供的同步方式之外,程序中特有的同步方式需要由開發(fā)自己來實現(xiàn)。常見的一種需求是對有限個共享資源的,比如多臺個人電腦,2臺,當(dāng)多個線FIFO隊列。如果程序中的同步方式可以抽象成對有限個資源的,那么可以使 QueuedLongSynchronizerint類型的變量來long類型。(可以將這個變量理解為共享資源個數(shù))通過 、 pareAndSetState3個方法更新變量的值compareAndSetState3[java]viewplain1.publicclassprivatestaticclassInnerSynchronizer{protectedinttryAcquireShared(intintavailablecompareAndSetState3[java]viewplain1.publicclassprivatestaticclassInnerSynchronizer{protectedinttryAcquireShared(intintavailable=if(remain<0||comapreAndSetState(available,}}intnext=available+return} synchronizer=new publicvoidacquire()throws pubicvoid publicSimpleResourceManager(int}}intavailable=protectedbooleantryReleaseShared(int}returnintremain=available-}InnerSynchronizer(intprivatefinalInnerSynchronizer}七、高級同步對象(提高開發(fā)效率atomic和locks包提供的Java類可以滿足基本的互斥和同步的需求,但這些Java類1、信號量在使用資源時,需要從該信號量上獲取,成功獲取,資源的可用數(shù)-1;完成對資源的使用,,資源可用數(shù)+1;當(dāng)資源數(shù)為0時,需要獲取資源的線程以阻塞的SimpleResourceManager類實際上時信號量的一個簡單實現(xiàn))java.util.concurrent.SemaphoreSemaphore類的對象時指定資源的可用數(shù)b、tryAcquire(),以非阻塞方式獲取[java]viewplaind、accquireUninterruptibly(),[java]viewplain1.1.publicclassprivatefinalList<Printer>printers=newthis.semaphore=newpublicPrinteracquirePrinter()throwsreturn publicvoidreleasePrinter(Printer privatesynchronizedPrinter }publicPrinterManager(Collection<?extendsPrinter>privatefinalSemphore printerresult= return privatesynchronizedvoidputBackPrinter(Printer 2、倒數(shù)java.util.concurrent.CountDownLatch類,創(chuàng)建該類時,指定等待完成的任務(wù)數(shù);當(dāng)一個態(tài),直到任務(wù)數(shù)量為0。CountDownLatch類為,一旦任務(wù)數(shù)為0,再調(diào)用await()[java][java]viewplain1.publicclass 并發(fā)性能遠遠優(yōu)于HashTable的Map實現(xiàn),hashTable做任何操作都需要獲得鎖,同一時間只有有個線程能使用,而ConcurrentHashMap是分段加鎖,不同線程不同的數(shù)據(jù)段,完全不受影響,忘記HashTable privatestaticfinalConcurrentHashMap<String,Interger>sizeMap=new privatestaticclassGetSizeWorkerimplements privatefinalString publicGetSizeWorker(StringurlString,CountDownLatch this.urlString= this.signal= publicvoid InputStreamis=new intsize= sizeMap.put(urlString, }catch(IOException sizeMap.put(urlString,- signal.countDown()://完成一個任務(wù),任務(wù)數(shù)- privatevoid List<Entry<String,Integer>list=new Collections.slort(list,new publicintcompare(Entry<String,Integer>o1,Entry<Sting,r> publicvoidsortPageSize(Collection<String>urls)throws CountDownLatchsortSignal=new for(Stringurl: newThread(newGetSizeWorker(url, 3、循環(huán)屏循環(huán)屏障在作用上類似倒數(shù),不過他不像倒數(shù)是的,可以循環(huán)使用。另java.uti.concurrent.CyclicBarrier用來表示循環(huán)屏障,創(chuàng)建時指定使用該對象的線程數(shù)Runnable接口的對象作為每次循環(huán)后執(zhí)行的動作。(當(dāng)最后一個線Runnalbe接口的對象來處理)。awaitawait方法之[java]view[java]viewplain1.publicclassPriprivatestaticfinalintTOTAL_COUTN=privatestaticfinalintRANGE_LENGTH=privatestaticfinalintWORKER_NUMBER=privatestaticvolatitlebooleandone=privatestaticintrangeCount=privatestaticfinalList<Long>results=new privatestaticfinalCyclicBarrierbarrier=newCyclicBarrier(WORKER_NUMBER,newRunnable(){publicvoidif(results.size()>=done= privatestaticclassPrimeFinderimplementspublicvoid while(!done){//整個過一個while循環(huán)下,await()等待,下次循環(huán)開始,會再次判斷執(zhí)行條件intrange=longstart=rang*longend=(range+1)*for(longi=start;}}}catch(InterruptedException|done=}}}}privatesynchronizedstaticvoidupdateResult(long}privatesynchronizedstaticintreturn}privatestaticbooleanisPrime(long}publicvoid for(int newThread(new 4、對象交換適合于兩個線程需要進行的場景(一個線程完成后,把結(jié)果交給另一個線程繼續(xù)icurrent.Exchar類,提供了這種對象交換能力,兩個線程共個ExchanrExchar類的c)ce方法的返回結(jié)果是另外一個線程鎖提供的相同類型的對象。如果另外一個線程未完成對數(shù)據(jù)的處gc方法來進行。[java]view[java]viewplainpublicclass privatefinalExchanger<StringBuilder>exchanger=newExchanger<StringBuprivateclassSenderimplementspublicvoidStringBuildercontent=newcontent=}catch(InterruptedException}}}privateclassReceiverimplementspublicvoidStringBuildercontent=newcontent=}catch(InterruptedException publicvoid newThread(new newThread(new 八、數(shù)據(jù)結(jié)構(gòu)(多線程程序使用的高性能數(shù)據(jù)結(jié)構(gòu)java.util.concurrent包中提供了一些適合多線程程序使用的高性能數(shù)據(jù)結(jié)構(gòu),包括隊列和1、隊a、BlockingQueue接口:線程安全的阻塞式隊列;當(dāng)隊列已滿時,想隊列添加會阻塞;ArrayBolockingQueue和基于鏈表結(jié)構(gòu)的不固定元LinkedBlockQueue類。b、BlockingDeque接口BlockingQueue相似,但可以對頭尾進行添加和刪除操作java.util包中的集合a、ConcurrentMap接口java.util.Map接口replace(key,value)valuekey上。replace(key,oldvalue,newvalue):CAS的實現(xiàn)。HashMap也一樣,只是多線程下更耗時)。創(chuàng)建時,預(yù)估進行更新操作的線程數(shù),這樣實現(xiàn)中會根據(jù)這個數(shù)把空間劃分為對應(yīng)數(shù)量的部分。(默認是,如果只有一個線程進行寫操作,其他都是,那么把值設(shè)為1可以提高性能)。Map元素時,不一定能看到正在添加的數(shù)據(jù),只能和集合保證弱一致性。(Map,而拋出CopyOnWriteArrayList的實現(xiàn)類,所有對列表的更新操作都會新創(chuàng)建一個底九、多線程任務(wù)的執(zhí)過去線程的執(zhí)行,是先創(chuàng)建Thread類的想,再調(diào)用start方法啟動,這種做法要求開發(fā)人J2SE5.0中,java.util.concurrent1、基本接口(描述任務(wù)a、CallableRunnable接口受限于run方法的類型簽名,而Callable只有一個方法call(),可以有返回b、FutureFutureget()方法可以獲取異步的c、Delayed接口:2、組合接口(描述任務(wù)a、RunnableFutureRunnableFuture當(dāng)來自Runnalbe接口中的run方法成功執(zhí)行之后,相當(dāng)于Future接口表示的異步任務(wù)已get()獲取運行結(jié)果。b、ScheduledFutureFutureDelayed接口,表示一個可以調(diào)用的異步c、RunnableScheduledFutureRunnable、DelayedFuture,接口中包含3、Executor接口、ExcutorServer接口、ScheduleExecutorService接口CompletionService接口(描述任務(wù)執(zhí)行b、excutorServerFuture提供批量執(zhí)行:kk)a;k),會等待Future的列表;k),任何一個任務(wù)成功完成,即返回該任務(wù)結(jié)果。c、ScheduleExecutorServiceexcutorServer接口:支持任務(wù)的延遲執(zhí)行和CallableRunnable。ScheduledFutured、CompletionServiceExecutorServicesubmitFuture接口來獲Future在CompletionService就是解決這個問題,程序不同部分可以共享CompletionServicetake(阻塞),poll(非阻塞)來獲[java]viewplain pletionService,在創(chuàng)建時,需要提供一個Executor接[java]viewplain privatefinalExecutorServiceexecutor privatefinalExecutorServiceexecutor=;publicbooleandownload(finalURLurl,finalPath // Future<Pathfutureexecutor.submit(newCallable<Pathsubmit提交 publicPath InputStreamis= Files.copy(is,path, return returnfuture.get()!=null?true: }<spanstyle="font-family:Arial,Helvetica,serif;">catch(InterruptedException|ExecutionException return publicvoidclose(){//FileDownloader類的對象時,應(yīng)該使用close方法關(guān)閉其中包含的ExecutorService接口的實現(xiàn)對象,否則虛擬機不會退出,占用內(nèi)存不釋放 executor.shutdown if(!executor.awaitTermination(3,TimeUnit.MINUTES)){//tion executor.shutdownNow束 executor.awaitTermination(1,TimeUnit.MINUTES }catch(InterruptedException 十、JavaSE7java.util.concurrentfork/join和多階段線1、輕量級任務(wù)執(zhí)行框架map/reduce算法來解決問題。fork/joinmap/reducefork操作是把一個大的問題劃分為若干個較小的問題,劃分過程一般為遞歸,直到可以直join相對一般的線實現(xiàn),F(xiàn)/J框架的優(yōu)勢在任務(wù)的處理方式上。在一般線中,一個線F/J,某個子問題由于等待另外一個子問題的完為了F/J能高效,在每個子問題視線中應(yīng)避免使用synchronized或其他方式進行同步,也不應(yīng)使用阻塞式IO或過多共享變量。在理想情況下,每個子問題都應(yīng)值進行CPU計算,只使用每個問題的對象,唯一的同步應(yīng)只發(fā)生在子問題和創(chuàng)建它的父問題之間。(HadoopMapReduce嘛a、ForkJoinTask類F/JFuture接口,可以Future接口的方式來使用。(表示任務(wù))RecuriveTaskRecursiveAction,前者可以返回結(jié)果,后者不行。b、ForkJoinPool類ExecutorServiceForkJoinTaskCallableRunnable。(任務(wù)執(zhí)行)第一類:execute、invokesubmit方法:直接提交任務(wù)。第二類:fork()ForkJoinTask在執(zhí)行過程中的子任務(wù)。ForkJoinTask用第一類提交,執(zhí)行過程中產(chǎn)生的子任務(wù)不需要處理,F(xiàn)orkJoinPool會負責(zé)子任務(wù)執(zhí)行。[java][java]viewplain1.privatestaticclassMaxValueTaskextends privatefinallong[] privatefinalint privatefinalint MaxValueTask(long[]array,intstart,int this.array= this.start= this.end= pute是RecursiveTask protectedlongif(endstartRANG_LENGTH){//if(array[i]>}}elseMaxValueTasklowTask=newMaxValueTask(array,start,lowTask.forkmaxMath.max(max,lowTask.join());//} MaxValueTasktask=newMaxValueTask(array,0,return Longresult= publicLong ong[]returnmax=Math.max(max,MaxValueTaskhighTask=newMaxValueTask(array,mid,intmid=(start+end)}max=for(inti=start;longmax=在實際中,F(xiàn)/J框架發(fā)揮作用的場合很多,比如在一個 F/J2、多階段線程同步工Phaser類是JavaSE7中新增的一個使用同步工具,功能和靈活性比倒數(shù)和循環(huán)屏障F/JPhaserPhaser把多個線程寫作執(zhí)行的任務(wù)劃分成多個階段(phase),編程時要明確各個階段的任務(wù),每個階段都可以有任意個參與者,線程可以隨時并參與到某個階段,當(dāng)一個階段中所有線程都成功完成之后,PhaseronAdvance()被調(diào)用,可以通過覆蓋添加自定義處理邏輯(Runnable接口),Phaser類會自動進入下個階Phaser不再包含任何參與者。Phaser創(chuàng)建后,初始階段為0,構(gòu)造函數(shù)中指定初始參與個數(shù)arriveAndDeregister(),任務(wù)完成,取消自己的。arriveAndAwaitAdvance()Phaser成awaitAdvance()、awaitAdvanceInterruptibly()phaser進入下個階段,參數(shù)為當(dāng)前階段的,后者可以設(shè)置超時和處理中斷請求。來指定當(dāng)前對象的父對象;當(dāng)一個子對象參與者>0,會自動到父對象中;當(dāng)=0,自動解除。例:從指定,img的階段1、處理對應(yīng)的html文本,和抽取img的;2、創(chuàng)建子線程,主[java]viewplainpublicclass privatefinalPhaserphasernewPhaser(1);//1publicvoiddownload(URLurl,finalPathpath)throwsStringcontentgetContent(url);//HTMLList<URL>imageUrls=extractImageUrls(content);//獲 ,省略for(finalURLimageUrl:newpublicvoid InputStreamis= File.copy(is,getSavePath(path,imageUrl),StandardCopyOpt}catch(IOException 線程一個ThreadLocal類的對象時,鎖和修改的事每個線程變量各自獨立的對ThreadLocal可以快速把一個非線程安全的對象轉(zhuǎn)換成線程安全的對象。(同時c、initialValue()setget,會通過initValue來獲取對象的初始值。[java]viewplainThreadLoacl的一般用法,創(chuàng)建一個ThreadLocal的子類并覆蓋[java]viewplainpublicclass privatefinalThreadLocal<IdGenerator>idGeneratornew getNext(){new} publicstaticint return}ThreadLocal中。java.util.Random會帶來競爭問題,java.util.concurrent.ThreadLocalRandom類提供多線ThreadLoacl??偨Y(jié):多線程開發(fā)中應(yīng)該優(yōu)先使用API,如果,使用java.util.concurrent.atomicjava.util.concurrent.locks包提供的APIsynchronizedvolatile,以wait,notify和notifyAll等低API應(yīng)該最后考慮。Java線程:概念與原一、操作系統(tǒng)中線程和進程的概以啟動多個線程。比如在Windowsexe就是一個進程。java.exe進程中可以運二、Java中的線1、java.lang.Threadjava.lang.Threadjava.lang.RunnableThreadJava中的任何其他對象一樣,具有變量和方法,生死于Java中,每個線程都有一個調(diào)用棧,即使不在程序中創(chuàng)建任何新的線程,線程也在運行當(dāng)所有用戶線程執(zhí)行完畢的時候,JVMJVM,守候線程一Java線程:創(chuàng)建與啟一、定義線1java.lang.ThreadpublicpublicvoidRunnableRunnablerun方法;否Thread2java.lang.RunnablevoidRunnable的對象創(chuàng)建一個線程時,啟動該線程將導(dǎo)致在獨立執(zhí)行的線程中調(diào)用對run方法。二、實例化線1java.lang.Thread類的線程,則直接new2java.lang.RunnableThreadThread(Runnable)Thread(Runnable,Stringname)Thread(ThreadGroupgroup,Runnable)Thread(ThreadGroupgroup,Runnable,Stringname)Thread(ThreadGroupgroup,Runnable,Stringname,long三、啟動線在調(diào)用rt(Tred當(dāng)該線程獲得機會執(zhí)行時,其目標(biāo)run()vaun(mai)unnblehredn四、例1Runnable*Runnable***@authorleizhimin2008-9-13publicclassDoSomethingimplementsRunnable{privateStringname;publicDoSomething(Stringname){thisname=name;}publicvoidrun()for(inti=0;i<5;i++)for(longk=0;k<100000000;k++);System.out.println(name+":"+i);}}}Runnable*@authorleizhimin2008-9-13publicclassTestRunnable{publicstaticvoidmain(String[]args){DoSomethingds1newDoSomething("阿三DoSomethingds2=new Threadt1=newThread(ds1);Threadt2=newThread(ds2);}}::阿三::阿三::::阿三::阿三:阿三:Processfinishedwithexitcode2Thread*@authorleizhimin2008-9-13publicclassTestThreadextendsThread{publicTestThread(Stringname){}publicvoidrun()for(inti=for(longk=0;k<100000000;k++);}}publicstaticvoidmain(String[]args)Threadt1newTestThread("阿三");Threadt2newTestThread("");}}Processfinishedwithexitcodefor(longk=0;五、一些常見mian,非主線程的名字不確定。7JVMCPU的機器上上,實際上一次只能運行一個線程。一次只有一個線程棧執(zhí)行。JVM線程調(diào)度程序決定實際運行哪個處于可運行狀態(tài)的線程。Java線程:線程棧模型與線程的變當(dāng)程序執(zhí)行到t.start();時候,程序多出一個分支(增加了一個調(diào)用棧B),這樣,棧A、棧B并Java線程:線程狀態(tài)的轉(zhuǎn)5、態(tài):當(dāng)線程的run()方法完成時就認為它死去。這個線程對象也許是活的,但是,它已start()方拋出java.lang.IllegalThreadStateException異常。對于線程的,考慮一下三個方面,不考慮IO阻塞的情況:Thread.sleep(longmillis)和Thread.sleep(longmillis,intnanos)靜態(tài)方法強制當(dāng)前正在執(zhí)行的線程Java規(guī)范不保證合理的輪try}catch(InterruptedExceptione){}例如 publicvoidrun()for(inti= for(longk=0;ktry}catch(InterruptedExceptione){e.printStackTrace();.}}}Processfinishedwithexitcode*100110***@authorleizhimin2008-9-14publicclassMyThreadextendsThreadpublicvoidrun()for(inti=0;i<100;i++){if((i)%10==0){ "+}try{ }catch(InterruptedExceptione){}}}publicstaticvoidmain(String[]args){newMyThread().start();}}0111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111Processfinishedwithexitcode要理解yield()1~10之間。JVM線程調(diào)度程序是基于優(yōu)先級的搶先調(diào)度機制。在大多數(shù)情況下,當(dāng)前運行的線程優(yōu)先當(dāng)線中線程都具有相同的優(yōu)先級,調(diào)度程序的JVM實現(xiàn)它喜歡的線程。這時候調(diào)Threadt=newMyThread();1~10之間的正整數(shù),JVM從不會改變一個線程的優(yōu)先級。然而,1~10之間的值并,變成少于10個的優(yōu)先級,則兩個或多個優(yōu)先級的線程可能被為一個優(yōu)先級。staticintstaticintstaticint行機會。因此,使用yield()的目的是讓相同優(yōu)先級的線程之間能適當(dāng)?shù)妮嗈D(zhuǎn)執(zhí)行。但是,實際中無法保證yield()達到讓步目的,因為讓步的線程還有可能被線程調(diào)度程序再次選中。Threadjoin()B“加入”A的尾部。在A執(zhí)行完畢之前,B不能工作。例如:Threadt=newMyThread();另外,join()t.join(5000);5000毫秒,如果1、線程的run()Java線程:線程的同步與一、同步問題ThreadA、ThreadBFooFoopublicclassFoo{privateintpublicclassFoo{privateintx=100;publicintgetX()return}publicintfix(inty)x=x-y;returnx;}}publicclasspublicclassMyRunnableimplementsRunnable{privateFoofoo=newFoo();publicstaticvoidmain(String[]args){MyRunnabler=newMyRunnable();Threadta=newThread(r,"Thread-A");Threadtb=newThread(r,"Thread-}publicvoidrun()for(inti=0;i<3;i++){try}catch(InterruptedExceptione){}System.out.println(Thread.currentThread().getName()foo對象的x值}}publicintfix(inty)returnfoo}}Thread-AThread-Afoo對象的x值=40Thread-Bfoo對象的x值=40Thread-Bfoo對象的x值20Thread-Afoo對象的x值50Thread-Afoo對象的x值80Thread-Bfoo對象的x值Processfinishedwithexitcode從結(jié)果發(fā)現(xiàn),這樣的輸出值明顯是不合理的。原因是兩個線程不加控制的Foo對象并修改如果要保持結(jié)果的合理性,只需要達到一個目的,就是將對Foo的加以限制,每次只能有一個線。這樣就能保證Foo對象中數(shù)據(jù)的合理性了。Java代碼中需要完成一下兩個操作:把競爭的資源類Foo變量x標(biāo)識為private;二、同步和鎖Java(this實例)有關(guān)的鎖。獲得一個對象的鎖也稱為獲取鎖、鎖定對象、在對象上鎖定或在對象個線程(或返回)鎖。這也意味著任何其他線程都不能進入該對象上的synchronized方法synchronized方法,并且兩個線程使用相同的實例來調(diào)用publicintfix(inty)synchronized(this){x=x-y;}return}publicsynchronizedintgetX(){returnx++;}與publicintgetX()synchronized(this){returnx;}}三、靜態(tài)方法publicstaticsynchronizedintsetName(Stringname){Xxxname=name;}publicstaticintsetName(Stringname){X=}}四、如果線程不能不能獲得鎖會怎3、靜態(tài)同步方法和非靜態(tài)同步方法將不會彼此阻塞,因為靜態(tài)方法鎖定在Class對象上,4、對于同步代碼塊,要看清楚什么對象已經(jīng)用于鎖定(synchronized后面括號的內(nèi)容)。在同五、何時需要SJCP考試范圍了。六、線程安全publicclasspublicclassNameList istnameList=Collections.synchronizedList(newpublicvoidadd(Stringname){}publicString ()if(nameList.size()>0)return(String)}else}}}publicclasspublicclassTestpublicstaticvoidmain(String[]args){finalNameListnl=newNameList();classNameDropperextendsThread{publicvoidrun(){Stringname=nl.remove }}Threadt1=newNameDropper();ThreadThreadt1=newNameDropper();Threadt2=newNameDropper();}}privaistnameList=Collections.synchronizedList(newpublicclasspublicclassNameList istnameList=Collections.synchronizedList(newpublicsynchronizedvoidadd(Stringname){}publicsynchronizedStringremove (){if(nameList.size()>0){return(String)}else}}}七、線程死死鎖對Java程序來說,是很復(fù)雜的,也很難發(fā)現(xiàn)問題。當(dāng)兩個線程被阻塞,每個線等待另publicclassDeadlockRisk{privatestaticclasspublicclassDeadlockRisk{privatestaticclassResource{publicint}privateResourceresourceA=newResource();privateResourceresourceB=newpublicintread()synchronized(resourceA){synchronized(resourceB){returnresourceB.value+}}}publicvoidwrite(inta,intb){synchronized(resourceB){synchronized(resourceA){resourceA.value=a;resourceB.value=}}}}實際上,上面這個例子發(fā)生死鎖的概率很小。因為在代碼內(nèi)的某個點,CPU必須從讀線程切換SCJP的考試范圍。八、線程同步Java線程:線程的交線程交互是比較復(fù)雜的問題,SCJP要求不很基礎(chǔ):給定一個場景,編寫代碼來恰當(dāng)使用等待、SCJPjava.lang.Objectvoidvoidvoidnotify()方法或notifyAll()voidwait(longnotify()方法或notifyAll()方法,或者超voidwait(longtimeout,intnotify()方法或notifyAll()方法,或者其wait()、notify()、notifyAll()Object的實例方法。與每個對象具有鎖一樣,每個對象可以有一個線程列表,他們等待來自該信號(通知)wait()方法獲得這個等待列表。從那時候起,它不再執(zhí)行任何其他指令,直到調(diào)用對象的notify()方法為止。如果多個*@authorleizhimin2008-9-15publicclassThreadApublicstaticvoidmain(String[]args){ThreadBb=newThreadB();//A擁有bwait()notify()方法,該線程必須是那個對象synchronized(b)try//A}catch(InterruptedExceptione){}System.out.println("b對象計算的總和是:}}}*1+2+3100***@authorleizhimin2008-9-15publicclassThreadBextendsThread{inttotal;publicvoidrun()synchronized(this)for(inti=0;i<101;i++){total+=i;}}}}等待對象等待對象bbProcessfinishedwithexitcode)noty()時,并意著這時程放棄其。果線程然完成同代,則線出之前會放棄鎖。因此,只要調(diào)用notfy(*@authorleizhimin2008-9-20publicclassCalculatorextendsThreadintintpublicvoidrun()synchronized(this)for(inti=0;i<101;i++){total+=i;}}}}*@authorleizhimin2008-9-20publicclassReaderResultextendsThread{Calculatorc;publicReaderResult(Calculatorc)this.c=}publicvoidrun()synchronized(c)trySystem.out.println(Thread.currentThread()果。。。}catch(InterruptedExceptione)}System.out.println(Thread.currentThread計算結(jié)果為:}}publicstaticvoidmain(String[]args){Calculatorcalculator=newCalculator();newReaderResult(calculator).start();newnewnew}}Exceptioninthread"Thread-0"java.lang.IllegalMonitorStateException:currentthreadnotowneratjava.lang.Object.notifyAll(NativeMethod)atthreadtest.Calculatorrun(Calculator.java:18)Processfinishedwithexitcode實際上,上面這個代碼中,我們期望的是結(jié)果的線計算線程調(diào)用notifyAll()之前等待即可。但是,如果計算線程先執(zhí)行,并在結(jié)果線程等待之前調(diào)用了notify()方法,那么又會 因此,如果計算線程已經(jīng)調(diào)用了notifyAll()方法,那么它就不會再次調(diào)Java線程:線程的調(diào)度-休Java線程調(diào)度是Java多線程的,只有良好的調(diào)度,才能充分發(fā)揮系統(tǒng)的性能,提高程序的CPUCPU資源交給Thread.sleep(longmillis)Thread.sleep(longmillis,intnanos),均為靜態(tài)方sleepsleep,就休眠哪個線程。Java線程:線程的調(diào)度-*@authorleizhimin2009-11-4publicclassTestpublicstaticvoidmain(String[]args){Threadt1=newMyThread1();Threadt2=newThread(newMyRunnable());}}classMyThread1extendsThread{publicvoidrun(){for(inti=0;i<3;i++){System.out.println("1第i次執(zhí)行!");try}catch(InterruptedExceptione)}}}}classMyRunnableimplementsRunnable{publicvoidrun(){forfor(inti=0;i<3;i++)System.out.println("2第itry}catch(InterruptedExceptione)}}}}201011211222ProcessfinishedwithexitcodeJava線程:線程的調(diào)度-Java線程:線程的調(diào)度-*@authorleizhimin2009-11-4publicclassTestpublicstaticvoidmain(String[]args)ThreadThreadt1=newThreadt2=newThread(newMyRunnable());}}classMyThread1extendsThread{publicvoidrun(){for(inti=0;i<10;i++)System.out.println("1第i次執(zhí)行!");try{}catch(InterruptedExceptione)}}}}classMyRunnableimplementsRunnable{publicvoidrun(){for(inti=0;i<10;i++){System.out.println("2第i次執(zhí)行!");try}catch(InterruptedExceptione)}}}}10202111221213ProcessfinishedwithexitcodeJava線程:線程的調(diào)度-讓CPU資源,但是然給誰不知道,僅僅是讓出,線程Java線程:線程的調(diào)度-*@authorleizhimin2009-11-4publicclassTestpublicstaticvoidmain(String[]args){Threadt1=newMyThread1();Threadt2=newThread(new}}classMyThread1extendsThread{publicvoidrun(){for(inti=0;i<10;i++)System.out.println("System.out.println("1第i}}}classMyRunnableimplementsRunnable{publicvoidrun(){for(inti=0;i<10;i++)System.out.println("2第i次執(zhí)行!");}}}2021222310111213141516171819242526272829ProcessfinishedwithexitcodeJava線程:線程的調(diào)度-合join方法。joinvoidvoidvoidjoin(longmillisvoidjoin(longmillis,intmillisnanosJava線程:線程的調(diào)度-*@authorleizhimin2009-11-4publicclassTestpublicstaticvoidmain(String[]args){Threadt1=newMyThread1();for(inti=0;i<20;i++)System.out.println("主線程第i次執(zhí)行!");if(i>2)try{//t1t1}catch(InterruptedExceptione)}}}}classMyThread1extendsThread{publicvoidrun(){for(inti=0;i<10;i++){System.out.println("1第i次執(zhí)行!");}}}012ProcessfinishedwithexitcodeJava線程:線程的調(diào)度-守護線守護線程使用的情況較少,但并非無用,舉例來說,JVM的回收、內(nèi)存管理等線程都是守publicfinalvoidpublicfinalvoidsetDaemon(booleanon)將該線程標(biāo)記為守護線程或用戶線程。當(dāng)正在運行的線程都是守護線程時,Java虛擬機退出。該方法首先調(diào)用該線程的checkAccess參數(shù)on如果為true,則將該線程標(biāo)記為守護線程。-SecurityException如果當(dāng)前線程無法修改該線程。isDaemon(),Java線程:線程的調(diào)度-*@authorleizhimin2009-11-4publicclassTestpublicstaticvoidmain(String[]args){Threadt1=new Threadt2newThread(newMyDaemon()); }} monextendsThread{publicvoidrun(){for(inti=0;i<5;i++){System.out.println("1第i次執(zhí)行!");try}catch(InterruptedExceptione)}}}}}classMyDaemonimplementsRunnable{publicvoidrun(){for(longi=0;i<9999999L;i++) 線程第itry}catch(InterruptedExceptione)}}}}010111212133144567Processfinishedwithexitcode實際上:JRE判斷程序是否執(zhí)行結(jié)束的標(biāo)準(zhǔn)是所有的前臺執(zhí)線程行完畢了,而不管線程的Java線程:線程的同步-同步方Java代碼中需要完成一下兩個操作:把競爭的資源標(biāo)識為private;synchronized為了演示同步方法的使用,構(gòu)建了一個賬戶,起初信用額為100w,然后模擬透支、存款Useroper(intJava*@authorleizhimin2009-11-4publicclassTestpublicstaticvoidmain(String[]args)Useru=new ",MyThreadt1=newMyThread("A",u,20);MyThreadt2newMyThread("B"u60);MyThreadt3newMyThread("C"u80);MyThreadt4newMyThread("Du,30);MyThreadt5=newMyThread("E",u,32);MyThreadt6=newMyThread("F",u,21);}}classMyThreadextendsThread{privateUseru;privateinty=MyThread(Stringname,Useru,inty)this.u=u;this.y=}publicvoidrun()}}classUserprivateStringcode;privateintUser(Stringcode,intcash)this.code=code;this.cash=cash;}publicStringgetCode()return}publicvoidsetCode(Stringcode)this.code=}@paramxxpublicsynchronizedvoidoper(intx)trytrythis.cash+=System.out.println(Thread.currentThread().getName運行結(jié)束,增加“"+x+"”,當(dāng)前用戶賬戶余額為:"+cash);}catch(InterruptedExceptione)}}publicStringtoString()return"User{""code='"+code+'\''+",cash="+cash+}}線程線程A運行結(jié)束,增加“20”,當(dāng)前用戶賬戶余額為:120線程F運行結(jié)束,增加“21”,當(dāng)前用戶賬戶余額為:141線程E運行結(jié)束,增加“32”,當(dāng)前用戶賬戶余額為:173C運行結(jié)束,增加“-80”,當(dāng)前用戶賬戶余額為:93B運行結(jié)束,增加“-60”,當(dāng)前用戶賬戶余額為:33線程D運行結(jié)束,增加“-30”,當(dāng)前用戶賬戶余額為:3Processfinishedwithexitcode,不同步的情況,也就是去掉oper(intx)synchronized修飾符,然后運行程序,線程線程A運行結(jié)束,增加“20”,當(dāng)前用戶賬戶余額為:61線程D運行結(jié)束,增加“-30”,當(dāng)前用戶賬戶余額為:63B運行結(jié)束,增加“-60”,當(dāng)前用戶賬戶余額為:3線程F運行結(jié)束,增加“21”,當(dāng)前用戶賬戶余額為:61線程E運行結(jié)束,增加“32”,當(dāng)前用戶賬戶余額為:93C運行結(jié)束,增加“-80”,當(dāng)前用戶賬戶余額為:61Processfinishedwithexitcode很顯然,上面的結(jié)果是錯誤的,導(dǎo)致錯誤的原因是多個線程并發(fā)了競爭資源u,并對u的java.lang.Object類。voidvoidvoidvoid導(dǎo)致當(dāng)前的線程等待,直到其他線程調(diào)用此對象的notify()notifyAll()voidwai

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論