单例模式中饿汉模式和懒汉模式的线程安全问题
单例模式
单例模式是指整个程序的运行中只有一个实例,并提供一个全局访问点。
单例模式模式的三个基本要点:
- 这个类只能有一个实例;
- 它必须自行创建这个实例;
- 它必须自行向整个系统提供这个实例。
1. 饿汉方式
程序启动之后就会创建,但是创建完了之后可能不会使用,从而浪费了系统资源
优点:没有任何锁,执行效率高
适用于单例模式较少的场景:
如果我们在程序启动后,一定会加载到类,那么用饿汉模式实现的单例简单又实用;
如果我们是写一些工具类,则优先考虑使用懒汉模式,可以避免提前被加载到内存中,占用系统资源。
public class Singleton {// 1.创建私有的构造函数,为了防止其他类直接创建private Singleton(){}// 2.定义私有类变量(线程安全)private static Singleton singleton = new Singleton();// 3.提供公共的获取实例的方法public static Singleton getInstance() {return singleton;}
}
2. 懒汉模式
2.1 懒汉方式 (v1):
针对饿汉方式浪费资源的问题,将第二步
private static Singleton singleton = new Singleton()
修改为
private static Singleton singleton = null;
再在公共的获取实例的方法内进行判断,是否第一次访问,这样当程序启动之后并不会实例化,等什么时候调用什么时候才会初始化,防止资源的浪费
最后代码为:
public class Singleton {private Singleton(){}private static Singleton singleton = null;private static Singleton getInstance() {if(singleton == null) {singleton = new Singleton();}return singleton;}
}
这样解决了:
因为类加载时就初始化,浪费内存的问题,但是同样也带来的新的问题: 线程不安全
线程不安全的代码演示:
public class ThreadDemo {/*** 1.懒汉方式 V1(线程不安全)演示:*/static class Singleton {// 1.创建一个私有的构造函数private Singleton(){}// 2. 创建一个私有的类变量private static Singleton singleton = null;// 3. 提供统一的访问方法public static Singleton getInstance() throws InterruptedException {if (singleton == null) {Thread.sleep(1000);// 第一次访问singleton = new Singleton();}return singleton;}}private static Singleton s1 = null;private static Singleton s2 = null;public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {try {s1 = Singleton.getInstance();} catch (InterruptedException e) {e.printStackTrace();}}});t1.start();Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {try {s2 = Singleton.getInstance();} catch (InterruptedException e) {e.printStackTrace();}}});t2.start();t1.join();t2.join();System.out.println(s1 == s2);}
}
运行结果可能为 false
线程 | t1 | t2 |
---|---|---|
第一次访问 | if (singleton == null) 括号内判断为 true | |
t2 获得时间片 | 还未实例化对象,t2 进入 if 判断也为 true |
线程 t1 和 t2实例化了两个对象,线程不安全
2.2 懒汉方式 (v2):
给 getInstance() 方法加锁:
public class Singleton {private Singleton(){}private static Singleton singleton = null;// 给方法加锁private static synchronized Singleton getInstance() {if(singleton == null) {singleton = new Singleton();}return singleton;}
}
是解决了 v1 版本的第一次访问会出现线程不安全的问题
但是因为简单粗暴的给getInstance() 方法加锁,导致无论什么时候访问都要排队执行,大大降低了性能
2.3 懒汉方式 (v3):
使用双重校验
目录 (MS) 1. 饿汉实现 2. 懒汉模式 ① 单线程版本 ② 线程安全版 ③ 线程安全改进版⼀ 以上存在线程安全问题. ④ 线程安全改进版⼆ 以上存在线程安全问题,对象创建需要三步: ⑤ 线程 ... 本文内容:什么是单例模式,单例的作用,饿汉模式,懒汉模式的安全与非安全的实现,饿汉模式与懒汉模式的区别. 什么是单例模式? 单例模式:保证一个类,仅有一个实例.提供一个访问它的全局访问点. 单例的作用 ... 首先,设计模式是我们程序员在软件开发过程中面临的一般问题的解决方案,通过学习设计模式可以使我们在编程时更加有条理性,同时培养我们写代码的思维能力,从而提高我们的工作效率.接下来就跟着博主的脚步往下走吧 ... 目录 1.什么是单例模式 2.为什么需要单例模式? 3.如何实现单例模式 3.1饿汉方式 3.2懒汉模式 1.什么是单例模式 单例模式是一种设计模式,单例模式能保证某个类在程序中只存在唯一一份实例, ... 目录 1.单例模式 1.1 饿汉模式 1.2 懒汉模式 1.单例模式 单例模式能保证类在程序中只存在唯一一份实例.这一点在很多场景中都需要,比如JDBC中的DataSource实例就只需要一个. 单例 ... 目录 一.单例模式 二.饿汉模式和懒汉模式 1.饿汉模式,线程安全 2.懒汉模式 懒汉模式1,线程不安全(不常用) 懒汉模式2,线程安全(不常用) 懒汉模式3,线程安全,双重校验(不常用) 懒汉模式4 ... 什么是单例模式? 确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例. 首先要建立这个实例: class Factory{public string Name { get; set; }p ... 一,什么是单例模式 单例顾名思义指的是单个实例对象(所以单例模式要求构造方法私有化才能保证在类外不能创建该类的实例化对象):在有的场景中,不应该创建多个对象时就应该使用单例模式,一旦使用了单例模式,此 ... 文章目录 单例模式 单例模式是什么? 饿汉单例模式 饿汉单例是什么? 实现步骤 代码实现 懒汉单例模式 饿汉单例是什么? 实现步骤 代码实现 懒汉单例线程安全问题 解决方案 总结 单例模式 单例模式是 ... 文章目录 1.前言 2.怎么区分饿汉和懒汉模式 3. 饿汉 4.懒汉 (双重检查 Double Check Lock) 5.饿汉模式在JDK中的应用(Runtime) 6.相关文章 1.前言 面试时, ...单例模式中饿汉模式和懒汉模式的线程安全问题相关推荐
最新文章
热门文章