1.什么是单例模式
直接从网上扒一下单例模式的概念。 单例模式(Singleton Pattern)是 Java中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
单例模式有三个特点:
1)单例类只能有一个实例。
2)单例类必须自己创建自己的唯一实例。
3)单例类必须给所有其他对象提供这一实例。
单例模式的写法
2.1 懒汉式
/**
* 懒汉模式
* 单例实例在第一次使用时进行创建
*/
public class SingletonExample1 {
// 私有构造函数
private SingletonExample1() {
}
// 单例对象
private static SingletonExample1 instance = null;
// 静态的工厂方法
public static SingletonExample1 getInstance() {
if (instance == null) {
instance = new SingletonExample1();
}
return instance;
}
}
2.饿汉式
/**
* 饿汉模式
* 单例实例在类装载时进行创建
*/
public class SingletonExample2 {
// 私有构造函数
private SingletonExample2() {
}
// 单例对象
private static SingletonExample2 instance = new SingletonExample2();
// 静态的工厂方法
public static SingletonExample2 getInstance() {
return instance;
}
}
3.懒汉式(synchronized)
* 懒汉模式
* 单例实例在第一次使用时进行创建
*/
public class SingletonExample3 {
// 私有构造函数
private SingletonExample3() {
}
// 单例对象
private static SingletonExample3 instance = null;
// 静态的工厂方法
public static synchronized SingletonExample3 getInstance() {
if (instance == null) {
instance = new SingletonExample3();
}
return instance;
}
}
4.懒汉式(双重锁)
/**
* 懒汉模式 -》 双重同步锁单例模式
* 单例实例在第一次使用时进行创建
*/
public class SingletonExample4 {
// 私有构造函数
private SingletonExample4() {
}
// 1、memory = allocate() 分配对象的内存空间
// 2、ctorInstance() 初始化对象
// 3、instance = memory 设置instance指向刚分配的内存
// JVM和cpu优化,发生了指令重排
// 1、memory = allocate() 分配对象的内存空间
// 3、instance = memory 设置instance指向刚分配的内存
// 2、ctorInstance() 初始化对象
// 单例对象
private static SingletonExample4 instance = null;
// 静态的工厂方法
public static SingletonExample4 getInstance() {
if (instance == null) { // 双重检测机制 // B
synchronized (SingletonExample4.class) { // 同步锁
if (instance == null) {
instance = new SingletonExample4(); // A - 3
}
}
}
return instance;
}
}
5.懒汉式(双重同步锁)
A指令重排序,先执行了1,3分配完内存并赋值给了instance,还没进行初始化,线程B看到instance不为null,则将还未初始化的实例对象返回了
代码:
public class SingletonExample4 {
private SingletonExample4() {
}
//1.memory=allocate() 分配对象的内存空间
//2.ctorInstance() 初始化对象
//3.instance = nemory 设置instance指向刚分配的内存
// jvm和cpu优化发生了指令重排序
//单例对象
private static SingletonExample4 instance = null;
//静态工厂方法
public static SingletonExample4 getInstance() {
if (instance == null) { //线程B执行到这里
synchronized (SingletonExample4.class) {
if (instance == null) {
instance = new SingletonExample4();//线程A执行到这里
}
}
}
return instance;
}
}
正确的代码,使用volatile禁止指令重排:
public class SingletonExample4 {
private SingletonExample4() {
}
//1.memory=allocate() 分配对象的内存空间
//2.ctorInstance() 初始化对象
//3.instance = nemory 设置instance指向刚分配的内存
// jvm和cpu优化发生了指令重排序
//单例对象
private static volatile SingletonExample4 instance = null;
//静态工厂方法
public static SingletonExample4 getInstance() {
if (instance == null) { //线程B执行到这里
synchronized (SingletonExample4.class) {
if (instance == null) {
instance = new SingletonExample4();//线程A执行到这里
}
}
}
return instance;
}
}
6.饿汉式(静态代码块)
静态代码块写单例模式一定要注意对象声明一定要写在静态代码块赋值的前面(注意写代码的顺序),否则获取到的值是null值
/**
* 饿汉模式
* 单例实例在类装载时进行创建
*/
public class SingletonExample6 {
// 私有构造函数
private SingletonExample6() {
}
// 单例对象
private static SingletonExample6 instance = null;
static {
instance = new SingletonExample6();
}
// 静态的工厂方法
public static SingletonExample6 getInstance() {
return instance;
}
public static void main(String[] args) {
System.out.println(getInstance().hashCode());
System.out.println(getInstance().hashCode());
}
}
7.懒汉式(枚举)-推荐
推荐的方式,JVM保证这个方法绝对只调用一次,且是在被调用一次
/**
* 枚举模式:最安全
*/
public class SingletonExample7 {
// 私有构造函数
private SingletonExample7() {
}
public static SingletonExample7 getInstance() {
return Singleton.INSTANCE.getInstance();
}
private enum Singleton {
INSTANCE;
private SingletonExample7 singleton;
// JVM保证这个方法绝对只调用一次
Singleton() {
singleton = new SingletonExample7();
}
public SingletonExample7 getInstance() {
return singleton;
}
}
}
参考文档: