观察者模式与多线程

概述

在对象之间定义一个被观察者和多个观察者,当被观察者的状态改变的时候,所有观察者都回自动收到通知

demo

有一个注册接口的需求,注册后,发放体验金和发送邮件,发放体验金和发送邮件为观察者由被观察者根据需要使用多线程调用,如图
在这里插入图片描述

对于多线程的使用基于这样的思考,希望接口的响应时间尽可能短,这样userController.register()函数就不需要等到所有的handlerMessage函数都执行完成之后才返回结果给客户端。userController.register()函数从执行3个SQL语句才返回,减少到只需要执行1个SQL语句就返回,响应时间减少为原来的1/3。如何实现呐?做法是,使用线程池执行代码

public class UserController {

    private List<UserObserver> userObserves = new ArrayList<>();

    public String  register(String telephone,String password) throws Exception {

        UserService userService = new UserService();
        Long userId = userService.register(telephone,password);

        userObserves.add(new PromotionServiceHandler());
        userObserves.add(new SendEmailHandler());

        ExecutorService exec = Executors.newFixedThreadPool(10);

        Runnable run = new Runnable() {

            @SneakyThrows
            @Override
            public void run() {
                noticeObserver(userId);
            }
        };
        exec.execute(run);
        return "register完成";
    }

    private void noticeObserver(Long userId) throws Exception {
    
        if (userObserves==null||userObserves.size()<=0){
            throw new Exception("观察者列表不能为空");
        }

        for (UserObserver oneObserve:userObserves) {
            oneObserve.handlerMessage(userId);
        }
    }

    public static void main(String[] args) throws Exception {
        UserController userController = new UserController();
        String register = userController.register("1", "2");
        System.out.println(register);
    }
}
public class SendEmail {

    public void sendMsg(Long userId){
        System.out.println("sendMsgThread");
    }
}
public class SendEmailHandler implements UserObserver {    
    @Override
    public void handlerMessage(Long userId) {

        SendEmail sendEmail = new SendEmail();
        sendEmail.sendMsg(userId);

    }
}
public class PromotionService {
    
    public void issueNewUserExperienceCash(long userId) {
        System.out.println("进入PromotionServiceThread");
    }
}
public class PromotionServiceHandler implements UserObserver {

    @Override
    public void handlerMessage(Long userId) {
        PromotionService promotionService = new PromotionService();
        promotionService.issueNewUserExperienceCash(userId);
    }
}

当然如果你不愿意使用线程池,也可以使用Thread来开启一个新的线程
在这里插入图片描述

但是我们知道对于第一种实现方式,尽管利用了线程池解决了第一种实现方式的问题,但线程池、异步执行逻辑都耦合载来register函数中,增加了这部分业务代码的维护成本。第二种实现方式,频繁地创建和销毁线程比较耗时,并且并发线程数无法控制,创建过多的线程回导致堆栈溢出。

Google Guava类库提供了一个利用观察者模式实现EventBus类,它无需从0编写代码,只需要通过register函数注册观察者,通过post给观察者发送消息

基于EventBus,我们不需要定义Observer接口,任意类型的对象都可以注册到EventBus中,通过@Subscribe注解来标明哪个函数可以接收被观察者发送的消息

改造代码如下:

public class UserControllerWithBus {

    private List<UserObserver> userObserves = new ArrayList<>();

    private EventBus eventBus;

    public UserControllerWithBus(){

        eventBus = new AsyncEventBus(Executors.newFixedThreadPool(20));

    }

    public String  register(String telephone,String password) throws Exception {

        UserService userService = new UserService();
        Long userId = userService.register(telephone,password);

        eventBus.register(new PromotionServiceHandlerBus());
        eventBus.register(new SendEmailHandlerBus());

        eventBus.post(userId);

        return "register完成";

    }

    public static void main(String[] args) throws Exception {

        UserControllerWithBus userController = new UserControllerWithBus();
        String register = userController.register("1", "2");
        System.out.println(register);

    }

}
public class PromotionServiceHandlerBus implements UserObserver {

    @Subscribe
    public void handlerMessage(Long userId) {

        PromotionService promotionService = new PromotionService();
        promotionService.issueNewUserExperienceCash(userId);

    }
}
public class SendEmailHandlerBus implements UserObserver {

    @Subscribe
    public void handlerMessage(Long userId) {

        SendEmail sendEmail = new SendEmail();
        sendEmail.sendMsg(userId);

    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值