单例模式(Singleton Pattern)

单例模式:确保一个类只有一个实例,并提供一个全局访问点。

为什么需要单例模式?

有一些对象只需要一个,比如:线程池,对话框,注册表的对象,日志对象,打印机、显卡等设备的驱动程序对象。如果这些类有多个实例,会导致许多问题的产生。

 

1.第一种方式

是否延迟初始化:是

是否多线程安全:否

public class Singleton {
    
    private static Singleton instance = null;
    private SingleObject() {}
    
    public static Singleton getInstance() {
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}

这种方法只适合在单线程环境下。

 

2.第二种方式:

是否延迟初始化:是

是否多线程安全:是

public class Singleton {
    private static Singleton instance;
    private Singleton() {}
    public static synchronized Singleton getInstance() {
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}

这种方法采用synchronized关键字,迫使每个线程进入getInstance()方法之前,要等别的线程离开该方法,也就是不会有两个线程同时进入该方法。

缺点是:同步会降低性能,而且只有第一次执行此方法时,才很真正需要同步,一旦单例类被实例化后,之后每次调用,都不需要同步了。

 

3.第三种方式:

是否延迟初始化:否

是否多线程安全:是

public class Singleton {
    private static Singleton instance = new Singleton();
    
    private Singleton() {}
    
    public static Singleton getInstance(){
        return instance;
    }
    
}

当类被加载时,马上实例化Singleton对象。

缺点是,如果程序整个运行过程没有使用过Singleton对象,会导致浪费资源,因为该对象一直占用内存。

 

第四种方式:

是否延迟初始化:是

是否多线程安全:是

public class Singleton {
    private volatile static Singleton instance;
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        if(instance == null){
            synchronized(Singleton.class) {
                if(instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

这种方法利用双重检查加锁,能减少getInstance()同步,首先检查实例是否已经创建,如果未创建,进行同步,否则直接返回已经存在的实例。

 

第五种方式:

是否延迟初始化:是

是否多线程安全:是

public class Singleton {
    private static class SingletonInner {
        private static Singleton instance = new Singleton();
    }
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        return SingletonInner.instance;
    }
}

这种方式在Singleton类里面写了个内部类,实现当Singleton类被加载时,不会实例化Singleton对象,而是调用了Singleton.getInstance()时,将SingletonInner类加载时,Singleton才会实例化。相比第三种方法更加合理。

 

第六种方法:

是否延迟初始化:否

是否多线程安全:是

public enum Singleton {
    INSTANCE;
    private Singleton() {
    }
}

自JDK1.5起才能使用,更加简洁,自动支持序列化机制,绝对防止多次实例化,不能通过reflection attack来调用私有构造方法。

posted @ 2016-03-10 21:41  没有梦想的小灰灰  阅读(150)  评论(0编辑  收藏  举报