设计模式—创建型模式之单例模式

设计模式---创建型模式之单例模式

介绍

单例模式说明:一个单一的类,负责创建自己的对象,同时确保系统中只有单个对象被创建。

单例模式特点:

  1. 某个类只能有一个实例;(构造器私有)
  2. 它必须自行创建这个实例;(自己编写实例化逻辑)
  3. 它必须自行向整个系统提供这个实例;(对外提供实例化方法)

单例模式图示如下:

饿汉式

饿汉式,比较简单,代码如下:

java 复制代码
public class SingletonObject {
    private final static SingletonObject obj = new SingletonObject();
    private SingletonObject() {
        System.out.println("创建了单例对象");
    }
    public static SingletonObject getInstance() {
        return obj;
    }
}

懒汉式---效率低下实现方式1(线程安全)

获取实例的方法是static的,我们可以给整个方法加一个锁,这样锁的对象是整个类,可以保证线程安全:

代码实现如下:

java 复制代码
public class SingletonObject {
	//懒汉式
	private static SingletonObject obj;
	//保证构造器私有,外部不能实例化
	private SingletonObject() {
		System.out.println("创建了单例对象");
	}
	//这种锁粒度太大,导致效率低
	public static synchronized SingletonObject getInstance() {
		//懒汉式,如果没有再去创建
		if(obj == null) {
			obj = new SingletonObject();
		}
		return obj;
	}
}

懒汉式---效率低下实现方式2(线程安全)

我们可以不给整个方法加锁,可以给如下代码块加锁,但是这样的方式效率还是低;

java 复制代码
public class SingletonObject {
	//懒汉式
	private static SingletonObject obj;
	//保证构造器私有,外部不能实例化
	private SingletonObject() {
		System.out.println("创建了单例对象");
	}
	//但是这样锁粒度还是太大,进入到方法里边再加锁,这样效率还低
	public static SingletonObject getInstance() {
		synchronized(SingletonObject.class) {
			//懒汉式,如果没有再去创建
			if(obj == null) {
				obj = new SingletonObject();
			}
		}
		return obj;
	}
}

懒汉式---线程不安全

我们能否在创建时再加锁呢,于是有了如下的代码:

java 复制代码
public class SingletonObject {
	//懒汉式
	private static SingletonObject obj;
	//保证构造器私有,外部不能实例化
	private SingletonObject() {
		System.out.println("创建了单例对象");
	}
	//线程不安全
	public static SingletonObject getInstance() {
		//懒汉式,如果没有再去创建
		if(obj == null) {
			synchronized(SingletonObject.class) {
				obj = new SingletonObject();
			}
		}
		return obj;
	}
}

这样的方式是线程不安全的,比如:

  1. 有两个线程,线程1和线程2都进入到方法中,判断到obj为null;
  2. 假如线程1先获取到锁,为obj赋值完成,然后方法运行结束,返回obj;
  3. 然后线程2获取到锁,又把obj赋值一次;此时两次返回的就不是同一个对象了。

懒汉式---双重检查锁

下面的懒汉式设计模式,用了双重检查锁;

java 复制代码
public class SingletonObject {
    //懒汉式,线程可见性
    private volatile static SingletonObject obj;
    //首先保证构造器私有,外部不能实例化

    private SingletonObject() {
        System.out.println("创建了单例对象");
    }
    /**
     * 双重检查锁 + 内存可见性volatile
     */
    public static SingletonObject getInstance() {
        //懒汉式,如果没有再去创建
        if (obj == null) {
            synchronized (SingletonObject.class) {
                if(obj == null){
                    obj = new SingletonObject();
                }
            }
        }
        return obj;
    }
}

方法getInstance()中,如果单例对象为空,才会把方法块加锁,获取到锁的线程创建对象完成并赋值成功,且obj保证了线程可见性,其他线程便可以感知到obj不为null,就不会再创建赋值了。

相关推荐
一只会写代码的猫2 小时前
面向高性能计算与网络服务的C++微内核架构设计与多线程优化实践探索与经验分享
java·开发语言·jvm
萤丰信息3 小时前
智慧园区能源革命:从“耗电黑洞”到零碳样本的蜕变
java·大数据·人工智能·科技·安全·能源·智慧园区
曹牧3 小时前
Eclipse为方法添加注释
java·ide·eclipse
口袋物联4 小时前
设计模式之工厂模式在 C 语言中的应用(含 Linux 内核实例)
linux·c语言·设计模式·简单工厂模式
我叫张小白。4 小时前
Spring Boot拦截器详解:实现统一的JWT认证
java·spring boot·web·jwt·拦截器·interceptor
Gerardisite6 小时前
如何在微信个人号开发中有效管理API接口?
java·开发语言·python·微信·php
phdsky6 小时前
【设计模式】建造者模式
c++·设计模式·建造者模式
小毛驴8506 小时前
软件设计模式-装饰器模式
python·设计模式·装饰器模式
闲人编程7 小时前
Python的导入系统:模块查找、加载和缓存机制
java·python·缓存·加载器·codecapsule·查找器
故渊ZY7 小时前
Java 代理模式:从原理到实战的全方位解析
java·开发语言·架构