java设计模式-单例模式实现方法详解
作者:吾仄lo咚锵 发布时间:2022-02-15 13:56:01
单例模式,属于创建类型的一种常用的软件设计模式。通过单例模式的方法创建的类在当前进程中只有一个实例(根据需要,也有可能一个线程中属于单例,如:仅线程上下文内使用同一个实例)。就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)。
就是类在内存中只能存在一个实例对象
饿汉式
所谓饿汉式,就是直接创建出类的实例化,然后用private私有化,对外只用静态方法暴露。
静态变量
步骤
构造器私有化
类的内部创建对象
向外暴露一个静态的公共方法
优点 | 缺点 |
---|---|
写法简单,在类装载的时完成实例化,避免了线程同步问题 | 类装载时完成实例化,没有达到LazyLoading的效果,若该实例从未使用,则会造成内存浪费 |
class Singleton {
//私有化构造器
private Singleton() {
}
//内部创建对象实例
private final static Singleton instance = new Singleton();
//对外公有的静态方法
public static Singleton getInstance() {
return instance;
}
}
静态代码块
将类的实例化放到静态代码块中的写法,基本同上。
class Singleton { //静态代码块
//私有化构造器
private Singleton() {}
//内部创建对象实例
private static Singleton instance;
static { // 在静态代码块中,创建单例对象
instance = new Singleton();
}
//对外公有的静态方法
public static Singleton getInstance() {
return instance;
}
}
测试代码(后面都可使用这个测试代码,不在赘述运行截图,可以自己试试):
public static void main(String[] args) {
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance1 == instance2);
System.out.println("instance1.hashCode=" + instance1.hashCode());
System.out.println("instance2.hashCode=" + instance2.hashCode());
}
懒汉式
所谓懒汉式,就是在需要调用的时候再创建类的实例化。
线程不安全
起到了懒加载效果,但是只能在单线程使用,多线程会不安全,因为当多个线程并发同时判断instance为空时,就会相应的实例化多个对象。
class Singleton { //线程不安全
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() { //调用时才实例化对象,懒汉式
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
线程安全
上面线程不安全,那上锁不就好了,使用synchronized关键字。
这样虽然解决了线程安全,但其实实例化操作只做一次,而获取实例(即getInstance)的操作是很多次的,把调用的方法加上同步,会大大降低效率。
class Singleton { //线程安全
private static Singleton instance;
private Singleton() {}
//synchronized同步处理
public static synchronized Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
双重检查
上面代码效率低,那在同步前判断一下有没有实例化不就好了,若没有实例化则用同步方法new一个,否则直接return即可。即所谓的双重检查。
需要用到关键字volatile,防止指令重排。如果不用volatile关键字,就会和线程不安全情形一样,在if判断那会有并发。
class Singleton { //双重检查
private static volatile Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if(instance == null) { //判断是否实例化
synchronized (Singleton.class) {
if(instance == null) {
instance = new Singleton();
}
}
}
return instance; //否则直接return
}
}
这样既实现了懒加载,又保证了线程安全。
静态内部类
静态内部类在外部类装载时不会实例化,当调用的时候才会装载并实例化,且JVM保证了其装载时的线程安全性。也能保证懒加载和线程安全,有点像自带版的双重检查。
class Singleton {
private static volatile Singleton instance;
private Singleton() {}
//静态内部类,包含一个静态属性:Singleton
private static class SingletonInstance {
private static final Singleton INSTANCE = new Singleton();
}
//对外公有的静态方法,直接返回SingletonInstance.INSTANCE
public static synchronized Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}
枚举
其实,使用枚举也能实现单例模式,不仅能避免多线程同步问题,也能防止反序列化重新创建新的对象。
enum Singleton {
INSTANCE; //属性
public void say() {
System.out.println("记得三连~");
}
}
对应测试:
public static void main(String[] args) {
Singleton instance1 = Singleton.INSTANCE;
Singleton instance2 = Singleton.INSTANCE;
System.out.println(instance1 == instance2);
System.out.println(instance1.hashCode());
System.out.println(instance2.hashCode());
instance1.say();
}
总结
单例模式使用的场景:
需要频繁的进行创建和销毁的对象创建对象时耗时过多或耗费资源过多(重量级对象)经常用到的对象、工具类对象、频繁访问数据库或文件的对象(数据源、session工厂)
本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注脚本之家的更多内容!
来源:https://wzlodq.blog.csdn.net/article/details/109742462
猜你喜欢
- 看了网上关于记事本的查找替换很多,但都没有达到我想要的结果,然后自己学习总结了以下的方法:统计字符串(汉字,字母,数字,字符)先上效果图定义
- 条件:1、android:ellipsize=”marquee”2、TextView必须单行显示,即内容必须超出TextView
- 前提最近我的的朋友浏览一些网站,看到好看的图片,问我有没有办法不用手动一张一张保存图片!我说用Jsoup丫!测试网站打开开发者模式(F12)
- 项目需求最近项目中有一个需求就是让Java代码去代替人工操作,自动生成PPT,具体就是查询数据库数据,然后根据模板文件(PPT),将数据库数
- Android 有两种方式可以设置全屏.第一种方式:在protected void onCreate(Bundle savedInstanc
- 1.图集导航1.1 为什么对包名的命名要有所规范呢!使用规范的命名有益于程序的开发和后期阅读通俗的说:就是自己写的代码别人也能看的懂,代码结
- 通过yml配置文件为静态成员变量赋值我们对springboot为普通成员变量的方式很熟悉,所以经常定式思维的认为静态属性的赋值和普通属性一样
- 类1.什么是类类是事物的属性(外在特征)和行为(具备的功能)的集合2.想要知道Java中类是什么我们要先知道现实生活中的类是什么,因为Jav
- 注解的介绍@ControllerAdvice@ControllerAdvice注解是Spring3.2中新增的注解,学名是Controlle
- 前一段时间遇到一个问题,是关于读取项目中文件资源的问题。我是一个maven工程 我把一张照片放到resource下面,然后在本地读取的时候可
- 起因unity程序build到pc上,拿到其他人的机器上结果有些功能不正常,看log里面大概是Fallback handler could
- zenDiscovery实现机制ping是集群发现的基本手段,通过在网络上广播或者指定ping某些节点获取集群信息,从而可以找到
- 一 引入考虑实现一种三轴机器人控件。三轴机器人用来将某种工件从一个位置运送到另一个位置。其X轴为手臂轴,可以正向和反向运动,它处于末端,直接
- 前言此前部门内的一个线上系统上线后内存一路飙高、一段时间后直接占满。协助开发人员去分析定位,发现内存中某个Object的量远远超出了预期的范
- 前言:封装、继承和多态是面向对象编程的三大特征。1.封装1.1.封装概念封装就是把抽象出的数据(属性)和对数据的操作(方法)封装在一起,数据
- 通过主菜单对各级子菜单进行控制,并实现添加记录,查找记录,删除记录,修改记录,排序记录,以及退出系统功能的实现。一共六部分的功能模块。 上面
- 一些Java项目中在mybatis与spring整合中有MapperScannerConfigurer的使用,该类通过反向代理自动生成基于接
- 前言我通常是不太关心代码的具体实现的,因为我的开发语言很杂,倾向于一些最简单通用的方式去解决。今儿不小心在群里看到一位朋友发了下面的java
- Android内部没有控件来直接显示文档,跳转WPS或其他第三方文档App体验性不好,使用腾讯X5内核能很好的解决的这一问题。一、下载腾讯X
- 本文汇集36个Android开发常用经典代码片段,包括拨打电话、发送短信、唤醒屏幕并解锁、是否有网络连接、动态显示或者是隐藏软键盘等,希望对