一、实现单例模式的两个要素
1)私有的构造函数
2)提供一个static修饰的getInstance方法
二、难点:
1)线程安全
2)避免资源浪费
3)避免反序列化破坏单例
三、实现
1、饿汉模式(线程不安全,不推荐使用)
public class SingletonExample1 {
public static SingletonExample1 singleton = null;
private SingletonExample1() {
}
public static SingletonExample1 getInstance() {
if (Objects.isNull(singleton)) {
singleton = new SingletonExample1();
}
return singleton;
}
}
2、懒汉模式(线程安全,不推荐使用)
/** 优点
* 线程安全
* 缺点:
* 虽然是线程安全的,项目初始化时创建对象,如果初始化对象如果操作内容比较多,会拖慢项目启动速度
*
* @author
*/
ublic class SingletonExample2 {
public static SingletonExample2 singleton = new SingletonExample2();
private SingletonExample2() {
}
public static SingletonExample2 getInstance() {
return singleton;
}
}
3、双检锁模式
package com.sp.singleton;
import java.util.Objects;
/**
* 懒汉模式-> 双检锁模式
*
* 优点
* 线程安全
* 缺点
* 1、实现繁琐
*
* @author
*/
public class SingletonExample3 {
/**
* 使用volatile关键字,避免出现指令重拍和保持 变量的可见性
*/
public static volatile SingletonExample3 singleton = null;
private SingletonExample3() {
}
public static SingletonExample3 getInstance() {
//为空时创建
if (Objects.isNull(singleton)) {
synchronized (SingletonExample3.class) {
//第二次判空,为避免另外一个线程获取锁之后,重新创建
if (Objects.isNull(singleton)) {
singleton = new SingletonExample3();
}
}
}
return singleton;
}
/**
* 解决被序列化和反序列化破坏的单例模式
*
* @return
*/
private SingletonExample3 readObject() {
return singleton;
}
}
4、使用枚举创建单例(推荐使用)
package com.sp.singleton;
/**
* 使用枚举创建单例模式
*
* 1、JVM 保证线程安全
* 2、与懒汉模式相同用到时创建对象,避免资源浪费
*
* @author
*/
public class SingletonExample4 {
public static SingletonExample4 singleton = new SingletonExample4();
private SingletonExample4() {
}
public static SingletonExample4 getInstance() {
return SingletonEnum.SINGLETON.getInstance();
}
private enum SingletonEnum {
SINGLETON;
private SingletonExample4 singleton;
/**
* JVM保证构造函数只调用一次
*/
SingletonEnum () {
singleton = new SingletonExample4();
}
private SingletonExample4 getInstance() {
return singleton;
}
}
}
5、静态内部类实现单例(需理解classloader原理)
package com.sp.singleton;
/**
* 静态内部类 实现 单例模式
*
* 这种方式利用了classloader保证初始化对象时只要一个线程,与饿汉模式相比虽然虽然SingletonExample5被初始化了,
* SingletonHolder没有被用到也不会初始化对象,来保证懒加载
*
* @author
*/
public class SingletonExample5 {
private static class SingletonHolder {
private static final SingletonExample5 singleton = new SingletonExample5();
}
private SingletonExample5() {
}
public static SingletonExample5 getInstance() {
return SingletonHolder.singleton;
}
}