web小菜鸡的专栏

专注web架构30年

单例模式

1.定义
单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例
2. 懒汉式实现单例
//懒汉式单例类.在第一次调用的时候实例化自己

public class Singleton {
    private Singleton() {}
    private static Singleton instance=null;
    //静态工厂方法 
    public static Singleton getInstance() {
         if (instance== null) {  
             instance= new Singleton();
         }  
        return instance;
    }
}

这个是非线程安全的,实现线程安全有俩种方法。
第一在getInstance()方法上加上synchronized关键字实现同步 public synchronized static Singleton getInstance(){};
第二是双重检查锁定

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

如果不用volatile修饰single变量,则因为内存模型允许所谓的“无序写入”,可能导致失败。——某个线程可能会获得一个未完全初始化的实例。
如果不用volatile,则因为内存模型允许所谓的“无序写入”,可能导致失败。——某个线程可能会获得一个未完全初始化的实例。而volatile关键字就是提示VM:对于这个成员变量不能保存它的私有拷贝,而应直接与共享成员变量交互。
如果不用volatile修饰变量,可以用下面方法实现

public static Singleton getInstance()
{
  if (instance == null)
  {
    synchronized(Singleton.class) {      //1
      Singleton inst = instance;         //2
      if (inst == null)
      {
        synchronized(Singleton.class) {  //3
          inst = new Singleton();        //4
        }
        instance = inst;                
      }
    }
  }
  return instance;
}

3.饿汉式实现单例

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

该方法在类一加载就实例化了对象,没有延迟加载的功能。

4.静态内部类实现单例模式(线程安全且有延迟加载的功能,因为内部静态类只会被加载一次),public static class singletion=new Singleton(),这种形式会在类一初始化就会加载实例,不能延迟加载,静态内部类只会加载,不会初始化内部结构,内部类在被加载时候才初始化

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

由于上面方法都是通过把构造方法的修饰符改为private来禁止多次实例化,因此可以通过反射机制来调用私有的构造方法来实例化对象,所以严格老说上述方法都不是单利模式。下面通过反射来实例化对象

public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        Class<?> c = Singleton.class;
        //getDeclaredConstructor可以返回指定参数的构造函数,而getConstructor只能放回指定参数的public的构造函数
        Constructor<?> cons = c.getDeclaredConstructor();
        cons.setAccessible(true);
        Singleton single = (Singleton) cons.newInstance();
        System.out.println(single==Singleton.getInstance());
    }

还需要注意的是如果上述类加上“implements Serialization”时,就不是单例类。因为任何一个readObject()方法都会返回一个新的实例,他不同于该类初始化创建的实例。解决的办法:通过在上面类中加上readResolve()方法保证单例特性。

private Object readResolve() throws ObjectStreamException{
        return Singleton.getInstance();
}

Effective java第二版77条说:如果依赖readResolve进行实例控制,带有对象引用类型的所有实例域都必须声明为transient。否则就有可能在readResolve方法运行之前,保护指向反序列化对象的引用。(这段不是很理解)。
5. 枚举类型实现单例模式

public enum Singleton1 {
    INSTANCE;

该方法是最简单也是最有用的,无偿提供了序列化禁止,绝对防止多次实例化。

阅读更多
文章标签: 设计模式
个人分类: 设计模式
上一篇事务性质和隔离级别
下一篇JAVA虚拟机内存机制
想对作者说点什么? 我来说一句

单例模式单例模式单例模式

2011年07月31日 467KB 下载

研磨单例模式研磨单例模式

2010年12月15日 123KB 下载

单例模式(讲解单例模式)

2011年01月18日 317KB 下载

Java单例模式(DOC)

2009年10月21日 91KB 下载

php单例模式和工厂模式

2009年05月22日 54KB 下载

JAVA单例模式

2013年11月14日 46KB 下载

设计模式之单例模式

2017年12月01日 9KB 下载

线程安全的单例模式

2012年12月07日 345KB 下载

单例模式详解~~单例模式详解~~

2011年03月01日 39KB 下载

研磨设计模式之单例模式.pdf

2011年11月16日 311KB 下载

没有更多推荐了,返回首页

关闭
关闭