方式一:首先不考虑并发的情况下:
public class Singleton{
private static Singleton singleton = null;
public Singleton getInstance(){
if(null == singleton){
singleton = new Singleton();
}
return singleton ;
}
}
方式二:加锁(不考虑效率)
public class Solution {
private static Solution singleton = null;
public synchronized static Solution getInstance(){
if(null == singleton){
singleton = new Solution();
}
return singleton;
}
}
方式三:(双重检查加锁DCL(Double-Check-Locked))
public class Solution {
/**
* @return: The same instance of this class every time
*/
private static Solution singleton = null;
public static Solution getInstance() {
if(singleton == null){
synchronized (Solution.class){
if(singleton == null){
try{
singleton = (Solution)Class.forName("Solution").newInstance();
}catch(Exception e){
e.printStackTrace();
}
}
}
}
return singleton;
}
};
它的工作原理是:首先检查是否在没有同步的情况下需要初始化,如果singleton引用不为空,则无需初始化,直接使用它即可。否则就进行同步并再次检查singleton是否被初始化,从而保证了只有一个线程对singleton执行初始化。但是:在第一次检查的时候,由于没有采用同步,有可能得到一个“仅被部分构造的对象”,从而得到一个不正确(尚未初始化完成)的对象。产生这种糟糕结果的原因那就是java内存模型的指令冲排序现象——jvm为了优化程序性能而对指令重新排序执行的现象。
优化方案则是
public class Singleton{
private volatile static Singleton singleton;
public static Singleton getInstance(){
if(null == singleton){
synchronized(Singleton.class){
if(null == singleton){
singleton = new Singleton();
}
}
}
return singleton;
}
}
不过该优化方案在java5.0及更高的版本中才能生效。DCL的这种方案已经被广泛的废弃掉了。更通用的做法是采用延迟化占位类模式
方式四:即非延迟性加载方式,在类创建的同时就实例化一个singleton静态对象,在第一次调用的时候,速度会比延迟化加载模式要快,因为已经初始化完成。
public class Solution{
private static Solution singleton = new Solution();;
public static Solution getInstance(){
return singleton;
}
}
方式五:本质上同方式四没有多大区别
public class Solution{
private static Solution singleton = null;
static {
singleton = new Solution();
}
public static Solution getInstance(){
return singleton;
}
}
方式六:静态内部类(延迟化占位类方式) JVM推迟Solution的初始化操作,当开始调用getInstance()的时候Solution才会初始化,从而达到懒加载的目的。
public class TestClass{
public static Solution getInstance(){
return Solution.singleton;
}
static class Solution{
private static Solution singleton=new Solution();
}
}
方式七:枚举类型实现单例模式
避免序列化和反序列化得到单例对象不相同,以及通过反射机制调用对象的私有构造方法来构造单例对象的弊端:
public enum EnumSingleton {
INSTANCE;
public EnumSingleton getInstance(){
return INSTANCE;
}
}