目录
四、多线程案例之--单例模式
4.1 单例模式
4.2 怎么去设计一个单例?
饿汉模式
懒汉模式
4.3 两种模式的总结
四、多线程案例之--单例模式
4.1 单例模式
是校招中最常考的设计模式之一.
啥是设计模式?
设计模式好比象棋中的 " 棋谱 ". 红方当头炮 , 黑方马来跳 . 针对红方的一些走法 , 黑方应招的时候有一些固定的套路. 按照套路来走局势就不会吃亏 .软件开发中也有很多常见的 " 问题场景 ". 针对这些问题场景 , 大佬们总结出了一些固定的套路 . 按照这个套路来实现代码, 也不会吃亏 .
单例模式能保证某个类在程序中只存在唯一一份实例, 而不会创建出多个实例.
这一点在很多场景上都需要. 比如 JDBC 中的 DataSource 实例就只需要一个.
(定义了数据库的用户名,密码,连接串,通过DataSource的实例对象获取数据库的连接)
4.2 怎么去设计一个单例?
1.口头约定
对外提供一个方法,要求大家使用这个对象的时候,通过这个方法来获取
(不靠谱,不采用)
2.使用编程语言本身的特性来处理
首先要分析清楚,在Java中哪些对象是全局唯一的
.class对象 比如String.class 类对象
 
 
饿汉模式
既然是单例那么通过new的方式去获取对象是有歧义的 那么就不能让外部去new这个对象
Singleton singleton = new Singleton();//构造方法私有化
private Singleton(){}public static Singleton getInstance(){
 return instance;
}//用static修饰方法
private static Singleton instance = new Singleton();
//类似于这种类一加载就完成初始化的方式 称为饿汉模式
//书写简单不易出错懒汉模式
避免程序启动的时候浪费过多的系统资源,当程序使用这个对象时再对它进行初始化
//定义一个类成员变量
private static SingletonLazy instance = null;
public static SingletonLazy getInstance(){
//在获取成员变量的时候判断是否已经初始创建
//如果没有则创建出来
if(instance == nul){
     instance = new SingletonLazy();
  }
return instance;
}在多线程环境下获取单例对象:
  // 创建多个线程,并获取单例对象
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(() -> {
                // 获取单例对象,并打印
                SingletonLazy instance = SingletonLazy.getInstance();
                System.out.println(instance);
            });
            // 启动线程
            thread.start();
        }
    }
}
              
                                                                   
通过检查发现获取到了不同的对象,出现了线程不安全
分析造成线程不安全的原因:

为了解决这个问题,可以把初始化代码加锁:
public synchronized static SingletonLazy getInstance(){
可以看到依然出现了线程安全问题,那么就需要扩大锁的力度

 
输出正常、
但是还剩一个非常严重的问题!

 
举个栗子:

为了避免过度竞争消耗,加入一层判断
 public static SingletonDCL getInstance() {
        // 为了让后面的线程不再获取锁,避免了锁竞争造成的资源浪费
        if (instance == null) {
            synchronized (SingletonDCL.class) {
                // 完成初始化操作,只执行一次
                if (instance == null) {
                    instance = new SingletonDCL();
                }
            }
        }
        //双重检查锁通过加synchnized关键字解决了原子性,内存可见性问题,那有序性如何保证?
那么就需要给共享变量加volatile关键字
public class SingletonDCL {
    // 定义一个类成员变量
    private volatile static SingletonDCL instance;
    // 构造方法私有化
    private SingletonDCL() {
    }
    public static SingletonDCL getInstance() {
        // 为了让后面的线程不再获取锁,避免了锁竞争造成的资源浪费
        if (instance == null) {
            synchronized (SingletonDCL.class) {
                // 完成初始化操作,只执行一次
                if (instance == null) {
                    instance = new SingletonDCL();
                }
            }
        }
        // 返回实例对象
        return instance;
    }
}

4.3 两种模式的总结
 



















