设计模式
设计模式
设计模式是软件设计中反复出现问题的通用解决方案。它们是经过多次验证和应用的指导原则,旨在帮助软件开发人员解决特定类型的问题,提高代码的可维护性、可扩展性和可重用性。
创建型模式
关注对象的实例化过程,包括了如何实例化对象、隐藏对象的创建细节。
单例模式
单例模型确保一个类只能创建一个实例,该类负责创建自己的对象,并且保证只有单个对象被创建。单例类将自己的构造函数声明为私有,以防止外部代码之间创建实例。
饿汉式-方式一(静态变量方式)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
public class Singleton { private Singleton() {} private static Singleton instance = new Singleton(); public static Singleton getInstance() { return instance; } }
|
说明:
类初始化时JVM执行clinit指令从上至下执行静态代码赋值语句和静态代码块,instance对象被创建。如果对象足够大而一直没有被使用就会造成内存资源的浪费。
饿汉式-方式二(静态代码块方式)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
public class Singleton {
private Singleton() {}
private static Singleton instance;
static { instance = new Singleton(); }
public static Singleton getInstance() { return instance; } }
|
说明:
与饿汉式方式一相同
懒汉式-方式一(线程不安全)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
public class Singleton { private Singleton() {}
private static Singleton instance;
public static Singleton getInstance() {
if(instance == null) { instance = new Singleton(); } return instance; } }
|
说明:
类初始化不会进行instance对象的初始化,通过调用getInstance()静态方法获取Singleton类的对象时才会创建Singleton对象,实现了懒加载的效果。
线程不安全:
假设现在有两个线程t1和t2同时调用getInstance() 方法,t1刚判断instance == null为true进入内部,刚要进行创建,此时正好丢失CPU执行权,进入阻塞状态,而t2获得CPU执行权,也进行了instance == null判断,发现也是true,就进入了内部代码进行创建,此时我们发现t1和t2都会执行内部的new代码,从而获得了两个不同的实例对象。
懒汉式-方式二(线程安全)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
public class Singleton { private Singleton() {}
private static Singleton instance;
public static synchronized Singleton getInstance() {
if(instance == null) { instance = new Singleton(); } return instance; } }
|
说明:
对静态方法getInstance()加上了synchronized关键字修饰,导致该方法的执行效率低,而线程安全问题只发生在初始化instance的时候才会发生,一旦初始化完成后就不会有了。
懒汉式-方式三(双重检查锁)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
public class Singleton {
private Singleton() {}
private static Singleton instance;
public static Singleton getInstance() { if(instance == null) { synchronized (Singleton.class) { if(instance == null) { instance = new Singleton(); } } } return instance; } }
|
说明
双重检查锁是一种非常好的实例实现方式,解决了单例、性能、线程安全上的问题,但是存在多线程情况下的空指针问题。
1 2 3 4 5 6 7 8 9 10 11
|
memory=allocate(); ctorInstance(memory); instance=memory;
memory=allocate(); instance=memory; ctorInstance(memory);
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
public class Singleton { private Singleton() {} private static volatile Singleton instance; public static Singleton getInstance() { if(instance == null) { synchronized (Singleton.class) { if(instance == null) { instance = new Singleton(); } } } return instance; } }
|
懒汉式-方式四(静态内部类方式)
静态内部类单例模式中实例由内部类创建,由于 JVM 在加载外部类的过程中, 是不会加载静态内部类的, 只有内部类的属性/方法被调用时才会被加载, 并初始化其静态属性。静态属性由于被 static 修饰,保证只被实例化一次,并且严格保证实例化顺序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
public class Singleton { private Singleton() {} private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.INSTANCE; } }
|
说明:
第一次加载Singleton类时不会去初始化INSTANCE,只有第一次调用getInstance,虚拟机加载SingletonHolder并初始化INSTANCE,这样不仅能确保线程安全,也能保证 Singleton 类的唯一性。