作者简介: zoro-1,目前大二,正在学习Java,数据结构,javaee等
作者主页: zoro-1的主页
欢迎大家点赞 👍 收藏 ⭐ 加关注哦!💖💖
多线程代码案例之单例模式
- 单例模式
- 饿汉式单例模式
- 懒汉式单例模式
单例模式
单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问该实例。在单例模式中,类的实例化只会发生一次,并且可以在任何地方访问该实例。这种模式常用于需要共享资源的场景,例如数据库连接、线程池等。他分为饿汉式单例模式和懒汉式单例模式。
饿汉式单例模式
代码示例:
class Singletion{
private static Singletion singletion=new Singletion();
private Singletion(){
}
public static Singletion getInstance() {
return singletion;
}
}
饿汉式单例模式,没有线程安全问题,因为他的实例在类加载时就完成了
懒汉式单例模式
单线程下的懒汉式单例模式
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
以上的代码在单线程情况下是安全的,但在多线程情况下就是存在问题
如何解决以上的问题:
1.假设现在有两个线程调用getInstance方法获取实例对象,如下:
public class Main {
public static void main(String[] args) {
Thread t=new Thread(()->{
Singletion singletion=Singletion.getInstance();
});
Thread t1=new Thread(()->{
Singletion singletion=Singletion.getInstance();
});
t.start();
t1.start();
}
}
以上的两个线程的执行顺序就有可能是:
这样就会导致被实例化两次,如果这个对象所需的空间很大这个操作是很危险的,所以就要加锁,一个线程在实例是另一个线程阻塞
class Singleton {
private static Singleton instance;
private static Object loker=new Object();
private Singleton() {}
public static synchronized Singleton getInstance() {
synchronized (loker) {
if (instance == null) {
instance = new Singleton();
}
}
return instance;
}
}
但以上代码也存在一定的问题就是当对象已经在t实例化后,t2就不必获取到锁了,这样会大大影响代码速度所以要在加锁上加一个判断条件,只有实例对象为null的时候才加锁
class Singleton {
private static Singleton instance;
private static Object loker=new Object();
private Singleton() {}
public static synchronized Singleton getInstance() {
if(instance==null) {
synchronized (loker) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
现在已经差不多实现了,但还存在一个致命问题,就是指令重排序,这个问题是什么意思呢
指令重排序就是在执行以上代码时,jvm会将它进行优化,首先将以上代码原子化:
1.申请一段内存空间
2.在这个内存上调用构造方法创建实例
3.将这个内存地址赋值给变量 instance
通常都是123顺序执行,而jvm有可能将以上指令优化成132执行,这样的优化在单线程执行下没问题但在多线程代码下可能就会出现问题
假设在左边是t线程执行到实例 instance时执行了13两步就被t1线程挤走了,然后t1线程就会判断 instance为非null直接返回 instance,实际上还未真正实例化(2为指令),所以就可以使用volatile关键字解决这个问题他可以终止jvm的优化,按照123执行代码,就解决问题了
class Singleton {
private static volatile Singleton instance;
private static Object loker=new Object();
private Singleton() {}
public static synchronized Singleton getInstance() {
if(instance==null) {
synchronized (loker) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
今天的分享到这里就结束了,感谢大家支持