观察者模式大家应该十分熟悉,贴一张别人的图如下:
上图十分清晰的展示了观察者模式是什么样的。在java的util包里,实际上有内置的对观察者模式的实现,java.uti.Observable类就是这里的主题,而Observer接口对应的就是Observer观察者接口。
但是,实际上,虽然java对Observable的实现不是使用接口来实现,因此,实际上并不是很符合设计模式的多用组合,少用继承的原则,而且,其对应于setSate()方法也就是setChanged()方法访问权限为setChanged,因此,很难不通过继承来将其组合到自己的代码中去,但是,其对观察者模式的实现毕竟还是十分的严密而规范的,下面是我对Observable类的说明。
public class Observable {
private boolean changed = false;
private Vector 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;
}
public synchronized boolean hasChanged() {
return changed;
}
public synchronized int countObservers() {
return obs.size();
}
}
可以看出,通过bool类型变量changed的赋值,可以判断主题是否更新,以作为是否将信息推送给观察者的依据。changed的改变必需是线程安全的,这也是为什么setChanegd方法和clearChanged方法都用synchronized关键字声明。
使用了Vector容器来保存观察者的引用,而不是ArrayList,同样是出于线程安全的考虑,ArrayList线程不安全,Vector线程安全。
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);
}
上述代码段中,出于线程安全的需要,在将obs转为数组时,需要用同步控制块来做处理,这也是为了防止由于多个观察者线程并发对obs改变造成的线程异常,尽管这里是线程安全的,但是jdk源码的注释中指出,这里有可能出现刚刚加入的观察者无法通知到更新或者刚刚删除的观察者接收到了不该接受到的消息的情况。
分享到:
相关推荐
这是我在编写struts2中遇到的问题,整理出来,包括截图,希望可以帮到大家
详细介绍了java.util.logging.Logger的用法和结构,对如果扩展Logger起到抛砖引玉的作用!尊重劳动成果,亲下载了要给个评价!
jdk源码java.util包,所有类解析,包含整体架构及各个类详解
JDK7源码 包含rt.jar包下的 sun包源码 sun.security包等源码
JDK1.5中的线程池(java.util.concurrent.ThreadPoolExecutor)使用
java.util.stream.Stream:Stream 代码示例
2.将下载的两个JAR文件复制到:JDK安装目录\jre\lib\ext下,例如我的就是D:\Program Files (x86)\java\JDK1.6\jre\lib\ext 3.打开java.security文件:在JDK安装目录\jre\lib\security下的java.security文件。
一个高性能的Java线程库,该库是 JDK 1.5 中的 java.util.concurrent 包的补充,可用于基于并发消息机制的应用。该类库不提供远程的消息功能,其设计的宗旨是实现一个内存中的消息传递机制. 主要特点有: * All ...
合适研究底层研发员,但,一般程序员也必须掌握的要点 JDK研究系列--》util.concurrent(java.util part3)
可以用于解决jdk1.6下rt.jar中不支持Base64的问题。资源中包含替代包
主要介绍了出现java.util.ConcurrentModificationException 问题及解决办法的相关资料,需要的朋友可以参考下
1.Java 8允许我们给接口添加一个非抽象的方法实现,只需要使用 default关键字即可。 2.新增lambda表达式 3.提供函数式接口 4.Java 8 允许你使用关键字来传递方法或者构造函数引用 5.我们可以直接在lambda表达式中...
1.打开cmd,cd到jdk的path,本机是:cd C:\Java\jdk6\bin 2.资源javaConcurrentAnimated.jar放在D盘根目录 3.使用java -cp命令: java -cp D:\javaConcurrentAnimated.jar vgrazi.concurrent.samples.launcher....
Wrox.Professional.Java.JDK.6.Edition.Jan.2007.rar
合适研究底层研发员,但,一般程序员也必须掌握的要点 JDK研究系列--》util实用类util实用类(java.util part2)
bcprov-ext-jdk15on-1.54.jar和bcprov-jdk15on-1.54.jar压缩文件
众所周知java.exe是java class文件的执行程序这是我精心分析后还原的源代码已经在JDK 1.7_03测试通过适合分析java源代码的人使用项目IDE: Netbean编译工具mingw+mySYSThread model: win32gcc version 4.4.0 (GCC)
JDK1.5中的线程池(java.util.concurrent.ThreadPoolExecutor)使用简介
net.mindview.util包,jdk1.6和jdk1.8版本的tools.jar
Doug Lea关于jdk里面并发同步器的实现。