单例模式主要有3种,懒汉式,饿汉式和登记模式
先来看看它们是如何操作的:
懒汉式
//懒汉式,第一次调用时实例化,之后共用一个实例public class Singleton{//私有的默认构造子,务必是私有的,不然外部可以调用它来实例化,就无法控制实例化的只有一个了private Singleton(){}//静态private static Singleton single=null;//静态工厂方法public static Singleton getInstance(){if(single==null){single=new Singleton();}return single;}}
饿汉式
//饿汉式单例类.在类初始化时,已经自行实例化 public class Singleton1 { //私有的默认构造子 private Singleton1() {} //已经自行实例化 private static final Singleton1 single = new Singleton1(); //静态工厂方法 public static Singleton1 getInstance() { return single; } }
懒汉式单例的实现没有考虑线程安全问题,它是线程不安全的,并发环境下很可能出现多个Singleton实例
饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以是线程安全的
登记式单例
//类似Spring里面的方法,将类名注册,下次从里面直接获取。 public class Singleton3 { private static Mapmap = new HashMap (); static{ Singleton3 single = new Singleton3(); map.put(single.getClass().getName(), single); } //保护的默认构造子 protected Singleton3(){} //静态工厂方法,返还此类惟一的实例 public static Singleton3 getInstance(String name) { if(name == null) { name = Singleton3.class.getName(); System.out.println("name == null"+"--->name="+name); } if(map.get(name) == null) { try { map.put(name, (Singleton3) Class.forName(name).newInstance()); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } return map.get(name); } //一个示意性的商业方法 public String about() { return "Hello, I am RegSingleton."; } public static void main(String[] args) { Singleton3 single3 = Singleton3.getInstance(null); System.out.println(single3.about()); } }
登记式单例实际上维护了一组单例类的实例,将这些实例存放在一个Map(登记薄)中,对于已经登记过的实例,则从Map直接返回,对于没有登记的,则先登记,然后返回。