单例模式(Singleton) :保证一个类仅有一个实例,并提供一个访问它的全局访问点;
单例模式因为Singleton类封装了它的唯一实例,这样它可以严格的控制客户怎么访问以及何时访问,
简单说就是受控访问;单例对象通常作为程序中的存放配置信息的载体,因为它能保证其他对象读到一致的信息;
1、单线程环境代码:
package caosc.javaModel.Singleton;
public class Singleton {
private static Singleton instance = null;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
但是在多线程模式下,可能产生问题。如果第一个线程发现成员变量为null,准备创建对象;这是第二 个线程同时也发现成员变量为null,也会创建新对象。这就会造成在一个JVM中有多个单例类型的实例。如果这个单例类型的成员变量在运行过程中变化,会 造成多个单例类型实例的不一致,产生一些很奇怪的现象。例如,某服务进程通过检查单例对象的某个属性来停止多个线程服务,如果存在多个单例对象的实例,就 会造成部分线程服务停止,部分线程服务不能停止的情况。
2、多线程单例模式
package caosc.javaModel.Singleton;
public class SingletonTread {
private static SingletonTread instance = null;
private static final Object obj = new Object();
private SingletonTread() {
}
public static SingletonTread getInstance() {
if (instance == null) {
synchronized(obj){
if(instance == null){
instance = new SingletonTread();
}
}
}
return instance;
}
}
3、多线程单例修改属性信息;
package caosc.javaModel.Singleton;
import java.util.Vector;
public class SingletonProperty {
private static SingletonProperty instance;
private Vector properties = null;
private int readCount = 0;
private SingletonProperty() {
properties = new Vector();
properties.set(1, "caosc");
}
private static synchronized void syncInit() {
if (instance == null) {
instance = new SingletonProperty();
}
}
public static SingletonProperty getInstance() {
if (instance == null) {
syncInit();
}
return instance;
}
/**
* 修改单例属性信息
* @param p_data
*/
public synchronized void update(String p_data) {
syncUpdateIn();
}
private synchronized void syncUpdateIn() {
while (readCount > 0) {//修改同时如果有程序正在使用
try {
wait();//等待
} catch (Exception e) {
}
}
}
private synchronized void syncReadIn() {
readCount++;
}
private synchronized void syncReadOut() {
readCount--;
notifyAll();
}
public Vector getProperties() {
syncReadIn();
syncReadOut();
return properties;
}
}
通常,为了实现配置信息的实时更新,会有一个线程不停检测配置文件或配置数据库的内容,一旦发现变化,就更新到单例对象的属性中。在更新这些信 息的时候,很可能还会有其他线程正在读取这些信息,造成意想不到的后果。还是以通过单例对象属性停止线程服务为例,如果更新属性时读写不同步,可能访问该属性时这个属性正好为空(null),程序就会抛出异常。
或者
package caosc.javaModel.Singleton;
import java.util.Vector;
public class SingletonProperty {
private static SingletonProperty instance;
private Vector properties = null;
private SingletonProperty() {
properties = new Vector();
properties.set(1, "caosc");
}
private static synchronized void syncInit() {
if (instance == null) {
instance = new SingletonProperty();
}
}
public static SingletonProperty getInstance() {
if (instance == null) {
syncInit();
}
return instance;
}
public Vector getProperties() {
return properties;
}
public void updateProperties() {
//在更新属性时,直接生成另一个单例对象实例,这个新生成的单例对象实例将从数据库或文件中读取最新的配置信息;
//然后将这些配置信息直接赋值给旧单例对象的属性
SingletonProperty shadow = new SingletonProperty();
properties = shadow.getProperties();
}
}
采用"影子实例"的办法
具体说,就是在更新属性时,直接生成另一个单例对象实例,这个新生成的单例对象实例将从数据库或文件中读取最新的配置信息;然后将这些配置信息直接赋值给旧单例对象的属性;