单列模式
前言
参考文献:单列模式
**单例模式的含义**
通过单例模式可以保证系统中, 应用该模式的这个类永远只有一个实例。即一个类永远只有一个对象实例。 单例是为了节约内存,也可以适用于一些需要保证在程序运行期间,对象不被改变的场景。
单例的应用场景:
在实际开发中,有很多业务对象永远只需要一个,无论启动多少次
我们只需要一个对象,例如任务管理对象,只需要一个对象。节约内存和性能。
因为对象越多内存占用越大,极有可能出现内存溢出!
单例模式的两种方式
饿汉单例设计模式
在用类获取对象的时候,对象已经提前创建好了。
设计步骤:
a.定义一个类,把构造器私有。
b.定义一个静态变量存储一个对象。
懒汉单例设计模式
在真正需要该对象的时候,才去创建一个对象(延迟加载对象)。
设计步骤:
a.定义一个类,把构造器私有。
b.定义一个静态变量存储一个对象。
c.提供一个返回单例对象的静态方法。
一、饿汉创建
public class SingletonDemo1 {
//在 类加载的时候,有且会唯一创建一次对象
public static SingletonDemo1 singletonDemo1=new SingletonDemo1();
private SingletonDemo1(){//将构造器私有,确保无法在外部创建该类的对象
System.out.println("单列对象被创建");
}
}
二、懒汉创建
懒加载的原则,在需要的时候才会创建单列对象。
1.直接创建 (线程不安全)
public class SingletonDemo2 {
private static SingletonDemo2 singletonDemo2;
private SingletonDemo2(){
System.out.println("单列对象被创建");
}
//线程不安全
public static SingletonDemo2 getSingletonDemo2(){
if(singletonDemo2==null){//如果为空则创建
singletonDemo2=new SingletonDemo2();
}
return singletonDemo2; //对象不为空直接返回,时候唯一创建一次对象
}
}
2.静态同步方法
保证了线程的安全,但是锁粒度大,一次只能有一个线程访问,执行的效率太低。
public class SingletonDemo3 {
private static SingletonDemo3 singletonDemo3;
private SingletonDemo3(){
System.out.println("创建单列对象");
}
//提供一个线程安全的静态方法,获取单列对象,该锁是当前类
public static synchronized SingletonDemo3 getSingletonInstance(){
if(singletonDemo3==null){//为空则创建
singletonDemo3=new SingletonDemo3();
}
//不为空则直接返回
return singletonDemo3;
}
}
3、同步代码块实现(双重检查)
这里适用同步代码块,锁住的是不为空时创建对象的代码,并且增加了一次实列对象是否存在检查,有效避免了线程安全问题,又可以减少锁的使用,有效提高了效率。
public class SingletonDemo4 {
private static SingletonDemo4 singletonDemo4;
private SingletonDemo4(){
System.out.println("创建单列对象");
}
//提供一个线程安全的静态方法,获取单列对象,该锁锁住的是当前类
public static SingletonDemo4 getSingletonInstance(){
if(singletonDemo4==null){//这次检查是为了减少 synchronized 锁被开启的次数
synchronized(SingletonDemo4.class){
if(singletonDemo4==null){ //保证了只创建一次 实列对象
singletonDemo4=new SingletonDemo4();
}
}
}
return singletonDemo4;
}
}
4、静态内部类
静态内部类的方式效果类似双检锁,但实现更简单。但这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。
5、枚举(完美方式)
枚举的方式是比较少见的一种实现方式,但是看上面的代码实现,却更简洁清晰。并且她还自动支持序列化机制,绝对防止多次实例化。
public enum SingletonDemo5 {
INSTANCE;//SingletonDemo5.INSTANCE就可获取单列对象
//类当中的方法
public void print(){
System.out.println("我是单列对象的方法");
}
}
总结
原文链接:https://blog.csdn.net/absolute_chen/article/details/93380566
好了,上面就是单例模式的五种主要写法。我们来总结下,一般情况下,懒汉式(包含线程安全和线程不安全梁总方式)都比较少用;饿汉式和双检锁都可以使用,可根据具体情况自主选择;在要明确实现 lazy loading 效果时,可以考虑静态内部类的实现方式;若涉及到反序列化创建对象时,大家也可以尝试使用枚举方式。