• Java设计模式之创建型模式



    创建型模式包括:单例模式、工厂方法模式、抽象工厂模式、建造者模式和原型模式。

    1、单例模式

    定义:

    1:单例模式(Singleton Pattern)是指确保一个类在任何情况下都绝只有一个实例,并提供一个全局访问点。
    2:隐藏其所有的构造方法:
    3:属于创建型模式

    1-1 、应用场景

    在实际业务应用中,Java中的单例模式可以应用于以下场景:

    1. 资源池管理:在需要对资源进行集中管理的场景下,比如连接池、线程池、对象池等,可以使用单例模式来确保资源的唯一性和统一管理。这样可以提高资源的利用效率,避免资源泄露和浪费。
    2. 全局配置管理:当应用程序有全局配置信息需要被共享和使用时,可以使用单例模式来管理这些配置信息。比如系统属性配置、数据库连接配置、缓存配置等,通过单例模式可以保证全局的配置信息只有一个实例,方便访问和修改。
    3. 日志记录器:在应用程序中需要记录日志信息时,可以使用单例模式来管理日志记录器。这样可以确保日志记录的一致性和唯一性,避免多个日志记录器同时记录导致信息混乱。
    4. 计数器和统计信息:在需要对某个业务操作的计数或统计信息进行管理时,可以使用单例模式。比如网站访问量统计、订单数量计数等,通过单例模式可以保证计数器或统计信息的一致性和准确性。
    5. 框架中常见的单例 ServletContext、ServletConfig、ApplicationContext.........

    需要注意的是,单例模式应用于业务场景时需要谨慎,避免过度使用导致代码的复杂性和耦合度增加。在使用单例模式时,应根据具体业务需求进行评估,确保单例模式的适用性和合理性。

    1-2、饿汉式单例

    package com.tansun.goods.pack;
    
    /**
     * 优点:执行效率高,性能高,没有任何的锁
     * 缺点:某些情况下,可能会造成内存浪费
     * @author Administrator
     */
    public class HungrySingleton {
       
    
        private static final HungrySingleton hungrySingleton = new HungrySingleton();
    
        private HungrySingleton() {
       
        }
    
        public static HungrySingleton getInstance() {
       
            return hungrySingleton;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    1-3、懒汉式单例

    package com.tansun.goods.pack;
    /**
     * @author Administrator
     * 优点:节省内存
     * 缺点:线程不安全
     */
    public class LazySingleton {
       
    
        private static LazySingleton lazySingleton = null;
        private LazySingleton(){
       }
    
        public static LazySingleton getInstance(){
       
            if (lazySingleton == null){
       
                lazySingleton = new LazySingleton();
            }
            return lazySingleton;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    1-3-1、 测试类:

    package com.tansun.goods.pack;
    
    
    import lombok.extern.slf4j.Slf4j;
    
    /**
     * @author Administrator
     */
    @Slf4j
    public class ExecutorThread implements Runnable{
       
        @Override
        public void run() {
       
            LazySingleton instance = LazySingleton.getInstance();
            log.debug("The thread name is : {}, hashcode is {}" ,Thread.currentThread().getName(),instance.hashCode());
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    1-3-2、 RUN

    package com.tansun.goods.pack;
    
    /**
     * @author Administrator
     */
    public class LazySingletonTest {
       
    
        public static void main(String[] args) {
       
            new Thread(new ExecutorThread()).start();
            new Thread(new ExecutorThread()).start();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    1-3-3、 控制台结果

    已连接到目标 VM, 地址: ''127.0.0.1:60386',传输: '套接字''
    18:36:55.323 [Thread-0] DEBUG com.tansun.goods.pack.ExecutorThread - The thread name is : Thread-0, hashcode is 1995014693
    18:36:55.323 [Thread-1] DEBUG com.tansun.goods.pack.ExecutorThread - The thread name is : Thread-1, hashcode is 597340363
    与目标 VM 断开连接, 地址为: ''127.0.0.1:60386',传输: '套接字''
    
    进程已结束,退出代码0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    1-3-4、 改进 加锁 synchronized

    package com.tansun.goods.pack;
    /**
     * @author Administrator
     * 优点:节省内存,线程也安全了
     * 缺点:性能瓶颈,需要等待
     */
    public class LazySingleton {
       
    
        private static LazySingleton lazySingleton = null;
        private LazySingleton(){
       }
    
        public static synchronized LazySingleton getInstance(){
       
            if (lazySingleton == null){
       
                lazySingleton = new LazySingleton();
            }
            return lazySingleton;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    1-3-5、 控制台输出

    已连接到目标 VM, 地址: ''127.0.0.1:60540',传输: '套接字''
    18:43:31.807 [Thread-0] DEBUG com.tansun.goods.pack.ExecutorThread - The thread name is : Thread-0, hashcode is 761088712
    18:43:31.807 [Thread-1] DEBUG com.tansun.goods.pack.ExecutorThread - The thread name is : Thread-1, hashcode is 761088712
    与目标 VM 断开连接, 地址为: ''127.0.0.1:60540',传输: '套接字''
    
    进程已结束,退出代码0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    通过以上加锁的代码优化解决了出现不同实例的问题,但是新问题随之而来。虽然解决了出现不同实例的现象,随之而来的是性能问题,等待线程队伍太长,性能自然而然下降。

    1-3-6、 再改进,使用双检锁,懒汉式双重检查锁定(Lazy initialization with double-checked locking)

    package com.tansun.goods.pack;
    
    /**
     * @author Administrator
     */
    public class DoubleCheckLazySingleton {
       
    
    	//使用 volatile 关键字修饰的静态变量,确保在多线程环境下的可见性和禁止指令重排序。
        private static volatile DoubleCheckLazySingleton doubleCheckLazySingleton = null;
    
        private DoubleCheckLazySingleton() {
       //私有构造方法,防止其他类直接实例化对象
        }
        public static synchronized DoubleCheckLazySingleton getInstance() {
       
            //第一次检查,避免不必要的同步
            if (doubleCheckLazySingleton == null) {
       
                //加锁,确保只有一个线程进入同步块
                synchronized (DoubleCheckLazySingleton.class) {
       
                    //第二次检查,确保只有一个线程创建实例
                    if (doubleCheckLazySingleton == null) {
       
                        //创建实例
                        doubleCheckLazySingleton = new DoubleCheckLazySingleton();
                    }
                }
            }
            return doubleCheckLazySingleton;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    1-3-7、 控制台输出

    已连接到目标 VM, 地址
    • 相关阅读:
      SQL和Python,哪个更容易自学?哪个更适合数据工作的编程新手?
      最全Linux 应急响应-溯源-系统日志排查
      大数据日志可视化分析(Hadoop+SparkSQL)
      学生个人网页设计作品:旅游网页设计与实现——成都旅游网站4个页HTML+CSS web前端网页设计期末课程大作业 学生DW静态网页设计 学生个人网页设计作品
      攻防演练-紫队视角下的实战攻防演练组织
      2022年python国际化课程上机考试三题解
      使用VC++设计程序,实现基于拉普拉斯算子、Canny的边缘检测功能、实现Otsu分割方法
      堆栈的类型及特点
      代码复现: VoxelNet论文和代码解析 pytorch版本(二) Dataloader.py
      【Java 进阶篇】JQuery 遍历:发现元素的魔法之旅
    • 原文地址:https://blog.csdn.net/qq_34238798/article/details/132280856