版权声明:本文为博主原创文章,如需转载,请标明出处。
在软件开发过程中常会有一些对象我们只需要一个,如:线程池(threadpool)、缓存(cache)、对话框、偏好设置等。这些对象如果制造出多个实例的话可能会导致一些不必要的麻烦,如:程序行为异常、资源使用过量等。这时单例模式就可以确保一个类只有一个实例,并提供全局访问点。下面是从简单的单例类来探讨该用何种方法实现单例模式。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
从上面的例子可以看出Singleton类自己管理这个类的实例化过程,而且提供了全局访问点,就是设置成静态的getInstance()方法,在其他类要使用Singleton时它会返回一个实例。这中单例模式有个优点就是延迟实例化,简单地说延迟实例化就是延迟初始化,在类需要时才创建其实例,而不是在开始加载这个类时就创建出一个实例,这样的好处是可以避免性能的浪费。例如有些对象无需程序一开始就使用,或者其在程序执行的过程中就没有使用过。但是此例子却又一个缺点,那就是线程不够安全。因为如果有多个线程同时执行到getInstance()方法,而Singleton又还未new Singleton()一个实例,那么线程就会都认为singleInstance为null,就都会实例化Singleton,这时就会产生多个Singleton实例,明显不符合单例模式的初衷。那么接下来可能要做的就是对其进行改进
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
从这个例子上看增加了synchronized可以使getInstanceA()变成一个同步的方法,这时线程在进入这个方法之前就需要等待其他线程离开这个方法才能进入,也就使得该方法只能同时存在一个线程在执行它。
可能差不多问题解决了,但是要知道同步方法是会影响程序执行效率的,在此例子中我们只是为了解决第一个例子中第一次执行getInstance()方法不会产生多个实例,而这个例子中却会导致每次需要实例时都会调用getInstanceA()同步方法,而在已经有实例之后的调用synchronized就会是累赘,因为我们已经无需担心这个单例类会再次被创建出新的实例。因此我们还需要做一下改进。
既然上面说到延迟实例化,那么如果是不用的话那就简单多了。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
上面的这种做法是在JVM加载这个类时马上创建一个实例,因为JVM会在线程访问这个实例之前就创建出该实例,因此线程是安全的。但这相较于延迟实例化而言可能会出现资源的浪费。而且如果此类较大的情况下会时程序初始化时间加长。
那么是否可以在使用用延迟实例化的同时又不会造成线程不安全且增加访问效率呢。接下来就用双重检查加锁来改进一下。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
上面的例子是先检查实例,如果不存在则进入同步区块,进入同步区块之后再次检查,如果还是null才会创建实例,因而singletonC = new SingletonC()只会执行一次,而之后调用getInstanceC()时就因为有实例直接返回,所以除了第一次调用时会走同步,而之后便不会如第二个例子那样每次都会走同步方法。这样就可以使得执行getInstanceC()的时间减少。想必这里会发现有个volatile关键字,其作用是使得singletonC被初始化后对所有线程可见,多个线程可以正确地处理这个SingletonC变量。但要注意的:volatile关键字只能在Java 5及其之后使用,如果在此版本之前会导致这个双重检查失效。
在使用单例模式时,如果有多个类加载器(classloader)时需要自行指定类加载器,并指定用一个类加载器。因为每个类加载器都定义了一个命名空间,不同的类加载器可能会加载同一个类,从而导致单例类创建出多个实例。
-----------------------------------------------------------------------------------------------------------------------
版权声明:本文为博主原创文章,如需转载,请标明出处。
观测者模式定义了对象之间的一对多依赖,当一个对象状态发生改变时,其依赖者便会收到通知并做相应的更新。其原则是:为交互对象之间松耦合。以松耦合方式在一系列对象之间沟通状态,我们可以独立复用主题(Subject)/可观测者(Observable)和观测者(Observer),即只要遵守接口规则改变其中一方并不会影响到另一方。这也是其主要的设计原则。下面是一个简单的气象站发送天气信息给布告板,然后布告板把天气信息显示在板上的例子。
首先先建立三个接口,主题(Subject)、观测者(Observer)和显示内容(DisplayElement),分别代表气象站、布告板信息接收和布告板信息显示。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
接下来是实现气象站()和布告板()了。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
测试结果
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17