java多线程高级主题2.docx
- 文档编号:3302379
- 上传时间:2022-11-21
- 格式:DOCX
- 页数:18
- 大小:411.88KB
java多线程高级主题2.docx
《java多线程高级主题2.docx》由会员分享,可在线阅读,更多相关《java多线程高级主题2.docx(18页珍藏版)》请在冰豆网上搜索。
java多线程高级主题2
Java异步消息处理
在前一节实现异步调用的基础上,现在我们来看一下一个完善的Java异步消息处理机制.
[写在本节之前]
在所有这些地方,我始终没有提到设计模式这个词,而事实上,多线程编程几乎每一步都在应用
设计模式.你只要能恰如其份地应用它,为什么要在意你用了某某名称的模式呢?
一个说书人它可以把武功招数说得天花乱坠,引得一班听书客掌声如雷,但他只是说书的.真正的
武林高手也许并不知道自己的招式在说书人口中叫什么,这不重要,重要的是他能在最恰当的时机把他
不知名的招式发挥到极致!
你了解再多的设计模式,或你写出了此类的著作,并不重要,重要的是你能应用它设计出性能卓越
的系统.
本节的这个例子,如果你真正的理解了,不要怀疑自己,你已经是Java高手的行列了.如果你抛开
本节的内容,五天后能自己独立地把它再实现一次,那你完全可以不用再看我写的文章系列了,至少是
目前,我再也没有更高级的内容要介绍了.
在我的这个异步消息处理器组件中,使用了很多模式,或许我不能准确地命名它们,但我可以
把它们正确地应用到这个组件的实现上,包括这个组件本身,我给它命名为“主动服务模式”,因为组件
自身拥有自己独立的线程来配合客户端请求做出响应,在这个过程中,组件本身有极大的主动性在控制
整个调用过程,而不是依靠客户端的调用者来控制整个过程。
上节的Java异步调用为了简化调用关系,很多角色被合并到一个类中实现,为了帮助大家改快地
抓住核心的流程.那么一个真正的异步消息处理器,当然不是这样的简单.
1.它要能适应不同类型的请求:
本节用ResultTest来说明要求有返回值的请求.用noResultTest来说明不需要返回值的请求.
2.要能同时并发处理多个请求,并能按一定机制调度:
本节将用一个队列来存放请求,所以只能按FIFO机制调度,你可以改用LinkedList,就可以简单实现一个
优先级(优先级高的addFirst,低的addLast).
3.有能力将调用的边界从线程扩展到机器间(RMI)
4.分离过度耦合,如分离调用句柄(取货凭证)和真实数据的实现.分离调用和执行的过程,可以尽快地将调返回.
现在看具体的实现:
[java:
nogutter]viewplaincopyprint?
1.publicinterfaceISmartAxmanService{
2.ResultresultTest(intcount,charc);
3.
4.voidnoResultTest(Stringstr);
5.}
这个接口有两个方法要实现,就是有返回值的调用resultTest和不需要返回值的调用noResultTest,
我们把这个接口用一个代理类来实现,目的是将方法调用转化为对象,这样就可以将多个请求(多个方法调)
放到一个容器中缓存起来,然后统一处理,因为Java不支持方法指针,所以把方法调用转换为对象,然后在
这个对象上统一执行它们的方法,不仅可以做到异步处理,而且可以将代表方法调用的请求对象序列化后
通过网络传递到另一个机器上执行(RMI).这也是Java回调机制最有力的实现.
一个简单的例子.
如果1:
做A
如果2:
做B
如果3:
做C
如果有1000个情况,你不至于用1000个case吧?
以后再增加呢?
所以如果C/C++程序员,会这样实现:
(c和c++定义结构不同)
typedefinestructMyStruct{
intmark;
(*fn)();
}MyList;
然后你可以声明这个结构数据:
{1,A,2,B,3,C}
做一个循环:
for(i=0;i if(数据组[i].mark==传入的值){ (数据组[i].*fn)(); break; } } 简单说c/c++中将要被调用的函数可以被保存起来,然后去访问,调用,而Java中,我们无法将一个方法保存, 除了直接调用,所以将要调用的方法用子类来实现,然后把这些子类实例保存起来,然后在这些子类的实现上 调用方法: interfaceImy{ voidtest(); } classAimplementsImy{ publicvoidtest(){ System.out.println("A"): } } classBimplementsImy{ publicvoidtest(){ System.out.println("B"): } } classCimplementsImy{ publicvoidtest(){ System.out.println("C"): } } classMyStruct{ intmark; Imym; publicMyStruct(intmark,Imym){this.mark=amrk;this.m=m} } 数组: {newMyStruct(1,newA()),newMyStruct(2,newB()),newMyStruct(3,newC())} for(inti=0;i<数组.length;i++) if(参数==数组[i].mark){ 数组[i].m.test();break; } 这样把要调用的方法转换为对象的保程不仅仅是可以对要调用的方法进行调度,而且可以把对象序列化后 在另一台机器上执行,这样就把调用边界从线程扩展到了机器. 回到我们的例子: 代理其实就是在接口和实现类之间做一个中间人,一个实现如果直接执行接口的方法,我们无法对这些方法 的调用进行控制和跟踪等行为。 代理模式的意义在于用户要访问一个实现时其实是先访问这个对象的代理,由 这个代理来决定如何使用实现类,这样可以起到控制,延迟加载,缓存,隔离被代理的真正实现,也可以对 真正的实现的并发性,安全性和其它附加操作进行控制。 对于用户而言,请求时并不知道他请求的是代理对象,而是直接请求接口的操作,所以代理要和实现 类一样来实现类一样“继承”同一接口,在接口的方法中不去真正的实现而是调用实现类的实现。 [java: nogutter]viewplaincopyprint? 1.classProxyimplementsISmartAxmanService{ 2.privatefinalSchedulerscheduler;//这个调度者就是代理用来控制实现类的调用的 3.privatefinalSmartAxmanServiceImpserviceImp;//这个实现类完成接口方法的真正实现 4. 5.publicProxy(Schedulerscheduler,SmartAxmanServiceImpserviceImp){ 6.this.scheduler=scheduler; 7.this.serviceImp=serviceImp; 8.} 9. 10.publicResultresultTest(intcount,charc){ 11. 12.FutureResultfutrue=newFutureResult(); 13.//如果弱化代理的调度控制,这里就应该象下面注释掉的代码: 14.//doBeforeImpResultTest(); 15.//serviceImp.ResultTest(); 16.//doAfterImpResultTest(); 17.//这里进行了更复杂的控制,所以把实现和调度传递给ResultRequest来执行。 18.this.scheduler.invoke(newResultRequest(serviceImp,futrue,count,c)); 19.returnfutrue; 20.} 21. 22.publicvoidnoResultTest(Stringstr){ 23. 24.//同上 25.this.scheduler.invoke(newNoResultRequest(this.serviceImp,str)); 26.} 27.} SmartAxmanServiceImp就是去真实地实现方法: [java: nogutter]viewplaincopyprint? 1.classSmartAxmanServiceImpimplementsISmartAxmanService{ 2.publicResultresultTest(intcount,charc){ 3.char[]buf=newchar[count]; 4.for(inti=0;i 5.buf[i]=c; 6.try{ 7.Thread.sleep(100);//模拟耗时操作 8.}catch(Throwablet){} 9.} 10.returnnewRealResult(newString(buf)); 11.} 12. 13.publicvoidnoResultTest(Stringstr){ 14.try{ 15.System.out.println("displayString: "+str); 16.Thread.sleep(10); 17.}catch(Throwablet){} 18.} 19.} 在scheduler将方法的调用(invkoe)和执行(execute)进行了分离,调用就是开始“注册”方法到要执行的容器中,这样 就可以立即返回出来.真正执行多久就是execute的事了,就象一个人点燃爆竹的引信就跑了,至于那个爆竹什么时候 爆炸就不是他能控制的了. 因为这个组件有自己独立的线程在执行调用者的请求,是整个组件“主动性”的关键。 事实上,它还实现了WorkerThread 模式和生产者-消费者模式。 [java: nogutter]viewplaincopyprint? 1.classSchedulerextendsThread{ 2. 3.privatefinalSmartQueuequeue;//所有加载了请求方法的对象需要放在一个容器上以便统一调用处理。 4.//这里实现了一个队列 5.publicScheduler(SmartQueuequeue){ 6.this.queue=queue; 7.} 8. 9.publicvoidinvoke(MethodRequestrequest){ 10.this.queue.putRequest(request); 11.} 12. 13.publicvoidrun(){ 14.while(true){ 15.//如果队列中有请求线程,则开始执行请求 16.MethodRequestrequest=this.queue.takeRequest(); 17.request.execute(); 18.} 19.} 20.} 在scheduler中只用一个队列来保存代表方法和请求对象,实行简单的FIFO调度,你要实更复杂的调度就要在这里重新实现,这个队列其实是生产者与消费者模式中的channel构件: [java: nogutter]viewplaincopyprint? 1.classSmartQueue{ 2. 3.privatestaticfinalintMAX_METHOD_REQUEST=100; 4.privatefinalMethodRequest[]requestQueue; 5.privateinttail; 6.privateinthead; 7.privateintcount; 8. 9.publicSmartQueue(){ 10.this.requestQueue=newMethodRequest[MAX_METHOD_REQUEST]; 11.this.head=this.count=this.tail=0; 12.} 13. 14.publicsynchronizedvoidputRequest(MethodRequestrequest){ 15.while(this.count>=this.requestQueue.length){ 16.try{ 17.this.wait(); 18.}catch(Throwablet){} 19.} 20.this.requestQueue[this.tail]=request; 21.tail=(tail+1)%this.requestQueue.length;//如果到数组最后则从头开始 22.count++; 23.this.notifyAll(); 24.} 25. 26.publicsynchronizedMethodRequesttakeRequest(){ 27.while(this.count<=0){ 28.try{ 29.this.wait(); 30.}catch(Throwablet){ 31.} 32.} 33.MethodRequestrequest=this.requestQueue[this.head]; 34. 35.//this.requestQueue[this.head]=null; 36.//考虑注释掉的这一行代码,对于循环的队列还不是非常明显,如果是非循环的队列。 这个元素 37.//可能永远被持有,比如一个Stack中如果put了,再pop时,虽然对象被取走了,栈顶指针指象了index+1; 38.//但底层的数组中那个index位置的对象还被数组本身引用着,如果没有put动作替换这个位置的句柄指向一个 39.//新的对象,则已经pop出去的对象一直被数组本身引用着。 所以对于处于数据结构中的对象如果要从中取出, 40.//数据结果本身要取消对它的引用。 41. 42.this.head=(this.head+1)%this.requestQueue.length; 43.count--; 44.this.notifyAll(); 45.returnrequest; 46.} 47.} 为了将方法调用转化为对象,我们通过实现MethodRequest对象的execute方法来方法具体方法转换成具体对象: [java: nogutter]viewplaincopyprint? 1.publicabstractclassMethodRequest{ 2. 3.protectedfinalSmartAxmanServiceImpserviceImp; 4.protectedfinalFutureResultfuture; 5. 6.protectedMethodRequest(SmartAxmanServiceImpserviceImp,FutureResultfuture){ 7.this.serviceImp=serviceImp; 8.this.future=future; 9.} 10. 11.publicabstractvoidexecute(); 12. 13.} 14. 15.publicclassResultRequestextendsMethodRequest{ 16.privatefinalintcount; 17.privatefinalcharc; 18. 19.publicResultRequest(SmartAxmanServiceImpserviceImp, 20.FutureResultfuture, 21.intcount, 22.charc){ 23.super(serviceImp,future); 24.this.count=count; 25.this.c=c; 26.} 27. 28.publicvoidexecute(){ 29.Resultresult=serviceImp.resultTest(this.count,this.c); 30.this.future.setResult(result); 31.} 32.} 33. 34.publicclassNoResultRequestextendsMethodRequest{ 35.privateStringstr; 36. 37.publicNoResultRequest(SmartAxmanServiceImpserviceImp,Stringstr){ 38.super(serviceImp,null); 39.this.str=str; 40.} 41. 42.publicvoidexecute(){ 43.this.serviceImp.noResultTest(str); 44.} 45.} 而返回的数据我们也将真实数据的获取和取货凭证逻辑分离,这里虽然是经典的Future模式,但我们可以看到, FutureResult其本质也是Result与RealResult的代理,或桥梁。 [java: nogutter]viewplaincopyprint? 1.publicabstractclassResult{ 2.publicabstractObjectgetResultValue(); 3.} 4. 5.publicclassFutureResultextendsResult{ 6. 7.privateResultresult; 8.privatebooleancompleted; 9. 10.publicsynchronizedvoidsetResult(Resultresult){ 11.this.result=result; 12.pleted=true; 13.this.notifyAll(); 14.} 15. 16.publicsynchronizedObjectgetResultValue(){ 17.while(! pleted){ 18.try{ 19.this.wait(); 20.}catch(Throwablet){} 21.} 22.returnthis.result.getResultValue(); 23.} 24.} 25. 26.publicclassRealResultextendsResult{ 27. 28.privatefinalObjectresultValue; 29. 30.publicRealResult(ObjectresultValue){ 31.this.resultValue=resultValue; 32.} 33. 34.publicObjectgetResultValue(){ 35.returnthis.resultValue; 36.} 37.} OK,现在这个异步消息处理器已经有了模型,这个异步处理器中有哪些对象参与呢? SmartAxmanServiceImp忠心做真实的事务 SmartQueue将请求缓存起来以便调度 Scheduler对容器中的请求根据一定原则进行调度执行 Proxy将特定方法请求转换为特定对象 所有这些都是这个异步处理器的核心部件,既然是核心部件,我们就要进行封装而不能随便让调用者来修改,所以我们 用工厂模式(我KAO,我实在不想提模式但有时找不到其它词来表述)来产生处理器ISmartAxmanService对象: [java: nogutter]viewplaincopyprint? 1.classSmartAxmanServiceFactory{ 2.publicstaticsynchronizedISmartAxmanServicecreateService(){ 3.SmartAxmanServiceImpimp=newSmartAxmanServiceImp(); 4.SmartQueuequeue=newSmartQueue(); 5.Schedulerst=newScheduler(queue); 6.Proxyp=newProxy(st,imp); 7.st.start(); 8.returnp; 9.} 10. 11.} 好了,我们现在用两个请求的产生者不停产生请求: ResultInvokeThread发送有返回值的请求: [java: nogutter]viewplaincopyprint? 1.publicclassResultInvokeThreadextendsThread{ 2.privatefinalISmartAxmanServiceservice; 3.privatefinalcharc; 4. 5.publicResultInvokeThread(Stringname,ISmartAxmanServiceservice){ 6.this.service=service; 7.this.c=name.charAt(0); 8.} 9. 10.publicvoidrun(){ 11.try{ 12.inti=0; 13.while(true){ 14.Resultresult=this.service.resultTest(i++,c); 15.Thread.sleep(10); 16.Stringvalue=(String)result.getResultValue()
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- java 多线程 高级 主题
![提示](https://static.bdocx.com/images/bang_tan.gif)