• JAVA项目实战-设计模式——单例模式项目中运用


    关注Java中技术在项目中的实际运用,能做到学以致用,避免死记硬背的原理。

    JAVA设计模式之单例模式

     一.设计模式的种类

    创建型模式:对象实例化的模式,创建型模式用于解耦对象的实例化过程。

    结构型模式:把类或对象结合在一起形成一个更大的结构。

    行为型模式:类和对象如何交互,及划分责任和算法。

    如下图所示:

     

    二.单例模式示例代码

    /**
     * @description: 饿汉式-单例模式
     * @author: ZhuCJ 
     * @date: 2020-08-19 12:43
     */
    public class BadMashSingleClass {
    
        /**
         **************** 饿汉模式 ************************
         * 实现方法:
         * 1.构造器私有化 (目的:保证只能本类中 才能创建出对象)
         * 2.new 一个此类的静态对象(目的:静态属性资源,存放在JVM的静态资源区,全局共用一个属性)
         * 3.定义一个静态方法返回静态对象实例
         * 优点:
         * 1.高并发下能实现对象唯一性
         * 2.代码简洁,不需要考虑高并发场景
         * 缺点:
         * 1.不能实现对象的延迟加载,加载时就必须创建一个静态实例,比较消耗资源
         */
    
        /**
         * 定义一个静态的对象,保证唯一性
         */
        public static BadMashSingleClass singleClass = new BadMashSingleClass();
    
        /**
         * 私有化构造器
         */
        private BadMashSingleClass(){
    
        }
    
        /**
         * 定义一个静态方法。返回单例对象
         * @return
         */
        public static BadMashSingleClass createSingle(){
            return singleClass;
        }
        
    }
    
    
    /**
     * @description: 测试方法
     * @author: ZhuCJ
     * @date: 2020-08-19 13:07
     */
    public class Main {
    
    
        public static void main(String[] args) {
    
            /**
             * 定义10个线程,每个线程休眠0.5s后创建对象,
             * 观察toString方法返回的hashCode值是否相等
             * 注:此处创建线程建议采用线程池
             */
            for (int i =0;i<10;i++){
                new Thread(()->{
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    String name = Thread.currentThread().getName();
                    BadMashSingleClass singleOne = BadMashSingleClass.createSingle();
                    System.out.println("name:"+name +singleOne.toString());
                }).start();
            }
        }
    }
    
    
    ---------------------------------------------
    name:Thread-8com.spring.zhucj.rabbitmq.designmode.single.BadMashSingleClass@3673cfa8
    name:Thread-4com.spring.zhucj.rabbitmq.designmode.single.BadMashSingleClass@3673cfa8
    name:Thread-9com.spring.zhucj.rabbitmq.designmode.single.BadMashSingleClass@3673cfa8
    name:Thread-0com.spring.zhucj.rabbitmq.designmode.single.BadMashSingleClass@3673cfa8
    name:Thread-5com.spring.zhucj.rabbitmq.designmode.single.BadMashSingleClass@3673cfa8
    name:Thread-1com.spring.zhucj.rabbitmq.designmode.single.BadMashSingleClass@3673cfa8
    name:Thread-7com.spring.zhucj.rabbitmq.designmode.single.BadMashSingleClass@3673cfa8
    name:Thread-3com.spring.zhucj.rabbitmq.designmode.single.BadMashSingleClass@3673cfa8
    name:Thread-6com.spring.zhucj.rabbitmq.designmode.single.BadMashSingleClass@3673cfa8
    name:Thread-2com.spring.zhucj.rabbitmq.designmode.single.BadMashSingleClass@3673cfa8
    /**
     * @description: 懒汉模式-单例模式
     * @author: ZhuCJ  80004071
     * @date: 2020-08-19 12:43
     */
    public class IdlerMashSingleClass {
    
        /**
         * ****************懒汉模式*****************
         * 实现方法
         * 1.构造器私有化 (目的:保证只能本类中 才能创建出对象)
         * 2.定义一个空的此对象的静态属性,并用volatile修饰(指定线程共享保证同步性)
         * 3.定义一个静态方法,通过加锁的方式实现,线程之间同步
         * 优点
         * 1.可实现创建的对象唯一性
         * 2.能延迟加载对象,需要时才会创建
         * 缺点
         * 1.代码比较繁琐
         * 2.线程采用加锁处理,对性能影响比较大
         *
         */
    
        public static volatile IdlerMashSingleClass singleClass = null;
    
        /**
         * 私有化构造器
         */
        private IdlerMashSingleClass(){
    
        }
    
        /**
         * 方式一 不加锁,每个线程睡眠1秒后执行创建对象
         * 会发现,单线程下创建对象是唯一的,
         * 如果多个线程同时进入到if(){ }内 还是会创建多个对象
         * 缺点,多线程情况下不能保证唯一
         * @return
         */
        public static IdlerMashSingleClass createSingleOne(){
            if (singleClass == null){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                singleClass = new IdlerMashSingleClass();
            }
            return singleClass;
        }
    
        /**
         * 方式二 结合加锁操作 直接对对方法加锁
         * 可以完美解决,但是影响性能,高并发场景对方法进行加锁会导致访问时间增加
         * 例如:此处如果有1000个用户访问这个方法 每个人大于耗时0.01s 那么最后一个人
         * 访问时间是10s,即访问时间会增加
         * @return
         */
        public synchronized static IdlerMashSingleClass createSingleTwo(){
            if (singleClass == null){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                singleClass = new IdlerMashSingleClass();
            }
            return singleClass;
        }
    
        /**
         * 方式三 对对象进行加上锁
         * 缺点,多线程情况下不能保证唯一
         * 如果多个线程同时进入到if(){ }内 还是会创建多个对象
         * @return
         */
        public static IdlerMashSingleClass createSingleThere(){
            if (singleClass == null){
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (IdlerMashSingleClass.class){
                    singleClass = new IdlerMashSingleClass();
                }
            }
            return singleClass;
        }
    
        /**
         * 方式四 对对象进行加上锁后,在对对象进行判断
         * 可以完美解决,但是影响性能,高并发场景对方法进行加锁会导致访问时间增加
         * @return
         */
        public static IdlerMashSingleClass createSingleFour(){
            if (singleClass == null){
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (IdlerMashSingleClass.class){
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if (singleClass == null){
                        singleClass = new IdlerMashSingleClass();
                    }
                }
    
            }
            return singleClass;
        }
    
    }
    
    
    /**
     * @description: 测试方法
     * @author: ZhuCJ
     * @date: 2020-08-19 13:07
     */
    public class Main {
    
    
        public static void main(String[] args) {
    
            /**
             * 定义10个线程,每个线程休眠0.5s后创建对象,
             * 观察toString方法返回的hashCode值是否相等
             * 注:此处创建线程建议采用线程池
             */
            for (int i =0;i<10;i++){
                new Thread(()->{
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    String name = Thread.currentThread().getName();
                    IdlerMashSingleClass singleOne = IdlerMashSingleClass.createSingleFour();
                    System.out.println("name:"+name +singleOne.toString());
                }).start();
            }
        }
    }
    
    
    
    ---------------------------------------
    ----1.createSingleOne()方法执行结果
    name:Thread-8com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@658afb6a
    name:Thread-4com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@686e97cd
    name:Thread-0com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@6468d2
    name:Thread-6com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@3673cfa8
    name:Thread-1com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@3573fdb0
    name:Thread-2com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@76575e50
    name:Thread-9com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@5a318665
    name:Thread-7com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@6018d1f6
    name:Thread-3com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@47f6725c
    name:Thread-5com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@7d731227
    
    --------2.createSingleTwo()方法执行结果
    
    name:Thread-2com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@9ec32f5
    name:Thread-3com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@9ec32f5
    name:Thread-7com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@9ec32f5
    name:Thread-4com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@9ec32f5
    name:Thread-8com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@9ec32f5
    name:Thread-9com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@9ec32f5
    name:Thread-1com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@9ec32f5
    name:Thread-6com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@9ec32f5
    name:Thread-5com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@9ec32f5
    name:Thread-0com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@9ec32f5
    ----------3.createSingleThree()方法执行结果
    name:Thread-6com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@686e97cd
    name:Thread-2com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@6468d2
    name:Thread-7com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@7d731227
    name:Thread-4com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@76575e50
    name:Thread-3com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@3573fdb0
    name:Thread-5com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@47f6725c
    name:Thread-9com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@6018d1f6
    name:Thread-1com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@9ec32f5
    name:Thread-0com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@1f3f7e6a
    name:Thread-8com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@3673cfa8
    
    ----------4.createSingleFour()方法执行结果
    name:Thread-3com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@6468d2
    name:Thread-7com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@6468d2
    name:Thread-9com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@6468d2
    name:Thread-8com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@6468d2
    name:Thread-5com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@6468d2
    name:Thread-6com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@6468d2
    name:Thread-1com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@6468d2
    name:Thread-2com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@6468d2
    name:Thread-4com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@6468d2
    name:Thread-0com.spring.zhucj.rabbitmq.designmode.single.IdlerMashSingleClass@6468d2
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    /**
     * @description: 懒汉模式-单例模式
     * @author: ZhuCJ  
     * @date: 2020-08-19 12:43
     */
    public class LockIdlerMashSingleClass {
    
        /**
         * 哈哈,这个纯属娱乐
         * 其实JAVA还提供了除关键词synchronized
         * 还可以采用concurrent包下的Lock实例ReentrantLock来实现
         */
    
        /**
         * 定义一个静态的对象,保证唯一性
         */
        public static LockIdlerMashSingleClass singleClass = null;
    
        public static Lock Lock = new ReentrantLock();
        /**
         * 私有化构造器
         */
        private LockIdlerMashSingleClass(){
    
        }
    
        /**
         * 方式一 不加锁
         * 缺点,多线程情况下不能保证唯一
         * 如果多个线程同时进入到if(){ }内 还是会创建多个对象
         * @return
         */
        public static LockIdlerMashSingleClass createSingleOne(){
            if (singleClass == null){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                singleClass = new LockIdlerMashSingleClass();
            }
            return singleClass;
        }
    
        /**
         * 方式二 结合加锁操作
         * 可以完美解决,但是影响性能,高并发场景对方法进行加锁会导致访问时间增加
         * @return
         */
        public static LockIdlerMashSingleClass createSingleTwo(){
            Lock.lock();
            if (singleClass == null){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                singleClass = new LockIdlerMashSingleClass();
            }
            Lock.unlock();
            return singleClass;
        }
    
        /**
         * 方式三 对对象进行加上锁
         * 缺点,多线程情况下不能保证唯一
         * 如果多个线程同时进入到if(){ }内 还是会创建多个对象
         * @return
         */
        public static LockIdlerMashSingleClass createSingleThere(){
            if (singleClass == null){
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Lock.lock();
                singleClass = new LockIdlerMashSingleClass();
                Lock.unlock();
            }
            return singleClass;
        }
    
        /**
         * 方式四 对对象进行加上锁后,在对对象进行判断
         * 可以完美解决,但是影响性能,高并发场景对方法进行加锁会导致访问时间增加
         * @return
         */
        public static LockIdlerMashSingleClass createSingleFour(){
            if (singleClass == null){
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Lock.lock();
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (singleClass == null){
                    singleClass = new LockIdlerMashSingleClass();
                }
                Lock.unlock();
            }
            return singleClass;
        }
    
       
    }

    三.单例模式在项目中的运用场景

    1.如高并发场景下,生成客户订单号必须保证系统中唯一性,正常我们会根据规则写一个ID生成器,然后定义一个方法返回字符串。

      此时需要保证执行这个方法时保证唯一性,所有可以定义成单例模式

    2.对象经常被使用,可能一个对象中多个方法都需要使用。常见是Spring的@AutoWired注入时对象都为单例模式

    3.线程池的使用,线程池使用时,便于管理线程,会定义成全局的。

         

  • 相关阅读:
    Kali视频学习21-25
    20159315《网络攻防实践》第六周学习总结
    Kali视频学习16-20
    20159315《网络攻防实践》第五周学习总结
    一个PE文件的逆向分析
    一个好玩的CTF题
    对于安卓锁屏中知识点小结
    安卓系统安全措施
    安卓防逆向、防动态分析、渗透测试及加固
    安卓组件漏洞防护注意事项
  • 原文地址:https://www.cnblogs.com/zhucj-java/p/13534551.html
Copyright © 2020-2023  润新知