前言
单例模式:保证类只有一个实例,并提供一个访问它的全局的访问点
饿汉式
- 饿汉式:类加载就会导致该单实例对象被创建
- 实现:
代码如下:
public class Singleton5 {
private static Singleton5 instance = new Singleton5();
private Singleton5(){}
public static Singleton5 getInstance(){
return instance;
}
}
这样的一个方式是线程安全的,但是该种方式不是懒加载,无论是否需要用到该类的时候都会在程序启动之初就进行创建。会造成资源的浪费。
懒汉式
- 懒汉式:类加载不会导致该单实例对象被创建,而是首次使用该对象时才会创建。
- 实现
代码如下:
(1)懒汉式-线程不安全
public class Singleton1 {
private static Singleton1 instance;
private Singleton1(){
}
public static Singleton1 getInstance(){
if (instance == null) {
instance = new Singleton1();
}
return instance;
}
}
说明:
- 在上述代码中,声明成员变量
Singleton1
的时候并没有赋值,只有在调用getSingleton1()
方法时才赋值。避免了资源的浪费。 - 但是在多线程的情况下,有可能会创建多个实例对象,属于线程不安全的。
(2)懒汉式-线程安全
public class Singleton2 {
private static Singleton2 instance;
private Singleton2(){
}
public static synchronized Singleton2 getInstance(){
if (instance == null) {
instance = new Singleton2();
}
return instance;
}
}
说明:
- 相对于第一种方式,在
getSingleton2()
方法上加了锁synchronized
,解决了线程安全的问题 - 但是在
getSingleton2()
所有的访问都因需要锁占⽤导致资源的浪费,实际上,我们需要的是只在初始化Singleton2
的时候加上锁即可。
(3)懒汉式-双重校验锁
public class Singleton3 {
private static volatile Singleton3 instance;
private Singleton3(){}
public static Singleton3 getInstance(){
if (instance == null) {
synchronized(Singleton3.class){
if (instance == null) {
instance = new Singleton3();
}
}
}
return instance;
}
}
说明:
- 双重锁的⽅式是⽅法级锁的优化,满足线程安全,同时减少了资源的消耗。
- 使用
volatile
关键字保证可见性和有序性,防止JVM在实例化对象的时候进行优化和指令重排序操作造成空指针异常 - 是推荐的单例模式
(4)懒汉式-静态内部方法
public class Singleton4 {
private Singleton4(){}
private static class SingletonHolder{
/**
* 静态初始化容器,用JVM来保证线程安全
*/
private static final Singleton4 instance = new Singleton4();
}
public static Singleton4 getInstance(){
return SingletonHolder.instance;
}
}
说明:
- JVM 在加载外部类的过程中, 是不会加载静态内部类的, 只有内部类的属性/方法被调用时才会被加载, 并初始化其静态属性。同时不会因为加锁的⽅式耗费性能。
- 静态属性由于被
static
修饰,保证只被实例化一次,并且严格保证实例化顺序。 - 也是一种推荐的单例模式。
枚举
public enum Singleton6 {
INSTANCE;
}
说明:
- 枚举类型是线程安全的,并且只会装载一次
- 枚举的写法非常简单,而且枚举类型是所用单例实现中唯一一种不会被破坏的单例实现模式。
- 也是非常推荐的一种单例模式