单例模式是常用设计模式之一,其定义是单例对象的类只能允许一个实例存在。
基本实现思路
要求类能够有返回对象的一个引用(永远是同一个)和一个获得实例的方法(必须是静态方法)。
实现单例模式时,需要考虑使用的环境,注意多线程环境下确保只有一个实例被创建。
主要有以下几种写法
1、饿汉式(静态常量)【可用】
public class Singleton1 { private final static Singleton1 INSTANCE = new Singleton1(); private Singleton1(){} public static Singleton1 getInstance(){ return INSTANCE; }}
优点: 写法简单,类装载的时候完成实例化,避免了线程同步问题
缺点: 实例化之后,如果这个实例一直未被使用,那么就会浪费内存
2、饿汉式(静态代码块)【可用】
public class Singleton2 { private static Singleton2 instance; static { instance = new Singleton2(); } private Singleton2(){} public static Singleton2 getInstance(){ return instance; }}
优点:类装载过程中执行静态代码块中代码,完成初始化类的实例,避免线程同步问题
缺点:实例化之后,如果这个实例一直未被使用,也会浪费内存
3、懒汉式(线程不安全)【不可用】
public class Singleton3 { private static Singleton3 singleton; private Singleton3(){} public static Singleton3 getInstance(){ if(singleton == null){ singleton = new Singleton3(); } return singleton; }}
起到懒加载作用了,但是只能在单线程下使用,如果多线程使用时,可能会出现多个线程同时通过if判断的现象,从而创建出多个实例
4、懒汉式(线程安全-同步方法)【不推荐用】
public class Singleton4 { private static Singleton4 singleton; private Singleton4(){} public static synchronized Singleton4 getInstance(){ if(singleton == null){ singleton = new Singleton4(); } return singleton; }}
完成了懒加载,增加同步方法解决了线程不安全问题;但是同步方法效率过低需要改进
5、懒汉式(线程安全-同步代码块)【不可用】
public class Singleton5 { private static Singleton5 singleton; private Singleton5(){} public static Singleton5 getInstance(){ if(singleton == null){ synchronized(Singleton5.class){ singleton = new Singleton5(); } } return singleton; }}
将同步方法改进未同步代码块产生实例,但是也是会出现多线程同时通过if判断,从而产生多个实例
6、双重检查【推荐用】
public class Singleton6 { private volatile static Singleton6 singleton; private Singleton6(){} public static Singleton6 getInstance(){ if(singleton == null){ synchronized(Singleton6.class){ if(singleton == null){ singleton = new Singleton6(); } } } return singleton; }}
双重检查保证线程安全,volatile又避免多线程半实例化时返回空对象;线程安全,延迟加载;效率高
7、静态内部类【推荐用】
public class Singleton7 { private volatile static Singleton7 singleton; public static class SingletonInstance{ private final static Singleton7 INSTANCE= new Singleton7(); } public static Singleton7 getInstance(){ return SingletonInstance.INSTANCE; }}
装载类时保证只有一个线程会初始化实例,但是静态内部类被装载时不会立即实例化,在被调用getInstance()方法时才会装载内部类,从而完成实例化。
线程安全,延迟加载,效率高
8、枚举【推荐用】
public class Singleton8 { private Singleton8(){ } /** * 枚举类型是线程安全的,并且只会装载一次 */ private enum Singleton{ INSTANCE; private final Singleton8 instance; Singleton(){ instance = new Singleton8(); } private Singleton8 getInstance(){ return instance; } } public static Singleton8 getInstance(){ return Singleton.INSTANCE.getInstance(); }}
系统内存中只有存在一个对象,节省系统资源,枚举的写法非常简单,而且枚举类型是所用单例实现中唯一一种不会被破坏的单例实现模式。
参考: