首页 > 其他分享 >观察者模式在 JDK 中的应用

观察者模式在 JDK 中的应用

时间:2022-10-20 18:25:06浏览次数:38  
标签:函数 synchronized notifyObservers void JDK 观察者 模式 public

Google Guava 的 EventBus 框架,它提供了观察者模式的骨架代码。使用 EventBus,不需要从零开始开发观察者模式。实际上,Java JDK 也提供了观察者模式的简单框架实现。在平时的开发中,如果不希望引入 Google Guava 开发库,可以直接使用 Java 语言本身提供的这个框架类。

包含两个类:java.util.Observable 和 java.util.Observer。前者是被观察者,后者是观察者。它们的代码实现也非常简单

public interface Observer {
    void update(Observable o, Object arg);
}

public class Observable {
    private boolean changed = false;
    private Vector<Observer> obs;

    public Observable() {
        obs = new Vector<>();
    }

    public synchronized void addObserver(Observer o) {
        if (o == null)
            throw new NullPointerException();
        if (!obs.contains(o)) {
            obs.addElement(o);
        }
    }

    public synchronized void deleteObserver(Observer o) {
        obs.removeElement(o);
    }

    public void notifyObservers() {
        notifyObservers(null);
    }

    public void notifyObservers(Object arg) {
        Object[] arrLocal;

        synchronized (this) {
            if (!changed)
                return;
            arrLocal = obs.toArray();
            clearChanged();
        }

        for (int i = arrLocal.length-1; i>=0; i--)
            ((Observer)arrLocal[i]).update(this, arg);
    }

    public synchronized void deleteObservers() {
        obs.removeAllElements();
    }

    protected synchronized void setChanged() {
        changed = true;
    }

    protected synchronized void clearChanged() {
        changed = false;
    }
}

changed 成员变量

它用来表明被观察者(Observable)有没有状态更新。当有状态更新时,需要手动调用 setChanged() 函数,将 changed 变量设置为 true,这样才能在调用 notifyObservers() 函数的时候,真正触发观察者(Observer)执行 update() 函数。否则,即便你调用了 notifyObservers() 函数,观察者的 update() 函数也不会被执行。

也就是说,当通知观察者被观察者状态更新的时候,需要依次调用 setChanged() 和 notifyObservers() 两个函数,单独调用 notifyObservers() 函数是不起作用的。

notifyObservers() 函数

为了保证在多线程环境下,添加、移除、通知观察者三个操作之间不发生冲突,Observable 类中的大部分函数都通过 synchronized 加了锁,不过,也有特例,notifyObservers() 这函数就没有加 synchronized 锁。

notifyObservers() 函数之所以没有像其他函数那样,一把大锁加在整个函数上,主要是出于性能的考虑。

notifyObservers() 函数依次执行每个观察者的 update() 函数,每个 update() 函数执行的逻辑提前未知,有可能会很耗时。如果在 notifyObservers() 函数上加 synchronized 锁,notifyObservers() 函数持有锁的时间就有可能会很长,这就会导致其他线程迟迟获取不到锁,影响整个 Observable 类的并发性能。

Vector 类不是线程安全的,在多线程环境下,同时添加、删除、遍历 Vector 类对象中的元素,会出现不可预期的结果。所以,在 JDK 的代码实现中,为了避免直接给 notifyObservers() 函数加锁而出现性能问题,JDK 采用了一种折中的方案。这个方案有点类似让迭代器支持”快照“的解决方案。

在 notifyObservers() 函数中,我们先拷贝一份观察者列表,赋值给函数的局部变量,我们知道,局部变量是线程私有的,并不在线程间共享。这个拷贝出来的线程私有的观察者列表就相当于一个快照。我们遍历快照,逐一执行每个观察者的 update() 函数。而这个遍历执行的过程是在快照这个局部变量上操作的,不存在线程安全问题,不需要加锁。所以,我们只需要对拷贝创建快照的过程加锁,加锁的范围减少了很多,并发性能提高了。

为什么说这是一种折中的方案呢?这是因为,这种加锁方法实际上是存在一些问题的。在创建好快照之后,添加、删除观察者都不会更新快照,新加入的观察者就不会被通知到,新删除的观察者仍然会被通知到。这种权衡是否能接受完全看你的业务场景。实际上,这种处理方式也是多线程编程中减小锁粒度、提高并发性能的常用方法。

标签:函数,synchronized,notifyObservers,void,JDK,观察者,模式,public
From: https://www.cnblogs.com/ltaodream/p/16810802.html

相关文章

  • 设计模式之单例模式
    简介在实际开发中,为了节约系统资源,有时需要确保系统中某个类只有唯一一个实例,当这个唯一实例创建成功之后,无法再创建一个同类型的其他对象,所有的操作都只能基于这个唯一实......
  • Tutorial 6_原型模式
    向量的原型用C++完成数学中向量的封装,其中,用指针和动态申请支持向量长度的改变,使用浅克隆和深克隆复制向量类,比较这两种克隆方式的异同。浅克隆  深克隆  ......
  • Tutorial 7_单例模式
    学号的单一仿照课堂的身份证的例子,实现每个同学仅有一个学号这一问题。类图  代码  2.1StudentID.javapackagedanli;publicclassStudentID{......
  • Tutorial 8_适配器模式
    双向适配器实现一个双向适配器,使得猫可以学狗叫,狗可以学猫抓老鼠。  代码  ICat.javapackageshipeiqi;publicinterfaceICat{publicvoideat()......
  • Tutorial 9_桥接模式
    两个维度的桥接模式用桥接模式实现在路上开车这个问题,其中,车可以是car或bus,路可以是水泥路或沥青路。类图  代码Vehicle.javapackageqiaojie;publicinterfa......
  • Collections 类中设计模式的应用
    装饰器模式Collections类是一个集合容器的工具类,提供了很多静态方法,用来创建各种集合容器,比如通过unmodifiableColletion()静态方法,来创建UnmodifiableCollection类......
  • Calendar 类中设计模式的应用
    包名:java.util.Calendar工厂模式Calendar类提供了大量跟日期相关的功能代码,同时,又提供了一个getInstance()工厂方法,用来根据不同的TimeZone和Locale创建不同的Ca......
  • 享元模式
    实验13:享元模式本次实验属于模仿型实验,通过本次实验学生将掌握以下内容:1、理解享元模式的动机,掌握该模式的结构;2、能够利用享元模式解决实际问题。   ......
  • 注解-注解概述和JDK内置注解
    注解概述概念:说明程序的给计算机看的注释:用文字描述程序给程序员看的定义:注解(Annotation),也叫元数据一种代码级别的说明它事JDK1.5及以后版本引入的一种特性与......
  • 9000字,唠唠架构中的设计模式
    1设计模式概述​ 软件设计模式(SoftwareDesignPattern),俗称设计模式,设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。它描述了在软件设......