单例模式概念
单例模式是一种对象创建模式,它用于产生一个对象的具体实例,它可以
确保系统中一个类只产生一个实例。
好处:
对于频繁使用的对象,可以省略创建对象所花费的时间,这对于那些重量级
对象而言,是非常可观的一笔系统开销
由于new操作的次数减少,因而对系统内存的使用频率也会降低,这将减轻GC压力,
缩短GC停顿时间
饿汉
//饿汉
//无法对instance实例进行延迟加载
public class Hungry {
private static final Hungry hungry = new Hungry();
private Hungry() {
System.out.println("Single Hungry is create ");
}
public static Hungry getHungrySingleton() {
return hungry;
}
public static void createString() {
System.out.println("createString in singleton");
}
public static void main(String[] args) {
Hungry.createString();
}
}
懒汉
//懒汉
//在多线程并发下这样的实现是无法保证实例是唯一的/线程不安全
//创建多线程,会发现hashCode值是不一样的
//System.out.println(Lazy.getInstance.hashCode());
public class Lazy {
private static Lazy lazy;
private Lazy() {
}
public static Lazy getInstance() {
// 第一次调用的时候会被初始化
if (lazy == null) {
lazy = new Lazy();
}
return lazy;
}
public static void createString() {
System.out.println("createString in singleton");
}
public static void main(String[] args) {
Lazy.createString();
}
}
懒汉线程安全
//懒汉线程安全
//相比懒汉模式是线程安全的,但是有性能上的不足
//优化:DCL 双重检查锁模式
public class LazySafetSingleton {
private static LazySafetSingleton lazySafetSingleton;
private LazySafetSingleton() {
}
// 方法中声明synchronized关键字
public static synchronized LazySafetSingleton getInstance() {
if (lazySafetSingleton == null) {
lazySafetSingleton = new LazySafetSingleton();
}
return lazySafetSingleton;
}
// 同步代码块实现
public static LazySafetSingleton getInstance1() {
synchronized (LazySafetSingleton.class) {
if (lazySafetSingleton == null) {
lazySafetSingleton = new LazySafetSingleton();
}
return lazySafetSingleton;
}
}
public static void createString() {
System.out.println("createString in singleton");
}
public static void main(String[] args) {
LazySafetSingleton.createString();
}
}
DCL
//Dcl 双重检查锁模式 性能和安全会比懒汉和懒汉线程好些
public class DclSingleton {
//添加volatile禁止jvm的指令重排序优化
private static volatile DclSingleton dclSingleton = null;
private DclSingleton() {
}
//两次检查dclSingleton是否为null
public static DclSingleton getInstance() {
// 避免不必要的同步
if (dclSingleton == null) {
// 同步
synchronized (DclSingleton.class) {
// 在第一次调用时初始化
if (dclSingleton == null) {
dclSingleton = new DclSingleton();
//dclSingleton = new DclSingleton();这里不是原子操作,那么jvm在检验的时候
//1.给instance分配内存控件,
//2.调用Dclsingleton的构造方法,初始化变量,
//3.将dclSingleton指向jvm分配的内存空间,
//但jvm的即使编译器中存在指令重排序的优化,以上的步骤不一定会按照步骤走,
//这时候就会造成线程不安全,解决方法是将dclSingleton加上volatile
}
}
}
return dclSingleton;
}
}
静态内部类的单例模式
//静态内部类的单例模式 既能延时加载也是线程安全的
//jvm本身机制保证了线程安全/没有性能缺陷
/*
* jvm提供的同步控制,即static和final关键字
* static保证数据在内存中是独一份的
* final初始化后无法被修改
* */
public class StaticInnerSingleton {
private StaticInnerSingleton(){}
public static StaticInnerSingleton getInstance(){
return SingletonHolder.sInstance;
}
//静态内部类
private static class SingletonHolder{
private static final StaticInnerSingleton sInstance=new StaticInnerSingleton();
}
}
枚举
//枚举方式的单例模式
//写法简单/线程安全
//不写实例方法的话,默认枚举的实例创建是实例安全的,如果要添加变量和实例方法需要注意线程安全。
public enum EnumSingleton {
//定义一个枚举元素,它就是Singleton的一个实例
INSTANCE;
public void doSomeThing(){
//do something...
}
}
饿汉:无法对instance实例进行延迟加载
懒汉:多线程并发情况下无法保证实例的唯一性
懒汉线程安全:使用synchronized导致性能缺陷
DCL:JVM即使编译器的指令重排序
静态内部类/枚举:延迟加载/线程安全/性能优势 //推荐