设计模式-单例模式

设计模式-单例模式 官方定义

所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例。并且该类只提供一个取得其对象实例的方法(静态方法)

举个最常见的例子,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

轻量级的同步机制(低配版)没有保证原子性

三大特性

保证可见性

其中一个线程修改了主内存共享变量的值,要写回主内存,并要及时通知其他线程可见

没有保证原子性

(不能保证)不可以分割,完整,要么同时成功,要么同时失败

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wspzjz.html