java多线程高级主题2文档格式.docx
《java多线程高级主题2文档格式.docx》由会员分享,可在线阅读,更多相关《java多线程高级主题2文档格式.docx(18页珍藏版)》请在冰豆网上搜索。
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<
length;
i++){
if(数据组[i].mark==传入的值){
(数据组[i].*fn)();
break;
}
简单说c/c++中将要被调用的函数可以被保存起来,然后去访问,调用,而Java中,我们无法将一个方法保存,
除了直接调用,所以将要调用的方法用子类来实现,然后把这些子类实例保存起来,然后在这些子类的实现上
调用方法:
interfaceImy{
voidtest();
classAimplementsImy{
publicvoidtest(){
System.out.println("
A"
):
classBimplementsImy{
B"
classCimplementsImy{
C"
classMyStruct{
Imym;
publicMyStruct(intmark,Imym){this.mark=amrk;
this.m=m}
数组:
{newMyStruct(1,newA()),newMyStruct(2,newB()),newMyStruct(3,newC())}
for(inti=0;
数组.length;
i++)
if(参数==数组[i].mark){
数组[i].m.test();
这样把要调用的方法转换为对象的保程不仅仅是可以对要调用的方法进行调度,而且可以把对象序列化后
在另一台机器上执行,这样就把调用边界从线程扩展到了机器.
回到我们的例子:
代理其实就是在接口和实现类之间做一个中间人,一个实现如果直接执行接口的方法,我们无法对这些方法
的调用进行控制和跟踪等行为。
代理模式的意义在于用户要访问一个实现时其实是先访问这个对象的代理,由
这个代理来决定如何使用实现类,这样可以起到控制,延迟加载,缓存,隔离被代理的真正实现,也可以对
真正的实现的并发性,安全性和其它附加操作进行控制。
对于用户而言,请求时并不知道他请求的是代理对象,而是直接请求接口的操作,所以代理要和实现
类一样来实现类一样“继承”同一接口,在接口的方法中不去真正的实现而是调用实现类的实现。
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就是去真实地实现方法:
1.classSmartAxmanServiceImpimplementsISmartAxmanService{
2.publicResultresultTest(intcount,charc){
3.char[]buf=newchar[count];
4.for(inti=0;
i<
count;
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
模式和生产者-消费者模式。
1.classSchedulerextendsThread{
2.
3.privatefinalSmartQueuequeue;
//所有加载了请求方法的对象需要放在一个容器上以便统一调用处理。
4.//这里实现了一个队列
5.publicScheduler(SmartQueuequeue){
6.this.queue=queue;
7.}
8.
9.publicvoidinvoke(MethodRequestrequest){
10.this.queue.putRequest(request);
13.publicvoidrun(){
14.while(true){
15.//如果队列中有请求线程,则开始执行请求
16.MethodRequestrequest=this.queue.takeRequest();
17.request.execute();
在scheduler中只用一个队列来保存代表方法和请求对象,实行简单的FIFO调度,你要实更复杂的调度就要在这里重新实现,这个队列其实是生产者与消费者模式中的channel构件:
1.classSmartQueue{
3.privatestaticfinalintMAX_METHOD_REQUEST=100;
4.privatefinalMethodRequest[]requestQueue;
5.privateinttail;
6.privateinthead;
7.privateintcount;
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){}
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方法来方法具体方法转换成具体对象:
1.publicabstractclassMethodRequest{
3.protectedfinalSmartAxmanServiceImpserviceImp;
4.protectedfinalFutureResultfuture;
5.
6.protectedMethodRequest(SmartAxmanServiceImpserviceImp,FutureResultfuture){
8.this.future=future;
10.
11.publicabstractvoidexecute();
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;
27.
28.publicvoidexecute(){
29.Resultresult=serviceImp.resultTest(this.count,this.c);
30.this.future.setResult(result);
33.
34.publicclassNoResultRequestextendsMethodRequest{
35.privateStringstr;
36.
37.publicNoResultRequest(SmartAxmanServiceImpserviceImp,Stringstr){
38.super(serviceImp,null);
39.this.str=str;
40.}
42.publicvoidexecute(){
43.this.serviceImp.noResultTest(str);
44.}
45.}
而返回的数据我们也将真实数据的获取和取货凭证逻辑分离,这里虽然是经典的Future模式,但我们可以看到,
FutureResult其本质也是Result与RealResult的代理,或桥梁。
1.publicabstractclassResult{
2.publicabstractObjectgetResultValue();
3.}
5.publicclassFutureResultextendsResult{
6.
7.privateResultresult;
8.privatebooleancompleted;
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.}
26.publicclassRealResultextendsResult{
28.privatefinalObjectresultValue;
29.
30.publicRealResult(ObjectresultValue){
31.this.resultValue=resultValue;
34.publicObjectgetResultValue(){
35.returnthis.resultValue;
36.}
37.}
OK,现在这个异步消息处理器已经有了模型,这个异步处理器中有哪些对象参与呢?
SmartAxmanServiceImp忠心做真实的事务
SmartQueue将请求缓存起来以便调度
Scheduler对容器中的请求根据一定原则进行调度执行
Proxy将特定方法请求转换为特定对象
所有这些都是这个异步处理器的核心部件,既然是核心部件,我们就要进行封装而不能随便让调用者来修改,所以我们
用工厂模式(我KAO,我实在不想提模式但有时找不到其它词来表述)来产生处理器ISmartAxmanService对象:
1.classSmartAxmanServiceFactory{
2.publicstaticsynchronizedISmartAxmanServicecreateService(){
3.SmartAxmanServiceImpimp=newSmartAxmanServiceImp();
4.SmartQueuequeue=newSmartQueue();
5.Schedulerst=newScheduler(queue);
6.Proxyp=newProxy(st,imp);
7.st.start();
8.returnp;
好了,我们现在用两个请求的产生者不停产生请求:
ResultInvokeThread发送有返回值的请求:
1.publicclassResultInvokeThreadextendsThread{
2.privatefinalISmartAxmanServiceservice;
3.privatefinalcharc;
5.publicResultInvokeThread(Stringname,ISmartAxmanServiceservice){
6.this.service=service;
7.this.c=name.charAt(0);
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()