定义
单例模式即一个 JVM 内存中只存在一个类的对象实例。
分类
- 饿汉式指的是jvm加载类时就创建对象实例,调用效率高,不能延迟加载,影响系统性能,线程安全。具体代码如下:
/** * 饿汉式单例模式:类加载的时候就创建实例 * 优点:线程安全,类加载时就创建实例,调用效率高 * 缺点:不能延迟加载,影响系统性能 */ public class EagerSingleton { /* //jvm加载类时,就创建实例 private static EagerSingleton singleton = new EagerSingleton(); */ private static EagerSingleton singleton=null; //在静态代码块中,创建实例,静态块与类同时被jvm加载的 static { singleton = new EagerSingleton(); //私有构造方法 } private EagerSingleton(){} //提供一个静态方法给外部调用,获取该单例实例 public static EagerSingleton getInstance(){ return singleton; } }
- 懒汉式:需要使用实例对象才去创建对象,懒汉式又分二种,线程安全懒汉式,线程不安全懒汉式 线程不安全懒汉式特点:能延迟加载,线程不安全,线程安全懒汉式特点:延迟加载,线程安全,调用效率高。具体代码如下:
/** * 懒汉式单例模式:使用时才创建实例 * 分线程安全单例模式,线程不安全单例模式 * 线程安全懒汉式: * 优点:延迟加载,线程安全, * 缺点:执行效率低。 * 线程不安全懒汉式: * 优点:延迟加载, * 缺点:线程安全 */ public class LazySingleton { private static LazySingleton singleton; //私有构造方法 private LazySingleton(){} //1.线程不安全的的懒汉式单例,提供一个非同步的方法,给外部使用者调用,不推荐使用 /*public static LazySingleton getInstance(){ if(singleton==null){ singleton=new LazySingleton(); } return singleton; }*/ //2.线程不安全的的懒汉式单例同步块,只是单检验锁,依然可能创建多个实例 /* public static LazySingleton getInstance(){ if(singleton==null){ synchronized (LazySingleton.class){ singleton=new LazySingleton(); } } return singleton; }*/ // 线程安全的懒汉式:为了解决线程安全,提供一个同步静态方法,给外部使用者调用,但是调用效率低下 public static synchronized LazySingleton getInstance(){ if(singleton==null){ singleton=new LazySingleton(); } return singleton; } }
-
静态内部类单例模式:在静态内部类中创建外部类的实例,能延迟加载,调用效率高,线程安全,具体代码如下:
/** * 静态内部类单例模式 * 特点:线程安全,延迟加载,调用效率高,推荐使用 */ public class InnerClassInstance { //私有的构造 private InnerClassInstance(){} //在静态内部类内创建外部类实例。 private static class InnerSingleton{ private static final InnerClassInstance SINGLETON=new InnerClassInstance(); } //对外提供一个静态方法,获取该类的实例 public static final InnerClassInstance getInstance(){ return InnerSingleton.SINGLETON; } }
-
双重检验锁单例模式:实例变量用volatile进行锁定,保证不同线程对实例变量是可见的,再用同步代码块保证创建的实例是单例,是线程安全的,能延迟加载,调用效率比安全的懒汉式单例模式高
** * 双重检验锁单例模式:实例变量用volatile进行锁定,保证不同线程对实例变量是可见的,再用同步代码块保证创建的实例是单例,可以推荐使用 * 优点:线程安全,可延迟加载 * 缺点:调用效率不是很高,但比饿汉式同步方法进行锁定的效率要高。 */ public class DoubleLockSingleton { //volatile修饰实例,1:使得不同线程对该实例是可见的,禁止进行指令重排序 private static volatile DoubleLockSingleton singleton; //私有的构造方法 private DoubleLockSingleton(){} //对外提供一个获取该单例的方法 public static DoubleLockSingleton getInstance(){ if(singleton==null){ synchronized(DoubleLockSingleton.class){ if(singleton==null){ singleton=new DoubleLockSingleton(); } } } return singleton; } }
-
枚举单例模式:枚举常量是就是枚举类型的一个实例,枚举是天然的单例,代码如下:
/** * 枚举单例,枚举类型是天然的单例,一个成员变量就是枚举的一个实例 */ public enum EnumSingleton { SINGLETON; }
使用场景
- 工具类对象
- 只需要一个对象的类
- 创建频繁经常用到的对象
jdk单例的应用
-
Runntime类
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; }
- Spring容器内的实例默认是饿汉式单例,即容器启动时就实例化bean到容器,通过defalut-lazy-init="true"设置懒汉式实例化bean,使用到bean,才实例化bean,这就是容器化单例。