单例模式
单例模式核心在于为整个系统提供一个唯一的实例,为整个系统提供一个全局访问点。单例模式从实现上可以分为饿汉式单例和懒汉式单例两种,前者天生就是线程安全的,后者则需要考虑线程安全性。常见的线程安全的懒汉式单例的实现有内部类式和双重检查式两种。下面给出单例模式几种常见的形式:
(1). 饿汉式单例
// 饿汉式单例
public class Singleton1 {
// 指向自己实例的私有静态引用,主动创建
private static Singleton1 singleton1 = new Singleton1();
// 私有的构造方法
private Singleton1(){}
// 以自己实例为返回值的静态的公有方法,静态工厂方法
public static Singleton1 getSingleton1(){
return singleton1;
}
}
(2). 懒汉式单例
// 懒汉式单例
public class Singleton2 {
// 指向自己实例的私有静态引用
private static Singleton2 singleton2;
// 私有的构造方法
private Singleton2(){}
// 以自己实例为返回值的静态的公有方法,静态工厂方法
public static Singleton2 getSingleton2(){
// 被动创建,在真正需要使用时才去创建
if (singleton2 == null) {
singleton2 = new Singleton2();
}
return singleton2;
}
}
(3). 线程安全的懒汉式单例 —— 内部类方式
public class Singleton {
//静态私有内部类
private static class InnerClass {
private final static Singleton instance = new Singleton();
}
private Singleton(){
}
public static Singleton getInstance(){
return InnerClass.instance;
}
}
内部类方式线程安全懒汉式单例的内在原理在于:虚拟机会保证一个类的类构造器<clinit>()在多线程环境中被正确的加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的类构造器<clinit>(),其他线程都需要阻塞等待,直到活动线程执行<clinit>()方法完毕。特别需要注意的是,在这种情形下,其他线程虽然会被阻塞,但如果执行<clinit>()方法的那条线程退出后,其他线程在唤醒之后不会再次进入/执行<clinit>()方法,因为 在同一个类加载器下,一个类型只会被初始化一次。
(4). 线程安全的懒汉式单例 —— 双重检查方式
public class Singleton {
// volatile: 防止指令重排序
private volatile static Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
// 第一次检查
if(instance == null){
// 只在最初几次会进入该同步块,提高效率
synchronized(Singleton.class){
// 第二次检查
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
单例模式整理于 作者:书呆子Rico 原文:https://blog.csdn.net/justloveyou_/article/details/78653660