设计模式-单例模式 官方定义
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例。并且该类只提供一个取得其对象实例的方法(静态方法)
举个最常见的例子,Spring中bean的默认都是单例模式,每个bean定义只生成一个对象实例,每次getBean请求获得的都是此实例
单例模式八种方式那接下来我们来聊聊单例模式的八种实现方式,如下所示
饿汉式(静态常量)
饿汉式(静态代码块)
懒汉式(线程不安全)
懒汉式(线程安全,同步方法)
懒汉式(线程安全,同步代码块)
双重检查
静态内部类
枚举方式
饿汉式(静态常量) //案例演示 - 饿汉式(静态常量) class Singleton{ //一、构造器私有化,防止外部用构造器初始化。。。 private Singleton(){} //二、类的内部创建对象 final static private static final Singleton singleton = new Singleton(); //三、对外提供公共的静态方法,返回该类的唯一对象 public static Singleton getInstance(){ return singleton; } }写法分析
优势:简单、避免多线程的同步问题
劣势:没有达到懒加载的效果
饿汉式(静态代码块) class Singleton(){ //构造器私有化 private Singleton(){} //类的内部创建对象 private static final Singleton singleton; static { singleton = new Singleton(); } //对外提供公共的静态方法 public static Singleton getInstance(){ return singleton; } }写法分析
优势:简单,避免了多线程同步问题
劣势:没有实现懒加载效果
懒汉式(线程不安全) class Singleton(){ //构造器私有化 private Singleton(){} //类的内部创建对象 private static Singleton singleton; //对外提供公共的静态方法 public static Singleton getInstance(){ if(singleton == null){ singleton = new Singleton(); } return singleton; } }写法分析
优势:起到了懒加载的效果,不会造成内存浪费
劣势:线程不安全,实际开发中不推荐这个方式
懒汉式(同步方法) class Singleton(){ //构造器私有化 private Singleton(){} //类的内部创建对象 private static Singleton singleton; //对外提供公共的静态方法 public static synchronized Singleton getInstance(){ if(singleton == null){ singleton = new Singleton(); } return singleton; } }写法分析
解决了线程安全问题,但是效率太低
懒汉式(同步代码块) class Singleton(){ //构造器私有化 private Singleton(){} //类的内部创建对象 private static Singleton singleton; //对外提供公共的静态方法 public static Singleton getInstance(){ if(singleton == null){ synchronized(Singleton.class){ singleton = new Singleton(); } } return singleton; } }写法分析
不推荐,解决不了线程安全的问题
双重检查机制 class Singleton(){ //构造器私有化 private Singleton(){} //类的内部创建对象 private static Singleton singleton; //对外提供公共的静态方法 public static Singleton getInstance(){ if(singleton == null){ synchronized(Singleton.class){ if(singleton == null){ singleton = new Singleton(); } } } return singleton; } }写法分析
在实际开发中推荐使用这种方式
线程安全
懒加载
效率很高
可能出现的问题
我们认为的new Singleton()操作
分配内存地址M
在内存M上初始化Singleton对象
将M的地址值赋值给instance对象
JVM编译优化后(指令重排)可能的new Singleton()操作
分配内存地址M
将M的地址赋值给instance变量
在内存M上初始化Singleton对象
会出现空指针异常
解决方法
只需要关键字volatile 禁止指令重排
private static volatile Singleton singleton; 扩展-Volatile轻量级的同步机制(低配版)没有保证原子性
三大特性
保证可见性
其中一个线程修改了主内存共享变量的值,要写回主内存,并要及时通知其他线程可见
没有保证原子性
(不能保证)不可以分割,完整,要么同时成功,要么同时失败