定义
保证一个类只有一个实例,并提供一个全局访问点
具体写法
单例模式一般分为两种形式,第一种是饿汉式,第二种是懒汉式。(当然有很多其他的博客或者书写的说,单例模式还分为其他的什么枚举啊等形式,但是我们这里只讲主流的,也就是我们项目中用的最多的两种形式)
我们先来看看第一种饿汉式
public class Singleton_EHanShi {
public static void main(String[] args) {
}
}
/***
* 这种单例模式叫做饿汉式
*
* 饿汉式是在类装载的时候进行实例化的,所以就不存在线程安全问题
* 我们应该还记得static的作用
* static:
* 1.多个实例的static变量会共享同一块内存区域
* 2.静态变量在类装载的时候就会进行初始化
*
* 缺点是:不管有没有用到这个对象,都会实例化出来
*
* 提问:类是什么时候装载的?
* https://juejin.im/post/5d062ccc518825122925bc4b
*
* 类加载的步骤分为:加载--》验证--》准备--》解析--》初始化--》使用--》卸载
* 静态变量实在初始化这一步执行的
*
*
*/
class Singletom {
private static final Singletom mInstance = new Singletom();
private Singletom(){}
public static Singletom getInstance() {
return mInstance;
}
}
我们再来看看第二种懒汉式
注意:懒汉式和饿汉式有时候容易混淆,那我们怎么去记呢?
饿汉式:不管用不用,先创建放在哪里。不用考虑线程安全问题。在类装载的时候,就完成了实例化。(疑问:什么时候类装载)
饿汉式有什么缺点?可能会造成内存浪费,就是我都没用到这个类,你也给实例化出来了。那么怎么解决这个问题呢?也就是说可不可以我用到的时候再给我实例化呢?
于是就有了懒汉式。
懒汉式:当我们需要去使用这个类的时候,首次创建去使用才会创建这个对象。你要是没用到就不会去创建这个对象
public class Singleton_LanHanShi_Test1 {
public static void main(String[] args) {
}
}
/***
* 这种方式会有线程安全问题,遇到多个线程的时候,不能保证类的只有一个实例
*/
class Singletom1 {
private static Singletom1 instance;
private Singletom1(){
}
public static Singletom1 getInstance() {
if(instance == null) {
instance = new Singletom1();
}
return instance;
}
}
/***
* 这种方式线程安全了,但是每次获取实例都要排队等待,所以会造成效率低,因为每次都要排队
* 疑问:synchronized效率为什么会低?
*/
class Singletom2 {
private static Singletom2 instance;
private Singletom2(){}
public static synchronized Singletom2 getInstance() {
if(instance == null) {
instance = new Singletom2();
}
return instance;
}
}
/***
* 这种方式最完美
*
* 疑问:1 为什么要双重校验?
* 答:第一个判断null是为了解决以后不用每次都进入到同步代码块中,解决效率低的问题
* 第二个判断null是为了解决首次如果多个线程都到达synchronized同步代码块这里,当第一个线程执行完实例化操作之后,第二个线程进入同步代码块
* 这个时候是已经存在instance对象了,不需要再进行new的操作了。
*
* 2 为什么还要使用volatile关键字
* 答:是为了将线程工作内存中的数据刷新到主内存中
*/
class Singletom3 {
private static volatile Singletom3 instance;
private Singletom3(){}
public static Singletom3 getInstance() {
if(instance == null) {
synchronized(Singletom3.class) {
if(instance == null) {
instance = new Singletom3();
}
}
}
return instance;
}
}
最后我们还说一种静态内部类的实现单例的方式
public class Singleton_JingTaiNeiBuLei {
}
/***
* 这里是采用静态内部类的方式来实现单例模式
*
* 静态内部类也能保证线程安全
*
*/
class Singleton5 {
private Singleton5(){}
private static class SingletonInstance {
private static final Singleton5 INSTANCE = new Singleton5();
}
public static Singleton5 getInstance(){
return SingletonInstance.INSTANCE;
}
}
使用场景
1.需要频繁的进行创建和销毁的对象
2.创建时耗时过多或者耗费资源过大,但又经常用到的对象,比如频繁访问数据库或文件的对象
3.工具类
完!