顾名思义,单例模式,也就是在程序中只存在一个实例.比如常举的例子java.lang.Runtime 它定义了静态变量,私有了无参构造器,提供公开的public方法获取实例.这样的好处是我们经常需要一个实例来进行事件的处理,那就没必要去创造多个实例出来,给GC压力.
单例的种类
饿汉式
也就是初始即加载
静态变量
class Singleton {
// 定义实例对象
private final static Singleton singleton = new Singleton();
// 私有化构造方法
private Singleton() {}
// 提供公开静态方法-唯一的获取方式
public static Singleton getInstance() {
return singleton;
}
}
类型: 饿汉式-静态变量
原理: 在编译时已经创建,通过类加载器保证线程安全,静态成员变量在类加载中的准备阶段就划分内存区域并置零值, 通过final关键字,在准备时会用代码值覆盖零值,进行直接赋值,不会等待初始化阶段.
缺点: 类加载时创建,这样如果程序启动有大量的创建,会导致内存浪费以及cpu使用达到峰值,有风险性操作,不能做到即用即加载.这是线程安全的.使用jvm类加载机制
静态代码块
class Singleton1 {
// 定义实例对象
private static Singleton1 singleton;
static {
singleton = new Singleton1();
}
// 私有化构造方法
private Singleton1() {}
// 提供公开静态方法-唯一的获取方式
public static Singleton1 getInstance() {
return singleton;
}
}
类型: 饿汉式-静态代码块
原理: 也是通过类加载机制,静态代码块在类加载中的初始化时进行赋值,两者的差异是在类加载不同阶段.
缺点: 类加载时创建,这样如果程序启动有大量的创建,会导致内存浪费以及cpu使用达到峰值,有风险性操作,不能做到即用即加载
懒汉式
使用时再加载
懒加载(线程不安全)
class SingletonLazy1 {
// 错误示范,线程不安全
private static SingletonLazy1 singleton;
private SingletonLazy1() {}
public static SingletonLazy1 getInstance() {
if (singleton == null) {
singleton = new SingletonLazy1();
}
return singleton;
}
}
类型: 懒汉式,延迟到调用方法时再创建
原理: 通过方法中判断非空进行控制.
缺点: 线程不安全,并发会产生多个实例,实际开发不能使用,已经不属于单例模式,这是个错误示范
线程安全的懒加载
class SingletonLazy2 {
private volatile static SingletonLazy2 singleton;
private SingletonLazy2() {}
public static synchronized SingletonLazy2 getInstance() {
if (singleton == null) {
singleton = new SingletonLazy2();
}
return singleton;
}
}
类型: 懒汉式,延迟到调用方法时再创建
原理: 通过方法中判断非空进行控制.volatile 声明内存可见
缺点: 通过synchronized进行同步控制,但是粒度较大,会涉及锁升级.无锁->偏向锁->轻量锁->重量锁
双重检查
懒汉式-双重检查(推荐使用)
class SingletonLazy3 {
private volatile static SingletonLazy3 singleton;
private SingletonLazy3() {}
public static SingletonLazy3 getInstance() {
if (singleton == null) {
synchronized (SingletonLazy3.class) {
if (singleton == null) {
singleton = new SingletonLazy3();
}
}
}
return singleton;
}
}
类型: 懒汉式-双重检查,延迟到调用方法时再创建,懒加载
原理: 通过方法中判断非空进行控制.volatile 声明内存可见
缺点: 无
静态内部类(推荐使用)
class SingletonLazy4{
private SingletonLazy4(){}
private static class Singleton{
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance(){
return Singleton.INSTANCE;
}
}
类型: 懒汉式-静态内部类,延迟到调用方法时再创建,懒加载
原理: 通过类加载方式实现线程安全,因为类只会被加载一次,内部通过cas 实现线程安全,jvm级别控制
缺点: 无
枚举(推荐使用)
enum Singleton2 {
INSTANCE();
private SingletonType singletonType;
Singleton2() {
singletonType = new SingletonType();
}
public SingletonType getInstance() {
return singletonType;
}
}
类型: 枚举是天然的单例
原理: 每个枚举实例都是static final类型,所以只能被实例化一次,这样我们通过构造方法来保证其中代码也只能实例化一次.这样来控制线程安全
缺点: 无
本文借鉴尚硅谷Java设计模式,韩顺平图解java,传送门