java开发模式学习————单例模式

开发模式其实在平时的开发中有经常用到,但是自己平时也没注意,会用但是不理解,这是很大的问题。

遇到面试或者这方面的问题,不能深入的剖析。

参考:https://blog.csdn.net/zjf280441589/article/details/50235937

https://blog.csdn.net/a394268045/article/details/51801258

单例模式的概念

单例就是只有一个实例,就是对于某一个类,整个工程中,只有一个他的实例,并且这个类通过自行实例化,把这个对象向整个工程提供。

为什么要使用单例呢? 或者这样的好处是什么?

1. 在工程中,有一些核心类用来控制资源,单例只有一个Manager,方便资源之间的互相通信同时降低资源的损耗以及冲突

如数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。数据库软件系统中使用数据库连接池,主要是节省打开或者关闭数据库连接所引起的效率损耗,这种效率上的损耗还是非常昂贵的,因此用单例模式数据库的接连池都是一值存在于内存中,降低了开关的损耗。同时通过连接池可以管理其中的数据库连接,可以避免一条数据库连接同时被多个请求调用

单例模式的性能追求

1.线程安全

2.调用效率

3.延迟加载

单例模式的实现方法:

1.构造私有

2.静态实例

3.公开获取实例的方法

单例模式实现方式


1.懒汉模式:

//懒汉模式简单实现
public class Singleton {
	
	//类加载的时候,对象没有实例化,做到了延迟加载,使用静态修饰,保证引用在类加载时创建,保证唯一
	private static Singleton instance;

	//构造私有,外部无法通过构造方法创建类的实例
	private Singleton(){
	}
	
	//方法不是线程安全的
	public static Singleton getInstance(){
		if(instance == null){
			instance = new Singleton();
		}
		return instance;
	}
}

2. 懒汉模式进化版(实现线程安全)

//懒汉模式进阶版实现
public class Singleton {
	
	//类加载的时候,对象没有实例化,做到了延迟加载,使用静态修饰,保证引用在类加载时创建,保证唯一
	private static Singleton instance;

	//构造私有,外部无法通过构造方法创建类的实例
	private Singleton(){
	}
	
	//给整个getInstance方法加锁,线程安全
	public synchronized static Singleton getInstance(){
		if(instance == null){
			instance = new Singleton();
		}
		//但是如果不需要创建(跳过if语句),而是只需要调用instance,则此时还加锁,效率较低
		return instance;
	}
}


3. 懒汉模式究极版(提高效率)

//懒汉模式究极版实现
public class Singleton {
	
	//类加载的时候,对象没有实例化,做到了延迟加载,使用静态修饰,保证引用在类加载时创建,保证唯一
	private static Singleton instance;

	//构造私有,外部无法通过构造方法创建类的实例
	private Singleton(){
	}
	
	public static Singleton getInstance(){
		if(instance == null){
			//只在创建实例的时候加锁,实现线程安全
			synchronized(instance){
				if(instance == null){
					instance = new Singleton();
				}
			}
		}
		return instance;
	}
}

但是其实虽然加锁了还是会出现不安全的情况:


我们以A、B两个线程为例:

a>A、B线程同时进入了第一个if判断

b>A首先进入synchronized块,由于instance为null,所以它执行instance = new Singleton();

c>由于JVM内部的优化机制,JVM先画出了一些分配给Singleton实例的空白内存,并赋值给instance成员(注意此时JVM没有开始初始化这个实例),然后A离开了synchronized块。

d>B进入synchronized块,由于instance此时不是null,因此它马上离开了synchronized块并将结果返回给调用该方法的程序。

e>此时B线程打算使用Singleton实例,却发现它没有被初始化,于是错误发生了。

所以程序还是有可能发生错误,其实程序在运行过程是很复杂的,从这点我们就可以看出,尤其是在写多线程环境下的程序更有难度,有挑战性

4. 饿汉模式

//饿汉模式实现
public class Singleton {
	
	//类加载的时候,实例同时加载,没有做到了延迟加载
	private static Singleton instance = new Singleton();
	
	//构造私有,外部无法通过
	private Singleton(){
	}
	//方法不需要加锁,效率高
	public static Singleton getInstance(){
		return instance;
	}
}

5. 静态内部类模式

//静态内部类模式实现
public class Singleton {
	/*
	 * 加载一个类时,其内部类不会同时被加载。内部类被加载,当且仅当其某个静态成员(静态域、构造器、静态方法等)被调用时发生。
	 * 因此静态内部类实现了延迟加载 
	 */
	private static class innerClass{
		private static final Singleton instance = new Singleton();
	}
	
	//构造私有,外部无法通过
	private Singleton(){
	}
	
	public static Singleton getInstance(){
		return innerClass.instance;
	}
}

6. 枚举实现单例

基于JVM底层实现,Enum天然的就是单例并且线程安全。


实现对比

方式优点缺点
饿汉式线程安全, 调用效率高不能延迟加载
懒汉式线程安全, 可以延迟加载调用效率不高
双重检测锁线程安全, 调用效率高, 可以延迟加载-
静态内部类线程安全, 调用效率高, 可以延迟加载-
枚举线程安全, 调用效率高不能延迟加载



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值