创建型设计模式之单例模式
单例模式使用场景:
需要频繁和创建和销毁的对象
创建对象耗时过多或消耗资源过多,即重量级对象,但又经常用到的对象
工具类对象,频繁访问数据库或文件的对象(如数据源、session工厂等)
Runtime就是精典的饿汉单例模式应用
public class Runtime { private static Runtime currentRuntime = new Runtime(); /** * Returns the runtime object associated with the current Java application. * Most of the methods of class <code>Runtime</code> are instance * methods and must be invoked with respect to the current runtime object. * * @return the <code>Runtime</code> object associated with the current * Java application. */ public static Runtime getRuntime() { return currentRuntime; } /** Don't let anyone else instantiate this class */ private Runtime() {}
public static void main(String[] args) {
//精典的饿汉模式
Runtime.getRuntime();
Singleton s1 = Singleton.Instance;
Singleton s2= Singleton.Instance;
System.out.println(s1==s2);
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
s1.sayHello();
}
/** * 饿汉式(静态变量) * 优点:写法简单,在类装载时完成实例化,避免了线程同步问题 * 缺点:装载时完成实例化,没有达到懒加载效果,如果不使用这个实例,造成内存浪费。 * 结论:可用,会造成内存浪费。 */ public class Singleton { //1. 构造器私有化,外部不能new private Singleton(){ } //2. 内部创建实类对象 private final static Singleton instance = new Singleton(); //3. 对外提供静态方法,返回对象实例 public static Singleton getInstance(){ return instance; } } /** * 饿汉式(静态代码块) * 优点:写法简单,在类装载时完成实例化,避免了线程同步问题 * 缺点:装载时完成实例化,没有达到懒加载效果,如果不使用这个实例,造成内存浪费。 * 结论:可用,会造成内存浪费。 */ public class Singleton { //1. 构造器私有化,外部不能new private Singleton(){ } //2. 静态代码块中创建实类对象 private final static singleton.type2.Singleton instance; static{ instance = new singleton.type2.Singleton(); } //3. 对外提供静态方法,返回对象实例 public static singleton.type2.Singleton getInstance(){ return instance; } } /** * 懒汉式(线程不安全) * 只能在单线程下使用 */ public class Singleton { private Singleton(){}; private static Singleton instance; public static Singleton GetInstance(){ if(instance==null){ instance= new Singleton(); } return instance; } } /** * 懒汉式(同步方法解决线程安全) * 效率低 */ public class Singleton { private static Singleton instance; private Singleton(){}; public static synchronized Singleton getInstance(){ if(instance==null){ instance=new Singleton(); } return instance; } } /** * 同步代码块解决线程安全 * 不推荐 */ public class Singleton { private static Singleton instance; private Singleton(){}; public static Singleton getInstance(){ if(instance==null){ synchronized (Singleton.class){ instance=new Singleton(); } } return instance; } } /** * 双重检查 * 线程安全,延迟加载,效率较高 * 推荐使用 双重校验锁法会有怎样的情景: * STEP 1. 线程A访问getInstance()方法,因为单例还没有实例化,所以进入了锁定块。 * STEP 2. 线程B访问getInstance()方法,因为单例还没有实例化,得以访问接下来代码块,而接下来代码块已经被线程1锁定。 * STEP 3. 线程A进入下一判断,因为单例还没有实例化,所以进行单例实例化,成功实例化后退出代码块,解除锁定。 * STEP 4. 线程B进入接下来代码块,锁定线程,进入下一判断,因为已经实例化,退出代码块,解除锁定。 * STEP 5. 线程A初始化并获取到了单例实例并返回,线程B获取了在线程A中初始化的单例。 * 理论上双重校验锁法是线程安全的,并且,这种方法实现了lazyloading。 */ public class Singleton { private static volatile 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 SingletonInstantce{ private final static Singleton instance = new Singleton(); } private Singleton(){ } public static Singleton getInstance(){ return SingletonInstantce.instance; } } /** * 枚举法 */ public enum Singleton { Instance; public void sayHello(){ System.out.println("hello"); } }