结构
image.png1.为什么要使用单例模式?
- 空间角度:节省内存,因为内存中只有一个对象
- 时间角度:可以避免重复的创建对象和销毁对象,提高程序的性能
2.实现方式
1.饿汉模式
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
优点:线程安全
因为在类装载的时候就完成了实例化,可以避免线程同步的问题。JVM在类进行初始化的阶段会获得一个锁,这个锁可以同步多个线程对同一类进行初始化。而对static变量的初始化属于类初始化的一部分。
缺点:可能会造成内存浪费
如果在从来没有使用过这个类,那个这个实例化这个类就没有意义。
2.懒汉模式
懒汉模式就是为了解决饿汉模式中的缺点,他的目的就是让我们这使用这个类的时候才去实例化类,避免造成无用的实例化。
懒汉模式有以几种不同的实现方式
- 线程不安全版本。这个版本只能在单线程下使用
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
- 线程安全版本。效率低
因为在每次调用getInstance方法的时候都要进行同步操作。即使这个类已经被实例化了。很显然是没有必要的。
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
双重校验锁——线程安全的优化版本。(推荐使用)
这个是如何优化上面线程安全的版本的呢?
第一层的判断是为了避免不必要的同步,第二层判断则是在null的情况下创建实例
volatile关键词在过程中起到什么作用?
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
- 静态内部类实现单例模式,线程安全,并且是懒加载(推荐使用)
饿汉模式中提到JVM的类加载机制保证了在实例化对象时是线程安全。静态内部内就是利用这种思想来实现线程安全的。在对静态内部类static变量实例化的时候是线程安全的。并且这种方式也能实现在使用的时候才去实例化类。
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
网友评论