【狂神说Java】设计模式 您所在的位置:网站首页 java设计模式视频教程 【狂神说Java】设计模式

【狂神说Java】设计模式

2024-07-09 14:50| 来源: 网络整理| 查看: 265

本文章根据b站狂神说单例模式视频教程整理 b站狂神说单例模式视频链接

彻底玩转单例模式

饿汉式、DCL懒汉式

饿汉式: package com.ph.single; //饿汉使单利模式 public class Hungry { //可能会浪费空间,开辟了空间,却没有使用 private Hungry(){ } private final static Hungry HUNGRY = new Hungry(); public static Hungry getInstance(){ return HUNGRY; } } 懒汉式: 存在多线程并发模式,后面的DCL懒汉式解决并发问题 package com.ph.single; public class LazyMan { private LazyMan(){ System.out.println(Thread.currentThread().getName()+"OK"); } private static LazyMan lazyMan; //双重检测锁模式的 懒汉式单例 DCL懒汉式 public static LazyMan getInstance(){ if(lazyMan==null){ lazyMan = new LazyMan();//不是一个原子性操作 } return lazyMan; } /* * 1.分配内存空间 * 2、执行构造方法,初始化对象 * 3、把这个对象指向者个空间 * * 123 * 132 A * * B //此时lazyMan还没有完成构造 * * */ //多线程并发 public static void main(String[] args) { for (int i = 0; i LazyMan.getInstance(); }).start(); } } } DCL懒汉式:双重检测锁模式的懒汉式单例

注意:synchronized 解决并发问题,但是因为lazyMan = new LazyMan();不是原子性操作(可以分割,见代码注释),可能发生指令重排序的问题,通过volatil来解决

Java 语言提供了 volatile和 synchronized 两个关键字来保证线程之间操作的有序性,volatile 是因为其本身包含“禁止指令重排序”的语义,synchronized 是由“一个变量在同一个时刻只允许一条线程对其进行 lock 操作”这条规则获得的,此规则决定了持有同一个对象锁的两个同步块只能串行执行。原子性就是指该操作是不可再分的。不论是多核还是单核,具有原子性的量,同一时刻只能有一个线程来对它进行操作。简而言之,在整个操作过程中不会被线程调度器中断的操作,都可认为是原子性。比如 a = 1; package com.ph.single; public class LazyMan { private LazyMan(){ System.out.println(Thread.currentThread().getName()+"OK"); } private volatile static LazyMan lazyMan; //双重检测锁模式的 懒汉式单例 DCL懒汉式 public static LazyMan getInstance(){ if(lazyMan==null){ synchronized (LazyMan.class){//synchronized加锁解决多线程下的问题 if(lazyMan == null){ lazyMan = new LazyMan();//不是一个原子性操作 } } } return lazyMan; } /* * 1.分配内存空间 * 2、执行构造方法,初始化对象 * 3、把这个对象指向者个空间 * * 123 * 132 A * * B //此时lazyMan还没有完成构造 * * */ //多线程并发 public static void main(String[] args) { for (int i = 0; i LazyMan.getInstance(); }).start(); } } }

静态内部类

package com.ph.single; //静态内部类 public class Holder { //构造器私有 private Holder(){ } public static Holder getInstance(){ return InnerClass.HOLDER; } public static class InnerClass{ private static final Holder HOLDER = new Holder(); } }

单例不安全,反射破坏(见注释及main方法中反射破解步骤)

package com.ph.single; import java.lang.reflect.Constructor; import java.lang.reflect.Field; //单例懒汉式 //懒汉式单例 public class LazyMan { private static boolean qingjiang = false;//红绿等解决通过反射创建对象(反编译可以破解该方法) private LazyMan(){ synchronized (LazyMan.class){ if (qingjiang==false){ qingjiang = true; }else{ throw new RuntimeException("不要试图使用反射破坏单例"); } } System.out.println(Thread.currentThread().getName()+"OK"); } private volatile static LazyMan lazyMan;//volatile避免指令重排 //双重检测锁模式的 懒汉式单例 DCL懒汉式 public static LazyMan getInstance(){ if(lazyMan==null){ lazyMan = new LazyMan();//不是一个原子性操作 } return lazyMan; } //反射! public static void main(String[] args) throws Exception { //LazyMan instance = LazyMan.getInstance(); Field qingjiang = LazyMan.class.getDeclaredField("qingjiang"); qingjiang.setAccessible(true); Constructor declaredConstructor = LazyMan.class.getDeclaredConstructor(null); declaredConstructor.setAccessible(true);//无视私有的构造器 LazyMan instance1 = declaredConstructor.newInstance(); qingjiang.set(instance1,false); System.out.println(instance1); LazyMan instance2 = declaredConstructor.newInstance(); System.out.println(instance2); } /* * 1.分配内存空间 * 2、执行构造方法,初始化对象 * 3、把这个对象指向者个空间 * * 123 * 132 A * * B //此时lazyMan还没有完成构造 * * */ //多线程并发 /* public static void main(String[] args) { for (int i = 0; i < 10; i++) { new Thread(()->{ LazyMan.getInstance(); }).start(); } }*/ }

枚举:通过反射破解枚举发现不成功: 1、普通的反编译会欺骗开发者,说enum枚举是无参构造 2、实际enum为有参构造(见后面); 3、通过反射破解枚举会发现抛出异常 Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects at java.lang.reflect.Constructor.newInstance(Constructor.java:417) at com.ph.single.Test.main(EnumSingle.java:19)

package com.ph.single; import java.lang.reflect.Constructor; //enmu是什么?本身也是一个class类 public enum EnumSingle { INSTANCE; public EnumSingle getInstance(){ return INSTANCE; } } class Test{ public static void main(String[] args) throws Exception { EnumSingle instance = EnumSingle.INSTANCE; Constructor declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class); declaredConstructor.setAccessible(true); EnumSingle instance2 = declaredConstructor.newInstance(); //java.lang.NoSuchMethodException: com.ph.single.EnumSingle.() System.out.println(instance); System.out.println(instance2); } }

通过idea和jdk自带的反编译枚举如下:

在这里插入图片描述

通过jad反编译枚举的代码如下

在这里插入图片描述

发现枚举是有参构造



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有