Java同步异步玩转回调机制

北京这周终于凉快了不少,舒了一口气,但是中暑带来的后遗症还没减轻,晕晕乎乎地上了一周的班也不见好转,基本就是这状态:


程序员

好了,不扯了。上篇文章讲了回调的基本原理:调用方通过方法将自己身的实例传给被调用方,被调用方拿到实例之后,就可以将结果返回给调用方了。

不知道大家看了上一篇文章之后会不会觉得哪里怪怪的,有点蹩脚。蹩脚的原因在于,XueMei的实例里面其实有一个XueZhang的对象,那么回调的过程其实还是在一个线程里面,自己跟自己的方法打转,该等待的还是要等待啊,并没有达到让学妹不要等待的目的。

为了让大家一目了然,我们把代码修改一下:
学妹的问问题方法:

 public void askQuetion(){
        System.out.println("I have a question");
        Date start = new Date();
        xueZhang.processQuestion(this);
        System.out.println((new Date().getTime() - start.getTime())/1000+"s:"+"I'v got it,then do another job");
    }

学长的回答问题方法:

public void processQuestion(CallBack callBack) {
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        callBack.onResult( "zhi ge hao shuai");
    }

结果:


result.png

可以看到中间是间隔了10s的,学妹才去做的其他事情,其实这就是一种同步回调的方式,所以感觉起来会很蹩脚。当然我觉得同步回调有一种用处就在于:可以立马返回一个结果给调用方。
在XueZhang的代码中加一行:

public void processQuestion(CallBack callBack) {
        callBack.onResult("I receive your question");
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        callBack.onResult( "zhi ge hao shuai");
    }

结果:


result.png

我们就可以通过这个立马返回的结果知道被调用方已经收到我的请求,我可以安心去做其他事了。

那么,真正达到可以让调用方不等待的话,那就是异步回调。其实我才想起来在学前端和Andorid的时候,会经常接触到onCreate()方法,这就是回调的运用啊。
我们修改XueZhang的代码:

public void processQuestion(CallBack callBack) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                callBack.onResult("zhi ge hao shuai");
            }
        }).start();
    }

新起一个线程,当执行完了自己通知,于是结果就是这样了:


result3.png

看到了吧,学妹终于可以干自己的事情了,不用等那个装逼的学长的答案了。

可以的话,回顾一下我之前写的关于同步与异步,阻塞与非阻塞的关系,当时其实是有一个遗留问题的:异步操作既然是被调用方在执行结束后通知调用方,那究竟要怎么通知呢?现在相信你有了答案。

嗯,你以为就结束了吗?
不,我们可能还是在单机上转悠啊,现在做的大部分系统,都是分布式的,我们得赶紧从学校学的那种前端加后端的模式中跳出来。

先给大家开个头吧,这样理解,我们调用的服务已经从一个臃肿的垂直架构中抽离出来了,也就是服务的运行有自己的环境,你要调用服务的服务不在你本地,怎么办呢?
大概有这么几种方式:
1.RPC。这是运用广泛的一种模式。通常会借助一个服务管理中心,管理各种在线服务,如阿里的dubbo。
2.REST。我们的调用当然还可以采用网络传输的方式啊,所以restful风格的这种API就大行其道啊,当然网络其实是最不靠谱的。
3.消息队列。MQ,Kafka,这类的东西的思想就是,我把要做的任务推(Push)到topic里面,消费者自己去拉(Pull)吧。

既然这样,我们回调通常也有这种跨机器的回调模式了。
分享一段国内开源框架LTS的代码(我其实也没深看):

SubmitCallback submitCallback = new SubmitCallback() {
                @Override
                public void call(RemotingCommand responseCommand) {
                    if (responseCommand == null) {
                        response.setFailedJobs(jobs);
                        response.setSuccess(false);
                        response.setMsg("Submit Job failed: JobTracker is broken");
                        LOGGER.warn("Submit Job failed: {}, {}", jobs, "JobTracker is broken");
                        return;
                    }

                    if (JobProtos.ResponseCode.JOB_RECEIVE_SUCCESS.code() == responseCommand.getCode()) {
                        if (LOGGER.isDebugEnabled()) {
                            LOGGER.debug("Submit Job success: {}", jobs);
                        }
                        response.setSuccess(true);
                        return;
                    }
                    // 失败的job
                    JobSubmitResponse jobSubmitResponse = responseCommand.getBody();
                    response.setFailedJobs(jobSubmitResponse.getFailedJobs());
                    response.setSuccess(false);
                    response.setCode(JobProtos.ResponseCode.valueOf(responseCommand.getCode()).name());
                    response.setMsg("Submit Job failed: " + responseCommand.getRemark() + " " + jobSubmitResponse.getMsg());
                    LOGGER.warn("Submit Job failed: {}, {}, {}", jobs, responseCommand.getRemark(), jobSubmitResponse.getMsg());
                }
            };

            if (SubmitType.ASYNC.equals(type)) {
                asyncSubmit(requestCommand, submitCallback);
            } else {
                syncSubmit(requestCommand, submitCallback);
            }

不用关注逻辑,就看结构。有个内部类,或者说是匿名内部类获取SubmitCallback的对象,之后会通过同步和异步的方式发到另外的机器上处理请求。
之后的代码太多,我就不上传了,大概是:
异步的方式会将一个CallBack的实例一直往下传,而同步的方法则是选择等待一个返回值,从方法名就可以看出来:

public RemotingCommand invokeSync(RemotingCommand request)
public void invokeAsync(RemotingCommand request, AsyncCallback asyncCallback)

一个有返回值,一个没返回值。有兴趣的自己下着看一下,我研究的也不深,而且还有一些小疑问,等解决了之后再更吧。

回调太多就会使系统耦合加深,所以在单机的项目下还是少用吧。另外异步还有一种方式:Future,这感觉也是怪怪的,下次再讲。周末愉快,哦不,暑假愉快!哭,我还要上班!!!!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,639评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,277评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,221评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,474评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,570评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,816评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,957评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,718评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,176评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,511评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,646评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,322评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,934评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,755评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,987评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,358评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,514评论 2 348

推荐阅读更多精彩内容