JAVA网页设计Java多线程编程形式实战指南:Active Object形式(上)仓酷云
J2ME在手机游戏开发的作用也是无用质疑的。至于桌面程序,可能有人说java不行,界面不好看,但是请看看net网页编程Beans和Eclipse吧,他们都是利用java开发的,而他们的界面是多么的华丽,所以界面决不是java的缺点。还有一个不得不提的优点就是大多java人员都挂在嘴边的java的跨平台性,目前这确实也是java优点之一。ActiveObject形式简介ActiveObject形式是一种异步编程形式。它经由过程对办法的挪用与办法的实行举行解耦来进步并发性。若以义务的观点来讲,ActiveObject形式的中心则是它同意义务的提交(相称于对异步办法的挪用)和义务的实行(相称于异步办法的真正实行)分别。这有点相似于System.gc()这个办法:客户端代码挪用完gc()后,一个举行渣滓接纳的义务被提交,但此时JVM其实不必定举行了渣滓接纳,而多是在gc()办法挪用前往后的某段工夫才入手下手实行义务——接纳渣滓。我们晓得,System.gc()的挪用方代码是运转在本人的线程上(一般是main线程派生的子线程),而JVM的渣滓接纳这个举措则由专门的线程(渣滓接纳线程)来实行的。换言之,System.gc()这个办法所代表的举措(其所界说的功效)的挪用方和实行方是运转在分歧的线程中的,从而进步了并发性。
再进一步先容ActiveObject形式,我们可先复杂地将其中心了解为一个名为ActiveObject的类,该类对外表露了一些异步办法,如所示。
.ActiveObject对象示例
doSomething办法的挪用方和实行方运转在各自的线程上。在并发的情况下,doSomething办法会被多个线程挪用。这时候所需的线程平安把持封装在doSomething办法面前,使得挪用方代码无需体贴这点,从而简化了挪用方代码:从挪用方代码来看,挪用一个ActiveObject对象的办法与挪用一般Java对象的办法并没有太年夜不同。如清单1所示。
清单1.ActiveObject办法挪用示例
ActiveObjectao=...;Futurefuture=ao.doSomething("data");//实行别的操纵Stringresult=future.get();System.out.println(result);ActiveObject形式的架构
当ActiveObject形式对外表露的异步办法被挪用时,与该办法挪用相干的高低文信息,包含被挪用的异步办法名(或其代表的操纵)、挪用方代码所传送的参数等,会被封装成一个对象。该对象被称为办法哀求(MethodRequest)。办法哀求对象会被存进ActiveObject形式所保护的缓冲区(ActivationQueue)中,并由专门的事情线程卖力依据其包括的高低文信息实行响应的操纵。也就是说,办法哀求对象是由运转挪用方代码的线程经由过程挪用ActiveObject形式对外表露的异步办法天生的,而办法哀求所代表的操纵则由专门的线程来实行,从而完成了办法的挪用与实行的分别,发生了并发。
ActiveObject形式的次要介入者有以下几种。其类图如所示。
.ActiveObject形式的类图
(点击图象缩小)
[*]Proxy:卖力对外表露异步办法接口。当挪用方代码挪用该介入者实例的异步办法doSomething时,该办法会天生一个响应的MethodRequest实例并将其存储到Scheduler所保护的缓冲区中。doSomething办法的前往值是一个暗示其实行了局的外包装对象:Future介入者的实例。异步办法doSomething运转在挪用方代码地点的线程中。
[*]MethodRequest:卖力将挪用方代码对Proxy实例的异步办法的挪用封装为一个对象。该对象保存了异步办法的称号及挪用方代码传送的参数等高低文信息。它使得将Proxy的异步办法的挪用和实行分别成为大概。其call办法会依据其所包括高低文信息挪用Servant实例的响应办法。
[*]ActivationQueue:卖力一时存储由Proxy的异步办法被挪用时所创立的MethodRequest实例的缓冲区。
[*]Scheduler:卖力将Proxy的异步办法所创立的MethodRequest实例存进其保护的缓冲区中。并依据必定的调剂战略,对其保护的缓冲区中的MethodRequest实例举行实行。其调剂战略能够依据实践必要来定,如FIFO、LIFO和依据MethodRequest中包括的信息所定的优先级等。
[*]Servant:卖力对Proxy所表露的异步办法的详细完成。
[*]Future:卖力存储和前往ActiveObject异步办法的实行了局。
ActiveObject形式的序列图如所示。
.ActiveObject形式的序列图
(点击图象缩小)
第1步:挪用方代码挪用Proxy的异步办法doSomething。
第2~7步:doSomething办法创立Future实例作为该办法的前往值。并将挪用方代码对该办法的挪用封装为MethodRequest对象。然后以所创立的MethodRequest对象作为参数挪用Scheduler的enqueue办法,以将MethodRequest对象存进缓冲区。Scheduler的enqueue办法会挪用Scheduler所保护的ActivationQueue实例的enqueue办法,将MethodRequest对象存进缓冲区。
第8步:doSomething前往其所创立的Future实例。
第9步:Scheduler实例接纳专门的事情线程运转dispatch办法。
第10~12步:dispatch办法挪用ActivationQueue实例的dequeue办法,猎取一个MethodRequest对象。然后挪用MethodRequest对象的call办法
第13~16步:MethodRequest对象的call办法挪用与其联系关系的Servant实例的响应办法doSomething。并将Servant.doSomething办法的前往值设置到Future实例上。
第17步:MethodRequest对象的call办法前往。
上述步骤中,第1~8步是运转在ActiveObject的挪用者线程中的,这几个步骤完成了将挪用方代码对ActiveObject所供应的异步办法的挪用封装成对象(MethodRequest),并将其存进缓冲区。这几个步骤完成了义务的提交。第9~17步是运转在ActiveObject的事情线程中,这些步骤完成从缓冲区中读取MethodRequest,并对其举行实行,完成了义务的实行。从而完成了ActiveObject对外表露的异步办法的挪用与实行的分别。
假如挪用方代码体贴ActiveObject的异步办法的前往值,则能够在其必要时,挪用Future实例的get办法来取得异步办法的真正实行了局。
ActiveObject形式实战案例
某电信软件有一个彩信短号模块。其次要功效是完成手机用户给别的手机用户发送彩信时,吸收方号码能够填写为对方的短号。比方,用户13612345678给其同事13787654321发送彩信时,能够将吸收方号码填写为对方的短号,如776,而非其实在的号码。
该模块处置其吸收到的下发彩信哀求的一个关头操纵是查询数据库以取得吸收方短号对应的实在号码(长号)。该操纵大概由于数据库妨碍而失利,从而使全部哀求没法持续被处置。而数据库妨碍是可恢复的妨碍,因而在短号转换为长号的过程当中假如呈现数据库非常,能够先将全部下发彩信哀求动静缓存到磁盘中,比及数据库恢复后,再从磁盘中读取哀求动静,举行重试。为便利起见,我们能够经由过程Java的对象序列化API,将暗示下发彩信的对象序列化到磁盘文件中从而完成哀求缓存。上面我们会商这个哀求缓存操纵还必要思索的别的要素,和ActiveObject形式怎样匡助我们满意这些思索。
起首,哀求动静缓存到磁盘中触及文件I/O这类慢的操纵,我们不但愿它在哀求处置的主线程(即Web服务器的事情线程)中实行。由于如许会使该模块的呼应延时增年夜,下降体系的呼应性。并使得Web服务器的事情线程因守候文件I/O而下降了体系的吞吐量。这时候,异步处置就派上用处了。ActiveObject形式能够匡助我们完成哀求缓存这个义务的提交和实行分别:义务的提交是在Web服务器的事情线程中完成,而义务的实行(包含序列化对象到磁盘文件中等操纵)则是在ActiveObject事情线程中实行。如许,哀求处置的主线程在侦测到短号转长号失利时便可以触发对以后彩信下发哀求举行缓存,接着持续其哀求处置,如给客户端呼应。而此时,以后哀求动静大概正在被ActiveObject线程缓存到文件中。如所示。
.异步完成缓存
其次,每一个短号转长号失利的彩信下发哀求动静会被缓存为一个磁盘文件。但我们不但愿这些缓存文件被存在统一个子目次下。而是但愿多个缓存文件会被存储到多个子目次中。每一个子目次最多能够存储指定个数(如2000个)的缓存文件。若以后子目次已存满,则新建一个子目次寄存新的缓存文件,直到该子目次也存满,依此类推。当这些子目次的个数抵达指定命量(如100个)时,最老的子目次(连同其下的缓存文件,假如有的话)会被删除。从而包管子目次的个数也是流动的。明显,在并发情况下,完成这类把持必要一些并发会见把持(如经由过程锁来把持),可是我们不但愿这类把持表露给处置哀求的别的代码。而ActiveObject形式中的Proxy介入者能够匡助我们封装并发会见把持。
上面,我们看该案例的相干代码经由过程使用ActiveObject形式在完成缓存功效时满意上述两个方针。起首看哀求处置的出口类。该类就是本案例的ActiveObject形式的客挪用方代码。如清单2所示。
清单2.彩信下发哀求处置的出口类
publicclassMMSDeliveryServletextendsHttpServlet{privatestaticfinallongserialVersionUID=5886933373599895099L;@OverridepublicvoiddoPost(HttpServletRequestreq,HttpServletResponseresp)throwsServletException,IOException{//将哀求中的数据剖析为外部对象MMSDeliverRequestmmsDeliverReq=this.parseRequest(req.getInputStream());RecipientshortNumberRecipient=mmsDeliverReq.getRecipient();RecipientoriginalNumberRecipient=null;try{//将吸收方短号转换为长号originalNumberRecipient=convertShortNumber(shortNumberRecipient);}catch(SQLExceptione){//吸收方短号转换为长号时产生数据库非常,触发哀求动静的缓存AsyncRequestPersistence.getInstance().store(mmsDeliverReq);//持续对以后哀求的别的处置,如给客户端呼应resp.setStatus(202);}}privateMMSDeliverRequestparseRequest(InputStreamreqInputStream){MMSDeliverRequestmmsDeliverReq=newMMSDeliverRequest();//省略别的代码returnmmsDeliverReq;}privateRecipientconvertShortNumber(RecipientshortNumberRecipient)throwsSQLException{Recipientrecipent=null;//省略别的代码returnrecipent;}}清单2中的doPost办法在侦测到短号转换过程当中产生的数据库非常后,经由过程挪用AsyncRequestPersistence类的store办法触发对彩信下发哀求动静的缓存。这里,AsyncRequestPersistence类相称于ActiveObject形式中的Proxy介入者。只管本案例触及的是一个并发情况,但从清单2中的代码可见,AsyncRequestPersistence类的挪用方代码无需处置多线程同步成绩。这是由于多线程同步成绩被封装在AsyncRequestPersistence类以后。
AsyncRequestPersistence类的代码如清单3所示。
清单3.彩信下发哀求缓存出口类(ActiveObject形式的Proxy)
//ActiveObjectPattern.ProxypublicclassAsyncRequestPersistenceimplementsRequestPersistence{privatestaticfinallongONE_MINUTE_IN_SECONDS=60;privatefinalLoggerlogger;privatefinalAtomicLongtaskTimeConsumedPerInterval=newAtomicLong(0);privatefinalAtomicIntegerrequestSubmittedPerIterval=newAtomicInteger(0);//ActiveObjectPattern.ServantprivatefinalDiskbasedRequestPersistencedelegate=newDiskbasedRequestPersistence();//ActiveObjectPattern.SchedulerprivatefinalThreadPoolExecutorscheduler;privatestaticclassInstanceHolder{finalstaticRequestPersistenceINSTANCE=newAsyncRequestPersistence();}privateAsyncRequestPersistence(){logger=Logger.getLogger(AsyncRequestPersistence.class);scheduler=newThreadPoolExecutor(1,3,60*ONE_MINUTE_IN_SECONDS,TimeUnit.SECONDS,//ActiveObjectPattern.ActivationQueuenewLinkedBlockingQueue(200),newThreadFactory(){@OverridepublicThreadnewThread(Runnabler){Threadt;t=newThread(r,"AsyncRequestPersistence");returnt;}});scheduler.setRejectedExecutionHandler(newThreadPoolExecutor.DiscardOldestPolicy());//启动行列监控准时义务TimermonitorTimer=newTimer(true);monitorTimer.scheduleAtFixedRate(newTimerTask(){@Overridepublicvoidrun(){if(logger.isInfoEnabled()){logger.info("taskcount:"+requestSubmittedPerIterval+",Queuesize:"+scheduler.getQueue().size()+",taskTimeConsumedPerInterval:"+taskTimeConsumedPerInterval.get()+"ms");}taskTimeConsumedPerInterval.set(0);requestSubmittedPerIterval.set(0);}},0,ONE_MINUTE_IN_SECONDS*1000);}publicstaticRequestPersistencegetInstance(){returnInstanceHolder.INSTANCE;}@Overridepublicvoidstore(finalMMSDeliverRequestrequest){/**将对store办法的挪用封装成MethodRequest对象,并存进缓冲区。*///ActiveObjectPattern.MethodRequestCallablemethodRequest=newCallable(){@OverridepublicBooleancall()throwsException{longstart=System.currentTimeMillis();try{delegate.store(request);}finally{taskTimeConsumedPerInterval.addAndGet(System.currentTimeMillis()-start);}returnBoolean.TRUE;}};scheduler.submit(methodRequest);requestSubmittedPerIterval.incrementAndGet();}}AsyncRequestPersistence类所完成的接口RequestPersistence界说了ActiveObject对外表露的异步办法:store办法。因为本案例不体贴哀求缓存的了局,故该办法没有前往值。其代码如清单4所示。
清单4.RequestPersistence接口源码
publicinterfaceRequestPersistence{voidstore(MMSDeliverRequestrequest);}AsyncRequestPersistence类的实例变量scheduler相称于ActiveObject形式中的Scheduler介入者实例。这里我们间接利用了JDK1.5引进的ExecutorFramework中的ThreadPoolExecutor。在ThreadPoolExecutor类的实例化时,其机关器的第5个参数(BlockingQueue<Runnable>workQueue)我们指定了一个有界堵塞行列:newLinkedBlockingQueue<Runnable>(200)。该行列相称于ActiveObject形式中的ActivationQueue介入者实例。
AsyncRequestPersistence类的实例变量delegate相称于ActiveObject形式中的Servant介入者实例。
AsyncRequestPersistence类的store办法使用匿名类天生一个java.util.concurrent.Callable实例methodRequest。该实例相称于ActiveObject形式中的MethodRequest介入者实例。使用闭包(Closure),该实例封装了对store办法挪用的高低文信息(包含挪用参数、所挪用的办法对应的操纵信息)。AsyncRequestPersistence类的store办法经由过程挪用scheduler的submit办法,将methodRequest送进ThreadPoolExecutor所保护的缓冲区(堵塞行列)中。切实地说,ThreadPoolExecutor是Scheduler介入者的一个“近似”完成。ThreadPoolExecutor的submit办法相对Scheduler的enqueue办法,该办法用于回收MethodRequest对象,以将其存进缓冲区。当ThreadPoolExecutor以后利用的线程数目小于其中心线程数目时,submit办法所吸收的义务会间接被新建的线程实行。当ThreadPoolExecutor以后利用的线程数目年夜于其中心线程数时,submit办法所吸收的义务才会被存进其保护的堵塞行列中。不外,ThreadPoolExecutor的这类义务处置机制,其实不妨害我们将它用作Scheduler的完成。
methodRequest的call办法会挪用delegate的store办法来真正完成哀求缓存功效。delegate实例对应的类DiskbasedRequestPersistence是哀求动静缓存功效的真正完成者。其代码如清单5所示。
清单5.DiskbasedRequestPersistence类的源码
publicclassDiskbasedRequestPersistenceimplementsRequestPersistence{//卖力缓存文件的存储办理privatefinalSectionBasedDiskStoragestorage=newSectionBasedDiskStorage();privatefinalLoggerlogger=Logger.getLogger(DiskbasedRequestPersistence.class);@Overridepublicvoidstore(MMSDeliverRequestrequest){//请求缓存文件的文件名String[]fileNameParts=storage.apply4Filename(request);Filefile=newFile(fileNameParts);try{ObjectOutputStreamobjOut=newObjectOutputStream(newFileOutputStream(file));try{objOut.writeObject(request);}finally{objOut.close();}}catch(FileNotFoundExceptione){storage.decrementSectionFileCount(fileNameParts);logger.error("Failedtostorerequest",e);}catch(IOExceptione){storage.decrementSectionFileCount(fileNameParts);logger.error("Failedtostorerequest",e);}}classSectionBasedDiskStorage{privateDequesectionNames=newLinkedList();/**Key->value:存储子目次名->子目次下缓存文件计数器*/privateMapmethodRequest的call办法的挪用者代码是运转在ThreadPoolExecutor所保护的事情者线程中,这就包管了store办法的挪用方和真实的实行方是分离运转在分歧的线程中:服务器事情线程卖力触发哀求动静缓存,ThreadPoolExecutor所保护的事情线程卖力将哀求动静序列化到磁盘文件中。
你通过从书的数量和开发周期及运行速度来证明:net网页编程和ruby要比java简单。 是一种突破用户端机器环境和CPU 关于设计模式的资料,还是向大家推荐banq的网站 http://www.jdon.com/,他把GOF的23种模式以通俗易懂的方式诠释出来,纯Java描述,真是经典中的经典。 是一种为 Internet发展的计算机语言 设计模式是高级程序员真正掌握面向对象核心思想的必修课。设计模式并不是一种具体"技术",它讲述的是思想,它不仅仅展示了接口或抽象类在实际案例中的灵活应用和智慧 让你能够真正掌握接口或抽象类的应用,从而在原来的Java语言基础上跃进一步,更重要的是,设计模式反复向你强调一个宗旨:要让你的程序尽可能的可重用。 有时间再研究一下MVC结构(把Model-View-Control分离开的设计思想) 接着就是EJB了,EJB就是Enterprise JavaBean, 看名字好象它是Javabean,可是它和Javabean还是有区别的。它是一个体系结构,你可以搭建更安全、更稳定的企业应用。它的大量代码已由中间件(也就是我们常听到的 Weblogic,Websphere这些J2EE服务器)完成了,所以我们要做的程序代码量很少,大部分工作都在设计和配置中间件上。 是一种简化的C++语言 是一种安全的语言,具有阻绝计算机病毒传输的功能 你一定会高兴地说,哈哈,原来成为Java高手就这么简单啊!记得Tomjava也曾碰到过一个项目经理,号称Java很简单,只要三个月就可以学会。
页:
[1]