当前位置: 首页 > news >正文

JAVA:单例模式

单例模式是设计模式之一

设计模式,就像古代打仗,我们都听过孙子兵法,把计谋概括下来弄成一种模式,形成一种套路。

软件开发中也有很多场景,多数类似的问题场景,解决方案就形成固定的模式,单例模式就是其中一种

单例模式就是保证在某个类中只存在唯一一份实例,不会创建出多个实例

单例模式实现方式有很多,最常见的就是饿汉与懒汉两种模式,区别就是创建实例的时机不同

饿汉模式

饿汉模式是在类加载的时候创建

class Singleton{private static Singleton singleton=new Singleton();private Singleton(){}public static Singleton GetInstance(){return singleton;}
}

写一个具体的示例来看:

public class ThreadDemo1 {public static void main(String[] args) throws InterruptedException {Thread[] thread=new Thread[10];for(int i=0;i<5;i++){thread[i]=new Thread(()->{System.out.println(Singleton.GetInstance());});thread[i].start();}for (int i = 0; i < 5; i++) {thread[i].join();}}
}
class Singleton{private static Singleton singleton=new Singleton();private Singleton(){}public static Singleton GetInstance(){return singleton;}
}

根据运行结果我们能看到不同线程都是同一个实例 

懒汉模式

懒汉模式是在第一次使用的时候创建实例

单线程

class Singleton{private static Singleton instance=null;private Singleton (){}public static Singleton GetInstance(){if(instance==null) instance=new Singleton();return instance;}
}

多线程

在多线程情况下再使用单线程的懒汉模式是可能会出现线程不安全的,如果多个线程同时调用GetInstance 方法,可能就会出现多个实例

例如:

public class ThreadDemo2 {public static void main(String[] args) throws InterruptedException {Thread[] thread=new Thread[40];for(int i=0;i<40;i++){thread[i]=new Thread(()->{System.out.println(Singleton.GetInstance());});thread[i].start();}for(int i=0;i<40;i++){thread[i].join();}}
}
class Singleton{private static Singleton instance=null;private Singleton (){}public static Singleton GetInstance(){if(instance==null) instance=new Singleton();return instance;}
}

 在GetInstance 方法中加一个 synchronized 就能解决问题

public class ThreadDemo2 {public static void main(String[] args) throws InterruptedException {Thread[] thread=new Thread[40];for(int i=0;i<40;i++){thread[i]=new Thread(()->{System.out.println(Singleton.GetInstance());});thread[i].start();}for(int i=0;i<40;i++){thread[i].join();}}
}
class Singleton{private static Singleton instance=null;private Singleton (){}public static synchronized Singleton GetInstance(){if(instance==null) instance=new Singleton();return instance;}
}
 改进

加 synchronized 关键字确实解决了出现多个实例的问题,但是加锁与解锁是开销比较大的事,这里出现的线程不安全只发生在第一次创建实例时,在经过第一次创建实例后,后面就不需要加锁了

因此我们可以再加一个 if 判断一下

在给 instance 变量加上 volatile 关键字避免出现内存可见性的线程不安全

public class ThreadDemo2 {public static void main(String[] args) throws InterruptedException {Thread[] thread=new Thread[40];for(int i=0;i<40;i++){thread[i]=new Thread(()->{System.out.println(Singleton.GetInstance());});thread[i].start();}for(int i=0;i<40;i++){thread[i].join();}}
}
class Singleton{private static volatile Singleton instance=null;private Singleton (){}public static Singleton GetInstance(){if(instance==null){synchronized (Singleton.class){if(instance==null) instance=new Singleton();}}return instance;}
}

在 thread[1] 刚判断是否为空以后,thread[2] 也调用此方法并执行完,再执行thread[1] 后续加锁操作,这样也会创建多个实例

相关文章:

  • 【锂电池剩余寿命预测】Transformer锂电池剩余寿命预测(Pytorch完整源码和数据)
  • Java : GUI
  • RC吸收电路参数设置实战
  • Python包的编译、构建与打包指南
  • IDEA常用快捷键及操作整理(详细图解,持续更新)
  • Allegro23.1新功能之如何冻结动态铜皮操作指导
  • 二、Web服务常用的I/O操作
  • 【Go语言】ORM(对象关系映射)库
  • 层级时间轮的 Golang 实现原理与实践
  • Grok发布了Grok Studio 和 Workspaces两个强大的功能。该如何使用?如何使用Grok3 API?
  • Win10安装 P104-100 驱动
  • Gin 框架中集成 runtime/debug 打印日志堆栈信息
  • Conda 虚拟环境复用
  • react的 Fiber 节点的链表存储
  • 通过示例学习:连续 XOR
  • 如何配置osg编译使支持png图标加载显示
  • mybatis首个创建相关步骤
  • 【音视频】SDL简介
  • 实验:串口通信
  • electron-vite 应用打包自定义图标不显示问题
  • 早睡1小时,变化有多惊人?第一个就没想到
  • “中国游”带火“中国购”,“即买即退”让外国游客购物更丝滑
  • 人民时评:投资于人,促高质量充分就业
  • 民航局:中方航空公司一季度运输国际旅客同比大增34%
  • 委员呼吁提高政府机构电话号码准确性,辽宁阜新回应
  • 当代视角全新演绎,《风雪夜归人》重归首都剧场