什么是G0F设计模式:https://blog.csdn.net/weixin_51250404/article/details/119777525?spm=1001.2014.3001.5501
建造者模式:https://blog.csdn.net/weixin_51250404/article/details/119905179?spm=1001.2014.3001.5501
工厂模式https://blog.csdn.net/weixin_51250404/article/details/119852808?spm=1001.2014.3001.5501
## 介绍
- 就是一个类里只有一个实例,提供一个访问该实例的全局访问点
- 优点
- 由于单例模式只生成一个实例,减少了性能的开销,当一个对象的产生需要比较多的资源的时候,如读取配置,产生其它依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决
5种实现方式:
- 饿汉式(线程安全,调用效率高,但是不能支持延迟加载)
- 懒汉式(线程安全,调用效率不高,但是可以支持延迟加载)
- 双重检测锁式(由于JVM底层内部模型原因,偶尔会出现问题,不建议使用)
- 静态内部类式(线程安全,调用效率高,可以延迟加载)
- 枚举单例(线程安全,调用效率高,不能延迟加载,并且天然的防止反射和反序列化漏洞!)
饿汉式:
- 饿汉式单例模式代码中,static变量会在类加载器加载时初始化,这个时候不会涉及到多个线程访问,虚拟机保证只会加载一次该类,所以并不会发生并发访问,此处可以省略synchronized关键字.
- 但如果只是加载了本类,而没有去调用getInstance(),甚至永远没有调用 就会造成资源浪费
package Singlethon; /** * 饿汉式 */ public class SingletonDemo1 { private static /*final*/ SingletonDemo1 s=new SingletonDemo1(); //构造器私有化 private SingletonDemo1(){ } public static SingletonDemo1 getInstance(){ return s; } }
懒汉式:
- 延迟加载,懒加载,真正用的时候才去加载
- 虽然利用率变高了,但是每次调用getInstance()方法都要同步,并发效率低
package Singlethon;
/**
* 懒汉式
*/
public class SingletonDemo2 {
private static SingletonDemo2 s;
private SingletonDemo2() {
}
public static synchronized SingletonDemo2 getInstance(){
if (s == null) {
s =new SingletonDemo2();
}
return s;
}
}
双重检测锁式:
- 延迟加载,懒加载
- 这个模式将同步下方if内部,提高了执行效率,不必每次获取对象都进行同步,只有第一次同步,创建以后就没有必要了
- 但由于JVM底层内存模型和编译器优化问题,偶尔会出下问题,不建议使用
package Singlethon;
/**
* 双重检测锁式
*/
public class SingletonDemo3 {
private static SingletonDemo3 instance=null;
public static SingletonDemo3 getInstance() {
if (instance == null) {
SingletonDemo3 sc;
synchronized (SingletonDemo3.class){
sc=instance;
if (sc == null){
synchronized (SingletonDemo3.class){
if (sc == null){
sc = new SingletonDemo3();
}
}
instance = sc;
}
}
}
return instance;
}
private SingletonDemo3() {
}
}
静态内部类:
- 也是一种延迟加载
- 只有真正调用getinstance()才会加载静态内部类,加载静态内部类时线程是天然安全的,instance是static final类型,保证了内存中只有一个实例存在,而且只能被赋值一次,从而保证了线程安全
package Singlethon;
/**
* 静态内部类
* 这种方式:线程安全,调用效率高,并且实现了延迟加载
*/
public class SingletonDemo4 {
private static class SingletonClass{
private static final SingletonDemo4 instance=new SingletonDemo4();
}
private SingletonDemo4() {
}
//方法没有同步调用效率高
public static SingletonDemo4 getInstance() {
return SingletonClass.instance;
}
}
枚举类型:
- 实现简单
- 枚举本身就是单例模式,由JVM从根本上提供了保证,避免反射和反序列化漏洞!
- 但无延迟加载
package Singlethon;
/**
* 枚举单例模式
* 没有懒加载
*/
public enum SingletonDemo5 {
//这个枚举本身就是一个单例对象
INSTANCE;
//添加自己需要的操作
public void SingletonDemo(){
}
}
破解单例:
- 反射是可以破解上面的几种(不包含枚举)的实现方式!(我们在构造方法中手动抛出异常控制)
- 反序列化也可以破解上面几种(不含枚举)的实现方式
- 可以通过readResolve()防止获得不同对象
- 反序列化时,如果对象所在类定义了readResolve(),定义返回那个对象
特别注意:其实没有必要了解如何破解单例,我们是做项目,又不是编写JDK,破解单例就纯属炫技