诗剑书生的专栏

我在灌江口上住,花开花落,不知流年度.雁过空遗秋色暮,抚琴细听梧桐雨. 轻舞残虹漫展书,云卷云舒,思愫万千缕.安得婵娟与共处,长作识字耕田夫.                   诗剑书生 于灌江口.听潮居

用户操作
[即时聊天] [发私信] [加为好友]
诗剑书生ID:axman
114347次访问,排名809,好友33人,关注者41人。
一个男人. 一个写程序男人. 一个写程序并从程序中寻找快乐的男人. 一个写程序并从程序中寻找快乐又把快乐传递给大家的男人.
一个书生. 一个寂寞的书生. 一个寂寞的梅香竹影下敲声写韵的书生. 一个寂寞的梅香竹影下敲声写韵晨钟暮鼓中逸气扬剑的书生.
那个男人是位书生。没有人知道他的姓名,居无定所,行无定踪,亦耕亦读,或渔或樵。
axman的文章
原创 89 篇
翻译 0 篇
转载 0 篇
评论 174 篇
axman的公告
最近评论
axman:这个组件经过N年检验没有任何问题,你的调用方式错误。只从form.getCsvPath()这几个字符我就可以判断你一定是使用了某种框架,先处理了request对象.

如果真正了解sevlet底层的人,request一经处理过滤,除非pushback,否则不可能再次读出原来的数据.这是最最起码的常识.
zhoche2008:Upload up = new Upload();
up.init(request);
up.setSaveDir(form.getCsvPath());
up.setTagFileName(fileName);
up.uploadFile();
String pathName = up.getFileName()[0];
按你的……
YuLimin:也只有axman老大才会如何深刻地描述并分享这种技术的根源,憾动ing!
hujianshi:喜欢看您的文章,支持!!!!
xiaozhang927:一个有心人.
文章分类
收藏
    相册
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 多线程编程 高级主题(二)收藏

    新一篇: 多线程编程 实战篇秘籍 (一)  | 旧一篇: 多线程编程 高级主题(一)

                                                     Java 异步消息处理

           在前一节实现异步调用的基础上,现在我们来看一下一个完善的Java异步消息处理机制.

    [写在本节之前]

           在所有这些地方,我始终没有提到设计模式这个词,而事实上,多线程编程几乎每一步都在应该设计模式.你只要能恰如其份地应用它,为什么要在意你用了某某名称的模式呢?

           一个说书人它可以把武功招数说得天花乱坠,引得一班听书客掌声如雷,但他只是说书的.真正的武林高手也许并不知道自己的招式在说书人口中叫什么,这不重要,重要的是他能在最恰当的时机把他不知名的招式发挥到极致!

           你了解再多的设计模式,或你写出了此类的著作,并不重要,重要的是你能应用它设计出性能卓越的系统.

     

     

           本节的这个例子,如果你真正的理解了,不要怀疑自己,你已经是Java高手的行列了.如果你抛开本节的内容,五天后能自己独立地把它再实现一次,那你完全可以不用再看我写的文章系列了,至少是目前,我再也没有更高级的内容要介绍了.

           上节的Java异步调用为了简化调用关系,很多角色被合并到一个类中实现,为了帮助大家改快地抓住核心的流程.那么一个真正的异步消息处理器,当然不是这样的简单.

    一.   它要能适应不同类型的请求:

    本节用 makeString来说明要求有返回值的请求.displayString来说明不需要返回值的请求.

    二.   要能同时并发处理多个请求,并能按一定机制调度:

    本节将用一个队列来存放请求,所以只能按FIFO机制调度,你可以改用LinkedList,就可以简单实现一个优先级(优先级高的addFirst,低的addLast).

    三.   有能力将调用的边界从线程扩展到机器间(RMI)

    四.   分离过度耦合,如分离调用句柄(取货凭证)和真实数据的实现.分离调用和执行的过程,可以尽快地将调返回.

     

    现在看具体的实现:

    public interface Axman {

      Result resultTest(int count,char c);

      void noResultTest(String str);

    }

    这个接口有两个方法要实现,就是有返回值的调用resultTest和不需要返回值的调用

    noResultTest,我们把这个接口用一个代理类来实现,目的是将方法调用转化为对象,这样就可以将多个请求(多个方法调)放到一个容器中缓存起来,然后统一处理,因为Java不支持方法指针,所以把方法调用转换为对象,然后在这个对象上统一执行它们的方法,不仅可以做到异步处理,而且可以将代表方法调用的请求对象序列化后通过网络传递到另一个机器上执行(RMI).这也是Java回调机制最有力的实现.

           一个简单的例子.

           如果 1: A

           如果 2: B

    如果 3: C

    如果有1000个情况,你不至于用1000case?以后再增加呢?

    所以如果C/C++程序员,会这样实现: (cc++定义结构不同)

     

    type define struct MyStruct{

    int mark;

    (*fn) ();

    } MyList;

          

           然后你可以声明这个结构数据:

           {1,A,

            2,B

            3,C

    }

    做一个循环:

    for(i=0;i<length;i++) {

           if(数据组[i].mark == 传入的值) (数据组[i].*fn)();

    }

    简单说c/c++中将要被调用的涵数可以被保存起来,然后去访问,调用,Java,我们无法将一个方法保存,除了直接调用,所以将要调用的方法用子类来实现,然后把这些子类实例保存起来,然后在这些子类的实现上调用方法:

    interface My{

           void test();

    }

     

    class A implements My{

           public void test(){

                  System.out.println(“A”):

    }

    }

    class B implements My{

           public void test(){

                  System.out.println(“B”):

    }

    }

     

    class C implements My{

           public void test(){

                  System.out.println(“C”):

    }

    }

     

    class MyStruct {

          

           int mark;

           My m;

           public MyStruct(int mark,My m){this.mark = amrk;this.m = m}

    }

    数组:

    { new MyStruct(1,new A()),new MyStruct(2,new B()),new MyStruct(3,new C())}

    for(xxxxxxxxx) if(参数 ==数组[i].mark) 数组[i].m.test();

     

    这样把要调用的方法转换为对象的保程不仅仅是可以对要调用的方法进行调度,而且可以把对象序列化后在另一台机器上执行,这样就把调用边界从线程扩展到了机器.

     

    回到我们的例子:

    class Proxy implements Axman{

      private final Scheduler scheduler;

      private final Servant servant;

     

      public Proxy(Scheduler scheduler,Servant servant){

        this.scheduler = scheduler;

        this.servant = servant;

      }

      public Result resultTest(int count,char c){

        FutureResult futrue = new FutureResult();

        this.scheduler.invoke(new ResultRequest(servant,futrue,count,c));

        return futrue;

      }

     

      public void noResultTest(String str){

        this.scheduler.invoke(new NoResultRequest(this.servant,str));

      }

    }

     

    其中scheduler是管理对调用的调度, servant是真正的对方法的执行:

     

    Servant就是去真实地实现方法:

     

    class Servant implements Axman{

      public Result resultTest(int count,char c){

        char[] buf = new char[count];

        for(int i = 0;i < count;i++){

          buf[i] = c;

          try{

            Thread.sleep(100);

          }catch(Throwable t){}

        }

        return new RealResult(new String(buf));

      }

     

      public void noResultTest(String str){

        try{

          System.out.println("displayString :" + str);

          Thread.sleep(10);

        }catch(Throwable t){}

      }

    }

    scheduler将方法的调用(invkoe)和执行(execute)进行了分离,调用就是开始注册方法到要执行的容器中,这样就可以立即返回出来.真正执行多久就是execute的事了,就象一个人点燃爆竹的引信就跑了,至于那个爆竹什么时候爆炸就不是他能控制的了.

    public class Scheduler extends Thread {

      private final ActivationQueue queue;

      public Scheduler(ActivationQueue queue){

        this.queue = queue;

      }

     

      public void invoke(MethodRequest request){

        this.queue.putRequest(request);

      }

     

      public void run(){

        while(true){

     

          //如果队列中有请求线程,测开始执行请求

          MethodRequest request = this.queue.takeRequest();

          request.execute();

        }

      }

    }

    scheduler中只用一个队列来保存代表方法和请求对象,实行简单的FIFO调用,你要实更复杂的调度就要在这里重新实现:

    class ActivationQueue{

      private static final int MAX_METHOD_REQUEST = 100;

      private final MethodRequest[] requestQueue;

      private int tail;

      private int head;

      private int count;

     

      public ActivationQueue(){

        this.requestQueue = new MethodRequest[MAX_METHOD_REQUEST];

        this.head = this.count = this.tail = 0;

      }

     

      public synchronized void putRequest(MethodRequest request){

        while(this.count >= this.requestQueue.length){

          try {

            this.wait();

          }

          catch (Throwable t) {}

        }

        this.requestQueue[this.tail] = request;

        tail = (tail + 1)%this.requestQueue.length;

        count ++ ;

        this.notifyAll();

     

      }

     

     

      public synchronized MethodRequest takeRequest(){

        while(this.count <= 0){

          try {

            this.wait();

          }

          catch (Throwable t) {}

     

        }

     

        MethodRequest request = this.requestQueue[this.head];

        this.head = (this.head + 1) % this.requestQueue.length;

        count --;

        this.notifyAll();

        return request;

      }

    }

     

    为了将方法调用转化为对象,我们通过实现MethodRequest对象的execute方法来方法具体方法转换成具体对象:

    abstract class MethodRequest{

      protected final Servant servant;

      protected final FutureResult future;

     

      protected MethodRequest(Servant servant,FutureResult future){

        this.servant = servant;

        this.future = future;

      }

     

      public abstract void execute();

    }

     

    class ResultRequest extends MethodRequest{

      private final int count;

      private final char c;

      public ResultRequest(Servant servant,FutureResult future,int count,char c){

        super(servant,future);

        this.count = count;

        this.c = c;

      }

      public void execute(){

        Result result = servant.resultTest(this.count,this.c);

        this.future.setResult(result);

      }

    }

     

    class NoResultRequest extends MethodRequest{

      private String str;

      public NoResultRequest(Servant servant,String str){

        super(servant,null);

        this.str = str;

      }

     

      public void execute(){

        this.servant.noResultTest(str);

      }

    }

     

    而返回的数据我们也将真实数据的获取和取货凭证逻辑分离:

    package com.axman.jasync;

     

    public abstract class Result {

      public abstract Object getResultValue();

    }

     

    class FutureResult extends Result{

      private Result result;

      private boolean completed;

     

      public synchronized void setResult(Result result){

        this.result = result;

        this.completed = true;

        this.notifyAll();

      }

     

      public synchronized Object getResultValue(){

        while(!this.completed){

          try{

            this.wait();

          }catch(Throwable t){}

        }

        return this.result.getResultValue();

      }

    }

     

    class RealResult extends Result{

      private final Object resultValue;

     

      public RealResult(Object resultValue){

        this.resultValue = resultValue;

      }

      public Object getResultValue(){

        return this.resultValue;

      }

    }

    OK,现在这个异步消息处理器已经有了模型,这个异步处理器中有昭雪些对象参与呢?

        Servant 忠心做真实的事务

        ActivationQueue将请求缓存起来以便调度

        Scheduler对容器中的请求根据一定原则进行调度执行

        Proxy将特定方法请求转换为特定对象

    所有这些都是这个异步处理器的核心部件,虽然是核心部件,我们就要进行封装而不能随便让调用者来修改,所以我们用工厂模式(KAO,我实在不想提模式但有时找不到其它词来表述)来产生处理器Axman对象:

    package com.axman.jasync;

     

    public class AxmanFactory {

      public static Axman createAxman() {

        Servant s = new Servant();

        ActivationQueue queue = new ActivationQueue();

        Scheduler st = new Scheduler(queue);

        Proxy p = new Proxy(st,s);

        st.start();

        return p;

      }

    }

    好了,我们现在用两个请求的产生者不停产生请求:

    ResultInvokeThreadv 发送有返回值的请求:

    package com.axman.jasync;

     

    public class ResultInvokeThread extends Thread{

      private final Axman ao;

      private final char c;

      public ResultInvokeThread(String name,Axman ao){

        this.ao = ao;

        this.c = name.charAt(0);

      }

     

      public void run(){

        try{

          int i = 0;

          while(true){

            Result result  = this.ao.resultTest(i++,c);

            Thread.sleep(10);

            String value = (String)result.getResultValue();

            System.out.println(Thread.currentThread().getName() + " value = " + value);

          }

        }

        catch(Throwable t){}

      }

    }

     

    NoResultInvokeThread发送无返回值的请求:

    package com.axman.jasync;

     

    public class NoResultInvokeThread extends Thread{

      private final Axman ao;

      public NoResultInvokeThread(String name,Axman ao){

        super(name);

        this.ao = ao;

      }

     

      public void run(){

        try{

          int i = 0;

          while(true){

            String s = Thread.currentThread().getName() + i++;

            ao.noResultTest(s);

            Thread.sleep(20);

          }

        }

        catch(Throwable t){}

      }

    }

     

    对了,我们还需要一个什么东西来产生一个演示:

    package com.axman.jasync;

     

    public class Program {

      public static void main(String[] args) {

        Axman ao = AxmanFactory.createAxman();

        new ResultInvokeThread("Axman",ao).start();

        new ResultInvokeThread("Sager",ao).start();

        new NoResultInvokeThread("Macke",ao).start();

      }

    }

    看看结果吧.你可以把不同类型的请求不断地向处理器发送,处理器会不断地接收请求,放到队列中,并同时不断从队列中提出请求进行处理.

    发表于 @ 2006年03月09日 11:10:00|评论(loading...)|编辑

    新一篇: 多线程编程 实战篇秘籍 (一)  | 旧一篇: 多线程编程 高级主题(一)

    评论

    #zhoche2008 发表于2007-10-18 17:45:42  IP: 58.246.80.*
    昨天偶然在dev2dev上发现axman的文章,读了几篇之后,发现以前在baidu.google上搜索到的一些比较深刻的文章都是出自这位大师级作者,只是我没有记住名字罢了。
    今天,我一口气将作者在CSDN上的文章读到此处,已接近下班时间。
    我只能说:牛!14个java类中竟然没有一个import,足以证明这个轮子是纯手工制造。
    我完全没有看懂本节的内容,准备明天继续研究(如果明天没有事情的话)。
    到此,我有个非技术性的问题,相信这也是其他很多和我一样崇拜axman的共同问题:
    您是如何从一个policeman成为了个高深莫测的IT人士?你刚开始是如何学习的?后来又是如何学习的?现在又是如何学习的?现在有很多所谓的java程序员,包括我在内,甚至不知道该学什么,怎么去学?要学到多少?学到什么程度?
    但愿您能看到此回复,尽管来着稍晚了一些。
    #axman 发表于2007-10-19 09:29:38  IP: 61.135.207.*
    如何学习每个人都有适应自己的方法.无法COPY,我能说的是学什么才是最重要的.流行的最终会被淘汰的,最最基础的才是最最重要的.
    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录