一,前言
单例模式在23中设计模式中是最为基础的一种,并且使用范围非常广泛,属于设计模式中的创建型模式。
什么是单例:指某一个类只允许存在一个实例对象。
单例模式特点:
- 单例只允许一个实例存在,减少资源浪费。
- 对于频繁创建和销毁的对象,单例模式可以很好的解决,提高系统的性能。
- 单例类只能自己提供自己的实例对象,因为单例模式构造方法是私有的。
- 对外提供唯一的全局访问方式。
单例模式的实现:懒汉式,饿汉式。
二,饿汉式
饿汉式单例模式,字面理解就是很饿很急的感觉。因此这种单例对象就是即时创建,类初始化完成时该对象就已经创建完成。使用起来很方便,但是很容易产生较多的垃圾对象,同时浪费内存空间,下面请看示例代码:
public class Singleton {
private static Singleton singleton = new Singleton();
// 私有化无参构造
private Singleton(){}
// 对外提供访问对象的接口
public static Singleton getSingleton(){
return singleton;
}
}
饿汉式是线程安全的,在类加载时就已经创建完成。
三,懒汉式
懒汉式的创建方式与饿汉式相反,即什么时候用到就什么时候创建,典型的懒加载机制。因此在多线程情况下是线程不安全的,容易重复创建对象,违背了单例模式的原则。
public class Singleton2 {
private static Singleton2 singleton2;
// 私有构造方法
private Singleton2() {}
public static Singleton2 getInstance() {
// 判断如果不存在,则创建
if (singleton2 == null) {
singleton2 = new Singleton2();
}
return singleton2;
}
}
对于懒加载线程不安全问题,可以使用synchronized,双重检验锁。
四,synchronized
synchronized可以保证线程安全,但是我们都知道,使用这种方式效率是很低的,因为程序会不断判断锁是否存在,判断获取锁,释放锁。(不推荐使用)
public class Singleton {
private static Singleton instance;
private Singleton (){}
// 同步方法
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
五,双重检验锁
这里先说明以下,双重检验锁不是指使用两次synchronized关键字,而是在锁之前先判断一次单例对象是否已经存在,如果存在则直接获取。不存在再进入同步方法中,但是静态成员变量需要被volatile修饰,防止发生指令重排。
public class Singleton3 {
private volatile static Singleton3 singleton;
private Singleton3 (){}
public static Singleton3 getSingleton() {
if (singleton == null) {
synchronized (Singleton3.class) {
if (singleton == null) {
singleton = new Singleton3();
}
}
}
return singleton;
}
}
六,静态内部类
静态内部类,这种内部类与其外部类之间并没有先后级别,加载外部类的时候,并不会同时加载静态内部类,而只有调用的时候才会进行加载,此时便创建出单例对象。那么对于线程安全问题来说,因为使用静态初始化方式,所以在JVM中就会自动保证线程安全问题。
public class Singleton4 {
private static class SingletonMethod {
private static final Singleton4 instance = new Singleton4();
}
private Singleton4 (){}
public static final Singleton4 getInstance() {
return SingletonMethod.instance;
}
}
七,总结
对于以上几种方式,要根据实际业务进行选择,但通常情况下饿汉式的使用会多一些,但这不绝对。
以上内容均是自主学习总结,如有不适之处欢迎留言指正。
感谢阅读!