1.懒汉模式
package org.example.base.test;
/**
* @author l
* @date Created in 2021/4/13 14:20
*所谓懒汉模式,就是太懒了。懒得先创建好实例。只有需要的时候,才去判断是否有实例,没有才去创建。
*/
public class Singleton {
private static Singleton singleton;
/**
* @date 14:44 2021/4/13
* 构造方法私有化
**/
private Singleton() {
}
public static Singleton getInstance() {
/**
* @date 14:41 2021/4/13
* 这个地方存在线程安全问题。当有多个线程同时执行到这个哩。会创建多个实例。就不是单例模式了。
**/
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
2.懒汉模式,双重检验锁实现。
package org.example.base.test;
/**
* @author l
* @date Created in 2021/4/13 14:20
* 懒汉模式 -> 双重检验锁
*/
public class Singleton {
/**
* @date 15:13 2021/4/13
* 这里使用volatile关键字是因为volatile能保证共享变量对多个线程是可见的。既保证了可见性。
* 同时它还能禁止指令重排序。既保证了有序性。
**/
private volatile static Singleton singleton;
/**
* @date 14:44 2021/4/13
* 构造方法私有化
**/
private Singleton() {
}
public static Singleton getInstance() {
//第一次检验,一旦实例化完成,以后就减少获取和释放锁的开销
if (singleton == null) {
synchronized (Singleton.class) {
//第二次检验
if (singleton == null) {
/**
* 这里的new操作,并不是原子性操作
* 创建一个对象实例可以分为三步
* 1.为对象分配内存空间
* 2.调用构造函数初始化
* 3.把对象引用赋值给变量
*这里2 3 步有可能发生指令重排序。
*当线程一按照132执行,执行到3时,线程二刚好执行到判断,并且判断不为null,从而访问一个未初始化的对象,报异常。
* 因而使用volatile关键字修饰变量,保证变量对所有线程都是可见的。同时禁止指令重排序。
**/
singleton = new Singleton();
}
}
}
return singleton;
}
}
3.懒汉模式,静态内部类实现
package org.example.base.test;
/**
* @author l
* @date Created in 2021/4/13 14:20
* 懒汉模式 -> 静态内部类
*/
public class Singleton {
private Singleton() {
}
/**
* 静态内部类。外部类加载的时候并不会立即加载内部类,所以是懒汉式。
* 只有第一次调用getInstance方法时才会加载内部类,初始化Singleton实例。
* 同时,内部类SingletonInner初始化过程中是线程安全的。
*/
private static class SingletonInner {
private static final Singleton singleton = new Singleton();
}
public Singleton getInstance() {
return SingletonInner.singleton;
}
}
4.枚举单例
package org.example.base.test;
/**
* @author l
* @date Created in 2021/4/13 14:20
* 单例模式->枚举单例
* 在第一次使用枚举类的时候,会被虚拟机加载并初始化,而这个初始化过程是线程安全的
* 所以枚举实例创建是线程安全的,在任何情况下,它都是一个单例
*/
public enum Singleton {
ONE(1,"1"),TWO(2,"2"),THREE(3,"3");
private Integer num;
private String str;
Singleton(Integer num, String str) {
this.num = num;
this.str = str;
}
@Override
public String toString() {
return "Singleton{" +
"num=" + num +
", str='" + str + '\'' +
'}';
}
public static void main(String[] args) {
System.out.println(Singleton.ONE);
}
}
5.饿汉模式
package org.example.base.test;
/**
* @author l
* @date Created in 2021/4/13 14:20
* 饿汉模式
*/
public class Singleton {
/**
* private 修饰变量保证了其私有性,不可见,不可访问。
* static 修饰变量保证了该变量引用不依赖于类的对象进行访问,它当且仅当在类初次加载时会被初始化,可以通过类名访问。
* 同时也不会被GC垃圾回收器给回收掉
* final 修饰变量,保证其引用不可更改
**/
private static final Singleton singleton = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return singleton;
}
}