如果本文对你们的开发之路有所帮助,请帮忙点个赞,您的支持是我坚持写博客的动力
【设计模式相关书籍】wx关注【Java从零学架构】,后 台回复【设计模式】自取
上一篇文章带着大家输入学习了设计模式的工厂模式,这篇文章带着大家深入单例模式
项目代码见 https://gitee.com/janyxe/design_patterns
保证一个类只有一个实例,并且提供一个全局访问点
当前JVM中只会有一个实例对象
单例模式
保证一个类只有一个实例
恶汉式
、懒汉式
、饿汉式(线程安全)
、双重检验锁
、枚举
、内部类
、静态类
延迟加载,只有真正使用的时候,才开始实例化
代码见
cn.jany.singleton.slacker.SlackerSingleton
/**
* 懒汉模式线程不安全实现
*/
public class SlackerSingleton {
private static SlackerSingleton slackerSingleton = null;
private SlackerSingleton(){
}
/**
* 获取实例方法
* @return
*/
public static SlackerSingleton getInstance(){
if (slackerSingleton == null){
// 当获取实例为null时创建实例
slackerSingleton = new SlackerSingleton();
}
return slackerSingleton;
}
public static void main(String[] args) throws InterruptedException {
SlackerSingleton slackerSingleton = SlackerSingleton.getInstance();
SlackerSingleton slackerSingleton2 = SlackerSingleton.getInstance();
// 控制台输出true,表示获取的实例为同一个
System.out.println(slackerSingleton == slackerSingleton2);
}
}
控制台输出true,代表两个对象一致
在多线程环境中存在多个对象 ,线程不安全
代码见
cn.jany.singleton.slacker.SlackerSingleton1
public class SlackerSingleton1 {
public static void main(String[] args){
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
SlackerSingleton slackerSingleton = SlackerSingleton.getInstance();
System.out.println(slackerSingleton);
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
SlackerSingleton slackerSingleton = SlackerSingleton.getInstance();
System.out.println(slackerSingleton);
}
});
// 创建2个线程
thread.start();
thread2.start();
}
}
输出对象不同
cn.jany.singleton.slacker.SlackerSingleton@4909e27e
cn.jany.singleton.slacker.SlackerSingleton@593fdda8
通过synchronized
关键字可以保证线程安全,不过效率相对较低
代码见
cn.jany.singleton.slacker.SlackerSingleton2
public class SlackerSingleton2 {
private static SlackerSingleton2 slackerSingleton2 = null;
public static synchronized SlackerSingleton2 getInstance(){
if (slackerSingleton2 == null){
slackerSingleton2 = new SlackerSingleton2();
}
return slackerSingleton2;
}
public static void main(String[] args) {
SlackerSingleton2 instance = SlackerSingleton2.getInstance();
SlackerSingleton2 instance1 = SlackerSingleton2.getInstance();
System.out.println(instance == instance1);
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(SlackerSingleton2.getInstance());
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(SlackerSingleton2.getInstance());
}
}).start();
}
}
通过双重检验锁加锁优化
编译器(JIT),CPU 有可能对指令进行重排序
类加载过程:分配空间、初始化、引用赋值
重排序之后可能的结果:分配空间、引用赋值(多线程其他线程获取实例可能为未初始化的实例)、初始化
通过volatile
关键字进行修饰可以防止重排序
代码见
cn.jany.singleton.slacker.SlackerSingleton3
public class SlackerSingleton3 {
public static void main(String[] args) {
Singleton instance = Singleton.getInstance();
Singleton instance1 = Singleton.getInstance();
System.out.println(instance == instance1);
}
}
class Singleton{
/**
* volatile 防止重排序
*/
private volatile static Singleton singleton = null;
/**
* 构造函数
*/
private Singleton(){
}
/**
* 获取实例
* @return
*/
public static Singleton getInstance(){
// 第一层校验
if (singleton == null){
synchronized (Singleton.class){
// 第二层校验
if (singleton == null){
singleton = new Singleton();
}
}
}
return singleton;
}
}
类加载的 初始化阶段就完成了实例的初始化。
通过jvm加载机制保证实例唯一性(初始化只会执行一次)
和线程安全(JVM 以同步
方式完成类加载过程)
类加载过程会经过:
加载
、验证
、准备
、解析
、初始化
、使用
、卸载
类加载过程各阶段解析:
静态代码块
只有在真正使用对应的类时,才会触发初始化
代码见
cn.jany.singleton.villain.VillainSingleton
/**
* 恶汉模式
*/
public class VillainSingleton {
public static final VillainSingleton villainSingleton = new VillainSingleton();
/**
* 构造方法
*/
private VillainSingleton(){
}
/**
* 获取实例
* @return
*/
private static VillainSingleton getInstance(){
return villainSingleton;
}
public static void main(String[] args) {
VillainSingleton instance = VillainSingleton.getInstance();
VillainSingleton instance2 = VillainSingleton.getInstance();
System.out.println(instance == instance2);
}
}
控制台输出
true
代码见
cn.jany.singleton.villain.VillainSingleton2
/**
* 恶汉模式
*/
public class VillainSingleton2 {
public static final VillainSingleton2 singleton = new VillainSingleton2();
/**
* 构造函数
*/
private VillainSingleton2(){
}
public static void main(String[] args) {
VillainSingleton2 singleton = VillainSingleton2.singleton;
VillainSingleton2 singleton1 = VillainSingleton2.singleton;
System.out.println(singleton == singleton1);
}
}
控制台输出
true
代码见
cn.jany.singleton.inner.InnerClassSingletonTest
public class InnerClassSingletonTest {
public static void main(String[] args) {
InnerClassSingleton instance = InnerClassSingleton.getInstance();
InnerClassSingleton instance2 = InnerClassSingleton.getInstance();
System.out.println(instance == instance2);
}
}
class InnerClassSingleton{
static {
System.out.println("InnerClassSingleton static ");
}
private InnerClassSingleton(){
}
public static InnerClassSingleton getInstance() {
return SingletonHolder.instance;
}
private static class SingletonHolder {
private static InnerClassSingleton instance= new InnerClassSingleton();
static {
System.out.println( "SingletonHolder static" );
}
}
}
控制台输出
InnerClassSingleton static
SingletonHolder static
true
代码见
cn.jany.singleton.inner.StaticSingleton
/**
* 静态代码块
*/
public class StaticSingleton {
private static StaticSingleton staticSingleton;
static {
staticSingleton = new StaticSingleton();
}
public static StaticSingleton getInstance(){
return staticSingleton;
}
public static void main(String[] args) {
StaticSingleton instance = StaticSingleton.getInstance();
StaticSingleton instance1 = StaticSingleton.getInstance();
System.out.println(instance == instance1);
}
}
控制台输出
true
代码见
cn.jany.singleton.enums.EnumSingletonTest
/**
* 枚举实现单例模式
*/
public enum EnumSingleton {
INSTANCE;
}
public class EnumSingletonTest {
public static void main(String[] args) {
EnumSingleton instance = EnumSingleton.INSTANCE;
EnumSingleton instance1 = EnumSingleton.INSTANCE;
System.out.println(instance == instance1);
}
}
控制台输出
true