丨如何使用設計模式優(yōu)化并發(fā)編程_第1頁
丨如何使用設計模式優(yōu)化并發(fā)編程_第2頁
丨如何使用設計模式優(yōu)化并發(fā)編程_第3頁
丨如何使用設計模式優(yōu)化并發(fā)編程_第4頁
丨如何使用設計模式優(yōu)化并發(fā)編程_第5頁
已閱讀5頁,還剩22頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

publicclassQueryIdActionpublicvoidexecute(Contextcontext)trytrylongid=}(InterruptedException{}}}//執(zhí)行方publicclassExecutionTaskimplementsRunnableprivateQueryNameActionqueryNameAction=newprivateQueryIdActionqueryIdAction=newpublicvoidrun()finalContextcontext=newSystem.out.println("ThenamequerySystem.out.println("TheidquerySystem.out.println("TheNameis"+context.getName()"and}}publicstaticvoidmain(String[]args)72

IntStream.range(1,5).forEach(i->newThread(newContextTest().new}執(zhí)行結果代ThenamequeryThenamequeryThenamequeryThenamequeryTheidqueryTheidqueryTheidqueryTheidqueryTheNameisThread-1andidTheNameisThread-2andidTheNameisThread-3andidTheNameisThread-0andid然而這種方式太笨拙了,每次調用方法時,都需要傳入Context為參數,而且影響一些除了以上這些方法,其實我們還可以使用ThreadLocal實現上下文。ThreadLocal是線程本地變量,可以實現多線程的數據。ThreadLocal為每一個使用該變量的線程都提供一份獨立的副本,線程間的數據是的,每一個線程只能各自內部的副本變量。ThreadLocal中有三個常用的方法:set、get、initialValue,我們可以通過以下一個簡單的例子來看看ThreadLocal的使用:代privatevoidtestThreadLocal()Threadt=newThread()ThreadLocal<String>mStringThreadLocal=new4publicvoidrun() 14接下來,我們使用ThreadLocal來重新實現最開始的上下文設計。你會發(fā)現,我們在兩個方法中并沒有通過變量來傳下文,只是通過ThreadLocal獲取了當前線程的上下文信代publicclassContextTest//上下文publicstaticclassContextprivateStringprivatelong6publiclonggetId()return publicvoidsetId(longid) this.id= publicStringgetName() return publicvoidsetName(Stringname) = //上下文到ThreadLocal publicfinalstaticclassActionContext privatestaticfinalThreadLocal<Context>threadLocal=new protectedContextinitialValue() returnnew publicstaticActionContextgetActionContext() return publicContextgetContext() return //獲取ActionContext單 publicstaticclassContextHolder privatefinalstaticActionContextactionContext=new //設置上下文名publicclassQueryNameActionpublicvoidexecute()tryStringname= }catch(InterruptedExceptione) //設置上下文publicclassQueryIdActionpublicvoidexecute()trylongid=}catch(InterruptedExceptione) //執(zhí)行方publicclassExecutionTaskimplementsRunnableprivateQueryNameActionqueryNameAction=newprivateQueryIdActionqueryIdAction=new publicvoidrun() queryNameAction.execute();// System.out.println("Thenamequery queryIdAction.execute();//設置線程 System.out.println("Theidquery System.out.println("TheNameis"+ publicstaticvoidmain(String[]args)IntStream.range(1,5).forEach(i->newThread(newContextTest().new 93運行結果代ThenamequeryThenamequeryThenamequeryThenamequeryTheidqueryTheidqueryTheidqueryTheidqueryTheNameisThread-2andidTheNameisThread-0andidTheNameisThread-1andidTheNameisThread-3andidThread-Per-Message設計模式翻譯過來的意思就是每個消息一個線程的意思。例如,我們在處理Socket通信的時候,通常是一個線程處理以及I/O讀寫,如果I/O讀這個時候Thread-Per-Message模式就可以很好地解決這個問題,一個線程I/O事件,每當到一個I/O,則交給另一個處理線程執(zhí)行I/O操作。下面,我們還是通代//IO處publicclassServerHandlerimplementsprivateSocket4publicServerHandler(Socketsocket)this.socket= 8publicvoidrun()BufferedReaderin=PrintWriterout=Stringmsg=tryin=newBufferedReader(newout=newwhile((msg=in.readLine())!=null&&msg.length()!=0){//當連接成功后在System.out.println("serverreceived:"+ }catch(Exceptione)}finallytry}catch(IOExceptione) try}catch(Exceptione) try}catch(IOExceptione) 41代//SocketpublicclassServer3privatestaticintDEFAULT_PORT=privatestaticServerSocket6publicstaticvoidstart()throwsIOException publicstaticvoidstart(intport)throwsIOExceptionif(server!=null) try //啟動服 server=new //通過無線循環(huán)客戶端連 while(true) Socketsocket= //當有新的客戶端接入時,會執(zhí)行下 longstart= newThread(new longend= }finally

System.out.println("Spendtimeis"+(end-

if(server!=null)System.out.println服務器已關閉。");}} publicstaticvoidmain(String[]args)throws//運行服務newThread(new{publicvoidrun()try}catch(IOExceptione)}}}}以上,我們是完成了一個使用Thread-Per-Message計模式實現的Socket務端的代使用這種設計模式,如果遇到大的高并發(fā),就會出現嚴重的性能問題。如果針對每個I/O請求都創(chuàng)建一個線程來處理,在有大量請求同時進來時,就會創(chuàng)建大量線程,而此時JVM這里的Worker是工人的意思,代表在WorkerThread設計模式中,會有一些工人(線來。除了工人角色,WorkerThread設計模式中還包括了流水線和產品。這種設計模式相比Thread-Per-Message計模式,可以減少頻繁創(chuàng)建、銷毀線程所帶來我們可以假設一個場景來看下該模式的實現,通過WorkerThread計模式來完成一個物假設一個物流倉庫的物流分揀流水線上有8個機器人,它們不斷從流水線上獲取包裹并對代//publicclassPackageprivateStringprivateString5publicStringgetName()return 9publicvoidsetName(Stringname)= publicStringgetAddress()return publicvoidsetAddress(Stringaddress)this.address= publicvoidexecute()System.out.println(Thread.currentThread().getName()+"executed 25//3finalstaticint3finalstaticintMAX_PACKAGE_NUM=45finalPackage[]6finalWorker[]7int8int9intPackageChannel(intworkers)this.packageQueue=newthis.head=this.tail=this.count=this.workerPool=new}voidinit()for(inti=0;i<workerPool.length;i++){workerPool[i]=newWorker("Worker-"+i,}}*switchtostartallofworkertovoidstartWorker()}synchronizedvoidput(Packagepackagereq)while(count>=packageQueue.length)try}catch(InterruptedExceptione)}}this.packageQueue[tail]=this.tail=(tail+1)%}synchronizedPackagetake()while(count<=0)try

代 }catch(InterruptedExceptione)

}Packagerequest=this.head=(this.head+1)%this.count--return}}代//publicclassWorkerextendsprivatestaticfinalRandomrandom=newprivatefinalPackageChannel5 publicWorker(Stringname,PackageChannelchannel)78this.channel=9}publicvoidrun()while(true)try}catch(InterruptedExceptione)}}}}代publicclassTestpublicstaticvoidmain(String[]args)//新建8finalPackageChannelchannel=new//開始工78915

//為流水線添加for(inti=0;i<100;i++)Packagepackagereq=newPackage();}}我們可以看到,這里有8個工人在不斷地分揀倉庫中已經包裝好的商讀寫分離的業(yè)務場景中,則經常會用到ThreadLocal實現動態(tài)切換數據源操作。但在使用ThreadLocal時,我們需要注意內存泄漏問題,在之前的第25講中,我們已經討論過這個當主線程處理每次請求都非常耗時時,就可能出現阻塞問題,這時候我們可以考慮將主線程業(yè)務分工到新的業(yè)務線程中,從而提高系統(tǒng)的并行處理能力。而Threa-Per-Message設計模式

溫馨提示

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

評論

0/150

提交評論