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