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.线程池的使用,线程池使用时,便于管理线程,会定义成全局的。

     

原文地址:https://www.cnblogs.com/zhucj-java/p/13534551.html