单例模式,往往用作我们只需要一个的对象上,
例如数据库的连接 Connection 。
Connection这个对象,在连DB的程序中,自始至终都要拥有,并且一般来说只有一个。
往往用于数据库的连接池,线程池,缓存,一些应用服务中等等。
所以为了保持面向对象程序设计的封装性,针对这种情况,演化成了一种设计模式, 就叫做单例模式
一、简单实现
public class Singleton {
/*
* 饿汉子单例
* */
private static Singleton singleton=new Singleton();
public static Singleton getSingleton(){
return singleton;
}
}
饿汉子就是急不可耐了,所以直接就new出来了。
懒汉子就是懒的要命,需要了再new出来。
二、延迟创建单例模式
public class Singleton {
/*
* 懒汉子单例
* */
private static Singleton singleton=null;
public static Singleton getSingleton(){
if(singleton==null)
singleton=new Singleton();
return singleton;
}
}
三、线程安全
以前没有考虑过这个问题,可能自己写的程序还不够多吧。
单例模式的线程安全貌似是一个很重要的问题了。
以懒汉子为例。当有两个线程进入getSingleton方法时,可能会发生线程不安全问题。从而创建两个单例singleton并返回。
对此的方法是给代码中加上synchronized
然后代码变成了这样
public class Singleton {
/*
* 懒汉子单例
* */
private static Singleton singleton=null;
public static synchronized Singleton getSingleton(){
if(singleton==null)
singleton=new Singleton();
return singleton;
}
}
public class Singleton {
/*
* 懒汉子单例
* */
private static Singleton singleton=null;
public Singleton getSingleton(){
if(singleton==null)
singleton=new Singleton();
return singleton;
}
}
四、高并发下的线程安全
但是当程序高并发运行时,又会出现性能瓶颈问题。因为每一个需要调用单例的对象都需要等别人拿完了自己才能够拿。
所以呢将上述代码做一个改变
public static Singleton getInstance() {
if (instance == null){ ①
synchronized (SingletonMain.class) { ②
if (instance == null) { ③
instance = new Singleton();
}
}
}
return instance;
}
在①处呢是首先判断一下,当前单例是否创建,如果没有的话才进入括号内。此处不牵扯到线程安全问题。
在②处对当前的类进行加锁,
在③处呢,是再一次的判断是否实例为空,原因是很有可能有多个类在②处等待着,如果不再一次判断,那大家都又重新创建实例了。
这里的中间加锁,两边判断是否为空,非常的精巧。。
五、序列化问题。
当单例类从数据库中拿出来的时候与当前内存的单例实例又会产生冲突。
public class SerializableSingleton implements Serializable{
private static final long serialVersionUID = -4470433994306593807L;
static SerializableSingleton singleton=new SerializableSingleton();
private SerializableSingleton(){
}
/**
* 序列化解决办法
* */
private Object readResove(){
return singleton;
}
}
六、分布式系统下,如何保证多个JVM只有一个Singleton实例?
总结:软件开发真难。。。