Java设计模式之单例模式简单解析
单例模式的优缺点
优点:
- 在内存中某个类只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例
- 避免对资源的多重暂用
缺点: 没有接口,不能继承
单例模式的几种实现方式
1、饿汉式(线程安全)
类加载时就初始化实例,避免了多线程同步问题,天然线程安全。
为什么饿汉式是线程安全的? 类加载的方式是按需加载,且只加载一次。因此,在上述单例类被加载时,就会实例化一个对象并交给自己的引用,供系统使用,即在线程访问单例对象之前,其就已经创建好了。线程每次都只能拿到这个唯一的对象。因此,饿汉式单例天生就是线程安全的。
class Singleton{ //1、私有化构造器,这样外部就不能通过构造器来创建对象 private Singleton(){ } //2、本类内部创建对象实例 private final static Singleton instance = new Singleton(); //3、对外提供一个共有的静态方法,返回对象实例 public static Singleton getInstance(){ return instance; } }
2、饿汉式(静态代码块方式)
class Singleton{ //1、私有化构造器,这样外部就不能通过构造器来创建对象 private Singleton(){ } //2、本类内部创建对象实例 private static Singleton instance; //3、在静态代码块中创建单例对象 static { instance = new Singleton(); } //4、对外提供一个共有的静态方法,返回对象实例 public static Singleton getInstance(){ return instance; } }
3、懒汉式(线程不安全)
实例对象在第一次被调用的时候才真正构建的,而不是程序一启动就会自动构建。这种实现最大的问题就是不支持多线程,因为没有加锁 ,多线程场景下不要使用,因为可能会产生多个对象,不再是单例
class Singleton{ private static Singleton instance; private Singleton(){}; //提供一个静态的公有方法,当使用到该方法时,才会去创建instance public static Singleton getInstance(){ if(instance==null){ instance = new Singleton(); } return instance; } }
4、懒汉式+锁 实现多线程安全的单例模式
每次获取实例时,也需要等待其他线程的锁释放,效率低
class Singleton{ private static Singleton instance; private Singleton(){}; //提供一个静态的公有方法,当使用到该方法时,才会去创建instance public static synchronized Singleton getInstance(){ if(instance==null){ instance = new Singleton(); } return instance; } }
5、double-check locking实现单例模式
多个线程只在创建实例的时候加锁实现同步
class Singleton{ // volatile: 轻量级的synchronized, 由它修饰的变量在发生变化后会立即刷新到主存 private static volatile Singleton instance; private Singleton(){}; public static Singleton getInstance(){ if(instance==null){ synchronized (Singleton.class){ if(instance==null){ instance = new Singleton(); } } } return instance; } }
【注意】instance为什么需要采⽤ volatile 关键字修饰?
instance采⽤ volatile 关键字修饰也是很有必要的,在上述代码中有下面这一句代码
instance= SingletonDCL();
其实是分为三步执⾏的:
1.为 instance 分配内存空间
2. 初始化 instance
3. 将 instance指向分配的内存地址
但是由于 JVM 具有指令重排的特性,执⾏顺序有可能变成 1->3->2。指令重排在单线程环境下不会出现问题,但是在多线程环境下会导致⼀个线程获得还没有初始化的实例。
例如,线程A 执⾏了 1 和3,此时线程B调⽤ getInstance() 后发现 instance不为空,因此返回instance,但此时instance还未被初始化,使⽤ volatile 可以禁⽌ JVM 的指令重排 ,保证在多线程环境下也能正常运⾏。
到此这篇关于Java设计模式之单例模式简单解析的文章就介绍到这了,更多相关Java的单例模式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
Spring中@Configuration注解和@Component注解的区别详解
这篇文章主要介绍了Spring中@Configuration注解和@Component注解的区别详解,@Configuration 和 @Component 到底有何区别呢?我先通过如下一个案例,在不分析源码的情况下,小伙伴们先来直观感受一下这两个之间的区别,需要的朋友可以参考下2023-09-09SpringData整合ElasticSearch实现CRUD的示例代码(超详细)
本文主要介绍了SpringData整合ElasticSearch实现CRUD的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧2023-07-07登录EasyConnect后无法通过jdbc访问服务器数据库问题的解决方法
描述一下近期使用EasyConnect遇到的问题,下面这篇文章主要给大家介绍了关于登录EasyConnect后无法通过jdbc访问服务器数据库问题的解决方法,文中通过实例代码介绍的非常详细,需要的朋友可以参考下2023-02-02
最新评论