【设计模式】单例模式
创始人
2024-01-31 08:25:08
0

单例模式属于创建型模式,是最简单的一种设计模式。当一个类在程序中只需要创建唯一全局对象时(如网站计数类、日志管理类、线程池类……),就可以使用单例模式。单例模式规定一个类只能创建一个实例,之后不能再创建新的实例。所有线程无论何时获取的都是该类的唯一对象,这样做节省了创建一个新对象的资源开销。

文章目录

  • 单例模式的使用
    • 单例模式类图
    • 实现方法
      • 第一步,创建网站计数器类(单例类)
        • 网站计数器
      • 第二步,创建测试类测试
        • 测试类
        • 实现效果
    • 单例模式的几种实现方法
      • 线程安全的懒汉加载方法
        • 演示的单例类
      • 线程不安全的懒汉加载方法
        • 演示的单例类
      • 饿汉式加载方法
        • 演示的单例类
      • 双检锁加载方法
        • 演示的单例
      • 静态内部类登记方法
        • 演示的单例类
      • 枚举型加载方法
        • 演示的单例类
        • 测试类
        • 测试效果

单例模式的使用

​ 单例模式保证一个类只存在一个对象,并提供访问该对象的静态方法,为了防止该类被多次创建,需要将它的构造方法设置为私有的。

单例模式类图

image-20221118191559235

实现方法

第一步,创建网站计数器类(单例类)

网站计数器

package 设计模式.单例模式;public class 网站计数器 {// 静态属性,这里使用的饿汉式实现单例private static 网站计数器 唯一实例 = new 网站计数器();private int 网站点击数;// 将该类的构造方法设置为私有,导致无法在外部创建对象private 网站计数器(){ }// 获取唯一实例的静态方法public static 网站计数器 获取唯一实例(){return 唯一实例;}public void 点击数增加(){this.网站点击数 += 1;}public int 获取点击数(){return this.网站点击数;}}

第二步,创建测试类测试

测试类

package 设计模式.单例模式;public class 测试类 {public static void main(String[] args) {网站计数器 计数器 = 网站计数器.获取唯一实例();计数器.点击数增加();System.out.println("当前网站点击量为:"+计数器.获取点击数());网站计数器 计数器二 = 网站计数器.获取唯一实例();计数器二.点击数增加();计数器二.点击数增加();计数器二.点击数增加();System.out.println("当前网站点击量为:"+计数器.获取点击数());网站计数器 计数器三 = 网站计数器.获取唯一实例();计数器三.点击数增加();计数器三.点击数增加();System.out.println("当前网站点击量为:"+计数器.获取点击数());}
}

实现效果

image-20221118191959145

单例模式的几种实现方法

​ 单例模式的实现方法从线程安全以及资源消耗方面来讲,有线程安全懒汉式线程不安全懒汉式饿汉式双检锁静态内部类登记式枚举式六种

线程安全的懒汉加载方法

​ 此方法以懒加载的形式创建实例,当第一次需要使用该对象时才会创建实例,以此来避免浪费内存。同时,此方法使用synchronzed 同步锁来实现线程安全,保证多个线程同时调用时只会创建单个实例,但加锁难免损耗一些性能。

演示的单例类

package 设计模式.单例模式;public class 网站计数器 {/* 线程安全懒汉式创建单例 */// 用静态属性存储单例对象private static 网站计数器 唯一实例 ;private int 网站点击数;// 将该类的构造方法设置为私有,导致无法在外部创建对象private 网站计数器(){ }// 获取唯一实例的静态方法public static synchronized 网站计数器 获取唯一实例(){// 不存在唯一实例时先创建实例if (唯一实例 == null){唯一实例 = new 网站计数器();}return 唯一实例;}public void 点击数增加(){this.网站点击数 += 1;}public int 获取点击数(){return this.网站点击数;}}

线程不安全的懒汉加载方法

​ 此方法与上面线程安全的懒汉加载方法基本一样,但是此方法没有添加 sycnhronized 同步锁,所以在多线程同时请求时,可能会导致创建多个对象来覆盖之间的实例对象。

演示的单例类

public class 网站计数器 {/* 线程不安全的懒汉式创建单例 */// 用静态属性存储单例对象private static 网站计数器 唯一实例 ;private int 网站点击数;// 将该类的构造方法设置为私有,导致无法在外部创建对象private 网站计数器(){ }// 获取唯一实例的静态方法public static 网站计数器 获取唯一实例(){// 不存在唯一实例时先创建实例if (唯一实例 == null){唯一实例 = new 网站计数器();}return 唯一实例;}public void 点击数增加(){this.网站点击数 += 1;}public int 获取点击数(){return this.网站点击数;}}

饿汉式加载方法

​ 这种方法最为简单,同时也是线程安全的。但由于在类加载时就进行了初始化操作占据一部分内存空间,如果要过很久才会调用这个类的话,那么此类就是占着茅坑不拉屎浪费了程序的内存空间

演示的单例类

package 设计模式.单例模式;public class 网站计数器 {/* 饿汉式创建单例 */// 静态属性,这里使用的饿汉式实现单例private static 网站计数器 唯一实例 = new 网站计数器();private int 网站点击数;// 将该类的构造方法设置为私有,导致无法在外部创建对象private 网站计数器(){ }// 获取唯一实例的静态方法public static 网站计数器 获取唯一实例(){return 唯一实例;}public void 点击数增加(){this.网站点击数 += 1;}public int 获取点击数(){return this.网站点击数;}}

双检锁加载方法

​ 此方法优化了线程安全的懒汉式加载方法,它取消了获取实例方法上的synchronized同步锁,让多个线程获取实例时不需要排队获取,损耗性能。双检锁使用两重检查,先判断实例对象是否存在,如果已经存在则直接返回实例,而不存在实例时再通过同步锁保证线程安全的创建唯一实例。

演示的单例

package 设计模式.单例模式;public class 网站计数器 {/* 双检锁创建单例 */// 用静态属性存储单例对象private static 网站计数器 唯一实例;private int 网站点击数;// 将该类的构造方法设置为私有,导致无法在外部创建对象private 网站计数器(){ }// 获取唯一实例的静态方法public static 网站计数器 获取唯一实例(){// 如果唯一实例已经创建则直接返回实例if (唯一实例 == null){// 多个线程同时准备创建实例时,使用同步锁synchronized(网站计数器.class){// 如果有线程已经创建了实例,那此线程就不再创建了if (唯一实例 == null){唯一实例 = new 网站计数器();}}}return 唯一实例;}public void 点击数增加(){this.网站点击数 += 1;}public int 获取点击数(){return this.网站点击数;}}

静态内部类登记方法

​ 该方法利用Classloader的加载机制,当类被加载时,并不会加载它的内部类,只有当显式调用该内部类时,该内部类才会被加载。通过该机制,可以实现一种线程安全的懒汉式方法创建单例对象。

演示的单例类

package 设计模式.单例模式;public class 网站计数器 {/* 静态内部类创建单例 */private int 网站点击数;static class 内部类{private static final 网站计数器 唯一单例 = new 网站计数器();}public static final 网站计数器 获取唯一实例(){// 只有外部显示调用此方法时,内部类才会被加载,唯一单例对象才会被创建return 内部类.唯一单例;}public void 点击数增加(){this.网站点击数 += 1;}public int 获取点击数(){return this.网站点击数;}}

枚举型加载方法

​ 枚举是在jdk1.5后加入的,所以使用的人不是很多,但它却是最为便捷与简单的一种线程安全的单例创建方法。其本质是利用枚举值的唯一性与自动支持序列化的机制,杜绝在反序列化时创建新的对象。

演示的单例类

package 设计模式.单例模式;public enum 枚举类网站计数器 {唯一实例;private int 网站点击数;public void 点击数增加(){this.网站点击数 += 1;}public int 获取点击数(){return this.网站点击数;}
}

测试类

package 设计模式.单例模式;public class 测试类 {public static void main(String[] args) {枚举类网站计数器 计数 = 枚举类网站计数器.唯一实例;System.out.println("当前网站点击量为:"+计数.获取点击数());计数.点击数增加();System.out.println("当前网站点击量为:"+计数.获取点击数());枚举类网站计数器 计数二 = 枚举类网站计数器.唯一实例;计数二.点击数增加();计数二.点击数增加();计数二.点击数增加();System.out.println("当前网站点击量为:"+计数二.获取点击数());枚举类网站计数器 计数三 = 枚举类网站计数器.唯一实例;计数三.点击数增加();计数.点击数增加();计数三 = 计数二;计数三.点击数增加();System.out.println("当前网站点击量为:"+计数.获取点击数());}
}

测试效果

image-20221118203805758

相关内容

热门资讯

【世界说】美国媒体2025年终...   中国日报网12月31日电 2025年即将画上句号。年终盘点虽然见仁见智,无法面面俱到,但美国主流...
强化平台治理 筑牢网络安全法治...   作者:赵精武(北京航空航天大学法学院副教授)  数字经济的繁荣发展离不开人工智能等关键技术的创新...
视频丨连续两年超1.4万亿斤!...   今年,全国粮食产量14297.5亿斤,比上年增加167.5亿斤,增长1.2%。这也是我国粮食产量...
转发提醒!这些食物千万不要隔夜...   元旦假期将至,无论是准备外出游玩,还是亲朋好友相聚,享受美食都是不可或缺的一部分。但如果吃多了、...
文博日历丨跨年彩蛋!美好的祝福...   今天的跨年夜怎么过?  仪式感拉满的“漂亮饭”  想必是点亮夜晚的最佳方式  三个看点带你认识 ...
不动产转让增值税计算解析 不动产转让增值税计算解析近期,一则关于不动产转让增值税计算的咨询案例引发业内广泛关注。该案例涉及酒店...
​小微企业残保金的免征期限是多... 小微企业残保金的免征期限是多久残保金的减免政策主要是基于对残疾人的特别扶助和保障其权利的实现,而非简...
同一控制下企业吸收合并税务处理... 导读本文详细解析同一控制下子公司吸收合并的税务处理要点,重点介绍A105100表的填报方法,帮助企业...
突发意外!韩国知名男演员被送I...   据媒体12月31日报道,韩国知名演员安圣基30日中午就餐时噎食,被送院紧急抢救,他目前在重症监护...
甘肃定西市漳县发生3.4级地震   速报参数: 据中国地震台网正式测定,12月31日17时3分在甘肃定西市漳县发生3.4级地震,震源...