什么意思呢?就是当前进程确保一个类全局只有一个实例。
那单例模式有什么好处呢?[1]
-
单例模式在内存中只有一个实例,减少了内存开支
-
单例模式只生成一个实例,所以减少了系统的性能开销
-
单例模式可以避免对资源的多重占用
-
单例模式可以在系统设置全局的访问点
那单例模式是银弹吗?它有没有什么缺点?
-
单例模式一般没有接口,扩展很困难
-
单例模式不利于测试
-
单例模式与单一职责原则有冲突
那什么情况下要用单例模式呢?
-
要求生成唯一序列号的环境
-
在整个项目中需要一个共享访问点或共享数据
-
创建一个对象需要消耗的资源过多
-
需要定义大量的静态常量和静态方法(如工具类)的环境
接下来,进入今天的主题,我们来看看单例模式的七种写法!
==============================================================================
public class Singleton_1 {
private static Singleton_1 instance=new Singleton_1();
private Singleton_1() {
}
public static Singleton_1 getInstance() {
return instance;
}
}
饿汉式
,就像它的名字,饥不择食,定义的时候直接初始化。
因为instance
是个静态变量,所以它会在类加载的时候完成实例化,不存在线程安全的问题。
这种方式不是懒加载,不管我们的程序会不会用到,它都会在程序启动之初进行初始化。
所以我们就有了下一种方式👇
===============================================================================
public class Singleton_2 {
private static Singleton_2 instance;
private Singleton_2() {
}
public static Singleton_2 getInstance() {
if (instance == null) {
instance = new Singleton_2();
}
return instance;
}
}
懒汉式
是什么呢?只有用到的时候才会加载,这就实现了我们心心念的懒加载。
但是!
它又引入了新的问题?什么问题呢?线程安全问题。
图片也很清楚,多线程的情况下,可能存在这样的问题:
一个线程判断instance==null
,开始初始化对象;
还没来得及初始化对象时候,另一个线程访问,判断instance==null
,也创建对象。
最后的结果,就是实例化了两个Singleton对象。
这不符合我们单例的要求啊?怎么办呢?
===========================================================================
public class Singleton_3 {
private static Singleton_3 instance;
private Singleton_3() {
}
public synchronized static Singleton_3 getInstance() {
if (instance == null) {
instance = new Singleton_3();
}
return instance;
}
}
最直接的办法,直接上锁呗!
但是这种把锁直接方法上的办法,所有的访问都需要获取锁,导致了资源的浪费。
那怎么办呢?
===============================================================================
public class Singleton_4 {
//volatile修饰,防止指令重排
private static volatile Singleton_4 instance;
private Singleton_4() {
}
public static Singleton_4 getInstance() {
//第一重校验,检查实例是否存在
if (instance == null) {
//同步块
synchronized (Singleton_4.class) {
//第二重校验,检查实例是否存在,如果不存在才真正创建实例
if (instance == null) {
instance = new Singleton_4();
}
}
}
return instance;
}
}
这是比较推荐的一种,双重校验锁。
它的进步在哪里呢?
我们把synchronized
加在了方法的内部,一般的访问是不加锁的,只有在instance==null
的时候才加锁。
同时我们来看一下一些关键问题。
- 首先我们看第一个问题,为什么要双重校验?
小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
一线互联网大厂Java核心面试题库
正逢面试跳槽季,给大家整理了大厂问到的一些面试真题,由于文章长度限制,只给大家展示了部分题目,更多Java基础、异常、集合、并发编程、JVM、Spring全家桶、MyBatis、Redis、数据库、中间件MQ、Dubbo、Linux、Tomcat、ZooKeeper、Netty等等已整理上传,感兴趣的朋友可以看看支持一波!
讲义、实战项目、讲解视频**
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
[外链图片转存中…(img-Ycyau9fb-1711173137158)]
一线互联网大厂Java核心面试题库
[外链图片转存中…(img-nZhh9gRb-1711173137159)]
正逢面试跳槽季,给大家整理了大厂问到的一些面试真题,由于文章长度限制,只给大家展示了部分题目,更多Java基础、异常、集合、并发编程、JVM、Spring全家桶、MyBatis、Redis、数据库、中间件MQ、Dubbo、Linux、Tomcat、ZooKeeper、Netty等等已整理上传,感兴趣的朋友可以看看支持一波!