当前位置: 首页 > 科技观察

异步非阻塞框架是如何实现的?

时间:2023-03-15 15:12:00 科技观察

大家好,我是北军。本文介绍异步非阻塞框架是如何实现的。1.什么是观察者模式?定义对象之间的一对多依赖关系,这样当一个对象改变状态时,它的所有依赖关系都会被通知并自动更新。观察者模式(ObserverDesignPattern):定义对象之间一对多的依赖关系,当一个对象状态改变时,所有依赖的对象都会得到通知并自动更新。用人的话来说:也叫发布-订阅模式,可以解耦一个对象的变化,自动改变另一个对象的情况。2.观察者模式定义①Subject被观察对象定义了被观察对象必须实现的职责,必须能够动态添加和取消观察者。一般是抽象类或实现类,只完成作为被观察者必须实现的职责:管理观察者,通知观察者。②ObserverObserver观察者收到消息后,进行更新(update方法)操作,对接收到的信息进行处理。③ConcreteSubject具体的观察者定义了观察者自己的业务逻辑,同时定义了通知哪些事件。④ConcreteObserver具体的观察者在收到消息后有不同的处理反应,每个观察者都有自己的处理逻辑。3.观察者模式通用代码/***Observer*/publicinterfaceObserver{//更新方法voidupdate();}/***具体观察者*/publicclassConcreteObserverimplementsObserver{@Overridepublicvoidupdate(){System.out.println("接收信息并处理");}}/***Observer*/publicabstractclassSubject{//定义一个观察者数组privateListobsList=newArrayList<>();//添加一个观察者publicvoidaddObserver(Observerobserver){obsList.add(observer);}//删除一个观察者publicvoiddelObserver(Observerobserver){obsList.remove(observer);}//通知所有观察者publicvoidnotifyObservers(){for(Observerobserver:obsList){observer.update();}}}/***具体观察者*/publicclassConcreteSubjectextendsSubject{//具体业务publicvoiddoSomething(){super.notifyObservers();}}publicclassObserverClient{publicstaticvoidmain(String[]args){//创建一个观察者ConcreteSubjectsubject=newConcreteSubject();//定义一个观察者Observerobserver=newConcreteObserver();//观察者观察被观察者subject.addObserver(observer);subject.doSomething();}}4。JDK是在JDK的java中实现的。在util包下,为我们提供了观察者模式的抽象实现。如果你有兴趣,你可以看看。内部逻辑其实和我们上面介绍的观察者java.util.Observer类似。可观察的java.util.Observable。5、实例用户注册。注册完成后,将发送一封欢迎邮件。5.1公共实现publicclassUserController{publicvoidregister(StringuserName,StringpassWord){//1.根据用户名和密码存入数据库LonguserId=saveUser(userName,passWord);//2.如果上一步有结果则发送一封欢迎邮件if(userId!=null){Mail.sendEmail(userId);}}publicLongsaveUser(StringuserName,StringpassWord){return1L;}}上面的注册接口实现了两个东西,注册和发送Email,显然违反了单一职责原则,但是假设注册需求经常变化,这样写是没有问题的,但是如果需求变化了,比如不既发邮件又发短信,那么这样写,注册界面就复杂了。应该如何简化?没错,就是观察者模式。5.2观察者模式实现我们直接套用JDK的实现。importjava.util.Observable;/***用户登录-Observable*/publicclassUserControllerObservableextendsObservable{publicvoidregister(StringuserName,StringpassWord){//1.将用户名和密码保存到数据库中LonguserId=保存用户(用户名,密码);//2.如果上一步有结果,通知所有观察者if(userId!=null){super.setChanged();super.notifyObservers(用户名);}}publicLongsaveUser(StringuserName,StringpassWord){return1L;}}importjava.util.Observable;importjava.util.Observer;/***Sendmail-Observer*/publicclassMailObserverimplementsObserver{@Overridepublicvoidupdate(Observableo,Objectarg){System.out.println("发送邮件:"+arg+"欢迎");}}/***SendSMS-Observer*/publicclassSMSObserverimplementsObserver{@Overridepublicvoidupdate(Observableo,Objectarg){System.out.println("SendSMS:"+arg+"Welcome");}}测试:publicclassUserClient{publicstaticvoidmain(String[]args){UserControllerObservableobservable=newUserControllerObservable();observable.addObserver(newMailObserver());observable.addObserver(新的SMSObserver());observable.register("张三","123");}}通过observer模式改写后,后面会进行用户注册。即使我们添加其他操作,我们只需要添加一个观察者,注册接口register是不会改变的。5.3异步模式优化回到上图:注册后两步操作:发送邮件和发送短信。我们通过观察者模式重写上面之后,虽然流程很清晰,但是我们发现是顺序执行的,但是实际上这两个步骤并不是按顺序执行的,所以我们可以将其改为异步模式来提高执行效率。/***发送邮件-Observer*/publicclassMailObserverimplementsObserver{privateExecutorexecutor=Executors.newFixedThreadPool(2);@Overridepublicvoidupdate(Observableo,Objectarg){executor.execute(newRunnable(){@Overridepublicvoidrun(){System.out.println("发送邮件:"+arg+"欢迎");}});}}5.EventBus译为“事件总线”,它提供了实现观察orc模式的骨架代码。基于这个框架,我们可以很方便的在自己的业务场景中实现观察者模式,而无需从头开发。其中,GoogleGuavaEventBus是一个知名的EventBus框架,它不仅支持异步非阻塞模式,还支持同步阻塞模式。PS:GoogleGuava是一个特别好用的工具包,里面的代码也实现的比较优雅。有兴趣的可以研究下源码。https://github.com/google/guava下面我们用上面的例子来说明如何使用EventBus:①Guavapackagecom.google.guavaguava30.1.1-jre②具体代码如下:importcom.google.common.eventbus.AsyncEventBus;importcom.google.common.eventbus.EventBus;importjava.util.List;importjava.util.concurrent.Executors;publicclassUserController{privateEventBuseventBus;publicUserController(){eventBus=newAsyncEventBus(Executors.newFixedThreadPool(2));}/***注意:泛型参数是对象,不是接口观察者*@paramobserverList*/publicvoidsetObserverList(ListobserverList){for(Objectobserver:observerList){eventBus.register(observer);}}publicvoidregister(StringuserName,StringpassWord){//1.根据用户名和密码存入数据库LonguserId=saveUser(userName,passWord);//2.如果如果上一步有结果,通知所有观察者if(userId!=null){eventBus.post(userName);}}publicLongsaveUser(StringuserName,StringpassWord){return1L;}}importcom.google.common.eventbus.Subscribe;/***发送邮件——Observer*/publicclassMailObserver{@SubscribepublicvoidsendMail(StringuserName){System.out.println("发送邮件:"+用户名+"欢迎光临");}}importcom.google.common.eventbus.Subscribe;/***SendSMS-observer*/publicclassSMSObserver{@SubscribepublicvoidsendSMS(StringuserName){System.out.println("SendSMS:"+userName+“欢迎”);}}测试:publicclassEventBusClient{publicstaticvoidmain(String[]args){UserControlleruserController=newUserController();ListobserverList=newArrayList<>();observerList.add(newMailObserver());observerList.add(newSMSObserver());userController.setObserverList(observerList);用户控制器.注册er("张三","123");}}与从头写的观察者模式相比,使用EventBus框架实现的观察者模式在大流程方面的实现思路大致相同,都需要定义Observer,并通过register()函数注册Observer,也需要通过调用函数(例如EventBus中的post()函数)向Observer发送消息(EventBus中的消息称为event事件),但是在实现细节上,它们有些不同.基于EventBus,我们不需要定义Observer接口。EventBus中可以注册任何类型的对象,@Subscribe注解用于表示类中的哪个函数可以接收观察者发送的消息。6、观察者模式的优点①观察者与被观察者之间的抽象耦合,无论是添加观察者还是被观察者,都非常容易扩展,在系统扩展中得心应手。②建立触发机制,当被观察者发生变化时自动改变观察者。但是需要注意的是,Java的消息通知默认是一个观察者和多个观察者顺序执行的。如果一个观察者卡住了,整个进程都会卡住,这就是同步阻塞。所以在实际开发中,并没有顺序考虑异步的使用。异步非阻塞不仅可以实现代码解耦,还可以充分利用硬件资源,提高代码执行效率。此外,进程间还有一种观察者模式,通常基于消息队列实现,用于实现不同进程间观察者与被观察对象的交互。7.观察者模式应用场景①关联行为场景。②事件多级触发场景。③跨系统的消息交互场景,比如消息队列的处理机制。